diff --git a/.github/build.in.yml b/.github/build.in.yml index 3afe6166a83f42..bab96d693f6b24 100644 --- a/.github/build.in.yml +++ b/.github/build.in.yml @@ -156,6 +156,10 @@ jobs: run: | bash -o pipefail -c "env LEAN_ABORT_ON_PANIC=1 lake build --wfail -KCI" + - name: print the sizes of the oleans + run: | + du .lake/build/lib/Mathlib || echo "This code should be unreachable" + - name: upload cache # We only upload the cache if the build started (whether succeeding, failing, or cancelled) # but not if any earlier step failed or was cancelled. @@ -266,7 +270,7 @@ jobs: with: linters: gcc run: - lake test + lake --iofail test - name: check for unused imports id: shake diff --git a/.github/workflows/PR_summary.yml b/.github/workflows/PR_summary.yml index 09e8747fdd764f..6b854a59292d09 100644 --- a/.github/workflows/PR_summary.yml +++ b/.github/workflows/PR_summary.yml @@ -5,6 +5,7 @@ on: jobs: build: + name: "post-or-update-summary-comment" runs-on: ubuntu-latest steps: diff --git a/.github/workflows/add_label_from_comment.yml b/.github/workflows/add_label_from_comment.yml deleted file mode 100644 index 30a161785134fc..00000000000000 --- a/.github/workflows/add_label_from_comment.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Add "ready-to-merge" and "delegated" label from comment - -on: - issue_comment: - types: [created] - -jobs: - add_ready_to_merge_label: - name: Add ready-to-merge label - 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: - - id: user_permission - uses: actions-cool/check-user-permission@v2 - with: - require: '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 - with: - route: POST /repos/:repository/issues/:issue_number/labels - repository: ${{ github.repository }} - issue_number: ${{ github.event.issue.number }} - labels: '["ready-to-merge"]' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_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.issue.number }}/labels/awaiting-author \ - --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' - - add_delegated_label: - name: Add delegated label - 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: - - id: user_permission - uses: actions-cool/check-user-permission@v2 - with: - require: '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 - with: - route: POST /repos/:repository/issues/:issue_number/labels - repository: ${{ github.repository }} - issue_number: ${{ github.event.issue.number }} - labels: '["delegated"]' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/add_label_from_review.yml b/.github/workflows/add_label_from_review.yml deleted file mode 100644 index 9406866ff214e0..00000000000000 --- a/.github/workflows/add_label_from_review.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Add "ready-to-merge" and "delegated" label from PR review - -on: - pull_request_review: - types: [submitted] - -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), '\nbors r+') || startsWith(github.event.review.body, 'bors merge') || contains(toJSON(github.event.review.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.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 - 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.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 - # (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.review.body, 'bors d') || contains(toJSON(github.event.review.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.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 - 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/add_label_from_review_comment.yml b/.github/workflows/add_label_from_review_comment.yml deleted file mode 100644 index da8b643fb0ee41..00000000000000 --- a/.github/workflows/add_label_from_review_comment.yml +++ /dev/null @@ -1,62 +0,0 @@ -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/bench_summary_comment.yml b/.github/workflows/bench_summary_comment.yml index 6672fb8443e984..fe14ecdc32a79c 100644 --- a/.github/workflows/bench_summary_comment.yml +++ b/.github/workflows/bench_summary_comment.yml @@ -27,7 +27,7 @@ jobs: run: | { cat scripts/bench_summary.lean - printf $'run_cmd BenchAction.addBenchSummaryComment %s "leanprover-community/mathlib4"' "${PR}" + printf $'run_cmd BenchAction.addBenchSummaryComment %s "leanprover-community/mathlib4" %s' "${PR}" "${{ github.run_id }}" } | lake env lean --stdin env: diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 598668edd66d3a..e59f48d2c72675 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -166,6 +166,10 @@ jobs: run: | bash -o pipefail -c "env LEAN_ABORT_ON_PANIC=1 lake build --wfail -KCI" + - name: print the sizes of the oleans + run: | + du .lake/build/lib/Mathlib || echo "This code should be unreachable" + - name: upload cache # We only upload the cache if the build started (whether succeeding, failing, or cancelled) # but not if any earlier step failed or was cancelled. @@ -276,7 +280,7 @@ jobs: with: linters: gcc run: - lake test + lake --iofail test - name: check for unused imports id: shake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4afc15b2f59395..1c778a5720c23f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -173,6 +173,10 @@ jobs: run: | bash -o pipefail -c "env LEAN_ABORT_ON_PANIC=1 lake build --wfail -KCI" + - name: print the sizes of the oleans + run: | + du .lake/build/lib/Mathlib || echo "This code should be unreachable" + - name: upload cache # We only upload the cache if the build started (whether succeeding, failing, or cancelled) # but not if any earlier step failed or was cancelled. @@ -283,7 +287,7 @@ jobs: with: linters: gcc run: - lake test + lake --iofail test - name: check for unused imports id: shake diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 1964290d30bc78..e92f87fd50a686 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -170,6 +170,10 @@ jobs: run: | bash -o pipefail -c "env LEAN_ABORT_ON_PANIC=1 lake build --wfail -KCI" + - name: print the sizes of the oleans + run: | + du .lake/build/lib/Mathlib || echo "This code should be unreachable" + - name: upload cache # We only upload the cache if the build started (whether succeeding, failing, or cancelled) # but not if any earlier step failed or was cancelled. @@ -280,7 +284,7 @@ jobs: with: linters: gcc run: - lake test + lake --iofail test - name: check for unused imports id: shake diff --git a/.github/workflows/discover-lean-pr-testing.yml b/.github/workflows/discover-lean-pr-testing.yml index 9cc2434aea6158..349945a0ee8feb 100644 --- a/.github/workflows/discover-lean-pr-testing.yml +++ b/.github/workflows/discover-lean-pr-testing.yml @@ -24,19 +24,26 @@ jobs: git config --global user.name "github-actions" git config --global user.email "github-actions@github.com" - - name: Read date from lean-toolchain - id: fetch-date + - name: Determine old and new lean-toolchain + id: determine-toolchains run: | - TODAY=$(grep -oP 'nightly-\K\d{4}-\d{2}-\d{2}' lean-toolchain) - echo "TODAY=$TODAY" >> "$GITHUB_ENV" + # `lean-toolchain` contains a string of the form "leanprover/lean4:nightly-2024-11-20" + # We grab the part after the ":" + NEW=$(cut -f2 -d: lean-toolchain) - - name: Set YESTERDAY - id: set-yesterday - run: | - YESTERDAY=$(date -d "$TODAY -1 day" +%Y-%m-%d) - echo "YESTERDAY=$YESTERDAY" >> "$GITHUB_ENV" + # Find the commit hash of the previous change to `lean-toolchain` + PREV_COMMIT=$(git log -2 --format=format:%H -- lean-toolchain | tail -1) + + # Get the contents of `lean-toolchain` from the previous commit + # The "./" in front of the path is important for `git show` + OLD=$(git show "$PREV_COMMIT":./lean-toolchain | cut -f2 -d:) - - name: Clone lean4-nightly repository and get PRs + echo "old=$OLD" + echo "new=$NEW" + echo "old=$OLD" >> "$GITHUB_OUTPUT" + echo "new=$NEW" >> "$GITHUB_OUTPUT" + + - name: Clone lean4 repository and get PRs id: get-prs run: | NIGHTLY_URL="https://github.com/leanprover/lean4-nightly.git" @@ -44,26 +51,44 @@ jobs: # Create a temporary directory for cloning cd "$(mktemp -d)" || exit 1 - # Clone the repository with a depth of 30 (adjust as needed) - git clone --depth 30 "$NIGHTLY_URL" + # Clone the repository with a depth of 1 + git clone --depth 1 "$NIGHTLY_URL" # Navigate to the cloned repository cd lean4-nightly || exit 1 - YESTERDAY="${{ steps.set-yesterday.outputs.yesterday }}" - TODAY="${{ steps.fetch-date.outputs.today }}" - PRS=$(git log --oneline "nightly-$YESTERDAY..nightly-$TODAY" | sed 's/.*(#\([0-9]\+\))$/\1/') + + # Use the OLD and NEW toolchains determined in the previous step + OLD="${{ steps.determine-toolchains.outputs.old }}" + NEW="${{ steps.determine-toolchains.outputs.new }}" + + # Fetch the $OLD tag + git fetch --depth=1 origin tag "$OLD" --no-tags + # Fetch the $NEW tag. + # This will only fetch commits newer than previously fetched commits (ie $OLD) + git fetch origin tag "$NEW" --no-tags + + # Find all commits to lean4 between the $OLD and $NEW toolchains + # and extract the github PR numbers + # (drop anything that doesn't look like a PR number from the final result) + PRS=$(git log --oneline "$OLD..$NEW" | sed 's/.*(#\([0-9]\+\))$/\1/' | grep -E '^[0-9]+$') # Output the PRs echo "$PRS" - echo "prs=$PRS" >> "$GITHUB_OUTPUT" + printf "prs<> "$GITHUB_OUTPUT" - name: Use merged PRs information id: find-branches run: | # Use the PRs from the previous step PRS="${{ steps.get-prs.outputs.prs }}" + echo "=== PRS =========================" + echo "$PRS" echo "$PRS" | tr ' ' '\n' > prs.txt + echo "=== prs.txt =====================" + cat prs.txt MATCHING_BRANCHES=$(git branch -r | grep -f prs.txt) + echo "=== MATCHING_BRANCHES ===========" + echo "$MATCHING_BRANCHES" # Initialize an empty variable to store branches with relevant diffs RELEVANT_BRANCHES="" @@ -76,25 +101,26 @@ jobs: # Check if the diff contains files other than the specified ones if echo "$DIFF_FILES" | grep -v -e 'lake-manifest.json' -e 'lakefile.lean' -e 'lean-toolchain'; then # If it does, add the branch to RELEVANT_BRANCHES - RELEVANT_BRANCHES="$RELEVANT_BRANCHES $BRANCH" + RELEVANT_BRANCHES="$RELEVANT_BRANCHES"$'\n- '"$BRANCH" fi done # Output the relevant branches + echo "=== RELEVANT_BRANCHES ===========" echo "'$RELEVANT_BRANCHES'" - echo "branches=$RELEVANT_BRANCHES" >> "$GITHUB_OUTPUT" + printf "branches<> "$GITHUB_OUTPUT" - name: Check if there are relevant branches id: check-branches run: | if [ -z "${{ steps.find-branches.outputs.branches }}" ]; then - echo "no_branches=true" >> "$GITHUB_ENV" + echo "branches_exist=false" >> "$GITHUB_ENV" else - echo "no_branches=false" >> "$GITHUB_ENV" + echo "branches_exist=true" >> "$GITHUB_ENV" fi - name: Send message on Zulip - if: env.no_branches == 'false' + if: env.branches_exist == 'true' uses: zulip/github-actions-zulip/send-message@v1 with: api-key: ${{ secrets.ZULIP_API_KEY }} diff --git a/.github/workflows/maintainer_bors.yml b/.github/workflows/maintainer_bors.yml new file mode 100644 index 00000000000000..10a12e5f3a439f --- /dev/null +++ b/.github/workflows/maintainer_bors.yml @@ -0,0 +1,118 @@ +name: Add "ready-to-merge" and "delegated" label + +# triggers the action when +on: + # the PR receives a comment + issue_comment: + types: [created] + # the PR receives a review + pull_request_review: + # whether or not it is accompanied by a comment + types: [submitted] + # the PR receives a review comment + pull_request_review_comment: + types: [created] + +jobs: + add_ready_to_merge_label: + # we set some variables. The ones of the form `${{ X }}${{ Y }}` are typically not + # both set simultaneously: depending on the event that triggers the PR, usually only one is set + env: + AUTHOR: ${{ github.event.comment.user.login }}${{ github.event.review.user.login }} + COMMENT_EVENT: ${{ github.event.comment.body }} + COMMENT_REVIEW: ${{ github.event.review.body }} + name: Add ready-to-merge or delegated label + runs-on: ubuntu-latest + steps: + - name: Find bors merge/delegate + id: merge_or_delegate + run: | + COMMENT="${COMMENT_EVENT}${COMMENT_REVIEW}" + # we strip `\r` since line endings from GitHub contain this character + COMMENT="${COMMENT//$'\r'/}" + # for debugging, we print some information + printf '%s' "${COMMENT}" | hexdump -cC + printf 'Comment:"%s"\n' "${COMMENT}" + m_or_d="$(printf '%s' "${COMMENT}" | + sed -n 's=^bors *\(merge\|r+\) *$=ready-to-merge=p; s=^bors *d.*=delegated=p' | head -1)" + + printf $'"bors delegate" or "bors merge" found? \'%s\'\n' "${m_or_d}" + printf $'AUTHOR: \'%s\'\n' "${AUTHOR}" + printf $'PR_NUMBER: \'%s\'\n' "${{ github.event.issue.number }}${{ github.event.pull_request.number }}" + printf $'%s' "${{ github.event.issue.number }}${{ github.event.pull_request.number }}" | hexdump -cC + + printf $'mOrD=%s\n' "${m_or_d}" >> "${GITHUB_OUTPUT}" + if [ "${AUTHOR}" == 'leanprover-community-mathlib4-bot' ] || + [ "${AUTHOR}" == 'leanprover-community-bot-assistant' ] + then + printf $'bot=true\n' + printf $'bot=true\n' >> "${GITHUB_OUTPUT}" + else + printf $'bot=false\n' + printf $'bot=false\n' >> "${GITHUB_OUTPUT}" + fi + + - name: Check whether user is a mathlib admin + id: user_permission + if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' }} + uses: actions-cool/check-user-permission@v2 + with: + require: 'admin' + + - name: Add ready-to-merge or delegated label + id: add_label + if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' && + ( steps.user_permission.outputs.require-result == 'true' || + steps.merge_or_delegate.outputs.bot == 'true' ) }} + uses: octokit/request-action@v2.x + with: + route: POST /repos/:repository/issues/:issue_number/labels + repository: ${{ github.repository }} + issue_number: ${{ github.event.issue.number }}${{ github.event.pull_request.number }} + labels: '["${{ steps.merge_or_delegate.outputs.mOrD }}"]' + env: + GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} + + - if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' && + ( steps.user_permission.outputs.require-result == 'true' || + steps.merge_or_delegate.outputs.bot == 'true' ) }} + 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.issue.number }}${{ github.event.pull_request.number }}/labels/awaiting-author" \ + --header 'authorization: Bearer ${{ secrets.TRIAGE_TOKEN }}' + + - name: Set up Python + if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' && + ( steps.user_permission.outputs.require-result == 'true' || + steps.merge_or_delegate.outputs.bot == 'true' ) }} + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install dependencies + if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' && + ( steps.user_permission.outputs.require-result == 'true' || + steps.merge_or_delegate.outputs.bot == 'true' ) }} + run: | + python -m pip install --upgrade pip + pip install zulip + + - uses: actions/checkout@v4 + with: + sparse-checkout: | + scripts/zulip_emoji_merge_delegate.py + + - name: Run Zulip Emoji Merge Delegate Script + if: ${{ ! steps.merge_or_delegate.outputs.mOrD == '' && + ( steps.user_permission.outputs.require-result == 'true' || + steps.merge_or_delegate.outputs.bot == 'true' ) }} + env: + ZULIP_API_KEY: ${{ secrets.ZULIP_API_KEY }} + ZULIP_EMAIL: github-mathlib4-bot@leanprover.zulipchat.com + ZULIP_SITE: https://leanprover.zulipchat.com + run: | + python scripts/zulip_emoji_merge_delegate.py "$ZULIP_API_KEY" "$ZULIP_EMAIL" "$ZULIP_SITE" "${{ steps.merge_or_delegate.outputs.mOrD }}" "${{ github.event.issue.number }}${{ github.event.pull_request.number }}" diff --git a/.github/workflows/maintainer_merge.yml b/.github/workflows/maintainer_merge.yml index 87ab7583093b77..8be16fcfc4ed63 100644 --- a/.github/workflows/maintainer_merge.yml +++ b/.github/workflows/maintainer_merge.yml @@ -42,7 +42,8 @@ jobs: printf 'Comment:"%s"\n' "${COMMENT}" m_or_d="$(printf '%s' "${COMMENT}" | - sed -n 's=^maintainer *\(merge\|delegate\) *$=\1=p' | head -1)" + # captures `maintainer merge/delegate` as well as an optional `?`, ignoring subsequent spaces + sed -n 's=^maintainer *\(merge\|delegate\)\(?\?\) *$=\1\2=p' | head -1)" printf $'"maintainer delegate" or "maintainer merge" found? \'%s\'\n' "${m_or_d}" diff --git a/.github/workflows/sync_closed_tasks.yaml b/.github/workflows/sync_closed_tasks.yaml index 9c73e7e8a24c6e..6c5383d62099cf 100644 --- a/.github/workflows/sync_closed_tasks.yaml +++ b/.github/workflows/sync_closed_tasks.yaml @@ -12,6 +12,7 @@ on: jobs: build: + name: "Cross off linked issues" runs-on: ubuntu-latest steps: - name: Cross off any linked issue and PR references diff --git a/.github/workflows/update_dependencies.yml b/.github/workflows/update_dependencies.yml index 48111dc1fac1d1..a8ea709c6de9ee 100644 --- a/.github/workflows/update_dependencies.yml +++ b/.github/workflows/update_dependencies.yml @@ -40,6 +40,13 @@ jobs: # Only return if PR is still open filterOutClosed: true + - name: Print PR, if found + run: echo "Found PR ${prNumber} at ${prUrl}" + if: steps.PR.outputs.pr_found == 'true' + env: + prNumber: ${{ steps.PR.outputs.number }} + prUrl: ${{ steps.PR.outputs.pr_url }} + - name: Configure Git User if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} run: | diff --git a/.github/workflows/zulip_emoji_merge_delegate.yaml b/.github/workflows/zulip_emoji_merge_delegate.yaml index e44b4d07004d98..3de0bc2fd1aa4b 100644 --- a/.github/workflows/zulip_emoji_merge_delegate.yaml +++ b/.github/workflows/zulip_emoji_merge_delegate.yaml @@ -1,19 +1,19 @@ name: Zulip Emoji Merge Delegate on: - schedule: - - cron: '0 * * * *' # Runs every hour + push: + branches: + - master jobs: - zulip-emoji-merge-delegate: + zulip-emoji-merged: runs-on: ubuntu-latest steps: - name: Checkout mathlib repository uses: actions/checkout@v4 with: - sparse-checkout: | - scripts + fetch-depth: 0 # donwload the full repository - name: Set up Python uses: actions/setup-python@v5 @@ -30,6 +30,13 @@ jobs: ZULIP_API_KEY: ${{ secrets.ZULIP_API_KEY }} ZULIP_EMAIL: github-mathlib4-bot@leanprover.zulipchat.com ZULIP_SITE: https://leanprover.zulipchat.com - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - python scripts/zulip_emoji_merge_delegate.py "$ZULIP_API_KEY" "$ZULIP_EMAIL" "$ZULIP_SITE" "$GITHUB_TOKEN" + # scan the commits of the past 10 minutes, assuming that the timezone of the current machine + # is the same that performed the commit + git log --since="10 minutes ago" --pretty=oneline + + printf $'Scanning commits:\n%s\n\nContinuing\n' "$(git log --since="10 minutes ago" --pretty=oneline)" + while read -r pr_number; do + printf $'Running the python script with pr "%s"\n' "${pr_number}" + python scripts/zulip_emoji_merge_delegate.py "$ZULIP_API_KEY" "$ZULIP_EMAIL" "$ZULIP_SITE" "[Merged by Bors]" "${pr_number}" + done < <(git log --oneline -n 10 | awk -F# '{ gsub(/)$/, ""); print $NF}') diff --git a/Archive/Hairer.lean b/Archive/Hairer.lean index e9b91c32132a8a..6abb80f2542206 100644 --- a/Archive/Hairer.lean +++ b/Archive/Hairer.lean @@ -26,6 +26,7 @@ noncomputable section open Metric Set MeasureTheory open MvPolynomial hiding support open Function hiding eval +open scoped ContDiff variable {ι : Type*} [Fintype ι] @@ -110,7 +111,7 @@ lemma inj_L : Injective (L ι) := apply subset_closure lemma hairer (N : ℕ) (ι : Type*) [Fintype ι] : - ∃ (ρ : EuclideanSpace ℝ ι → ℝ), tsupport ρ ⊆ closedBall 0 1 ∧ ContDiff ℝ ⊤ ρ ∧ + ∃ (ρ : EuclideanSpace ℝ ι → ℝ), tsupport ρ ⊆ closedBall 0 1 ∧ ContDiff ℝ ∞ ρ ∧ ∀ (p : MvPolynomial ι ℝ), p.totalDegree ≤ N → ∫ x : EuclideanSpace ℝ ι, eval x p • ρ x = eval 0 p := by have := (inj_L ι).comp (restrictTotalDegree ι ℝ N).injective_subtype diff --git a/Archive/Imo/Imo1998Q2.lean b/Archive/Imo/Imo1998Q2.lean index 5e501114206bac..94378d663c5209 100644 --- a/Archive/Imo/Imo1998Q2.lean +++ b/Archive/Imo/Imo1998Q2.lean @@ -202,7 +202,7 @@ end theorem clear_denominators {a b k : ℕ} (ha : 0 < a) (hb : 0 < b) : (b - 1 : ℚ) / (2 * b) ≤ k / a ↔ ((b : ℕ) - 1) * a ≤ k * (2 * b) := by - rw [div_le_div_iff] + rw [div_le_div_iff₀] -- Porting note: proof used to finish with `<;> norm_cast <;> simp [ha, hb]` · convert Nat.cast_le (α := ℚ) · aesop diff --git a/Archive/Imo/Imo2001Q2.lean b/Archive/Imo/Imo2001Q2.lean index a7e630353b751d..98dc9266722ffb 100644 --- a/Archive/Imo/Imo2001Q2.lean +++ b/Archive/Imo/Imo2001Q2.lean @@ -34,7 +34,7 @@ namespace Imo2001Q2 theorem bound (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a ^ 4 / (a ^ 4 + b ^ 4 + c ^ 4) ≤ a ^ 3 / sqrt ((a ^ 3) ^ 2 + ↑8 * b ^ 3 * c ^ 3) := by - rw [div_le_div_iff (by positivity) (by positivity)] + rw [div_le_div_iff₀ (by positivity) (by positivity)] calc a ^ 4 * sqrt ((a ^ 3) ^ 2 + (8:ℝ) * b ^ 3 * c ^ 3) = a ^ 3 * (a * sqrt ((a ^ 3) ^ 2 + (8:ℝ) * b ^ 3 * c ^ 3)) := by ring _ ≤ a ^ 3 * (a ^ 4 + b ^ 4 + c ^ 4) := ?_ diff --git a/Archive/Imo/Imo2008Q2.lean b/Archive/Imo/Imo2008Q2.lean index 0340c3f70479b3..41687a4a977a07 100644 --- a/Archive/Imo/Imo2008Q2.lean +++ b/Archive/Imo/Imo2008Q2.lean @@ -106,12 +106,7 @@ theorem imo2008_q2b : Set.Infinite rationalSolutions := by exact ⟨rfl, rfl, rfl⟩ · have hg : -z = g (x, y, z) := rfl rw [hg, hz_def]; ring - have h₂ : q < t * (t + 1) := by - calc - q < q + 1 := by linarith - _ ≤ t := le_max_left (q + 1) 1 - _ ≤ t + t ^ 2 := by linarith [sq_nonneg t] - _ = t * (t + 1) := by ring + have h₂ : q < t * (t + 1) := by linarith [sq_nonneg t, le_max_left (q + 1) 1] exact ⟨h₁, h₂⟩ have hK_inf : Set.Infinite K := by intro h; apply hK_not_bdd; exact Set.Finite.bddAbove h exact hK_inf.of_image g diff --git a/Archive/Imo/Imo2013Q5.lean b/Archive/Imo/Imo2013Q5.lean index 225e64ae35b02b..eb996b73633a40 100644 --- a/Archive/Imo/Imo2013Q5.lean +++ b/Archive/Imo/Imo2013Q5.lean @@ -65,15 +65,9 @@ theorem le_of_all_pow_lt_succ' {x y : ℝ} (hx : 1 < x) (hy : 0 < y) refine le_of_all_pow_lt_succ hx ?_ h by_contra! hy'' : y ≤ 1 -- Then there exists y' such that 0 < y ≤ 1 < y' < x. - let y' := (x + 1) / 2 - have h_y'_lt_x : y' < x := - calc - (x + 1) / 2 < x * 2 / 2 := by linarith - _ = x := by field_simp - have h1_lt_y' : 1 < y' := - calc - 1 = 1 * 2 / 2 := by field_simp - _ < (x + 1) / 2 := by linarith + have h_y'_lt_x : (x + 1) / 2 < x := by linarith + have h1_lt_y' : 1 < (x + 1) / 2 := by linarith + set y' := (x + 1) / 2 have h_y_lt_y' : y < y' := by linarith have hh : ∀ n, 0 < n → x ^ n - 1 < y' ^ n := by intro n hn diff --git a/Archive/Imo/Imo2024Q5.lean b/Archive/Imo/Imo2024Q5.lean index 7b090f48cc987e..5cbdf23de02f8d 100644 --- a/Archive/Imo/Imo2024Q5.lean +++ b/Archive/Imo/Imo2024Q5.lean @@ -509,7 +509,7 @@ lemma Strategy.play_two (s : Strategy N) (m : MonsterData N) {k : ℕ} (hk : 2 < fin_cases i · rfl · have h : (1 : Fin 2) = Fin.last 1 := rfl - simp only [Fin.snoc_zero, Nat.reduceAdd, Fin.mk_one, Fin.isValue, Matrix.cons_val_one, + simp only [Fin.snoc_zero, Nat.reduceAdd, Fin.mk_one, Fin.isValue, id_eq, Matrix.cons_val_one, Matrix.head_cons] simp only [h, Fin.snoc_last] convert rfl diff --git a/Counterexamples/DirectSumIsInternal.lean b/Counterexamples/DirectSumIsInternal.lean index db6389188d856a..7632fb6414a312 100644 --- a/Counterexamples/DirectSumIsInternal.lean +++ b/Counterexamples/DirectSumIsInternal.lean @@ -12,10 +12,10 @@ import Mathlib.Tactic.FinCases # Not all complementary decompositions of a module over a semiring make up a direct sum This shows that while `ℤ≤0` and `ℤ≥0` are complementary `ℕ`-submodules of `ℤ`, which in turn -implies as a collection they are `CompleteLattice.Independent` and that they span all of `ℤ`, they +implies as a collection they are `iSupIndep` and that they span all of `ℤ`, they do not form a decomposition into a direct sum. -This file demonstrates why `DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top` must +This file demonstrates why `DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top` must take `Ring R` and not `Semiring R`. -/ @@ -57,9 +57,9 @@ theorem withSign.isCompl : IsCompl ℤ≥0 ℤ≤0 := by · exact Submodule.mem_sup_left (mem_withSign_one.mpr hp) · exact Submodule.mem_sup_right (mem_withSign_neg_one.mpr hn) -def withSign.independent : CompleteLattice.Independent withSign := by +def withSign.independent : iSupIndep withSign := by apply - (CompleteLattice.independent_pair UnitsInt.one_ne_neg_one _).mpr withSign.isCompl.disjoint + (iSupIndep_pair UnitsInt.one_ne_neg_one _).mpr withSign.isCompl.disjoint intro i fin_cases i <;> simp diff --git a/Mathlib.lean b/Mathlib.lean index 7566572fa39e6f..5785a8dab0524a 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -164,6 +164,7 @@ import Mathlib.Algebra.CharP.ExpChar import Mathlib.Algebra.CharP.IntermediateField import Mathlib.Algebra.CharP.Invertible import Mathlib.Algebra.CharP.Lemmas +import Mathlib.Algebra.CharP.LinearMaps import Mathlib.Algebra.CharP.LocalRing import Mathlib.Algebra.CharP.MixedCharZero import Mathlib.Algebra.CharP.Pi @@ -222,6 +223,7 @@ import Mathlib.Algebra.Field.Subfield.Defs import Mathlib.Algebra.Field.ULift import Mathlib.Algebra.Free import Mathlib.Algebra.FreeAlgebra +import Mathlib.Algebra.FreeAlgebra.Cardinality import Mathlib.Algebra.FreeMonoid.Basic import Mathlib.Algebra.FreeMonoid.Count import Mathlib.Algebra.FreeMonoid.Symbols @@ -269,6 +271,7 @@ import Mathlib.Algebra.Group.Fin.Basic import Mathlib.Algebra.Group.Fin.Tuple import Mathlib.Algebra.Group.FiniteSupport import Mathlib.Algebra.Group.ForwardDiff +import Mathlib.Algebra.Group.Graph import Mathlib.Algebra.Group.Hom.Basic import Mathlib.Algebra.Group.Hom.CompTypeclasses import Mathlib.Algebra.Group.Hom.Defs @@ -280,8 +283,12 @@ import Mathlib.Algebra.Group.Int import Mathlib.Algebra.Group.Invertible.Basic import Mathlib.Algebra.Group.Invertible.Defs import Mathlib.Algebra.Group.MinimalAxioms -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic +import Mathlib.Algebra.Group.Nat.Even +import Mathlib.Algebra.Group.Nat.TypeTags +import Mathlib.Algebra.Group.Nat.Units import Mathlib.Algebra.Group.NatPowAssoc +import Mathlib.Algebra.Group.Operations import Mathlib.Algebra.Group.Opposite import Mathlib.Algebra.Group.PNatPowAssoc import Mathlib.Algebra.Group.Pi.Basic @@ -289,7 +296,10 @@ 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.BigOperators import Mathlib.Algebra.Group.Pointwise.Set.Card +import Mathlib.Algebra.Group.Pointwise.Set.Finite +import Mathlib.Algebra.Group.Pointwise.Set.ListOfFn import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Semiconj.Basic import Mathlib.Algebra.Group.Semiconj.Defs @@ -298,6 +308,9 @@ import Mathlib.Algebra.Group.Subgroup.Actions import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.Algebra.Group.Subgroup.Defs import Mathlib.Algebra.Group.Subgroup.Finite +import Mathlib.Algebra.Group.Subgroup.Ker +import Mathlib.Algebra.Group.Subgroup.Lattice +import Mathlib.Algebra.Group.Subgroup.Map import Mathlib.Algebra.Group.Subgroup.MulOpposite import Mathlib.Algebra.Group.Subgroup.MulOppositeLemmas import Mathlib.Algebra.Group.Subgroup.Order @@ -318,7 +331,9 @@ import Mathlib.Algebra.Group.Subsemigroup.Membership import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.Group.Support import Mathlib.Algebra.Group.Translate -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Group.TypeTags.Basic +import Mathlib.Algebra.Group.TypeTags.Finite +import Mathlib.Algebra.Group.TypeTags.Hom import Mathlib.Algebra.Group.ULift import Mathlib.Algebra.Group.UniqueProds.Basic import Mathlib.Algebra.Group.UniqueProds.VectorSpace @@ -419,6 +434,7 @@ import Mathlib.Algebra.Homology.ImageToKernel import Mathlib.Algebra.Homology.Linear import Mathlib.Algebra.Homology.LocalCohomology import Mathlib.Algebra.Homology.Localization +import Mathlib.Algebra.Homology.Monoidal import Mathlib.Algebra.Homology.Opposite import Mathlib.Algebra.Homology.QuasiIso import Mathlib.Algebra.Homology.Refinements @@ -504,6 +520,7 @@ import Mathlib.Algebra.Module.Equiv.Basic import Mathlib.Algebra.Module.Equiv.Defs import Mathlib.Algebra.Module.Equiv.Opposite import Mathlib.Algebra.Module.FinitePresentation +import Mathlib.Algebra.Module.FreeLocus import Mathlib.Algebra.Module.GradedModule import Mathlib.Algebra.Module.Hom import Mathlib.Algebra.Module.Injective @@ -520,6 +537,7 @@ import Mathlib.Algebra.Module.LocalizedModule.Int import Mathlib.Algebra.Module.LocalizedModule.IsLocalization import Mathlib.Algebra.Module.LocalizedModule.Submodule import Mathlib.Algebra.Module.MinimalAxioms +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Module.PID import Mathlib.Algebra.Module.Pi @@ -533,6 +551,7 @@ import Mathlib.Algebra.Module.Presentation.Tautological import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Module.Projective import Mathlib.Algebra.Module.Rat +import Mathlib.Algebra.Module.RingHom import Mathlib.Algebra.Module.SnakeLemma import Mathlib.Algebra.Module.Submodule.Basic import Mathlib.Algebra.Module.Submodule.Bilinear @@ -636,6 +655,7 @@ import Mathlib.Algebra.Order.Group.CompleteLattice import Mathlib.Algebra.Order.Group.Cone import Mathlib.Algebra.Order.Group.Defs import Mathlib.Algebra.Order.Group.DenselyOrdered +import Mathlib.Algebra.Order.Group.Finset import Mathlib.Algebra.Order.Group.Indicator import Mathlib.Algebra.Order.Group.InjSurj import Mathlib.Algebra.Order.Group.Instances @@ -648,6 +668,7 @@ 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.Pointwise.Interval import Mathlib.Algebra.Order.Group.PosPart import Mathlib.Algebra.Order.Group.Prod import Mathlib.Algebra.Order.Group.Synonym @@ -658,6 +679,7 @@ 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.Finset import Mathlib.Algebra.Order.GroupWithZero.Submonoid import Mathlib.Algebra.Order.GroupWithZero.Synonym import Mathlib.Algebra.Order.GroupWithZero.Unbundled @@ -710,6 +732,7 @@ import Mathlib.Algebra.Order.Nonneg.Ring import Mathlib.Algebra.Order.Pi import Mathlib.Algebra.Order.Positive.Field import Mathlib.Algebra.Order.Positive.Ring +import Mathlib.Algebra.Order.Quantale import Mathlib.Algebra.Order.Rearrangement import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Algebra.Order.Ring.Basic @@ -717,7 +740,6 @@ import Mathlib.Algebra.Order.Ring.Canonical import Mathlib.Algebra.Order.Ring.Cast import Mathlib.Algebra.Order.Ring.Cone import Mathlib.Algebra.Order.Ring.Defs -import Mathlib.Algebra.Order.Ring.Finset import Mathlib.Algebra.Order.Ring.InjSurj import Mathlib.Algebra.Order.Ring.Int import Mathlib.Algebra.Order.Ring.Nat @@ -910,6 +932,7 @@ import Mathlib.AlgebraicGeometry.AffineScheme import Mathlib.AlgebraicGeometry.AffineSpace import Mathlib.AlgebraicGeometry.Cover.MorphismProperty import Mathlib.AlgebraicGeometry.Cover.Open +import Mathlib.AlgebraicGeometry.Cover.Over import Mathlib.AlgebraicGeometry.EllipticCurve.Affine import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Basic import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Degree @@ -938,6 +961,7 @@ import Mathlib.AlgebraicGeometry.Morphisms.Finite import Mathlib.AlgebraicGeometry.Morphisms.FinitePresentation import Mathlib.AlgebraicGeometry.Morphisms.FiniteType import Mathlib.AlgebraicGeometry.Morphisms.Immersion +import Mathlib.AlgebraicGeometry.Morphisms.Integral import Mathlib.AlgebraicGeometry.Morphisms.IsIso import Mathlib.AlgebraicGeometry.Morphisms.OpenImmersion import Mathlib.AlgebraicGeometry.Morphisms.Preimmersion @@ -947,6 +971,7 @@ import Mathlib.AlgebraicGeometry.Morphisms.QuasiSeparated import Mathlib.AlgebraicGeometry.Morphisms.RingHomProperties import Mathlib.AlgebraicGeometry.Morphisms.Separated import Mathlib.AlgebraicGeometry.Morphisms.Smooth +import Mathlib.AlgebraicGeometry.Morphisms.SurjectiveOnStalks import Mathlib.AlgebraicGeometry.Morphisms.UnderlyingMap import Mathlib.AlgebraicGeometry.Morphisms.UniversallyClosed import Mathlib.AlgebraicGeometry.Morphisms.UniversallyInjective @@ -961,6 +986,7 @@ import Mathlib.AlgebraicGeometry.PrimeSpectrum.Module import Mathlib.AlgebraicGeometry.PrimeSpectrum.Noetherian import Mathlib.AlgebraicGeometry.PrimeSpectrum.TensorProduct import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Basic +import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Proper import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Scheme import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Topology @@ -1008,6 +1034,7 @@ import Mathlib.AlgebraicTopology.FundamentalGroupoid.PUnit import Mathlib.AlgebraicTopology.FundamentalGroupoid.Product import Mathlib.AlgebraicTopology.FundamentalGroupoid.SimplyConnected import Mathlib.AlgebraicTopology.MooreComplex +import Mathlib.AlgebraicTopology.Quasicategory.Basic import Mathlib.AlgebraicTopology.SimplexCategory import Mathlib.AlgebraicTopology.SimplicialCategory.Basic import Mathlib.AlgebraicTopology.SimplicialCategory.SimplicialObject @@ -1017,7 +1044,6 @@ import Mathlib.AlgebraicTopology.SimplicialSet.KanComplex import Mathlib.AlgebraicTopology.SimplicialSet.Monoidal import Mathlib.AlgebraicTopology.SimplicialSet.Nerve import Mathlib.AlgebraicTopology.SimplicialSet.Path -import Mathlib.AlgebraicTopology.SimplicialSet.Quasicategory import Mathlib.AlgebraicTopology.SimplicialSet.StrictSegal import Mathlib.AlgebraicTopology.SingularSet import Mathlib.AlgebraicTopology.SplitSimplicialObject @@ -1167,6 +1193,7 @@ import Mathlib.Analysis.Calculus.SmoothSeries import Mathlib.Analysis.Calculus.TangentCone import Mathlib.Analysis.Calculus.Taylor import Mathlib.Analysis.Calculus.UniformLimitsDeriv +import Mathlib.Analysis.Calculus.VectorField import Mathlib.Analysis.Complex.AbelLimit import Mathlib.Analysis.Complex.AbsMax import Mathlib.Analysis.Complex.Angle @@ -1746,6 +1773,7 @@ import Mathlib.CategoryTheory.Limits.Connected import Mathlib.CategoryTheory.Limits.Constructions.BinaryProducts import Mathlib.CategoryTheory.Limits.Constructions.EpiMono import Mathlib.CategoryTheory.Limits.Constructions.Equalizers +import Mathlib.CategoryTheory.Limits.Constructions.EventuallyConstant import Mathlib.CategoryTheory.Limits.Constructions.Filtered import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts import Mathlib.CategoryTheory.Limits.Constructions.LimitsOfProductsAndEqualizers @@ -2137,6 +2165,7 @@ import Mathlib.Combinatorics.Enumerative.Composition import Mathlib.Combinatorics.Enumerative.DoubleCounting import Mathlib.Combinatorics.Enumerative.DyckWord import Mathlib.Combinatorics.Enumerative.IncidenceAlgebra +import Mathlib.Combinatorics.Enumerative.InclusionExclusion import Mathlib.Combinatorics.Enumerative.Partition import Mathlib.Combinatorics.HalesJewett import Mathlib.Combinatorics.Hall.Basic @@ -2424,6 +2453,7 @@ import Mathlib.Data.Finsupp.Fintype import Mathlib.Data.Finsupp.Indicator import Mathlib.Data.Finsupp.Interval import Mathlib.Data.Finsupp.Lex +import Mathlib.Data.Finsupp.MonomialOrder import Mathlib.Data.Finsupp.Multiset import Mathlib.Data.Finsupp.NeLocus import Mathlib.Data.Finsupp.Notation @@ -2489,7 +2519,6 @@ 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 import Mathlib.Data.List.Chain @@ -2802,11 +2831,7 @@ 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.BigOperators -import Mathlib.Data.Set.Pointwise.Finite -import Mathlib.Data.Set.Pointwise.Interval import Mathlib.Data.Set.Pointwise.Iterate -import Mathlib.Data.Set.Pointwise.ListOfFn import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Data.Set.Pointwise.Support import Mathlib.Data.Set.Prod @@ -2874,6 +2899,7 @@ import Mathlib.Deprecated.Combinator import Mathlib.Deprecated.Equiv import Mathlib.Deprecated.Group import Mathlib.Deprecated.HashMap +import Mathlib.Deprecated.LazyList import Mathlib.Deprecated.Logic import Mathlib.Deprecated.MinMax import Mathlib.Deprecated.NatLemmas @@ -2911,6 +2937,7 @@ import Mathlib.FieldTheory.AbsoluteGaloisGroup import Mathlib.FieldTheory.Adjoin import Mathlib.FieldTheory.AlgebraicClosure import Mathlib.FieldTheory.AxGrothendieck +import Mathlib.FieldTheory.CardinalEmb import Mathlib.FieldTheory.Cardinality import Mathlib.FieldTheory.ChevalleyWarning import Mathlib.FieldTheory.Differential.Basic @@ -2932,6 +2959,8 @@ import Mathlib.FieldTheory.IsAlgClosed.Classification import Mathlib.FieldTheory.IsAlgClosed.Spectrum import Mathlib.FieldTheory.IsPerfectClosure import Mathlib.FieldTheory.IsSepClosed +import Mathlib.FieldTheory.Isaacs +import Mathlib.FieldTheory.JacobsonNoether import Mathlib.FieldTheory.KrullTopology import Mathlib.FieldTheory.KummerExtension import Mathlib.FieldTheory.Laurent @@ -3382,6 +3411,7 @@ import Mathlib.LinearAlgebra.Reflection import Mathlib.LinearAlgebra.RootSystem.Basic import Mathlib.LinearAlgebra.RootSystem.Defs import Mathlib.LinearAlgebra.RootSystem.Finite.CanonicalBilinear +import Mathlib.LinearAlgebra.RootSystem.Finite.Nondegenerate import Mathlib.LinearAlgebra.RootSystem.Hom import Mathlib.LinearAlgebra.RootSystem.OfBilinear import Mathlib.LinearAlgebra.RootSystem.RootPairingCat @@ -3757,6 +3787,7 @@ import Mathlib.NumberTheory.LSeries.Linearity import Mathlib.NumberTheory.LSeries.MellinEqDirichlet import Mathlib.NumberTheory.LSeries.Nonvanishing import Mathlib.NumberTheory.LSeries.Positivity +import Mathlib.NumberTheory.LSeries.PrimesInAP import Mathlib.NumberTheory.LSeries.RiemannZeta import Mathlib.NumberTheory.LSeries.ZMod import Mathlib.NumberTheory.LegendreSymbol.AddCharacter @@ -3783,6 +3814,7 @@ import Mathlib.NumberTheory.ModularForms.JacobiTheta.Bounds import Mathlib.NumberTheory.ModularForms.JacobiTheta.Manifold import Mathlib.NumberTheory.ModularForms.JacobiTheta.OneVariable import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable +import Mathlib.NumberTheory.ModularForms.LevelOne import Mathlib.NumberTheory.ModularForms.QExpansion import Mathlib.NumberTheory.ModularForms.SlashActions import Mathlib.NumberTheory.ModularForms.SlashInvariantForms @@ -3891,6 +3923,7 @@ import Mathlib.Order.CompletePartialOrder import Mathlib.Order.CompleteSublattice import Mathlib.Order.Concept import Mathlib.Order.ConditionallyCompleteLattice.Basic +import Mathlib.Order.ConditionallyCompleteLattice.Defs import Mathlib.Order.ConditionallyCompleteLattice.Finset import Mathlib.Order.ConditionallyCompleteLattice.Group import Mathlib.Order.ConditionallyCompleteLattice.Indexed @@ -3927,6 +3960,7 @@ import Mathlib.Order.Filter.ENNReal import Mathlib.Order.Filter.EventuallyConst import Mathlib.Order.Filter.Extr import Mathlib.Order.Filter.FilterProduct +import Mathlib.Order.Filter.Finite import Mathlib.Order.Filter.Germ.Basic import Mathlib.Order.Filter.Germ.OrderedMonoid import Mathlib.Order.Filter.IndicatorFunction @@ -4183,6 +4217,7 @@ import Mathlib.RingTheory.Derivation.ToSquareZero import Mathlib.RingTheory.DiscreteValuationRing.Basic import Mathlib.RingTheory.DiscreteValuationRing.TFAE import Mathlib.RingTheory.Discriminant +import Mathlib.RingTheory.DividedPowers.Basic import Mathlib.RingTheory.DualNumber import Mathlib.RingTheory.EisensteinCriterion import Mathlib.RingTheory.EssentialFiniteness @@ -4293,6 +4328,7 @@ import Mathlib.RingTheory.LaurentSeries import Mathlib.RingTheory.LinearDisjoint import Mathlib.RingTheory.LittleWedderburn import Mathlib.RingTheory.LocalProperties.Basic +import Mathlib.RingTheory.LocalProperties.Exactness import Mathlib.RingTheory.LocalProperties.IntegrallyClosed import Mathlib.RingTheory.LocalProperties.Projective import Mathlib.RingTheory.LocalProperties.Reduced @@ -4353,6 +4389,7 @@ import Mathlib.RingTheory.Nakayama import Mathlib.RingTheory.Nilpotent.Basic import Mathlib.RingTheory.Nilpotent.Defs import Mathlib.RingTheory.Nilpotent.Lemmas +import Mathlib.RingTheory.Noetherian.Basic import Mathlib.RingTheory.Noetherian.Defs import Mathlib.RingTheory.Noetherian.Filter import Mathlib.RingTheory.Noetherian.Nilpotent @@ -4461,7 +4498,17 @@ import Mathlib.RingTheory.TwoSidedIdeal.Instances import Mathlib.RingTheory.TwoSidedIdeal.Kernel import Mathlib.RingTheory.TwoSidedIdeal.Lattice import Mathlib.RingTheory.TwoSidedIdeal.Operations -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Defs +import Mathlib.RingTheory.UniqueFactorizationDomain.FactorSet +import Mathlib.RingTheory.UniqueFactorizationDomain.Finite +import Mathlib.RingTheory.UniqueFactorizationDomain.Finsupp +import Mathlib.RingTheory.UniqueFactorizationDomain.GCDMonoid +import Mathlib.RingTheory.UniqueFactorizationDomain.Ideal +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicative +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicity +import Mathlib.RingTheory.UniqueFactorizationDomain.Nat +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors import Mathlib.RingTheory.Unramified.Basic import Mathlib.RingTheory.Unramified.Field import Mathlib.RingTheory.Unramified.Finite @@ -5243,7 +5290,9 @@ import Mathlib.Topology.UniformSpace.CompleteSeparated import Mathlib.Topology.UniformSpace.Completion import Mathlib.Topology.UniformSpace.Equicontinuity import Mathlib.Topology.UniformSpace.Equiv +import Mathlib.Topology.UniformSpace.HeineCantor import Mathlib.Topology.UniformSpace.Matrix +import Mathlib.Topology.UniformSpace.OfCompactT2 import Mathlib.Topology.UniformSpace.OfFun import Mathlib.Topology.UniformSpace.Pi import Mathlib.Topology.UniformSpace.Separation @@ -5272,6 +5321,7 @@ import Mathlib.Util.IncludeStr import Mathlib.Util.LongNames import Mathlib.Util.MemoFix import Mathlib.Util.Notation3 +import Mathlib.Util.ParseCommand import Mathlib.Util.Qq import Mathlib.Util.SleepHeartbeats import Mathlib.Util.Superscript diff --git a/Mathlib/Algebra/AddConstMap/Basic.lean b/Mathlib/Algebra/AddConstMap/Basic.lean index 0bf23cde46517f..25685a81e92e9e 100644 --- a/Mathlib/Algebra/AddConstMap/Basic.lean +++ b/Mathlib/Algebra/AddConstMap/Basic.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Action.Pi import Mathlib.Algebra.GroupPower.IterateHom -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.Order.Archimedean.Basic import Mathlib.Algebra.Order.Group.Instances import Mathlib.Logic.Function.Iterate @@ -28,6 +28,8 @@ We use parameters `a` and `b` instead of `1` to accommodate for two use cases: including orientation-reversing maps. -/ +assert_not_exists Finset + open Function Set /-- A bundled map `f : G → H` such that `f (x + a) = f x + b` for all `x`. @@ -431,7 +433,7 @@ variable {G : Type*} [AddMonoid G] {a : G} as a monoid homomorphism from `Multiplicative G` to `G →+c[a, a] G`. -/ @[simps! (config := .asFn)] def addLeftHom : Multiplicative G →* (G →+c[a, a] G) where - toFun c := Multiplicative.toAdd c +ᵥ .id + toFun c := c.toAdd +ᵥ .id map_one' := by ext; apply zero_add map_mul' _ _ := by ext; apply add_assoc diff --git a/Mathlib/Algebra/AddConstMap/Equiv.lean b/Mathlib/Algebra/AddConstMap/Equiv.lean index ee4c37b7168129..28779a4f482cca 100644 --- a/Mathlib/Algebra/AddConstMap/Equiv.lean +++ b/Mathlib/Algebra/AddConstMap/Equiv.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.AddConstMap.Basic import Mathlib.GroupTheory.Perm.Basic + /-! # Equivalences conjugating `(· + a)` to `(· + b)` @@ -14,6 +15,8 @@ to be the type of equivalences such that `∀ x, f (x + a) = f x + b`. We also define the corresponding typeclass and prove some basic properties. -/ +assert_not_exists Finset + open Function open scoped AddConstMap diff --git a/Mathlib/Algebra/AddTorsor.lean b/Mathlib/Algebra/AddTorsor.lean index 2ab53a91f84e3c..5c7a2b005055bf 100644 --- a/Mathlib/Algebra/AddTorsor.lean +++ b/Mathlib/Algebra/AddTorsor.lean @@ -358,7 +358,7 @@ theorem constVAdd_add (v₁ v₂ : G) : constVAdd P (v₁ + v₂) = constVAdd P /-- `Equiv.constVAdd` as a homomorphism from `Multiplicative G` to `Equiv.perm P` -/ def constVAddHom : Multiplicative G →* Equiv.Perm P where - toFun v := constVAdd P (Multiplicative.toAdd v) + toFun v := constVAdd P (v.toAdd) map_one' := constVAdd_zero G P map_mul' := constVAdd_add P @@ -404,13 +404,16 @@ theorem pointReflection_involutive (x : P) : Involutive (pointReflection x : P /-- `x` is the only fixed point of `pointReflection x`. This lemma requires `x + x = y + y ↔ x = y`. There is no typeclass to use here, so we add it as an explicit argument. -/ -theorem pointReflection_fixed_iff_of_injective_bit0 {x y : P} (h : Injective (2 • · : G → G)) : +theorem pointReflection_fixed_iff_of_injective_two_nsmul {x y : P} (h : Injective (2 • · : G → G)) : pointReflection x y = y ↔ y = x := by rw [pointReflection_apply, eq_comm, eq_vadd_iff_vsub_eq, ← neg_vsub_eq_vsub_rev, neg_eq_iff_add_eq_zero, ← two_nsmul, ← nsmul_zero 2, h.eq_iff, vsub_eq_zero_iff_eq, eq_comm] +@[deprecated (since := "2024-11-18")] alias pointReflection_fixed_iff_of_injective_bit0 := +pointReflection_fixed_iff_of_injective_two_nsmul + -- Porting note: need this to calm down CI -theorem injective_pointReflection_left_of_injective_bit0 {G P : Type*} [AddCommGroup G] +theorem injective_pointReflection_left_of_injective_two_nsmul {G P : Type*} [AddCommGroup G] [AddTorsor G P] (h : Injective (2 • · : G → G)) (y : P) : Injective fun x : P => pointReflection x y := fun x₁ x₂ (hy : pointReflection x₁ y = pointReflection x₂ y) => by @@ -418,6 +421,9 @@ theorem injective_pointReflection_left_of_injective_bit0 {G P : Type*} [AddCommG vsub_sub_vsub_cancel_right, ← neg_vsub_eq_vsub_rev, neg_eq_iff_add_eq_zero, ← two_nsmul, ← nsmul_zero 2, h.eq_iff, vsub_eq_zero_iff_eq] at hy +@[deprecated (since := "2024-11-18")] alias injective_pointReflection_left_of_injective_bit0 := +injective_pointReflection_left_of_injective_two_nsmul + end Equiv theorem AddTorsor.subsingleton_iff (G P : Type*) [AddGroup G] [AddTorsor G P] : diff --git a/Mathlib/Algebra/Algebra/Basic.lean b/Mathlib/Algebra/Algebra/Basic.lean index 3e1c923709bb39..98aab66f635a14 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -133,18 +133,24 @@ end CommSemiring section Ring -variable [CommRing R] -variable (R) - /-- A `Semiring` that is an `Algebra` over a commutative ring carries a natural `Ring` structure. See note [reducible non-instances]. -/ -abbrev semiringToRing [Semiring A] [Algebra R A] : Ring A := +abbrev semiringToRing (R : Type*) [CommRing R] [Semiring A] [Algebra R A] : Ring A := { __ := (inferInstance : Semiring A) __ := Module.addCommMonoidToAddCommGroup R intCast := fun z => algebraMap R A z intCast_ofNat := fun z => by simp only [Int.cast_natCast, map_natCast] intCast_negSucc := fun z => by simp } +instance {R : Type*} [Ring R] : Algebra (Subring.center R) R where + toFun := Subtype.val + map_one' := rfl + map_mul' _ _ := rfl + map_zero' := rfl + map_add' _ _ := rfl + commutes' r x := (Subring.mem_center_iff.1 r.2 x).symm + smul_def' _ _ := rfl + end Ring end Algebra diff --git a/Mathlib/Algebra/Algebra/Defs.lean b/Mathlib/Algebra/Algebra/Defs.lean index f21cc3fe2a3ef4..40ac1bbeaf52e0 100644 --- a/Mathlib/Algebra/Algebra/Defs.lean +++ b/Mathlib/Algebra/Algebra/Defs.lean @@ -175,6 +175,19 @@ def RingHom.toAlgebra' {R S} [CommSemiring R] [Semiring S] (i : R →+* S) smul_def' _ _ := rfl toRingHom := i +-- just simple lemmas for a declaration that is itself primed, no need for docstrings +set_option linter.docPrime false in +theorem RingHom.smul_toAlgebra' {R S} [CommSemiring R] [Semiring S] (i : R →+* S) + (h : ∀ c x, i c * x = x * i c) (r : R) (s : S) : + let _ := RingHom.toAlgebra' i h + r • s = i r * s := rfl + +set_option linter.docPrime false in +theorem RingHom.algebraMap_toAlgebra' {R S} [CommSemiring R] [Semiring S] (i : R →+* S) + (h : ∀ c x, i c * x = x * i c) : + @algebraMap R S _ _ (i.toAlgebra' h) = i := + rfl + /-- Creating an algebra from a morphism to a commutative semiring. -/ def RingHom.toAlgebra {R S} [CommSemiring R] [CommSemiring S] (i : R →+* S) : Algebra R S := i.toAlgebra' fun _ => mul_comm _ @@ -311,6 +324,36 @@ section end +section compHom + +variable (A) (f : S →+* R) + +/-- +Compose an `Algebra` with a `RingHom`, with action `f s • m`. + +This is the algebra version of `Module.compHom`. +-/ +abbrev compHom : Algebra S A where + smul s a := f s • a + toRingHom := (algebraMap R A).comp f + commutes' _ _ := Algebra.commutes _ _ + smul_def' _ _ := Algebra.smul_def _ _ + +theorem compHom_smul_def (s : S) (x : A) : + letI := compHom A f + s • x = f s • x := rfl + +theorem compHom_algebraMap_eq : + letI := compHom A f + algebraMap S A = (algebraMap R A).comp f := rfl + +theorem compHom_algebraMap_apply (s : S) : + letI := compHom A f + algebraMap S A s = (algebraMap R A) (f s) := rfl + +end compHom + + variable (R A) /-- The canonical ring homomorphism `algebraMap R A : R →+* A` for any `R`-algebra `A`, diff --git a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean index af1d1bc38d9afd..bea24677990a7d 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean @@ -1131,6 +1131,57 @@ end Centralizer end NonUnitalSubalgebra +namespace NonUnitalAlgebra + +open NonUnitalSubalgebra + +variable {R A : Type*} [CommSemiring R] [NonUnitalSemiring A] +variable [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] + +variable (R) in +lemma adjoin_le_centralizer_centralizer (s : Set A) : + adjoin R s ≤ centralizer R (centralizer R s) := + adjoin_le Set.subset_centralizer_centralizer + +lemma commute_of_mem_adjoin_of_forall_mem_commute {a b : A} {s : Set A} + (hb : b ∈ adjoin R s) (h : ∀ b ∈ s, Commute a b) : + Commute a b := by + have : a ∈ centralizer R s := by simpa only [Commute.symm_iff (a := a)] using h + exact adjoin_le_centralizer_centralizer R s hb a this + +lemma commute_of_mem_adjoin_singleton_of_commute {a b c : A} + (hc : c ∈ adjoin R {b}) (h : Commute a b) : + Commute a c := + commute_of_mem_adjoin_of_forall_mem_commute hc <| by simpa + +lemma commute_of_mem_adjoin_self {a b : A} (hb : b ∈ adjoin R {a}) : + Commute a b := + commute_of_mem_adjoin_singleton_of_commute hb rfl + +variable (R) in + +/-- If all elements of `s : Set A` commute pairwise, then `adjoin R s` is a non-unital commutative +semiring. + +See note [reducible non-instances]. -/ +abbrev adjoinNonUnitalCommSemiringOfComm {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : + NonUnitalCommSemiring (adjoin R s) := + { (adjoin R s).toNonUnitalSemiring with + mul_comm := fun ⟨_, h₁⟩ ⟨_, h₂⟩ ↦ + have := adjoin_le_centralizer_centralizer R s + Subtype.ext <| Set.centralizer_centralizer_comm_of_comm hcomm _ (this h₁) _ (this h₂) } + +/-- If all elements of `s : Set A` commute pairwise, then `adjoin R s` is a non-unital commutative +ring. + +See note [reducible non-instances]. -/ +abbrev adjoinNonUnitalCommRingOfComm (R : Type*) {A : Type*} [CommRing R] [NonUnitalRing A] + [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] {s : Set A} + (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : NonUnitalCommRing (adjoin R s) := + { (adjoin R s).toNonUnitalRing, adjoinNonUnitalCommSemiringOfComm R hcomm with } + +end NonUnitalAlgebra + section Nat variable {R : Type*} [NonUnitalNonAssocSemiring R] diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index 8decae0eb7f390..960f805fd05b7a 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -6,9 +6,9 @@ Authors: Kenny Lau import Mathlib.Algebra.Algebra.Bilinear import Mathlib.Algebra.Algebra.Opposite import Mathlib.Algebra.Group.Pointwise.Finset.Basic +import Mathlib.Algebra.Group.Pointwise.Set.BigOperators import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.Algebra.Module.Submodule.Pointwise -import Mathlib.Data.Set.Pointwise.BigOperators import Mathlib.Data.Set.Semiring import Mathlib.GroupTheory.GroupAction.SubMulAction.Pointwise @@ -285,12 +285,14 @@ theorem mul_eq_map₂ : M * N = map₂ (LinearMap.mul R A) M N := le_antisymm (mul_le.mpr fun _m hm _n ↦ apply_mem_map₂ _ hm) (map₂_le.mpr fun _m hm _n ↦ mul_mem_mul hm) -variable (R) +variable (R M N) theorem span_mul_span : span R S * span R T = span R (S * T) := by rw [mul_eq_map₂]; apply map₂_span_span -variable {R} (M N P Q) +lemma mul_def : M * N = span R (M * N : Set A) := by simp [← span_mul_span] + +variable {R} (P Q) protected theorem mul_one : M * 1 = M := by conv_lhs => rw [one_eq_span, ← span_eq M] @@ -353,6 +355,24 @@ theorem comap_op_mul (M N : Submodule R Aᵐᵒᵖ) : comap (↑(opLinearEquiv R : A ≃ₗ[R] Aᵐᵒᵖ) : A →ₗ[R] Aᵐᵒᵖ) M := by simp_rw [comap_equiv_eq_map_symm, map_unop_mul] +section +variable {α : Type*} [Monoid α] [DistribMulAction α A] [SMulCommClass α R A] + +instance [IsScalarTower α A A] : IsScalarTower α (Submodule R A) (Submodule R A) where + smul_assoc a S T := by + rw [← S.span_eq, ← T.span_eq, smul_span, smul_eq_mul, smul_eq_mul, span_mul_span, span_mul_span, + smul_span, smul_mul_assoc] + +instance [SMulCommClass α A A] : SMulCommClass α (Submodule R A) (Submodule R A) where + smul_comm a S T := by + rw [← S.span_eq, ← T.span_eq, smul_span, smul_eq_mul, smul_eq_mul, span_mul_span, span_mul_span, + smul_span, mul_smul_comm] + +instance [SMulCommClass A α A] : SMulCommClass (Submodule R A) α (Submodule R A) := + have := SMulCommClass.symm A α A; .symm .. + +end + section open Pointwise @@ -635,7 +655,7 @@ instance moduleSet : Module (SetSemiring A) (Submodule R A) where variable {R A} -theorem smul_def (s : SetSemiring A) (P : Submodule R A) : +theorem setSemiring_smul_def (s : SetSemiring A) (P : Submodule R A) : s • P = span R (SetSemiring.down (α := A) s) * P := rfl @@ -647,7 +667,7 @@ theorem smul_le_smul {s t : SetSemiring A} {M N : Submodule R A} theorem singleton_smul (a : A) (M : Submodule R A) : Set.up ({a} : Set A) • M = M.map (LinearMap.mulLeft R a) := by conv_lhs => rw [← span_eq M] - rw [smul_def, SetSemiring.down_up, span_mul_span, singleton_mul] + rw [setSemiring_smul_def, SetSemiring.down_up, span_mul_span, singleton_mul] exact (map (LinearMap.mulLeft R a) M).span_eq section Quotient diff --git a/Mathlib/Algebra/Algebra/Unitization.lean b/Mathlib/Algebra/Algebra/Unitization.lean index 42a25ab336b191..89f706b546d032 100644 --- a/Mathlib/Algebra/Algebra/Unitization.lean +++ b/Mathlib/Algebra/Algebra/Unitization.lean @@ -743,8 +743,7 @@ def starLift : (A →⋆ₙₐ[R] C) ≃ (Unitization R A →⋆ₐ[R] C) := right_inv := fun φ => Unitization.algHom_ext'' <| by simp } --- Note (#6057) : tagging simpNF because linter complains -@[simp high, nolint simpNF] +@[simp high] theorem starLift_symm_apply_apply (φ : Unitization R A →⋆ₐ[R] C) (a : A) : Unitization.starLift.symm φ a = φ a := rfl diff --git a/Mathlib/Algebra/BigOperators/Finsupp.lean b/Mathlib/Algebra/BigOperators/Finsupp.lean index a02b2d8a48142d..dffd8f94b48be4 100644 --- a/Mathlib/Algebra/BigOperators/Finsupp.lean +++ b/Mathlib/Algebra/BigOperators/Finsupp.lean @@ -86,22 +86,17 @@ theorem prod_ite_eq [DecidableEq α] (f : α →₀ M) (a : α) (b : α → M dsimp [Finsupp.prod] rw [f.support.prod_ite_eq] -/- Porting note: simpnf linter, added aux lemma below -Left-hand side simplifies from - Finsupp.sum f fun x v => if a = x then v else 0 -to - if ↑f a = 0 then 0 else ↑f a --/ --- @[simp] theorem sum_ite_self_eq [DecidableEq α] {N : Type*} [AddCommMonoid N] (f : α →₀ N) (a : α) : (f.sum fun x v => ite (a = x) v 0) = f a := by classical convert f.sum_ite_eq a fun _ => id simp [ite_eq_right_iff.2 Eq.symm] --- Porting note: Added this thm to replace the simp in the previous one. Need to add [DecidableEq N] +/-- +The left hand side of `sum_ite_self_eq` simplifies; this is the variant that is useful for `simp`. +-/ @[simp] -theorem sum_ite_self_eq_aux [DecidableEq α] {N : Type*} [AddCommMonoid N] (f : α →₀ N) (a : α) : +theorem if_mem_support [DecidableEq α] {N : Type*} [AddCommMonoid N] (f : α →₀ N) (a : α) : (if a ∈ f.support then f a else 0) = f a := by simp only [mem_support_iff, ne_eq, ite_eq_left_iff, not_not] exact fun h ↦ h.symm @@ -113,6 +108,7 @@ theorem prod_ite_eq' [DecidableEq α] (f : α →₀ M) (a : α) (b : α → M dsimp [Finsupp.prod] rw [f.support.prod_ite_eq'] +/-- A restatement of `sum_ite_self_eq` with the equality test reversed. -/ theorem sum_ite_self_eq' [DecidableEq α] {N : Type*} [AddCommMonoid N] (f : α →₀ N) (a : α) : (f.sum fun x v => ite (x = a) v 0) = f a := by classical diff --git a/Mathlib/Algebra/BigOperators/Group/Finset.lean b/Mathlib/Algebra/BigOperators/Group/Finset.lean index 29817d8370d977..282177e1ba7c00 100644 --- a/Mathlib/Algebra/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Finset.lean @@ -420,6 +420,12 @@ theorem prod_filter_mul_prod_filter_not have := Classical.decEq α rw [← prod_union (disjoint_filter_filter_neg s s p), filter_union_filter_neg_eq] +@[to_additive] +lemma prod_filter_not_mul_prod_filter (s : Finset α) (p : α → Prop) [DecidablePred p] + [∀ x, Decidable (¬p x)] (f : α → β) : + (∏ x ∈ s.filter fun x ↦ ¬p x, f x) * ∏ x ∈ s.filter p, f x = ∏ x ∈ s, f x := by + rw [mul_comm, prod_filter_mul_prod_filter_not] + section ToList @[to_additive (attr := simp)] @@ -2191,7 +2197,7 @@ variable [Monoid α] theorem ofMul_list_prod (s : List α) : ofMul s.prod = (s.map ofMul).sum := by simp [ofMul]; rfl @[simp] -theorem toMul_list_sum (s : List (Additive α)) : toMul s.sum = (s.map toMul).prod := by +theorem toMul_list_sum (s : List (Additive α)) : s.sum.toMul = (s.map toMul).prod := by simp [toMul, ofMul]; rfl end Monoid @@ -2204,7 +2210,7 @@ variable [AddMonoid α] theorem ofAdd_list_prod (s : List α) : ofAdd s.sum = (s.map ofAdd).prod := by simp [ofAdd]; rfl @[simp] -theorem toAdd_list_sum (s : List (Multiplicative α)) : toAdd s.prod = (s.map toAdd).sum := by +theorem toAdd_list_sum (s : List (Multiplicative α)) : s.prod.toAdd = (s.map toAdd).sum := by simp [toAdd, ofAdd]; rfl end AddMonoid @@ -2218,7 +2224,7 @@ theorem ofMul_multiset_prod (s : Multiset α) : ofMul s.prod = (s.map ofMul).sum simp [ofMul]; rfl @[simp] -theorem toMul_multiset_sum (s : Multiset (Additive α)) : toMul s.sum = (s.map toMul).prod := by +theorem toMul_multiset_sum (s : Multiset (Additive α)) : s.sum.toMul = (s.map toMul).prod := by simp [toMul, ofMul]; rfl @[simp] @@ -2227,7 +2233,7 @@ theorem ofMul_prod (s : Finset ι) (f : ι → α) : ofMul (∏ i ∈ s, f i) = @[simp] theorem toMul_sum (s : Finset ι) (f : ι → Additive α) : - toMul (∑ i ∈ s, f i) = ∏ i ∈ s, toMul (f i) := + (∑ i ∈ s, f i).toMul = ∏ i ∈ s, (f i).toMul := rfl end CommMonoid @@ -2242,7 +2248,7 @@ theorem ofAdd_multiset_prod (s : Multiset α) : ofAdd s.sum = (s.map ofAdd).prod @[simp] theorem toAdd_multiset_sum (s : Multiset (Multiplicative α)) : - toAdd s.prod = (s.map toAdd).sum := by + s.prod.toAdd = (s.map toAdd).sum := by simp [toAdd, ofAdd]; rfl @[simp] @@ -2251,7 +2257,7 @@ theorem ofAdd_sum (s : Finset ι) (f : ι → α) : ofAdd (∑ i ∈ s, f i) = @[simp] theorem toAdd_prod (s : Finset ι) (f : ι → Multiplicative α) : - toAdd (∏ i ∈ s, f i) = ∑ i ∈ s, toAdd (f i) := + (∏ i ∈ s, f i).toAdd = ∑ i ∈ s, (f i).toAdd := rfl end AddCommMonoid diff --git a/Mathlib/Algebra/BigOperators/Group/List.lean b/Mathlib/Algebra/BigOperators/Group/List.lean index 59dc2be68d10ae..2bd6c8a351d66c 100644 --- a/Mathlib/Algebra/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/BigOperators/Group/List.lean @@ -634,7 +634,7 @@ end MonoidHom end MonoidHom set_option linter.deprecated false in -@[simp, deprecated (since := "2024-10-17")] +@[simp, deprecated "No deprecation message was provided." (since := "2024-10-17")] lemma Nat.sum_eq_listSum (l : List ℕ) : Nat.sum l = l.sum := rfl namespace List @@ -657,7 +657,8 @@ theorem ranges_nodup {l s : List ℕ} (hs : s ∈ ranges l) : s.Nodup := /-- Any entry of any member of `l.ranges` is strictly smaller than `l.sum`. -/ 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] + (∃ s ∈ l.ranges, n ∈ s) ↔ n < l.sum := by + rw [← mem_range, ← ranges_flatten, mem_flatten] @[simp] theorem length_flatMap (l : List α) (f : α → List β) : diff --git a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean index 9c06d5e619d854..1053dac09d7575 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean @@ -16,7 +16,6 @@ with the forgetful functors to `RingCat` and `ModuleCat`. We furthermore show th associating to a type the free `R`-algebra on that type is left adjoint to the forgetful functor. -/ - open CategoryTheory Limits universe v u @@ -25,6 +24,8 @@ variable (R : Type u) [CommRing R] /-- The category of R-algebras and their morphisms. -/ structure AlgebraCat where + private mk :: + /-- The underlying type. -/ carrier : Type v [isRing : Ring carrier] [isAlgebra : Algebra R carrier] @@ -46,22 +47,97 @@ instance : CoeSort (AlgebraCat R) (Type v) := attribute [coe] AlgebraCat.carrier +/-- The object in the category of R-algebras associated to a type equipped with the appropriate +typeclasses. This is the preferred way to construct a term of `AlgebraCat R`. -/ +abbrev of (X : Type v) [Ring X] [Algebra R X] : AlgebraCat.{v} R := + ⟨X⟩ + +lemma coe_of (X : Type v) [Ring X] [Algebra R X] : (of R X : Type v) = X := + rfl + +variable {R} in +/-- The type of morphisms in `AlgebraCat R`. -/ +@[ext] +structure Hom (A B : AlgebraCat.{v} R) where + private mk :: + /-- The underlying algebra map. -/ + hom : A →ₐ[R] B + instance : Category (AlgebraCat.{v} R) where - Hom A B := A →ₐ[R] B - id A := AlgHom.id R A - comp f g := g.comp f + Hom A B := Hom A B + id A := ⟨AlgHom.id R A⟩ + comp f g := ⟨g.hom.comp f.hom⟩ + +instance {M N : AlgebraCat.{v} R} : CoeFun (M ⟶ N) (fun _ ↦ M → N) where + coe f := f.hom -instance {M N : AlgebraCat.{v} R} : FunLike (M ⟶ N) M N := - AlgHom.funLike +@[simp] +lemma hom_id {A : AlgebraCat.{v} R} : (𝟙 A : A ⟶ A).hom = AlgHom.id R A := rfl + +/- Provided for rewriting. -/ +lemma id_apply (A : AlgebraCat.{v} R) (a : A) : + (𝟙 A : A ⟶ A) a = a := by simp + +@[simp] +lemma hom_comp {A B C : AlgebraCat.{v} R} (f : A ⟶ B) (g : B ⟶ C) : + (f ≫ g).hom = g.hom.comp f.hom := rfl + +/- Provided for rewriting. -/ +lemma comp_apply {A B C : AlgebraCat.{v} R} (f : A ⟶ B) (g : B ⟶ C) (a : A) : + (f ≫ g) a = g (f a) := by simp + +@[ext] +lemma hom_ext {A B : AlgebraCat.{v} R} {f g : A ⟶ B} (hf : f.hom = g.hom) : f = g := + Hom.ext hf + +/-- Typecheck an `AlgHom` as a morphism in `AlgebraCat R`. -/ +abbrev ofHom {R : Type u} [CommRing R] {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] + (f : X →ₐ[R] Y) : of R X ⟶ of R Y := + ⟨f⟩ -instance {M N : AlgebraCat.{v} R} : AlgHomClass (M ⟶ N) R M N := - AlgHom.algHomClass +lemma hom_ofHom {R : Type u} [CommRing R] {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] + [Algebra R Y] (f : X →ₐ[R] Y) : (ofHom f).hom = f := rfl + +@[simp] +lemma ofHom_hom {A B : AlgebraCat.{v} R} (f : A ⟶ B) : + ofHom (Hom.hom f) = f := rfl + +@[simp] +lemma ofHom_id {X : Type v} [Ring X] [Algebra R X] : ofHom (AlgHom.id R X) = 𝟙 (of R X) := rfl + +@[simp] +lemma ofHom_comp {X Y Z : Type v} [Ring X] [Ring Y] [Ring Z] [Algebra R X] [Algebra R Y] + [Algebra R Z] (f : X →ₐ[R] Y) (g : Y →ₐ[R] Z) : + ofHom (g.comp f) = ofHom f ≫ ofHom g := + rfl + +lemma ofHom_apply {R : Type u} [CommRing R] {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] + [Algebra R Y] (f : X →ₐ[R] Y) (x : X) : ofHom f x = f x := rfl + +@[simp] +lemma inv_hom_apply {A B : AlgebraCat.{v} R} (e : A ≅ B) (x : A) : e.inv (e.hom x) = x := by + rw [← comp_apply] + simp + +@[simp] +lemma hom_inv_apply {A B : AlgebraCat.{v} R} (e : A ≅ B) (x : B) : e.hom (e.inv x) = x := by + rw [← comp_apply] + simp + +instance : Inhabited (AlgebraCat R) := + ⟨of R R⟩ instance : ConcreteCategory.{v} (AlgebraCat.{v} R) where forget := { obj := fun R => R - map := fun f => f.toFun } - forget_faithful := ⟨fun h => AlgHom.ext (by intros x; dsimp at h; rw [h])⟩ + map := fun f => f.hom } + forget_faithful := ⟨fun h => by ext x; simpa using congrFun h x⟩ + +lemma forget_obj {A : AlgebraCat.{v} R} : (forget (AlgebraCat.{v} R)).obj A = A := rfl + +lemma forget_map {A B : AlgebraCat.{v} R} (f : A ⟶ B) : + (forget (AlgebraCat.{v} R)).map f = f := + rfl instance {S : AlgebraCat.{v} R} : Ring ((forget (AlgebraCat R)).obj S) := (inferInstance : Ring S.carrier) @@ -72,12 +148,12 @@ instance {S : AlgebraCat.{v} R} : Algebra R ((forget (AlgebraCat R)).obj S) := instance hasForgetToRing : HasForget₂ (AlgebraCat.{v} R) RingCat.{v} where forget₂ := { obj := fun A => RingCat.of A - map := fun f => RingCat.ofHom f.toRingHom } + map := fun f => RingCat.ofHom f.hom.toRingHom } instance hasForgetToModule : HasForget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R) where forget₂ := { obj := fun M => ModuleCat.of R M - map := fun f => ModuleCat.asHom f.toLinearMap } + map := fun f => ModuleCat.asHom f.hom.toLinearMap } @[simp] lemma forget₂_module_obj (X : AlgebraCat.{v} R) : @@ -86,33 +162,10 @@ lemma forget₂_module_obj (X : AlgebraCat.{v} R) : @[simp] lemma forget₂_module_map {X Y : AlgebraCat.{v} R} (f : X ⟶ Y) : - (forget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R)).map f = ModuleCat.asHom f.toLinearMap := - rfl - -/-- The object in the category of R-algebras associated to a type equipped with the appropriate -typeclasses. -/ -def of (X : Type v) [Ring X] [Algebra R X] : AlgebraCat.{v} R := - ⟨X⟩ - -/-- Typecheck a `AlgHom` as a morphism in `AlgebraCat R`. -/ -def ofHom {R : Type u} [CommRing R] {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] - (f : X →ₐ[R] Y) : of R X ⟶ of R Y := - f - -@[simp] -theorem ofHom_apply {R : Type u} [CommRing R] {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] - [Algebra R Y] (f : X →ₐ[R] Y) (x : X) : ofHom f x = f x := + (forget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R)).map f = ModuleCat.asHom f.hom.toLinearMap := rfl -instance : Inhabited (AlgebraCat R) := - ⟨of R R⟩ - -@[simp] -theorem coe_of (X : Type u) [Ring X] [Algebra R X] : (of R X : Type u) = X := - rfl - -variable {R} - +variable {R} in /-- Forgetting to the underlying type and then building the bundled object returns the original algebra. -/ @[simps] @@ -120,58 +173,20 @@ def ofSelfIso (M : AlgebraCat.{v} R) : AlgebraCat.of R M ≅ M where hom := 𝟙 M inv := 𝟙 M -variable {M N U : ModuleCat.{v} R} - -@[simp] -theorem id_apply (m : M) : (𝟙 M : M → M) m = m := - rfl - -@[simp] -theorem coe_comp (f : M ⟶ N) (g : N ⟶ U) : (f ≫ g : M → U) = g ∘ f := - rfl - -variable (R) - /-- The "free algebra" functor, sending a type `S` to the free algebra on `S`. -/ -@[simps!] +@[simps! obj map] def free : Type u ⥤ AlgebraCat.{u} R where - obj S := - { carrier := FreeAlgebra R S - isRing := Algebra.semiringToRing R } - map f := FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): `apply FreeAlgebra.hom_ext` was `ext1`. - map_id := by intro X; apply FreeAlgebra.hom_ext; simp only [FreeAlgebra.ι_comp_lift]; rfl - map_comp := by - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): `apply FreeAlgebra.hom_ext` was `ext1`. - intros; apply FreeAlgebra.hom_ext; simp only [FreeAlgebra.ι_comp_lift]; ext1 - -- Porting node: this ↓ `erw` used to be handled by the `simp` below it - erw [CategoryTheory.coe_comp] - simp only [CategoryTheory.coe_comp, Function.comp_apply, types_comp_apply] - -- Porting node: this ↓ `erw` and `rfl` used to be handled by the `simp` above - erw [FreeAlgebra.lift_ι_apply, FreeAlgebra.lift_ι_apply] - rfl + obj S := of R (FreeAlgebra R S) + map f := ofHom <| FreeAlgebra.lift _ <| FreeAlgebra.ι _ ∘ f /-- The free/forget adjunction for `R`-algebras. -/ def adj : free.{u} R ⊣ forget (AlgebraCat.{u} R) := Adjunction.mkOfHomEquiv - { homEquiv := fun _ _ => (FreeAlgebra.lift _).symm - -- Relying on `obviously` to fill out these proofs is very slow :( - homEquiv_naturality_left_symm := by - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): `apply FreeAlgebra.hom_ext` was `ext1`. - intros; apply FreeAlgebra.hom_ext; simp only [FreeAlgebra.ι_comp_lift]; ext1 - simp only [free_map, Equiv.symm_symm, FreeAlgebra.lift_ι_apply, CategoryTheory.coe_comp, - Function.comp_apply, types_comp_apply] - -- Porting node: this ↓ `erw` and `rfl` used to be handled by the `simp` above - erw [FreeAlgebra.lift_ι_apply, CategoryTheory.comp_apply, FreeAlgebra.lift_ι_apply, - Function.comp_apply, FreeAlgebra.lift_ι_apply] - rfl - homEquiv_naturality_right := by - intros; ext - simp only [CategoryTheory.coe_comp, Function.comp_apply, - FreeAlgebra.lift_symm_apply, types_comp_apply] - -- Porting note: proof used to be done after this ↑ `simp`; added ↓ two lines - erw [FreeAlgebra.lift_symm_apply, FreeAlgebra.lift_symm_apply] - rfl } + { homEquiv := fun _ _ => + { toFun := fun f ↦ (FreeAlgebra.lift _).symm f.hom + invFun := fun f ↦ ofHom <| (FreeAlgebra.lift _) f + left_inv := fun f ↦ by aesop + right_inv := fun f ↦ by simp [forget_obj, forget_map] } } instance : (forget (AlgebraCat.{u} R)).IsRightAdjoint := (adj R).isRightAdjoint @@ -184,31 +199,19 @@ variable {X₁ X₂ : Type u} @[simps] def AlgEquiv.toAlgebraIso {g₁ : Ring X₁} {g₂ : Ring X₂} {m₁ : Algebra R X₁} {m₂ : Algebra R X₂} (e : X₁ ≃ₐ[R] X₂) : AlgebraCat.of R X₁ ≅ AlgebraCat.of R X₂ where - hom := (e : X₁ →ₐ[R] X₂) - inv := (e.symm : X₂ →ₐ[R] X₁) - hom_inv_id := by ext x; exact e.left_inv x - inv_hom_id := by ext x; exact e.right_inv x + hom := AlgebraCat.ofHom (e : X₁ →ₐ[R] X₂) + inv := AlgebraCat.ofHom (e.symm : X₂ →ₐ[R] X₁) namespace CategoryTheory.Iso /-- Build a `AlgEquiv` from an isomorphism in the category `AlgebraCat R`. -/ @[simps] def toAlgEquiv {X Y : AlgebraCat R} (i : X ≅ Y) : X ≃ₐ[R] Y := - { i.hom with + { i.hom.hom with toFun := i.hom invFun := i.inv - left_inv := fun x => by - -- Porting note: was `by tidy` - change (i.hom ≫ i.inv) x = x - simp only [hom_inv_id] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [id_apply] - right_inv := fun x => by - -- Porting note: was `by tidy` - change (i.inv ≫ i.hom) x = x - simp only [inv_hom_id] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [id_apply] } + left_inv := fun x ↦ by simp + right_inv := fun x ↦ by simp } end CategoryTheory.Iso @@ -223,18 +226,5 @@ def algEquivIsoAlgebraIso {X Y : Type u} [Ring X] [Ring Y] [Algebra R X] [Algebr instance AlgebraCat.forget_reflects_isos : (forget (AlgebraCat.{u} R)).ReflectsIsomorphisms where reflects {X Y} f _ := by let i := asIso ((forget (AlgebraCat.{u} R)).map f) - let e : X ≃ₐ[R] Y := { f, i.toEquiv with } + let e : X ≃ₐ[R] Y := { f.hom, i.toEquiv with } exact e.toAlgebraIso.isIso_hom - -/-! -`@[simp]` lemmas for `AlgHom.comp` and categorical identities. --/ - -@[simp] theorem AlgHom.comp_id_algebraCat - {R} [CommRing R] {G : AlgebraCat.{u} R} {H : Type u} [Ring H] [Algebra R H] (f : G →ₐ[R] H) : - f.comp (𝟙 G) = f := - Category.id_comp (AlgebraCat.ofHom f) -@[simp] theorem AlgHom.id_algebraCat_comp - {R} [CommRing R] {G : Type u} [Ring G] [Algebra R G] {H : AlgebraCat.{u} R} (f : G →ₐ[R] H) : - AlgHom.comp (𝟙 H) f = f := - Category.comp_id (AlgebraCat.ofHom f) diff --git a/Mathlib/Algebra/Category/AlgebraCat/Limits.lean b/Mathlib/Algebra/Category/AlgebraCat/Limits.lean index 94f312fee5673b..ea39419a2442ed 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Limits.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Limits.lean @@ -40,7 +40,7 @@ instance algebraObj (j) : def sectionsSubalgebra : Subalgebra R (∀ j, F.obj j) := { SemiRingCat.sectionsSubsemiring (F ⋙ forget₂ (AlgebraCat R) RingCat.{w} ⋙ forget₂ RingCat SemiRingCat.{w}) with - algebraMap_mem' := fun r _ _ f => (F.map f).commutes r } + algebraMap_mem' := fun r _ _ f => (F.map f).hom.commutes r } instance (F : J ⥤ AlgebraCat.{w} R) : Ring (F ⋙ forget _).sections := inferInstanceAs <| Ring (sectionsSubalgebra F) @@ -88,9 +88,10 @@ namespace HasLimits def limitCone : Cone F where pt := AlgebraCat.of R (Types.Small.limitCone (F ⋙ forget _)).pt π := - { app := limitπAlgHom F - naturality := fun _ _ f => - AlgHom.coe_fn_injective ((Types.Small.limitCone (F ⋙ forget _)).π.naturality f) } + { app := fun j ↦ ofHom <| limitπAlgHom F j + naturality := fun _ _ f => by + ext : 1 + exact AlgHom.coe_fn_injective ((Types.Small.limitCone (F ⋙ forget _)).π.naturality f) } /-- Witness that the limit cone in `AlgebraCat R` is a limit cone. (Internal use only; use the limits API.) @@ -101,41 +102,36 @@ def limitConeIsLimit : IsLimit (limitCone.{v, w} F) := by -- Porting note: in mathlib3 the function term -- `fun v => ⟨fun j => ((forget (AlgebraCat R)).mapCone s).π.app j v` -- was provided by unification, and the last argument `(fun s => _)` was `(fun s => rfl)`. - (fun s => { toFun := _, map_one' := ?_, map_mul' := ?_, map_zero' := ?_, map_add' := ?_, - commutes' := ?_ }) + (fun s => ofHom + { toFun := _, map_one' := ?_, map_mul' := ?_, map_zero' := ?_, map_add' := ?_, + commutes' := ?_ }) (fun s => rfl) · congr ext j - simp only [Functor.comp_obj, Functor.mapCone_pt, Functor.mapCone_π_app, - forget_map_eq_coe] - rw [map_one] - rfl + simp only [Functor.mapCone_π_app, forget_map, map_one, Pi.one_apply] · intro x y - simp only [Functor.comp_obj, Functor.mapCone_pt, Functor.mapCone_π_app] - rw [← equivShrink_mul] - apply congrArg ext j - simp only [Functor.comp_obj, Functor.mapCone_pt, Functor.mapCone_π_app, - forget_map_eq_coe, map_mul] - rfl - · simp only [Functor.mapCone_π_app, forget_map_eq_coe] - congr - funext j - simp only [map_zero, Pi.zero_apply] + simp only [Functor.comp_obj, forget_obj, Equiv.toFun_as_coe, Functor.mapCone_pt, + Functor.mapCone_π_app, forget_map, Equiv.symm_apply_apply, + Types.Small.limitCone_pt, equivShrink_symm_mul] + apply map_mul + · ext j + simp only [Functor.comp_obj, forget_obj, Equiv.toFun_as_coe, Functor.mapCone_pt, + Functor.mapCone_π_app, forget_map, Equiv.symm_apply_apply, + equivShrink_symm_zero] + apply map_zero · intro x y - simp only [Functor.mapCone_π_app] - rw [← equivShrink_add] - apply congrArg ext j - simp only [forget_map_eq_coe, map_add] - rfl + simp only [Functor.comp_obj, forget_obj, Equiv.toFun_as_coe, Functor.mapCone_pt, + Functor.mapCone_π_app, forget_map, Equiv.symm_apply_apply, + Types.Small.limitCone_pt, equivShrink_symm_add] + apply map_add · intro r - simp only [← Shrink.algEquiv_symm_apply _ R, limitCone, Equiv.algebraMap_def, - Equiv.symm_symm] + simp only [← Shrink.algEquiv_symm_apply _ R, limitCone, Equiv.algebraMap_def, Equiv.symm_symm] apply congrArg apply Subtype.ext ext j - exact (s.π.app j).commutes r + exact (s.π.app j).hom.commutes r end HasLimits diff --git a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean index ac5df5ca0f2ddb..fa16a8aac4bcd6 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean @@ -37,7 +37,7 @@ noncomputable abbrev tensorObj (X Y : AlgebraCat.{u} R) : AlgebraCat.{u} R := `AlgebraCat.instMonoidalCategory`. -/ noncomputable abbrev tensorHom {W X Y Z : AlgebraCat.{u} R} (f : W ⟶ X) (g : Y ⟶ Z) : tensorObj W Y ⟶ tensorObj X Z := - Algebra.TensorProduct.map f g + ofHom <| Algebra.TensorProduct.map f.hom g.hom open MonoidalCategory diff --git a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean index fb1f40ffe10183..59fe5b8fefba2c 100644 --- a/Mathlib/Algebra/Category/BialgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/BialgebraCat/Basic.lean @@ -103,7 +103,7 @@ instance concreteCategory : ConcreteCategory.{v} (BialgebraCat.{v} R) where instance hasForgetToAlgebra : HasForget₂ (BialgebraCat R) (AlgebraCat R) where forget₂ := { obj := fun X => AlgebraCat.of R X - map := fun {X Y} f => (f.toBialgHom : X →ₐ[R] Y) } + map := fun {X Y} f => AlgebraCat.ofHom f.toBialgHom } @[simp] theorem forget₂_algebra_obj (X : BialgebraCat R) : @@ -112,7 +112,7 @@ theorem forget₂_algebra_obj (X : BialgebraCat R) : @[simp] theorem forget₂_algebra_map (X Y : BialgebraCat R) (f : X ⟶ Y) : - (forget₂ (BialgebraCat R) (AlgebraCat R)).map f = (f.toBialgHom : X →ₐ[R] Y) := + (forget₂ (BialgebraCat R) (AlgebraCat R)).map f = AlgebraCat.ofHom f.toBialgHom := rfl instance hasForgetToCoalgebra : HasForget₂ (BialgebraCat R) (CoalgebraCat R) where diff --git a/Mathlib/Algebra/Category/Grp/FiniteGrp.lean b/Mathlib/Algebra/Category/Grp/FiniteGrp.lean index b1f4d7ead61ee2..ac01e3ac8ce3c2 100644 --- a/Mathlib/Algebra/Category/Grp/FiniteGrp.lean +++ b/Mathlib/Algebra/Category/Grp/FiniteGrp.lean @@ -3,6 +3,7 @@ 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.Data.Finite.Defs import Mathlib.Algebra.Category.Grp.Basic /-! diff --git a/Mathlib/Algebra/Central/Defs.lean b/Mathlib/Algebra/Central/Defs.lean index c88a10b8b3abaf..363464e22abef1 100644 --- a/Mathlib/Algebra/Central/Defs.lean +++ b/Mathlib/Algebra/Central/Defs.lean @@ -19,7 +19,7 @@ is a (not necessarily commutative) `K`-algebra. ## Implementation notes We require the `K`-center of `D` to be smaller than or equal to the smallest subalgebra so that when -we prove something is central, there we don't need to prove `⊥ ≤ center K D` even though this +we prove something is central, we don't need to prove `⊥ ≤ center K D` even though this direction is trivial. ### Central Simple Algebras @@ -34,11 +34,11 @@ but an instance of `[Algebra.IsCentralSimple K D]` would not imply `[IsSimpleRin synthesization orders (`K` cannot be inferred). Thus, to obtain a central simple `K`-algebra `D`, one should use `Algebra.IsCentral K D` and `IsSimpleRing D` separately. -Note that the predicate `Albgera.IsCentral K D` and `IsSimpleRing D` makes sense just for `K` a +Note that the predicate `Algebra.IsCentral K D` and `IsSimpleRing D` makes sense just for `K` a `CommRing` but it doesn't give the right definition for central simple algebra; for a commutative ring base, one should use the theory of Azumaya algebras. In fact ideals of `K` immediately give rise to nontrivial quotients of `D` so there are no central simple algebras in this case according -to our definition, if K is not a field. +to our definition, if `K` is not a field. The theory of central simple algebras really is a theory over fields. Thus to declare a central simple algebra, one should use the following: diff --git a/Mathlib/Algebra/CharP/Defs.lean b/Mathlib/Algebra/CharP/Defs.lean index eb523f7e90fac4..093c600a4a3103 100644 --- a/Mathlib/Algebra/CharP/Defs.lean +++ b/Mathlib/Algebra/CharP/Defs.lean @@ -232,7 +232,7 @@ section NoZeroDivisors variable [NoZeroDivisors R] lemma char_is_prime_of_two_le (p : ℕ) [CharP R p] (hp : 2 ≤ p) : Nat.Prime p := - suffices ∀ (d) (_ : d ∣ p), d = 1 ∨ d = p from Nat.prime_def_lt''.mpr ⟨hp, this⟩ + suffices ∀ (d) (_ : d ∣ p), d = 1 ∨ d = p from Nat.prime_def.mpr ⟨hp, this⟩ fun (d : ℕ) (hdvd : ∃ e, p = d * e) => let ⟨e, hmul⟩ := hdvd have : (p : R) = 0 := (cast_eq_zero_iff R p p).mpr (dvd_refl p) diff --git a/Mathlib/Algebra/CharP/LinearMaps.lean b/Mathlib/Algebra/CharP/LinearMaps.lean new file mode 100644 index 00000000000000..36f3baf18a80d7 --- /dev/null +++ b/Mathlib/Algebra/CharP/LinearMaps.lean @@ -0,0 +1,60 @@ +/- +Copyright (c) 2024 Wanyi He. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Wanyi He, Huanyu Zheng +-/ +import Mathlib.Algebra.CharP.Algebra +/-! +# Characteristic of the ring of linear Maps + +This file contains properties of the characteristic of the ring of linear maps. +The characteristic of the ring of linear maps is determined by its base ring. + +## Main Results + +- `CharP_if` : For a commutative semiring `R` and a `R`-module `M`, + the characteristic of `R` is equal to the characteristic of the `R`-linear + endomorphisms of `M` when `M` contains an element `x` such that + `r • x = 0` implies `r = 0`. + +## Notations + +- `R` is a commutative semiring +- `M` is a `R`-module + +## Implementation Notes + +One can also deduce similar result via `charP_of_injective_ringHom` and + `R → (M →ₗ[R] M) : r ↦ (fun (x : M) ↦ r • x)`. But this will require stronger condition + compared to `CharP_if`. + +-/ + +namespace Module + +variable {R M : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + +/-- For a commutative semiring `R` and a `R`-module `M`, if `M` contains an + element `x` such that `r • x = 0` implies `r = 0` (finding such element usually + depends on specific `•`), then the characteristic of `R` is equal to the + characteristic of the `R`-linear endomorphisms of `M`.-/ +theorem charP_end {p : ℕ} [hchar : CharP R p] + (hreduction : ∃ x : M, ∀ r : R, r • x = 0 → r = 0) : CharP (M →ₗ[R] M) p where + cast_eq_zero_iff' n := by + have exact : (n : M →ₗ[R] M) = (n : R) • 1 := by + simp only [Nat.cast_smul_eq_nsmul, nsmul_eq_mul, mul_one] + rw [exact, LinearMap.ext_iff, ← hchar.1] + exact ⟨fun h ↦ Exists.casesOn hreduction fun x hx ↦ hx n (h x), + fun h ↦ (congrArg (fun t ↦ ∀ x, t • x = 0) h).mpr fun x ↦ zero_smul R x⟩ + +end Module + +/-- For a division ring `D` with center `k`, the ring of `k`-linear endomorphisms + of `D` has the same characteristic as `D`-/ +instance {D : Type*} [DivisionRing D] {p : ℕ} [CharP D p] : + CharP (D →ₗ[(Subring.center D)] D) p := + charP_of_injective_ringHom (Algebra.lmul (Subring.center D) D).toRingHom.injective p + +instance {D : Type*} [DivisionRing D] {p : ℕ} [ExpChar D p] : + ExpChar (D →ₗ[Subring.center D] D) p := + expChar_of_injective_ringHom (Algebra.lmul (Subring.center D) D).toRingHom.injective p diff --git a/Mathlib/Algebra/CharP/Subring.lean b/Mathlib/Algebra/CharP/Subring.lean index e6d5faa37044a2..23ed075efbeb13 100644 --- a/Mathlib/Algebra/CharP/Subring.lean +++ b/Mathlib/Algebra/CharP/Subring.lean @@ -3,8 +3,7 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ -import Mathlib.Algebra.CharP.Defs -import Mathlib.Algebra.Ring.Subring.Defs +import Mathlib.Algebra.CharP.Algebra /-! # Characteristic of subrings @@ -33,4 +32,18 @@ instance subring (R : Type u) [Ring R] (p : ℕ) [CharP R p] (S : Subring R) : C instance subring' (R : Type u) [CommRing R] (p : ℕ) [CharP R p] (S : Subring R) : CharP S p := CharP.subring R p S +/-- The characteristic of a division ring is equal to the characteristic + of its center-/ +theorem charP_center_iff {R : Type u} [Ring R] {p : ℕ} : + CharP (Subring.center R) p ↔ CharP R p := + (algebraMap (Subring.center R) R).charP_iff Subtype.val_injective p + end CharP + +namespace ExpChar + +theorem expChar_center_iff {R : Type u} [Ring R] {p : ℕ} : + ExpChar (Subring.center R) p ↔ ExpChar R p := + (algebraMap (Subring.center R) R).expChar_iff Subtype.val_injective p + +end ExpChar diff --git a/Mathlib/Algebra/CharZero/Quotient.lean b/Mathlib/Algebra/CharZero/Quotient.lean index a0e14ca270865b..d3872fea29c7ec 100644 --- a/Mathlib/Algebra/CharZero/Quotient.lean +++ b/Mathlib/Algebra/CharZero/Quotient.lean @@ -5,7 +5,7 @@ Authors: Eric Wieser -/ import Mathlib.Algebra.Field.Basic import Mathlib.Algebra.Order.Group.Unbundled.Int -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.NatInt import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.Algebra.Group.Subgroup.ZPowers.Basic diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Basic.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Basic.lean index 44e1c3d71de18c..f269dd69e86706 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Basic.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Basic.lean @@ -58,6 +58,7 @@ with a head term (`seq1`) is then transformed to a generalized continued fractio numerics, number theory, approximations, fractions -/ +assert_not_exists Finset namespace GenContFract diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean index d732ff25b6a7a1..0b971d47951635 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean @@ -37,6 +37,7 @@ of three sections: parts. -/ +assert_not_exists Finset namespace GenContFract diff --git a/Mathlib/Algebra/CubicDiscriminant.lean b/Mathlib/Algebra/CubicDiscriminant.lean index 42e56fed93eff9..4104d2add1285b 100644 --- a/Mathlib/Algebra/CubicDiscriminant.lean +++ b/Mathlib/Algebra/CubicDiscriminant.lean @@ -40,8 +40,6 @@ structure Cubic (R : Type*) where namespace Cubic -open Cubic Polynomial - open Polynomial variable {R S F K : Type*} diff --git a/Mathlib/Algebra/DirectSum/Basic.lean b/Mathlib/Algebra/DirectSum/Basic.lean index 4aab3891bf5605..50045a6c1ba5b3 100644 --- a/Mathlib/Algebra/DirectSum/Basic.lean +++ b/Mathlib/Algebra/DirectSum/Basic.lean @@ -367,8 +367,8 @@ theorem coe_of_apply {M S : Type*} [DecidableEq ι] [AddCommMonoid M] [SetLike S `M` is said to be internal if the canonical map `(⨁ i, A i) →+ M` is bijective. For the alternate statement in terms of independence and spanning, see -`DirectSum.subgroup_isInternal_iff_independent_and_supr_eq_top` and -`DirectSum.isInternal_submodule_iff_independent_and_iSup_eq_top`. -/ +`DirectSum.subgroup_isInternal_iff_iSupIndep_and_supr_eq_top` and +`DirectSum.isInternal_submodule_iff_iSupIndep_and_iSup_eq_top`. -/ def IsInternal {M S : Type*} [DecidableEq ι] [AddCommMonoid M] [SetLike S M] [AddSubmonoidClass S M] (A : ι → S) : Prop := Function.Bijective (DirectSum.coeAddMonoidHom A) diff --git a/Mathlib/Algebra/DirectSum/Internal.lean b/Mathlib/Algebra/DirectSum/Internal.lean index 34fbe957a61747..a75722faa88dc3 100644 --- a/Mathlib/Algebra/DirectSum/Internal.lean +++ b/Mathlib/Algebra/DirectSum/Internal.lean @@ -28,7 +28,7 @@ to represent this case, `(h : DirectSum.IsInternal A) [SetLike.GradedMonoid A]` needed. In the future there will likely be a data-carrying, constructive, typeclass version of `DirectSum.IsInternal` for providing an explicit decomposition function. -When `CompleteLattice.Independent (Set.range A)` (a weaker condition than +When `iSupIndep (Set.range A)` (a weaker condition than `DirectSum.IsInternal A`), these provide a grading of `⨆ i, A i`, and the mapping `⨁ i, A i →+ ⨆ i, A i` can be obtained as `DirectSum.toAddMonoid (fun i ↦ AddSubmonoid.inclusion <| le_iSup A i)`. diff --git a/Mathlib/Algebra/DirectSum/LinearMap.lean b/Mathlib/Algebra/DirectSum/LinearMap.lean index 25ffc82193de41..ff8f8b3d653a4a 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.WellFoundedGT.finite_ne_bot_of_independent - h.submodule_independent + have hN : {i | N i ≠ ⊥}.Finite := WellFoundedGT.finite_ne_bot_of_iSupIndep + h.submodule_iSupIndep 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) @@ -109,10 +109,10 @@ lemma trace_comp_eq_zero_of_commute_of_trace_restrict_eq_zero (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 + have hds := DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top f.independent_maxGenEigenspace hf have h_fin : {μ | f.maxGenEigenspace μ ≠ ⊥}.Finite := - CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent f.independent_maxGenEigenspace + WellFoundedGT.finite_ne_bot_of_iSupIndep f.independent_maxGenEigenspace simp [trace_eq_sum_trace_restrict' hds h_fin hfg, this] intro μ replace h_comm : Commute (g.restrict (f.mapsTo_maxGenEigenspace_of_comm h_comm μ)) @@ -136,14 +136,14 @@ Note that it is important the statement gives the user definitional control over _type_ of the term `trace R p (f.restrict hp')` depends on `p`. -/ lemma trace_eq_sum_trace_restrict_of_eq_biSup [∀ i, Module.Finite R (N i)] [∀ i, Module.Free R (N i)] - (s : Finset ι) (h : CompleteLattice.Independent <| fun i : s ↦ N i) + (s : Finset ι) (h : iSupIndep <| fun i : s ↦ N i) {f : Module.End R M} (hf : ∀ i, MapsTo f (N i) (N i)) (p : Submodule R M) (hp : p = ⨆ i ∈ s, N i) (hp' : MapsTo f p p := hp ▸ mapsTo_biSup_of_mapsTo (s : Set ι) hf) : trace R p (f.restrict hp') = ∑ i ∈ s, trace R (N i) (f.restrict (hf i)) := by classical let N' : s → Submodule R p := fun i ↦ (N i).comap p.subtype - replace h : IsInternal N' := hp ▸ isInternal_biSup_submodule_of_independent (s : Set ι) h + replace h : IsInternal N' := hp ▸ isInternal_biSup_submodule_of_iSupIndep (s : Set ι) h have hf' : ∀ i, MapsTo (restrict f hp') (N' i) (N' i) := fun i x hx' ↦ by simpa using hf i hx' let e : (i : s) → N' i ≃ₗ[R] N i := fun ⟨i, hi⟩ ↦ (N i).comapSubtypeEquivOfLe (hp ▸ le_biSup N hi) have _i1 : ∀ i, Module.Finite R (N' i) := fun i ↦ Module.Finite.equiv (e i).symm diff --git a/Mathlib/Algebra/DirectSum/Module.lean b/Mathlib/Algebra/DirectSum/Module.lean index 299c5d4caad54a..dba8c5158d5d0c 100644 --- a/Mathlib/Algebra/DirectSum/Module.lean +++ b/Mathlib/Algebra/DirectSum/Module.lean @@ -319,8 +319,11 @@ theorem IsInternal.submodule_iSup_eq_top (h : IsInternal A) : iSup A = ⊤ := by exact Function.Bijective.surjective h /-- If a direct sum of submodules is internal then the submodules are independent. -/ -theorem IsInternal.submodule_independent (h : IsInternal A) : CompleteLattice.Independent A := - CompleteLattice.independent_of_dfinsupp_lsum_injective _ h.injective +theorem IsInternal.submodule_iSupIndep (h : IsInternal A) : iSupIndep A := + iSupIndep_of_dfinsupp_lsum_injective _ h.injective + +@[deprecated (since := "2024-11-24")] +alias IsInternal.submodule_independent := IsInternal.submodule_iSupIndep /-- Given an internal direct sum decomposition of a module `M`, and a basis for each of the components of the direct sum, the disjoint union of these bases is a basis for `M`. -/ @@ -374,7 +377,7 @@ the two submodules are complementary. Over a `Ring R`, this is true as an iff, a `DirectSum.isInternal_submodule_iff_isCompl`. -/ theorem IsInternal.isCompl {A : ι → Submodule R M} {i j : ι} (hij : i ≠ j) (h : (Set.univ : Set ι) = {i, j}) (hi : IsInternal A) : IsCompl (A i) (A j) := - ⟨hi.submodule_independent.pairwiseDisjoint hij, + ⟨hi.submodule_iSupIndep.pairwiseDisjoint hij, codisjoint_iff.mpr <| Eq.symm <| hi.submodule_iSup_eq_top.symm.trans <| by rw [← sSup_pair, iSup, ← Set.image_univ, h, Set.image_insert_eq, Set.image_singleton]⟩ @@ -387,60 +390,76 @@ variable {ι : Type v} [dec_ι : DecidableEq ι] variable {M : Type*} [AddCommGroup M] [Module R M] /-- Note that this is not generally true for `[Semiring R]`; see -`CompleteLattice.Independent.dfinsupp_lsum_injective` for details. -/ -theorem isInternal_submodule_of_independent_of_iSup_eq_top {A : ι → Submodule R M} - (hi : CompleteLattice.Independent A) (hs : iSup A = ⊤) : IsInternal A := +`iSupIndep.dfinsupp_lsum_injective` for details. -/ +theorem isInternal_submodule_of_iSupIndep_of_iSup_eq_top {A : ι → Submodule R M} + (hi : iSupIndep A) (hs : iSup A = ⊤) : IsInternal A := ⟨hi.dfinsupp_lsum_injective, -- Note: https://github.com/leanprover-community/mathlib4/pull/8386 had to specify value of `f` (LinearMap.range_eq_top (f := DFinsupp.lsum _ _)).1 <| (Submodule.iSup_eq_range_dfinsupp_lsum _).symm.trans hs⟩ -/-- `iff` version of `DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top`, -`DirectSum.IsInternal.submodule_independent`, and `DirectSum.IsInternal.submodule_iSup_eq_top`. -/ -theorem isInternal_submodule_iff_independent_and_iSup_eq_top (A : ι → Submodule R M) : - IsInternal A ↔ CompleteLattice.Independent A ∧ iSup A = ⊤ := - ⟨fun i ↦ ⟨i.submodule_independent, i.submodule_iSup_eq_top⟩, - And.rec isInternal_submodule_of_independent_of_iSup_eq_top⟩ +@[deprecated (since := "2024-11-24")] +alias isInternal_submodule_of_independent_of_iSup_eq_top := + isInternal_submodule_of_iSupIndep_of_iSup_eq_top + +/-- `iff` version of `DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top`, +`DirectSum.IsInternal.iSupIndep`, and `DirectSum.IsInternal.submodule_iSup_eq_top`. -/ +theorem isInternal_submodule_iff_iSupIndep_and_iSup_eq_top (A : ι → Submodule R M) : + IsInternal A ↔ iSupIndep A ∧ iSup A = ⊤ := + ⟨fun i ↦ ⟨i.submodule_iSupIndep, i.submodule_iSup_eq_top⟩, + And.rec isInternal_submodule_of_iSupIndep_of_iSup_eq_top⟩ + +@[deprecated (since := "2024-11-24")] +alias isInternal_submodule_iff_independent_and_iSup_eq_top := + isInternal_submodule_iff_iSupIndep_and_iSup_eq_top /-- If a collection of submodules has just two indices, `i` and `j`, then `DirectSum.IsInternal` is equivalent to `isCompl`. -/ theorem isInternal_submodule_iff_isCompl (A : ι → Submodule R M) {i j : ι} (hij : i ≠ j) (h : (Set.univ : Set ι) = {i, j}) : IsInternal A ↔ IsCompl (A i) (A j) := by have : ∀ k, k = i ∨ k = j := fun k ↦ by simpa using Set.ext_iff.mp h k - rw [isInternal_submodule_iff_independent_and_iSup_eq_top, iSup, ← Set.image_univ, h, - Set.image_insert_eq, Set.image_singleton, sSup_pair, CompleteLattice.independent_pair hij this] + rw [isInternal_submodule_iff_iSupIndep_and_iSup_eq_top, iSup, ← Set.image_univ, h, + Set.image_insert_eq, Set.image_singleton, sSup_pair, iSupIndep_pair hij this] exact ⟨fun ⟨hd, ht⟩ ↦ ⟨hd, codisjoint_iff.mpr ht⟩, fun ⟨hd, ht⟩ ↦ ⟨hd, ht.eq_top⟩⟩ @[simp] theorem isInternal_ne_bot_iff {A : ι → Submodule R M} : IsInternal (fun i : {i // A i ≠ ⊥} ↦ A i) ↔ IsInternal A := by - simp only [isInternal_submodule_iff_independent_and_iSup_eq_top] - exact Iff.and CompleteLattice.independent_ne_bot_iff_independent <| by simp + simp [isInternal_submodule_iff_iSupIndep_and_iSup_eq_top] -lemma isInternal_biSup_submodule_of_independent {A : ι → Submodule R M} (s : Set ι) - (h : CompleteLattice.Independent <| fun i : s ↦ A i) : +lemma isInternal_biSup_submodule_of_iSupIndep {A : ι → Submodule R M} (s : Set ι) + (h : iSupIndep <| fun i : s ↦ A i) : IsInternal <| fun (i : s) ↦ (A i).comap (⨆ i ∈ s, A i).subtype := by - refine (isInternal_submodule_iff_independent_and_iSup_eq_top _).mpr ⟨?_, by simp [iSup_subtype]⟩ + refine (isInternal_submodule_iff_iSupIndep_and_iSup_eq_top _).mpr ⟨?_, by simp [iSup_subtype]⟩ let p := ⨆ i ∈ s, A i have hp : ∀ i ∈ s, A i ≤ p := fun i hi ↦ le_biSup A hi let e : Submodule R p ≃o Set.Iic p := p.mapIic suffices (e ∘ fun i : s ↦ (A i).comap p.subtype) = fun i ↦ ⟨A i, hp i i.property⟩ by - rw [← CompleteLattice.independent_map_orderIso_iff e, this] - exact CompleteLattice.independent_of_independent_coe_Iic_comp h + rw [← iSupIndep_map_orderIso_iff e, this] + exact .of_coe_Iic_comp h ext i m change m ∈ ((A i).comap p.subtype).map p.subtype ↔ _ rw [Submodule.map_comap_subtype, inf_of_le_right (hp i i.property)] +@[deprecated (since := "2024-11-24")] +alias isInternal_biSup_submodule_of_independent := isInternal_biSup_submodule_of_iSupIndep + /-! Now copy the lemmas for subgroup and submonoids. -/ -theorem IsInternal.addSubmonoid_independent {M : Type*} [AddCommMonoid M] {A : ι → AddSubmonoid M} - (h : IsInternal A) : CompleteLattice.Independent A := - CompleteLattice.independent_of_dfinsupp_sumAddHom_injective _ h.injective +theorem IsInternal.addSubmonoid_iSupIndep {M : Type*} [AddCommMonoid M] {A : ι → AddSubmonoid M} + (h : IsInternal A) : iSupIndep A := + iSupIndep_of_dfinsupp_sumAddHom_injective _ h.injective + +@[deprecated (since := "2024-11-24")] +alias IsInternal.addSubmonoid_independent := IsInternal.addSubmonoid_iSupIndep + +theorem IsInternal.addSubgroup_iSupIndep {G : Type*} [AddCommGroup G] {A : ι → AddSubgroup G} + (h : IsInternal A) : iSupIndep A := + iSupIndep_of_dfinsupp_sumAddHom_injective' _ h.injective -theorem IsInternal.addSubgroup_independent {M : Type*} [AddCommGroup M] {A : ι → AddSubgroup M} - (h : IsInternal A) : CompleteLattice.Independent A := - CompleteLattice.independent_of_dfinsupp_sumAddHom_injective' _ h.injective +@[deprecated (since := "2024-11-24")] +alias IsInternal.addSubgroup_independent := IsInternal.addSubgroup_iSupIndep end Ring diff --git a/Mathlib/Algebra/DirectSum/Ring.lean b/Mathlib/Algebra/DirectSum/Ring.lean index aa5a84bec944c0..883dc0bb086a7f 100644 --- a/Mathlib/Algebra/DirectSum/Ring.lean +++ b/Mathlib/Algebra/DirectSum/Ring.lean @@ -63,9 +63,8 @@ instances for: * `A : ι → Submodule S`: `DirectSum.GSemiring.ofSubmodules`, `DirectSum.GCommSemiring.ofSubmodules`. -If `CompleteLattice.independent (Set.range A)`, these provide a gradation of `⨆ i, A i`, and the -mapping `⨁ i, A i →+ ⨆ i, A i` can be obtained as -`DirectSum.toMonoid (fun i ↦ AddSubmonoid.inclusion <| le_iSup A i)`. +If `sSupIndep A`, these provide a gradation of `⨆ i, A i`, and the mapping `⨁ i, A i →+ ⨆ i, A i` +can be obtained as `DirectSum.toMonoid (fun i ↦ AddSubmonoid.inclusion <| le_iSup A i)`. ## Tags diff --git a/Mathlib/Algebra/FreeAlgebra/Cardinality.lean b/Mathlib/Algebra/FreeAlgebra/Cardinality.lean new file mode 100644 index 00000000000000..801dea8a9298ca --- /dev/null +++ b/Mathlib/Algebra/FreeAlgebra/Cardinality.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2024 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.Algebra.FreeAlgebra +import Mathlib.SetTheory.Cardinal.Free + +/-! +# Cardinality of free algebras + +This file contains some results about the cardinality of `FreeAlgebra`, +parallel to that of `MvPolynomial`. +-/ + +universe u v + +variable (R : Type u) [CommSemiring R] + +open Cardinal + +namespace FreeAlgebra + +variable (X : Type v) + +@[simp] +theorem cardinalMk_eq_max_lift [Nonempty X] [Nontrivial R] : + #(FreeAlgebra R X) = Cardinal.lift.{v} #R ⊔ Cardinal.lift.{u} #X ⊔ ℵ₀ := by + have hX := mk_freeMonoid X + haveI : Infinite (FreeMonoid X) := infinite_iff.2 (by simp [hX]) + rw [equivMonoidAlgebraFreeMonoid.toEquiv.cardinal_eq, MonoidAlgebra, + mk_finsupp_lift_of_infinite, hX, lift_max, lift_aleph0, sup_comm, ← sup_assoc] + +@[simp] +theorem cardinalMk_eq_lift [IsEmpty X] : #(FreeAlgebra R X) = Cardinal.lift.{v} #R := by + have := lift_mk_eq'.2 ⟨show (FreeMonoid X →₀ R) ≃ R from Equiv.finsuppUnique⟩ + rw [lift_id'.{u, v}, lift_umax] at this + rwa [equivMonoidAlgebraFreeMonoid.toEquiv.cardinal_eq, MonoidAlgebra] + +@[nontriviality] +theorem cardinalMk_eq_one [Subsingleton R] : #(FreeAlgebra R X) = 1 := by + rw [equivMonoidAlgebraFreeMonoid.toEquiv.cardinal_eq, MonoidAlgebra, mk_eq_one] + +theorem cardinalMk_le_max_lift : + #(FreeAlgebra R X) ≤ Cardinal.lift.{v} #R ⊔ Cardinal.lift.{u} #X ⊔ ℵ₀ := by + cases subsingleton_or_nontrivial R + · exact (cardinalMk_eq_one R X).trans_le (le_max_of_le_right one_le_aleph0) + cases isEmpty_or_nonempty X + · exact (cardinalMk_eq_lift R X).trans_le (le_max_of_le_left <| le_max_left _ _) + · exact (cardinalMk_eq_max_lift R X).le + +variable (X : Type u) + +theorem cardinalMk_eq_max [Nonempty X] [Nontrivial R] : #(FreeAlgebra R X) = #R ⊔ #X ⊔ ℵ₀ := by + simp + +theorem cardinalMk_eq [IsEmpty X] : #(FreeAlgebra R X) = #R := by + simp + +theorem cardinalMk_le_max : #(FreeAlgebra R X) ≤ #R ⊔ #X ⊔ ℵ₀ := by + simpa using cardinalMk_le_max_lift R X + +end FreeAlgebra + +namespace Algebra + +theorem lift_cardinalMk_adjoin_le {A : Type v} [Semiring A] [Algebra R A] (s : Set A) : + lift.{u} #(adjoin R s) ≤ lift.{v} #R ⊔ lift.{u} #s ⊔ ℵ₀ := by + have H := mk_range_le_lift (f := FreeAlgebra.lift R ((↑) : s → A)) + rw [lift_umax, lift_id'.{v, u}] at H + rw [Algebra.adjoin_eq_range_freeAlgebra_lift] + exact H.trans (FreeAlgebra.cardinalMk_le_max_lift R s) + +theorem cardinalMk_adjoin_le {A : Type u} [Semiring A] [Algebra R A] (s : Set A) : + #(adjoin R s) ≤ #R ⊔ #s ⊔ ℵ₀ := by + simpa using lift_cardinalMk_adjoin_le R s + +end Algebra diff --git a/Mathlib/Algebra/FreeMonoid/Count.lean b/Mathlib/Algebra/FreeMonoid/Count.lean index df4dcfd27f672e..53b2c0e4c51c35 100644 --- a/Mathlib/Algebra/FreeMonoid/Count.lean +++ b/Mathlib/Algebra/FreeMonoid/Count.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.FreeMonoid.Basic +import Mathlib.Algebra.Group.TypeTags.Hom /-! # `List.count` as a bundled homomorphism diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index 53093778e08834..7e6e9ce83070c0 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -7,8 +7,6 @@ import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Group.NatPowAssoc import Mathlib.Algebra.Order.BigOperators.Ring.Finset -import Mathlib.Algebra.Order.Field.Basic -import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Algebra.Ring.Opposite import Mathlib.Tactic.Abel import Mathlib.Algebra.Ring.Regular @@ -382,7 +380,7 @@ theorem geom_sum_Ico_le_of_lt_one [LinearOrderedField α] {x : α} (hx : 0 ≤ x {m n : ℕ} : ∑ i ∈ Ico m n, x ^ i ≤ x ^ m / (1 - x) := by rcases le_or_lt m n with (hmn | hmn) · rw [geom_sum_Ico' h'x.ne hmn] - apply div_le_div (pow_nonneg hx _) _ (sub_pos.2 h'x) le_rfl + apply div_le_div₀ (pow_nonneg hx _) _ (sub_pos.2 h'x) le_rfl simpa using pow_nonneg hx _ · rw [Ico_eq_empty, sum_empty] · apply div_nonneg (pow_nonneg hx _) diff --git a/Mathlib/Algebra/Group/Action/Defs.lean b/Mathlib/Algebra/Group/Action/Defs.lean index 823dbf69f35866..294281be04be57 100644 --- a/Mathlib/Algebra/Group/Action/Defs.lean +++ b/Mathlib/Algebra/Group/Action/Defs.lean @@ -297,9 +297,15 @@ lemma smul_mul_smul_comm [Mul α] [Mul β] [SMul α β] [IsScalarTower α β β] (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"))] +@[to_additive] alias smul_mul_smul := smul_mul_smul_comm +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated smul_mul_smul_comm (since := "2024-08-29")] smul_mul_smul +attribute [deprecated vadd_add_vadd_comm (since := "2024-08-29")] vadd_add_vadd + + /-- Note that the `IsScalarTower α β β` and `SMulCommClass α β β` typeclass arguments are usually satisfied by `Algebra α β`. -/ @[to_additive] diff --git a/Mathlib/Algebra/Group/Action/TypeTags.lean b/Mathlib/Algebra/Group/Action/TypeTags.lean index 0fa009b36d114b..1e65ced1a6024e 100644 --- a/Mathlib/Algebra/Group/Action/TypeTags.lean +++ b/Mathlib/Algebra/Group/Action/TypeTags.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Yury Kudryashov -/ import Mathlib.Algebra.Group.Action.End -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Group.TypeTags.Hom /-! # Additive and Multiplicative for group actions @@ -24,15 +24,15 @@ section open Additive Multiplicative -instance Additive.vadd [SMul α β] : VAdd (Additive α) β where vadd a := (toMul a • ·) +instance Additive.vadd [SMul α β] : VAdd (Additive α) β where vadd a := (a.toMul • ·) -instance Multiplicative.smul [VAdd α β] : SMul (Multiplicative α) β where smul a := (toAdd a +ᵥ ·) +instance Multiplicative.smul [VAdd α β] : SMul (Multiplicative α) β where smul a := (a.toAdd +ᵥ ·) -@[simp] lemma toMul_smul [SMul α β] (a) (b : β) : (toMul a : α) • b = a +ᵥ b := rfl +@[simp] lemma toMul_smul [SMul α β] (a:Additive α) (b : β) : (a.toMul : α) • b = a +ᵥ b := rfl @[simp] lemma ofMul_vadd [SMul α β] (a : α) (b : β) : ofMul a +ᵥ b = a • b := rfl -@[simp] lemma toAdd_vadd [VAdd α β] (a) (b : β) : (toAdd a : α) +ᵥ b = a • b := rfl +@[simp] lemma toAdd_vadd [VAdd α β] (a:Multiplicative α) (b : β) : (a.toAdd : α) +ᵥ b = a • b := rfl @[simp] lemma ofAdd_smul [VAdd α β] (a : α) (b : β) : ofAdd a • b = a +ᵥ b := rfl diff --git a/Mathlib/Algebra/Group/AddChar.lean b/Mathlib/Algebra/Group/AddChar.lean index 23505cff4f7524..0279bc188d39a8 100644 --- a/Mathlib/Algebra/Group/AddChar.lean +++ b/Mathlib/Algebra/Group/AddChar.lean @@ -115,7 +115,7 @@ def toMonoidHom (φ : AddChar A M) : Multiplicative A →* M where -- this instance was a bad idea and conflicted with `instFunLike` above @[simp] lemma toMonoidHom_apply (ψ : AddChar A M) (a : Multiplicative A) : - ψ.toMonoidHom a = ψ (Multiplicative.toAdd a) := + ψ.toMonoidHom a = ψ a.toAdd := rfl /-- An additive character maps multiples by natural numbers to powers. -/ @@ -142,7 +142,7 @@ def toMonoidHomEquiv : AddChar A M ≃ (Multiplicative A →* M) where ⇑(toMonoidHomEquiv.symm ψ) = ψ ∘ Multiplicative.ofAdd := rfl @[simp] lemma toMonoidHomEquiv_apply (ψ : AddChar A M) (a : Multiplicative A) : - toMonoidHomEquiv ψ a = ψ (Multiplicative.toAdd a) := rfl + toMonoidHomEquiv ψ a = ψ a.toAdd := rfl @[simp] lemma toMonoidHomEquiv_symm_apply (ψ : Multiplicative A →* M) (a : A) : toMonoidHomEquiv.symm ψ a = ψ (Multiplicative.ofAdd a) := rfl @@ -180,7 +180,7 @@ lemma coe_toAddMonoidHomEquiv (ψ : AddChar A M) : toAddMonoidHomEquiv ψ a = Additive.ofMul (ψ a) := rfl @[simp] lemma toAddMonoidHomEquiv_symm_apply (ψ : A →+ Additive M) (a : A) : - toAddMonoidHomEquiv.symm ψ a = Additive.toMul (ψ a) := rfl + toAddMonoidHomEquiv.symm ψ a = (ψ a).toMul := rfl /-- The trivial additive character (sending everything to `1`). -/ instance instOne : One (AddChar A M) := toMonoidHomEquiv.one @@ -253,7 +253,7 @@ 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")] +@[deprecated "No deprecation message was provided." (since := "2024-06-06")] def IsNontrivial (ψ : AddChar A M) : Prop := ∃ a : A, ψ a ≠ 1 set_option linter.deprecated false in diff --git a/Mathlib/Algebra/Group/Aut.lean b/Mathlib/Algebra/Group/Aut.lean index ac678be0258c9c..012f362054268f 100644 --- a/Mathlib/Algebra/Group/Aut.lean +++ b/Mathlib/Algebra/Group/Aut.lean @@ -260,9 +260,9 @@ theorem conj_symm_apply [AddGroup G] (g h : G) : (conj g).symm h = -g + h + g := -- Porting note: the exact translation of this mathlib3 lemma would be`(-conj g) h = -g + h + g`, -- but this no longer pass the simp_nf linter, as the LHS simplifies by `toMul_neg` to --- `(Additive.toMul (conj g))⁻¹`. +-- `(conj g).toMul⁻¹`. @[simp] -theorem conj_inv_apply [AddGroup G] (g h : G) : (Additive.toMul (conj g))⁻¹ h = -g + h + g := +theorem conj_inv_apply [AddGroup G] (g h : G) : (conj g).toMul⁻¹ h = -g + h + g := rfl /-- Isomorphic additive groups have isomorphic automorphism groups. -/ diff --git a/Mathlib/Algebra/Group/Defs.lean b/Mathlib/Algebra/Group/Defs.lean index 3abfe30a7d4174..3d069aab663a38 100644 --- a/Mathlib/Algebra/Group/Defs.lean +++ b/Mathlib/Algebra/Group/Defs.lean @@ -6,12 +6,9 @@ Authors: Jeremy Avigad, Leonardo de Moura, Simon Hudon, Mario Carneiro import Mathlib.Data.Int.Notation import Mathlib.Data.Nat.BinaryRec import Mathlib.Algebra.Group.ZeroOne +import Mathlib.Algebra.Group.Operations import Mathlib.Logic.Function.Defs -import Mathlib.Tactic.Lemma -import Mathlib.Tactic.TypeStar import Mathlib.Tactic.Simps.Basic -import Mathlib.Tactic.ToAdditive -import Mathlib.Util.AssertExists import Batteries.Logic /-! @@ -29,21 +26,15 @@ The file does not contain any lemmas except for For basic lemmas about these classes see `Algebra.Group.Basic`. -We also introduce notation classes `SMul` and `VAdd` for multiplicative and additive -actions and register the following instances: +We register the following instances: - `Pow M ℕ`, for monoids `M`, and `Pow G ℤ` for groups `G`; - `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). - ## Notation - `+`, `-`, `*`, `/`, `^` : the usual arithmetic operations; the underlying functions are `Add.add`, `Neg.neg`/`Sub.sub`, `Mul.mul`, `Div.div`, and `HPow.hPow`. -- `a • b` is used as notation for `HSMul.hSMul a b`. -- `a +ᵥ b` is used as notation for `HVAdd.hVAdd a b`. -/ @@ -55,187 +46,8 @@ universe u v w open Function -/-- -The notation typeclass for heterogeneous additive actions. -This enables the notation `a +ᵥ b : γ` where `a : α`, `b : β`. --/ -class HVAdd (α : Type u) (β : Type v) (γ : outParam (Type w)) where - /-- `a +ᵥ b` computes the sum of `a` and `b`. - The meaning of this notation is type-dependent. -/ - hVAdd : α → β → γ - -/-- -The notation typeclass for heterogeneous scalar multiplication. -This enables the notation `a • b : γ` where `a : α`, `b : β`. - -It is assumed to represent a left action in some sense. -The notation `a • b` is augmented with a macro (below) to have it elaborate as a left action. -Only the `b` argument participates in the elaboration algorithm: the algorithm uses the type of `b` -when calculating the type of the surrounding arithmetic expression -and it tries to insert coercions into `b` to get some `b'` -such that `a • b'` has the same type as `b'`. -See the module documentation near the macro for more details. --/ -class HSMul (α : Type u) (β : Type v) (γ : outParam (Type w)) where - /-- `a • b` computes the product of `a` and `b`. - The meaning of this notation is type-dependent, but it is intended to be used for left actions. -/ - hSMul : α → β → γ - -attribute [notation_class smul Simps.copySecond] HSMul -attribute [notation_class nsmul Simps.nsmulArgs] HSMul -attribute [notation_class zsmul Simps.zsmulArgs] HSMul - -/-- Type class for the `+ᵥ` notation. -/ -class VAdd (G : Type u) (P : Type v) where - /-- `a +ᵥ b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent, - but it is intended to be used for left actions. -/ - vadd : G → P → P - -/-- Type class for the `-ᵥ` notation. -/ -class VSub (G : outParam Type*) (P : Type*) where - /-- `a -ᵥ b` computes the difference of `a` and `b`. The meaning of this notation is - type-dependent, but it is intended to be used for additive torsors. -/ - vsub : P → P → G - -/-- Typeclass for types with a scalar multiplication operation, denoted `•` (`\bu`) -/ -@[to_additive (attr := ext)] -class SMul (M : Type u) (α : Type v) where - /-- `a • b` computes the product of `a` and `b`. The meaning of this notation is type-dependent, - but it is intended to be used for left actions. -/ - smul : M → α → α - -@[inherit_doc] infixl:65 " +ᵥ " => HVAdd.hVAdd -@[inherit_doc] infixl:65 " -ᵥ " => VSub.vsub -@[inherit_doc] infixr:73 " • " => HSMul.hSMul - -/-! -We have a macro to make `x • y` notation participate in the expression tree elaborator, -like other arithmetic expressions such as `+`, `*`, `/`, `^`, `=`, inequalities, etc. -The macro is using the `leftact%` elaborator introduced in -[this RFC](https://github.com/leanprover/lean4/issues/2854). - -As a concrete example of the effect of this macro, consider -```lean -variable [Ring R] [AddCommMonoid M] [Module R M] (r : R) (N : Submodule R M) (m : M) (n : N) -#check m + r • n -``` -Without the macro, the expression would elaborate as `m + ↑(r • n : ↑N) : M`. -With the macro, the expression elaborates as `m + r • (↑n : M) : M`. -To get the first interpretation, one can write `m + (r • n :)`. - -Here is a quick review of the expression tree elaborator: -1. It builds up an expression tree of all the immediately accessible operations - that are marked with `binop%`, `unop%`, `leftact%`, `rightact%`, `binrel%`, etc. -2. It elaborates every leaf term of this tree - (without an expected type, so as if it were temporarily wrapped in `(... :)`). -3. Using the types of each elaborated leaf, it computes a supremum type they can all be - coerced to, if such a supremum exists. -4. It inserts coercions around leaf terms wherever needed. - -The hypothesis is that individual expression trees tend to be calculations with respect -to a single algebraic structure. - -Note(kmill): If we were to remove `HSMul` and switch to using `SMul` directly, -then the expression tree elaborator would not be able to insert coercions within the right operand; -they would likely appear as `↑(x • y)` rather than `x • ↑y`, unlike other arithmetic operations. --/ - -@[inherit_doc HSMul.hSMul] -macro_rules | `($x • $y) => `(leftact% HSMul.hSMul $x $y) - -attribute [to_additive existing] Mul Div HMul instHMul HDiv instHDiv HSMul -attribute [to_additive (reorder := 1 2) SMul] Pow -attribute [to_additive (reorder := 1 2)] HPow -attribute [to_additive existing (reorder := 1 2, 5 6) hSMul] HPow.hPow -attribute [to_additive existing (reorder := 1 2, 4 5) smul] Pow.pow - -@[to_additive (attr := default_instance)] -instance instHSMul {α β} [SMul α β] : HSMul α β β where - hSMul := SMul.smul - -@[to_additive] -theorem SMul.smul_eq_hSMul {α β} [SMul α β] : (SMul.smul : α → β → β) = HSMul.hSMul := rfl - -attribute [to_additive existing (reorder := 1 2)] instHPow - variable {G : Type*} -/-- Class of types that have an inversion operation. -/ -@[to_additive, notation_class] -class Inv (α : Type u) where - /-- Invert an element of α. -/ - inv : α → α - -@[inherit_doc] -postfix:max "⁻¹" => Inv.inv - -section ite -variable {α : Type*} (P : Prop) [Decidable P] - -section Mul -variable [Mul α] - -@[to_additive] -lemma mul_dite (a : α) (b : P → α) (c : ¬ P → α) : - (a * if h : P then b h else c h) = if h : P then a * b h else a * c h := by split <;> rfl - -@[to_additive] -lemma mul_ite (a b c : α) : (a * if P then b else c) = if P then a * b else a * c := mul_dite .. - -@[to_additive] -lemma dite_mul (a : P → α) (b : ¬ P → α) (c : α) : - (if h : P then a h else b h) * c = if h : P then a h * c else b h * c := by split <;> rfl - -@[to_additive] -lemma ite_mul (a b c : α) : (if P then a else b) * c = if P then a * c else b * c := dite_mul .. - --- We make `mul_ite` and `ite_mul` simp lemmas, but not `add_ite` or `ite_add`. --- The problem we're trying to avoid is dealing with sums of the form `∑ x ∈ s, (f x + ite P 1 0)`, --- in which `add_ite` followed by `sum_ite` would needlessly slice up --- the `f x` terms according to whether `P` holds at `x`. --- There doesn't appear to be a corresponding difficulty so far with `mul_ite` and `ite_mul`. -attribute [simp] mul_dite dite_mul mul_ite ite_mul - -@[to_additive] -lemma dite_mul_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : - ((if h : P then a h else b h) * if h : P then c h else d h) = - if h : P then a h * c h else b h * d h := by split <;> rfl - -@[to_additive] -lemma ite_mul_ite (a b c d : α) : - ((if P then a else b) * if P then c else d) = if P then a * c else b * d := by split <;> rfl - -end Mul - -section Div -variable [Div α] - -@[to_additive] -lemma div_dite (a : α) (b : P → α) (c : ¬ P → α) : - (a / if h : P then b h else c h) = if h : P then a / b h else a / c h := by split <;> rfl - -@[to_additive] -lemma div_ite (a b c : α) : (a / if P then b else c) = if P then a / b else a / c := div_dite .. - -@[to_additive] -lemma dite_div (a : P → α) (b : ¬ P → α) (c : α) : - (if h : P then a h else b h) / c = if h : P then a h / c else b h / c := by split <;> rfl - -@[to_additive] -lemma ite_div (a b c : α) : (if P then a else b) / c = if P then a / c else b / c := dite_div .. - -@[to_additive] -lemma dite_div_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : - ((if h : P then a h else b h) / if h : P then c h else d h) = - if h : P then a h / c h else b h / d h := by split <;> rfl - -@[to_additive] -lemma ite_div_ite (a b c d : α) : - ((if P then a else b) / if P then c else d) = if P then a / c else b / d := dite_div_dite .. - -end Div -end ite - section Mul variable [Mul G] diff --git a/Mathlib/Algebra/Group/Equiv/Basic.lean b/Mathlib/Algebra/Group/Equiv/Basic.lean index fc891d4f3cf98c..b0b66218245bee 100644 --- a/Mathlib/Algebra/Group/Equiv/Basic.lean +++ b/Mathlib/Algebra/Group/Equiv/Basic.lean @@ -45,37 +45,6 @@ theorem map_ne_one_iff {f : F} {x : M} : end EmbeddingLike -/-- Makes a `OneHom` inverse from the bijective inverse of a `OneHom` -/ -@[to_additive (attr := simps) - "Make a `ZeroHom` inverse from the bijective inverse of a `ZeroHom`"] -def OneHom.inverse [One M] [One N] - (f : OneHom M N) (g : N → M) - (h₁ : Function.LeftInverse g f) : - OneHom N M := - { toFun := g, - map_one' := by rw [← f.map_one, h₁] } - -/-- Makes a multiplicative inverse from a bijection which preserves multiplication. -/ -@[to_additive (attr := simps) - "Makes an additive inverse from a bijection which preserves addition."] -def MulHom.inverse [Mul M] [Mul N] (f : M →ₙ* N) (g : N → M) - (h₁ : Function.LeftInverse g f) - (h₂ : Function.RightInverse g f) : N →ₙ* M where - toFun := g - map_mul' x y := - calc - g (x * y) = g (f (g x) * f (g y)) := by rw [h₂ x, h₂ y] - _ = g (f (g x * g y)) := by rw [f.map_mul] - _ = g x * g y := h₁ _ - -/-- The inverse of a bijective `MonoidHom` is a `MonoidHom`. -/ -@[to_additive (attr := simps) - "The inverse of a bijective `AddMonoidHom` is an `AddMonoidHom`."] -def MonoidHom.inverse {A B : Type*} [Monoid A] [Monoid B] (f : A →* B) (g : B → A) - (h₁ : Function.LeftInverse g f) (h₂ : Function.RightInverse g f) : B →* A := - { (f : OneHom A B).inverse g h₁, - (f : A →ₙ* B).inverse g h₁ h₂ with toFun := g } - /-- `AddEquiv α β` is the type of an equiv `α ≃ β` which preserves addition. -/ structure AddEquiv (A B : Type*) [Add A] [Add B] extends A ≃ B, AddHom A B @@ -111,6 +80,11 @@ infixl:25 " ≃* " => MulEquiv /-- Notation for an `AddEquiv`. -/ infixl:25 " ≃+ " => AddEquiv +@[to_additive] +lemma MulEquiv.toEquiv_injective {α β : Type*} [Mul α] [Mul β] : + Function.Injective (toEquiv : (α ≃* β) → (α ≃ β)) + | ⟨_, _⟩, ⟨_, _⟩, rfl => rfl + /-- `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? @@ -120,12 +94,28 @@ 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 -@[to_additive (attr := deprecated (since := "2024-11-10"))] +@[to_additive] alias MulEquivClass.map_eq_one_iff := EmbeddingLike.map_eq_one_iff -@[to_additive (attr := deprecated (since := "2024-11-10"))] +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated EmbeddingLike.map_eq_one_iff (since := "2024-11-10")] +MulEquivClass.map_eq_one_iff +attribute [deprecated EmbeddingLike.map_eq_zero_iff (since := "2024-11-10")] +AddEquivClass.map_eq_zero_iff + + +@[to_additive] alias MulEquivClass.map_ne_one_iff := EmbeddingLike.map_ne_one_iff +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated EmbeddingLike.map_ne_one_iff (since := "2024-11-10")] +MulEquivClass.map_ne_one_iff +attribute [deprecated EmbeddingLike.map_ne_zero_iff (since := "2024-11-10")] +AddEquivClass.map_ne_zero_iff + + namespace MulEquivClass variable (F) diff --git a/Mathlib/Algebra/Group/Equiv/TypeTags.lean b/Mathlib/Algebra/Group/Equiv/TypeTags.lean index 78c085f0746665..12338d2419e5a3 100644 --- a/Mathlib/Algebra/Group/Equiv/TypeTags.lean +++ b/Mathlib/Algebra/Group/Equiv/TypeTags.lean @@ -5,7 +5,7 @@ Authors: Johannes Hölzl, Callum Sutton, Yury Kudryashov -/ import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.Prod -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Group.TypeTags.Hom /-! # Additive and multiplicative equivalences associated to `Multiplicative` and `Additive`. @@ -118,8 +118,8 @@ and multiplicative endomorphisms of `Multiplicative A`. -/ @[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) + toFun x := fun i ↦ Multiplicative.ofAdd <| x.toAdd i + invFun x := Multiplicative.ofAdd fun i ↦ (x i).toAdd left_inv _ := rfl right_inv _ := rfl map_mul' _ _ := rfl @@ -134,8 +134,8 @@ abbrev MulEquiv.funMultiplicative [Add G] : @[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) + toFun x := fun i ↦ Additive.ofMul <| x.toMul i + invFun x := Additive.ofMul fun i ↦ (x i).toMul left_inv _ := rfl right_inv _ := rfl map_add' _ _ := rfl @@ -164,9 +164,9 @@ def MulEquiv.multiplicativeAdditive [MulOneClass H] : Multiplicative (Additive 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) + toFun x := (Multiplicative.ofAdd x.toAdd.1, + Multiplicative.ofAdd x.toAdd.2) + invFun := fun (x, y) ↦ Multiplicative.ofAdd (x.toAdd, y.toAdd) left_inv _ := rfl right_inv _ := rfl map_mul' _ _ := rfl @@ -175,9 +175,9 @@ def MulEquiv.prodMultiplicative [Add G] [Add 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) + toFun x := (Additive.ofMul x.toMul.1, + Additive.ofMul x.toMul.2) + invFun := fun (x, y) ↦ Additive.ofMul (x.toMul, y.toMul) left_inv _ := rfl right_inv _ := rfl map_add' _ _ := rfl diff --git a/Mathlib/Algebra/Group/Even.lean b/Mathlib/Algebra/Group/Even.lean index 5bd24647c2f65a..8df0d5b3613c91 100644 --- a/Mathlib/Algebra/Group/Even.lean +++ b/Mathlib/Algebra/Group/Even.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ import Mathlib.Algebra.Group.Opposite -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Group.TypeTags.Basic /-! # Squares and even elements @@ -62,7 +62,7 @@ instance [DecidablePred (IsSquare : α → Prop)] : DecidablePred (IsSquare : α lemma even_ofMul_iff {a : α} : Even (Additive.ofMul a) ↔ IsSquare a := Iff.rfl @[simp] -lemma isSquare_toMul_iff {a : Additive α} : IsSquare (Additive.toMul a) ↔ Even a := Iff.rfl +lemma isSquare_toMul_iff {a : Additive α} : IsSquare (a.toMul) ↔ Even a := Iff.rfl instance Additive.instDecidablePredEven [DecidablePred (IsSquare : α → Prop)] : DecidablePred (Even : Additive α → Prop) := @@ -76,7 +76,7 @@ variable [Add α] @[simp] lemma isSquare_ofAdd_iff {a : α} : IsSquare (Multiplicative.ofAdd a) ↔ Even a := Iff.rfl @[simp] -lemma even_toAdd_iff {a : Multiplicative α} : Even (Multiplicative.toAdd a) ↔ IsSquare a := Iff.rfl +lemma even_toAdd_iff {a : Multiplicative α} : Even a.toAdd ↔ IsSquare a := Iff.rfl instance Multiplicative.instDecidablePredIsSquare [DecidablePred (Even : α → Prop)] : DecidablePred (IsSquare : Multiplicative α → Prop) := diff --git a/Mathlib/Algebra/Group/Graph.lean b/Mathlib/Algebra/Group/Graph.lean new file mode 100644 index 00000000000000..a3cf4bee29867b --- /dev/null +++ b/Mathlib/Algebra/Group/Graph.lean @@ -0,0 +1,231 @@ +/- +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, David Loeffler +-/ +import Mathlib.Algebra.Group.Subgroup.Ker + +/-! +# Vertical line test for group homs + +This file proves the vertical line test for monoid homomorphisms/isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of monoids. Assume that `f` is surjective on the +first factor and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` at most +once. Then the image of `f` is the graph of some monoid homomorphism `f' : H → I`. + +Furthermore, if `f` is also surjective on the second factor and its image intersects every +"horizontal line" `{(h, i) | h : H}` at most once, then `f'` is actually an isomorphism +`f' : H ≃ I`. + +We also prove specialised versions when `f` is the inclusion of a subgroup of the direct product. +(The version for general homomorphisms can easily be reduced to this special case, but the +homomorphism version is more flexible in applications.) +-/ + +open Function Set + +variable {G H I : Type*} + +section Monoid +variable [Monoid G] [Monoid H] [Monoid I] + +namespace MonoidHom + +/-- The graph of a monoid homomorphism as a submonoid. + +See also `MonoidHom.graph` for the graph as a subgroup. -/ +@[to_additive +"The graph of a monoid homomorphism as a submonoid. + +See also `AddMonoidHom.graph` for the graph as a subgroup."] +def mgraph (f : G →* H) : Submonoid (G × H) where + carrier := {x | f x.1 = x.2} + one_mem' := map_one f + mul_mem' {x y} := by simp +contextual + +-- TODO: Can `to_additive` be smarter about `simps`? +attribute [simps! coe] mgraph +attribute [simps! coe] AddMonoidHom.mgraph +set_option linter.existingAttributeWarning false in +attribute [to_additive existing] coe_mgraph + +@[to_additive (attr := simp)] +lemma mem_mgraph {f : G →* H} {x : G × H} : x ∈ f.mgraph ↔ f x.1 = x.2 := .rfl + +@[to_additive] +lemma mgraph_eq_mrange_prod (f : G →* H) : f.mgraph = mrange ((id _).prod f) := by aesop + +/-- **Vertical line test** for monoid homomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of monoids. Assume that `f` is surjective on the +first factor and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` at most +once. Then the image of `f` is the graph of some monoid homomorphism `f' : H → I`. -/ +@[to_additive "**Vertical line test** for monoid homomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of monoids. Assume that `f` is surjective on the +first factor and that the image of `f` intersects every \"vertical line\" `{(h, i) | i : I}` at most +once. Then the image of `f` is the graph of some monoid homomorphism `f' : H → I`."] +lemma exists_mrange_eq_mgraph {f : G →* H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 → (f g₁).2 = (f g₂).2) : + ∃ f' : H →* I, mrange f = f'.mgraph := by + obtain ⟨f', hf'⟩ := exists_range_eq_graphOn_univ hf₁ hf + simp only [Set.ext_iff, Set.mem_range, mem_graphOn, mem_univ, true_and, Prod.forall] at hf' + use + { toFun := f' + map_one' := (hf' _ _).1 ⟨1, map_one _⟩ + map_mul' := by + simp_rw [hf₁.forall] + rintro g₁ g₂ + exact (hf' _ _).1 ⟨g₁ * g₂, by simp [Prod.ext_iff, (hf' (f _).1 _).1 ⟨_, rfl⟩]⟩ } + simpa [SetLike.ext_iff] using hf' + +/-- **Line test** for monoid isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of monoids. Assume that `f` is surjective on both +factors and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` and every +"horizontal line" `{(h, i) | h : H}` at most once. Then the image of `f` is the graph of some monoid +isomorphism `f' : H ≃ I`. -/ +@[to_additive "**Line test** for monoid isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of monoids. Assume that `f` is surjective on both +factors and that the image of `f` intersects every \"vertical line\" `{(h, i) | i : I}` and every +\"horizontal line\" `{(h, i) | h : H}` at most once. Then the image of `f` is the graph of some +monoid isomorphism `f' : H ≃ I`."] +lemma exists_mulEquiv_mrange_eq_mgraph {f : G →* H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf₂ : Surjective (Prod.snd ∘ f)) (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 ↔ (f g₁).2 = (f g₂).2) : + ∃ e : H ≃* I, mrange f = e.toMonoidHom.mgraph := by + obtain ⟨e₁, he₁⟩ := f.exists_mrange_eq_mgraph hf₁ fun _ _ ↦ (hf _ _).1 + obtain ⟨e₂, he₂⟩ := (MulEquiv.prodComm.toMonoidHom.comp f).exists_mrange_eq_mgraph (by simpa) <| + by simp [hf] + have he₁₂ h i : e₁ h = i ↔ e₂ i = h := by + rw [SetLike.ext_iff] at he₁ he₂ + aesop (add simp [Prod.swap_eq_iff_eq_swap]) + exact ⟨ + { toFun := e₁ + map_mul' := e₁.map_mul' + invFun := e₂ + left_inv := fun h ↦ by rw [← he₁₂] + right_inv := fun i ↦ by rw [he₁₂] }, he₁⟩ + +end MonoidHom + +/-- **Vertical line test** for monoid homomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of monoids. Assume that `G` maps bijectively to the +first factor. Then `G` is the graph of some monoid homomorphism `f : H → I`. -/ +@[to_additive "**Vertical line test** for additive monoid homomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of monoids. Assume that `G` surjects onto the first +factor and `G` intersects every \"vertical line\" `{(h, i) | i : I}` at most once. Then `G` is the +graph of some monoid homomorphism `f : H → I`."] +lemma Submonoid.exists_eq_mgraph {G : Submonoid (H × I)} (hG₁ : Bijective (Prod.fst ∘ G.subtype)) : + ∃ f : H →* I, G = f.mgraph := by + simpa using MonoidHom.exists_mrange_eq_mgraph hG₁.surjective + fun a b h ↦ congr_arg (Prod.snd ∘ G.subtype) (hG₁.injective h) + +/-- **Goursat's lemma** for monoid isomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of monoids. Assume that the natural maps from `G` to +both factors are bijective. Then `G` is the graph of some isomorphism `f : H ≃* I`. -/ +@[to_additive "**Goursat's lemma** for additive monoid isomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of additive monoids. Assume that the natural maps from +`G` to both factors are bijective. Then `G` is the graph of some isomorphism `f : H ≃+ I`."] +lemma Submonoid.exists_mulEquiv_eq_mgraph {G : Submonoid (H × I)} + (hG₁ : Bijective (Prod.fst ∘ G.subtype)) (hG₂ : Bijective (Prod.snd ∘ G.subtype)) : + ∃ e : H ≃* I, G = e.toMonoidHom.mgraph := by + simpa using MonoidHom.exists_mulEquiv_mrange_eq_mgraph hG₁.surjective hG₂.surjective + fun _ _ ↦ hG₁.injective.eq_iff.trans hG₂.injective.eq_iff.symm + +end Monoid + +section Group +variable [Group G] [Group H] [Group I] + +namespace MonoidHom + +/-- The graph of a group homomorphism as a subgroup. + +See also `MonoidHom.mgraph` for the graph as a submonoid. -/ +@[to_additive +"The graph of a group homomorphism as a subgroup. + +See also `AddMonoidHom.mgraph` for the graph as a submonoid."] +def graph (f : G →* H) : Subgroup (G × H) where + toSubmonoid := f.mgraph + inv_mem' {x} := by simp +contextual + +-- TODO: Can `to_additive` be smarter about `simps`? +attribute [simps! coe toSubmonoid] graph +attribute [simps! coe toAddSubmonoid] AddMonoidHom.graph +set_option linter.existingAttributeWarning false in +attribute [to_additive existing] coe_graph graph_toSubmonoid + +@[to_additive] +lemma mem_graph {f : G →* H} {x : G × H} : x ∈ f.mgraph ↔ f x.1 = x.2 := .rfl + +@[to_additive] +lemma graph_eq_range_prod (f : G →* H) : f.graph = range ((id _).prod f) := by aesop + +/-- **Vertical line test** for group homomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of groups. Assume that `f` is surjective on the +first factor and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` at most +once. Then the image of `f` is the graph of some group homomorphism `f' : H → I`. -/ +@[to_additive "**Vertical line test** for group homomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of groups. Assume that `f` is surjective on the +first factor and that the image of `f` intersects every \"vertical line\" `{(h, i) | i : I}` at most +once. Then the image of `f` is the graph of some group homomorphism `f' : H → I`."] +lemma exists_range_eq_graph {f : G →* H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 → (f g₁).2 = (f g₂).2) : + ∃ f' : H →* I, range f = f'.graph := by + simpa [SetLike.ext_iff] using exists_mrange_eq_mgraph hf₁ hf + +/-- **Line test** for group isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of groups. Assume that `f` is surjective on both +factors and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` and every +"horizontal line" `{(h, i) | h : H}` at most once. Then the image of `f` is the graph of some group +isomorphism `f' : H ≃ I`. -/ +@[to_additive "**Line test** for monoid isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of groups. Assume that `f` is surjective on both +factors and that the image of `f` intersects every \"vertical line\" `{(h, i) | i : I}` and every +\"horizontal line\" `{(h, i) | h : H}` at most once. Then the image of `f` is the graph of some +group isomorphism `f' : H ≃ I`."] +lemma exists_mulEquiv_range_eq_graph {f : G →* H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf₂ : Surjective (Prod.snd ∘ f)) (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 ↔ (f g₁).2 = (f g₂).2) : + ∃ e : H ≃* I, range f = e.toMonoidHom.graph := by + simpa [SetLike.ext_iff] using exists_mulEquiv_mrange_eq_mgraph hf₁ hf₂ hf + +end MonoidHom + +/-- **Vertical line test** for group homomorphisms. + +Let `G ≤ H × I` be a subgroup of a product of monoids. Assume that `G` maps bijectively to the +first factor. Then `G` is the graph of some monoid homomorphism `f : H → I`. -/ +@[to_additive "**Vertical line test** for additive monoid homomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of monoids. Assume that `G` surjects onto the first +factor and `G` intersects every \"vertical line\" `{(h, i) | i : I}` at most once. Then `G` is the +graph of some monoid homomorphism `f : H → I`."] +lemma Subgroup.exists_eq_graph {G : Subgroup (H × I)} (hG₁ : Bijective (Prod.fst ∘ G.subtype)) : + ∃ f : H →* I, G = f.graph := by + simpa [SetLike.ext_iff] using Submonoid.exists_eq_mgraph hG₁ + +/-- **Goursat's lemma** for monoid isomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of monoids. Assume that the natural maps from `G` to +both factors are bijective. Then `G` is the graph of some isomorphism `f : H ≃* I`. -/ +@[to_additive "**Goursat's lemma** for additive monoid isomorphisms. + +Let `G ≤ H × I` be a submonoid of a product of additive monoids. Assume that the natural maps from +`G` to both factors are bijective. Then `G` is the graph of some isomorphism `f : H ≃+ I`."] +lemma Subgroup.exists_mulEquiv_eq_graph {G : Subgroup (H × I)} + (hG₁ : Bijective (Prod.fst ∘ G.subtype)) (hG₂ : Bijective (Prod.snd ∘ G.subtype)) : + ∃ e : H ≃* I, G = e.toMonoidHom.graph := by + simpa [SetLike.ext_iff] using Submonoid.exists_mulEquiv_eq_mgraph hG₁ hG₂ + +end Group diff --git a/Mathlib/Algebra/Group/Hom/Defs.lean b/Mathlib/Algebra/Group/Hom/Defs.lean index 14f51627f6d9d2..ea061a0993f08e 100644 --- a/Mathlib/Algebra/Group/Hom/Defs.lean +++ b/Mathlib/Algebra/Group/Hom/Defs.lean @@ -30,6 +30,7 @@ building blocks for other homomorphisms: * `→+`: Bundled `AddMonoid` homs. Also use for `AddGroup` homs. * `→*`: Bundled `Monoid` homs. Also use for `Group` homs. +* `→ₙ+`: Bundled `AddSemigroup` homs. * `→ₙ*`: Bundled `Semigroup` homs. ## Implementation notes @@ -95,7 +96,9 @@ end Zero section Add -/-- `AddHom M N` is the type of functions `M → N` that preserve addition. +/-- `M →ₙ+ N` is the type of functions `M → N` that preserve addition. The `ₙ` in the notation +stands for "non-unital" because it is intended to match the notation for `NonUnitalAlgHom` and +`NonUnitalRingHom`, so a `AddHom` is a non-unital additive monoid hom. When possible, instead of parametrizing results over `(f : AddHom M N)`, you should parametrize over `(F : Type*) [AddHomClass F M N] (f : F)`. @@ -108,6 +111,9 @@ structure AddHom (M : Type*) (N : Type*) [Add M] [Add N] where /-- The proposition that the function preserves addition -/ protected map_add' : ∀ x y, toFun (x + y) = toFun x + toFun y +/-- `M →ₙ+ N` denotes the type of addition-preserving maps from `M` to `N`. -/ +infixr:25 " →ₙ+ " => AddHom + /-- `AddHomClass F M N` states that `F` is a type of addition-preserving homomorphisms. You should declare an instance of this typeclass when you extend `AddHom`. -/ @@ -843,6 +849,37 @@ protected theorem MonoidHom.map_zpow' [DivInvMonoid M] [DivInvMonoid N] (f : M (hf : ∀ x, f x⁻¹ = (f x)⁻¹) (a : M) (n : ℤ) : f (a ^ n) = f a ^ n := map_zpow' f hf a n +/-- Makes a `OneHom` inverse from the bijective inverse of a `OneHom` -/ +@[to_additive (attr := simps) + "Make a `ZeroHom` inverse from the bijective inverse of a `ZeroHom`"] +def OneHom.inverse [One M] [One N] + (f : OneHom M N) (g : N → M) + (h₁ : Function.LeftInverse g f) : + OneHom N M := + { toFun := g, + map_one' := by rw [← f.map_one, h₁] } + +/-- Makes a multiplicative inverse from a bijection which preserves multiplication. -/ +@[to_additive (attr := simps) + "Makes an additive inverse from a bijection which preserves addition."] +def MulHom.inverse [Mul M] [Mul N] (f : M →ₙ* N) (g : N → M) + (h₁ : Function.LeftInverse g f) + (h₂ : Function.RightInverse g f) : N →ₙ* M where + toFun := g + map_mul' x y := + calc + g (x * y) = g (f (g x) * f (g y)) := by rw [h₂ x, h₂ y] + _ = g (f (g x * g y)) := by rw [f.map_mul] + _ = g x * g y := h₁ _ + +/-- The inverse of a bijective `MonoidHom` is a `MonoidHom`. -/ +@[to_additive (attr := simps) + "The inverse of a bijective `AddMonoidHom` is an `AddMonoidHom`."] +def MonoidHom.inverse {A B : Type*} [Monoid A] [Monoid B] (f : A →* B) (g : B → A) + (h₁ : Function.LeftInverse g f) (h₂ : Function.RightInverse g f) : B →* A := + { (f : OneHom A B).inverse g h₁, + (f : A →ₙ* B).inverse g h₁ h₂ with toFun := g } + section End namespace Monoid diff --git a/Mathlib/Algebra/Group/Int.lean b/Mathlib/Algebra/Group/Int.lean index 1fcf3f10ef98c3..e9b98108c5110b 100644 --- a/Mathlib/Algebra/Group/Int.lean +++ b/Mathlib/Algebra/Group/Int.lean @@ -3,7 +3,8 @@ 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.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Even +import Mathlib.Algebra.Group.Nat.Units import Mathlib.Algebra.Group.Units.Basic import Mathlib.Data.Int.Sqrt @@ -73,9 +74,9 @@ section Multiplicative open Multiplicative -lemma toAdd_pow (a : Multiplicative ℤ) (b : ℕ) : toAdd (a ^ b) = toAdd a * b := mul_comm _ _ +lemma toAdd_pow (a : Multiplicative ℤ) (b : ℕ) : (a ^ b).toAdd = a.toAdd * b := mul_comm _ _ -lemma toAdd_zpow (a : Multiplicative ℤ) (b : ℤ) : toAdd (a ^ b) = toAdd a * b := mul_comm _ _ +lemma toAdd_zpow (a : Multiplicative ℤ) (b : ℤ) : (a ^ b).toAdd = a.toAdd * b := mul_comm _ _ @[simp] lemma ofAdd_mul (a b : ℤ) : ofAdd (a * b) = ofAdd a ^ b := (toAdd_zpow ..).symm diff --git a/Mathlib/Algebra/Group/Invertible/Defs.lean b/Mathlib/Algebra/Group/Invertible/Defs.lean index 58a3021aca7123..44a1421f131e78 100644 --- a/Mathlib/Algebra/Group/Invertible/Defs.lean +++ b/Mathlib/Algebra/Group/Invertible/Defs.lean @@ -230,23 +230,23 @@ section variable [Monoid α] {a b c : α} [Invertible c] variable (c) in -theorem mul_right_inj_of_invertible : a * c = b * c ↔ a = b := +theorem mul_left_inj_of_invertible : a * c = b * c ↔ a = b := ⟨fun h => by simpa using congr_arg (· * ⅟c) h, congr_arg (· * _)⟩ variable (c) in -theorem mul_left_inj_of_invertible : c * a = c * b ↔ a = b := +theorem mul_right_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_cancel_left] + rw [← mul_right_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_cancel_left] + rw [← mul_right_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), invOf_mul_cancel_right] + rw [← mul_left_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_invOf_cancel_right] + rw [← mul_left_inj_of_invertible (c := ⅟c), mul_invOf_cancel_right] end diff --git a/Mathlib/Algebra/Group/Nat/Basic.lean b/Mathlib/Algebra/Group/Nat/Basic.lean new file mode 100644 index 00000000000000..75212737a122bd --- /dev/null +++ b/Mathlib/Algebra/Group/Nat/Basic.lean @@ -0,0 +1,65 @@ +/- +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.Algebra.Group.Defs + +/-! +# The natural numbers form a monoid + +This file contains the additive and multiplicative monoid instances on the natural numbers. + +See note [foundational algebra order theory]. +-/ + +assert_not_exists MonoidWithZero +assert_not_exists DenselyOrdered + +namespace Nat + +/-! ### Instances -/ + +instance instAddCancelCommMonoid : AddCancelCommMonoid ℕ where + add := Nat.add + add_assoc := Nat.add_assoc + zero := Nat.zero + zero_add := Nat.zero_add + add_zero := Nat.add_zero + add_comm := Nat.add_comm + nsmul m n := m * n + nsmul_zero := Nat.zero_mul + nsmul_succ := succ_mul + add_left_cancel _ _ _ := Nat.add_left_cancel + +instance instCommMonoid : CommMonoid ℕ where + mul := Nat.mul + mul_assoc := Nat.mul_assoc + one := Nat.succ Nat.zero + one_mul := Nat.one_mul + mul_one := Nat.mul_one + mul_comm := Nat.mul_comm + npow m n := n ^ m + npow_zero := Nat.pow_zero + npow_succ _ _ := rfl + +/-! +### Extra instances to short-circuit type class resolution + +These also prevent non-computable instances being used to construct these instances non-computably. +-/ + +instance instAddCommMonoid : AddCommMonoid ℕ := by infer_instance +instance instAddMonoid : AddMonoid ℕ := by infer_instance +instance instMonoid : Monoid ℕ := by infer_instance +instance instCommSemigroup : CommSemigroup ℕ := by infer_instance +instance instSemigroup : Semigroup ℕ := by infer_instance +instance instAddCommSemigroup : AddCommSemigroup ℕ := by infer_instance +instance instAddSemigroup : AddSemigroup ℕ := by infer_instance + +/-! ### Miscellaneous lemmas -/ + +-- We set the simp priority slightly lower than default; later more general lemmas will replace it. +@[simp 900] protected lemma nsmul_eq_mul (m n : ℕ) : m • n = m * n := rfl + +end Nat diff --git a/Mathlib/Algebra/Group/Nat.lean b/Mathlib/Algebra/Group/Nat/Even.lean similarity index 60% rename from Mathlib/Algebra/Group/Nat.lean rename to Mathlib/Algebra/Group/Nat/Even.lean index 42bd89df34d7bb..86fcfd3209c0da 100644 --- a/Mathlib/Algebra/Group/Nat.lean +++ b/Mathlib/Algebra/Group/Nat/Even.lean @@ -4,76 +4,18 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Algebra.Group.Even -import Mathlib.Algebra.Group.Units.Defs +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Data.Nat.Sqrt /-! -# The natural numbers form a monoid - -This file contains the additive and multiplicative monoid instances on the natural numbers. - -See note [foundational algebra order theory]. +# `IsSquare` and `Even` for natural numbers -/ assert_not_exists MonoidWithZero assert_not_exists DenselyOrdered -open Multiplicative - namespace Nat -/-! ### Instances -/ - -instance instAddCancelCommMonoid : AddCancelCommMonoid ℕ where - add := Nat.add - add_assoc := Nat.add_assoc - zero := Nat.zero - zero_add := Nat.zero_add - add_zero := Nat.add_zero - add_comm := Nat.add_comm - nsmul m n := m * n - nsmul_zero := Nat.zero_mul - nsmul_succ := succ_mul - add_left_cancel _ _ _ := Nat.add_left_cancel - -instance instCommMonoid : CommMonoid ℕ where - mul := Nat.mul - mul_assoc := Nat.mul_assoc - one := Nat.succ Nat.zero - one_mul := Nat.one_mul - mul_one := Nat.mul_one - mul_comm := Nat.mul_comm - npow m n := n ^ m - npow_zero := Nat.pow_zero - npow_succ _ _ := rfl - -/-! -### Extra instances to short-circuit type class resolution - -These also prevent non-computable instances being used to construct these instances non-computably. --/ - -instance instAddCommMonoid : AddCommMonoid ℕ := by infer_instance -instance instAddMonoid : AddMonoid ℕ := by infer_instance -instance instMonoid : Monoid ℕ := by infer_instance -instance instCommSemigroup : CommSemigroup ℕ := by infer_instance -instance instSemigroup : Semigroup ℕ := by infer_instance -instance instAddCommSemigroup : AddCommSemigroup ℕ := by infer_instance -instance instAddSemigroup : AddSemigroup ℕ := by infer_instance - -/-! ### Miscellaneous lemmas -/ - --- We set the simp priority slightly lower than default; later more general lemmas will replace it. -@[simp 900] protected lemma nsmul_eq_mul (m n : ℕ) : m • n = m * n := rfl - -section Multiplicative - -lemma toAdd_pow (a : Multiplicative ℕ) (b : ℕ) : toAdd (a ^ b) = toAdd a * b := mul_comm _ _ - -@[simp] lemma ofAdd_mul (a b : ℕ) : ofAdd (a * b) = ofAdd a ^ b := (toAdd_pow _ _).symm - -end Multiplicative - /-! #### Parity -/ variable {m n : ℕ} @@ -158,23 +100,4 @@ example (m n : ℕ) (h : Even m) : ¬Even (n + 3) ↔ Even (m ^ 2 + m + n) := by -- Porting note: the `simp` lemmas about `bit*` no longer apply. example : ¬Even 25394535 := by decide -/-! #### Units -/ - -lemma units_eq_one (u : ℕˣ) : u = 1 := Units.ext <| Nat.eq_one_of_dvd_one ⟨u.inv, u.val_inv.symm⟩ - -lemma addUnits_eq_zero (u : AddUnits ℕ) : u = 0 := - AddUnits.ext <| (Nat.eq_zero_of_add_eq_zero u.val_neg).1 - -@[simp] protected lemma isUnit_iff {n : ℕ} : IsUnit n ↔ n = 1 where - mp := by rintro ⟨u, rfl⟩; obtain rfl := Nat.units_eq_one u; rfl - mpr h := h.symm ▸ ⟨1, rfl⟩ - -instance unique_units : Unique ℕˣ where - default := 1 - uniq := Nat.units_eq_one - -instance unique_addUnits : Unique (AddUnits ℕ) where - default := 0 - uniq := Nat.addUnits_eq_zero - end Nat diff --git a/Mathlib/Algebra/Group/Nat/TypeTags.lean b/Mathlib/Algebra/Group/Nat/TypeTags.lean new file mode 100644 index 00000000000000..a312f69a4aab79 --- /dev/null +++ b/Mathlib/Algebra/Group/Nat/TypeTags.lean @@ -0,0 +1,24 @@ +/- +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.Algebra.Group.Nat.Basic +import Mathlib.Algebra.Group.TypeTags.Basic + +/-! +# Lemmas about `Multiplicative ℕ` +-/ + +assert_not_exists MonoidWithZero +assert_not_exists DenselyOrdered + +open Multiplicative + +namespace Nat + +lemma toAdd_pow (a : Multiplicative ℕ) (b : ℕ) : (a ^ b).toAdd = a.toAdd * b := mul_comm _ _ + +@[simp] lemma ofAdd_mul (a b : ℕ) : ofAdd (a * b) = ofAdd a ^ b := (toAdd_pow _ _).symm + +end Nat diff --git a/Mathlib/Algebra/Group/Nat/Units.lean b/Mathlib/Algebra/Group/Nat/Units.lean new file mode 100644 index 00000000000000..edc5970d8d2e47 --- /dev/null +++ b/Mathlib/Algebra/Group/Nat/Units.lean @@ -0,0 +1,38 @@ +/- +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.Algebra.Group.Nat.Basic +import Mathlib.Algebra.Group.Units.Defs +import Mathlib.Logic.Unique + +/-! +# The unit of the natural numbers +-/ + +assert_not_exists MonoidWithZero +assert_not_exists DenselyOrdered + +namespace Nat + +/-! #### Units -/ + +lemma units_eq_one (u : ℕˣ) : u = 1 := Units.ext <| Nat.eq_one_of_dvd_one ⟨u.inv, u.val_inv.symm⟩ + +lemma addUnits_eq_zero (u : AddUnits ℕ) : u = 0 := + AddUnits.ext <| (Nat.eq_zero_of_add_eq_zero u.val_neg).1 + +@[simp] protected lemma isUnit_iff {n : ℕ} : IsUnit n ↔ n = 1 where + mp := by rintro ⟨u, rfl⟩; obtain rfl := Nat.units_eq_one u; rfl + mpr h := h.symm ▸ ⟨1, rfl⟩ + +instance unique_units : Unique ℕˣ where + default := 1 + uniq := Nat.units_eq_one + +instance unique_addUnits : Unique (AddUnits ℕ) where + default := 0 + uniq := Nat.addUnits_eq_zero + +end Nat diff --git a/Mathlib/Algebra/Group/Operations.lean b/Mathlib/Algebra/Group/Operations.lean new file mode 100644 index 00000000000000..dcc6957a258a7d --- /dev/null +++ b/Mathlib/Algebra/Group/Operations.lean @@ -0,0 +1,215 @@ +/- +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, Simon Hudon, Mario Carneiro +-/ + +import Mathlib.Tactic.Lemma +import Mathlib.Tactic.TypeStar +import Mathlib.Tactic.ToAdditive +import Mathlib.Util.AssertExists + +/-! +# Typeclasses for algebraic operations + +Notation typeclass for `Inv`, the multiplicative analogue of `Neg`. + +We also introduce notation classes `SMul` and `VAdd` for multiplicative and additive +actions. + +`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). + +## Notation + +- `a • b` is used as notation for `HSMul.hSMul a b`. +- `a +ᵥ b` is used as notation for `HVAdd.hVAdd a b`. + +-/ + +assert_not_exists One +assert_not_exists Function.Injective + +universe u v w + + +/-- +The notation typeclass for heterogeneous additive actions. +This enables the notation `a +ᵥ b : γ` where `a : α`, `b : β`. +-/ +class HVAdd (α : Type u) (β : Type v) (γ : outParam (Type w)) where + /-- `a +ᵥ b` computes the sum of `a` and `b`. + The meaning of this notation is type-dependent. -/ + hVAdd : α → β → γ + +/-- +The notation typeclass for heterogeneous scalar multiplication. +This enables the notation `a • b : γ` where `a : α`, `b : β`. + +It is assumed to represent a left action in some sense. +The notation `a • b` is augmented with a macro (below) to have it elaborate as a left action. +Only the `b` argument participates in the elaboration algorithm: the algorithm uses the type of `b` +when calculating the type of the surrounding arithmetic expression +and it tries to insert coercions into `b` to get some `b'` +such that `a • b'` has the same type as `b'`. +See the module documentation near the macro for more details. +-/ +class HSMul (α : Type u) (β : Type v) (γ : outParam (Type w)) where + /-- `a • b` computes the product of `a` and `b`. + The meaning of this notation is type-dependent, but it is intended to be used for left actions. -/ + hSMul : α → β → γ + +attribute [notation_class smul Simps.copySecond] HSMul +attribute [notation_class nsmul Simps.nsmulArgs] HSMul +attribute [notation_class zsmul Simps.zsmulArgs] HSMul + +/-- Type class for the `+ᵥ` notation. -/ +class VAdd (G : Type u) (P : Type v) where + /-- `a +ᵥ b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent, + but it is intended to be used for left actions. -/ + vadd : G → P → P + +/-- Type class for the `-ᵥ` notation. -/ +class VSub (G : outParam Type*) (P : Type*) where + /-- `a -ᵥ b` computes the difference of `a` and `b`. The meaning of this notation is + type-dependent, but it is intended to be used for additive torsors. -/ + vsub : P → P → G + +/-- Typeclass for types with a scalar multiplication operation, denoted `•` (`\bu`) -/ +@[to_additive (attr := ext)] +class SMul (M : Type u) (α : Type v) where + /-- `a • b` computes the product of `a` and `b`. The meaning of this notation is type-dependent, + but it is intended to be used for left actions. -/ + smul : M → α → α + +@[inherit_doc] infixl:65 " +ᵥ " => HVAdd.hVAdd +@[inherit_doc] infixl:65 " -ᵥ " => VSub.vsub +@[inherit_doc] infixr:73 " • " => HSMul.hSMul + +/-! +We have a macro to make `x • y` notation participate in the expression tree elaborator, +like other arithmetic expressions such as `+`, `*`, `/`, `^`, `=`, inequalities, etc. +The macro is using the `leftact%` elaborator introduced in +[this RFC](https://github.com/leanprover/lean4/issues/2854). + +As a concrete example of the effect of this macro, consider +```lean +variable [Ring R] [AddCommMonoid M] [Module R M] (r : R) (N : Submodule R M) (m : M) (n : N) +#check m + r • n +``` +Without the macro, the expression would elaborate as `m + ↑(r • n : ↑N) : M`. +With the macro, the expression elaborates as `m + r • (↑n : M) : M`. +To get the first interpretation, one can write `m + (r • n :)`. + +Here is a quick review of the expression tree elaborator: +1. It builds up an expression tree of all the immediately accessible operations + that are marked with `binop%`, `unop%`, `leftact%`, `rightact%`, `binrel%`, etc. +2. It elaborates every leaf term of this tree + (without an expected type, so as if it were temporarily wrapped in `(... :)`). +3. Using the types of each elaborated leaf, it computes a supremum type they can all be + coerced to, if such a supremum exists. +4. It inserts coercions around leaf terms wherever needed. + +The hypothesis is that individual expression trees tend to be calculations with respect +to a single algebraic structure. + +Note(kmill): If we were to remove `HSMul` and switch to using `SMul` directly, +then the expression tree elaborator would not be able to insert coercions within the right operand; +they would likely appear as `↑(x • y)` rather than `x • ↑y`, unlike other arithmetic operations. +-/ + +@[inherit_doc HSMul.hSMul] +macro_rules | `($x • $y) => `(leftact% HSMul.hSMul $x $y) + +attribute [to_additive existing] Mul Div HMul instHMul HDiv instHDiv HSMul +attribute [to_additive (reorder := 1 2) SMul] Pow +attribute [to_additive (reorder := 1 2)] HPow +attribute [to_additive existing (reorder := 1 2, 5 6) hSMul] HPow.hPow +attribute [to_additive existing (reorder := 1 2, 4 5) smul] Pow.pow + +@[to_additive (attr := default_instance)] +instance instHSMul {α β} [SMul α β] : HSMul α β β where + hSMul := SMul.smul + +@[to_additive] +theorem SMul.smul_eq_hSMul {α β} [SMul α β] : (SMul.smul : α → β → β) = HSMul.hSMul := rfl + +attribute [to_additive existing (reorder := 1 2)] instHPow + +variable {G : Type*} + +/-- Class of types that have an inversion operation. -/ +@[to_additive, notation_class] +class Inv (α : Type u) where + /-- Invert an element of α. -/ + inv : α → α + +@[inherit_doc] +postfix:max "⁻¹" => Inv.inv + +section ite +variable {α : Type*} (P : Prop) [Decidable P] + +section Mul +variable [Mul α] + +@[to_additive] +lemma mul_dite (a : α) (b : P → α) (c : ¬ P → α) : + (a * if h : P then b h else c h) = if h : P then a * b h else a * c h := by split <;> rfl + +@[to_additive] +lemma mul_ite (a b c : α) : (a * if P then b else c) = if P then a * b else a * c := mul_dite .. + +@[to_additive] +lemma dite_mul (a : P → α) (b : ¬ P → α) (c : α) : + (if h : P then a h else b h) * c = if h : P then a h * c else b h * c := by split <;> rfl + +@[to_additive] +lemma ite_mul (a b c : α) : (if P then a else b) * c = if P then a * c else b * c := dite_mul .. + +-- We make `mul_ite` and `ite_mul` simp lemmas, but not `add_ite` or `ite_add`. +-- The problem we're trying to avoid is dealing with sums of the form `∑ x ∈ s, (f x + ite P 1 0)`, +-- in which `add_ite` followed by `sum_ite` would needlessly slice up +-- the `f x` terms according to whether `P` holds at `x`. +-- There doesn't appear to be a corresponding difficulty so far with `mul_ite` and `ite_mul`. +attribute [simp] mul_dite dite_mul mul_ite ite_mul + +@[to_additive] +lemma dite_mul_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : + ((if h : P then a h else b h) * if h : P then c h else d h) = + if h : P then a h * c h else b h * d h := by split <;> rfl + +@[to_additive] +lemma ite_mul_ite (a b c d : α) : + ((if P then a else b) * if P then c else d) = if P then a * c else b * d := by split <;> rfl + +end Mul + +section Div +variable [Div α] + +@[to_additive] +lemma div_dite (a : α) (b : P → α) (c : ¬ P → α) : + (a / if h : P then b h else c h) = if h : P then a / b h else a / c h := by split <;> rfl + +@[to_additive] +lemma div_ite (a b c : α) : (a / if P then b else c) = if P then a / b else a / c := div_dite .. + +@[to_additive] +lemma dite_div (a : P → α) (b : ¬ P → α) (c : α) : + (if h : P then a h else b h) / c = if h : P then a h / c else b h / c := by split <;> rfl + +@[to_additive] +lemma ite_div (a b c : α) : (if P then a else b) / c = if P then a / c else b / c := dite_div .. + +@[to_additive] +lemma dite_div_dite (a : P → α) (b : ¬ P → α) (c : P → α) (d : ¬ P → α) : + ((if h : P then a h else b h) / if h : P then c h else d h) = + if h : P then a h / c h else b h / d h := by split <;> rfl + +@[to_additive] +lemma ite_div_ite (a b c d : α) : + ((if P then a else b) / if P then c else d) = if P then a / c else b / d := dite_div_dite .. + +end Div +end ite diff --git a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean index a7cd803e05c074..4330e3cf9abaef 100644 --- a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean @@ -5,11 +5,11 @@ Authors: Floris van Doorn, Yaël Dillies -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Group.Action.Pi +import Mathlib.Algebra.Group.Pointwise.Set.Finite +import Mathlib.Algebra.Group.Pointwise.Set.ListOfFn import Mathlib.Data.Finset.Density import Mathlib.Data.Finset.Max import Mathlib.Data.Finset.NAry -import Mathlib.Data.Set.Pointwise.Finite -import Mathlib.Data.Set.Pointwise.ListOfFn import Mathlib.Data.Set.Pointwise.SMul /-! diff --git a/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean index 479121a3d4a1b9..d06c3e7259b133 100644 --- a/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Group.Pointwise.Finset.Basic -import Mathlib.Data.Set.Pointwise.Interval +import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.Order.Interval.Finset.Defs /-! # Pointwise operations on intervals diff --git a/Mathlib/Data/Set/Pointwise/BigOperators.lean b/Mathlib/Algebra/Group/Pointwise/Set/BigOperators.lean similarity index 100% rename from Mathlib/Data/Set/Pointwise/BigOperators.lean rename to Mathlib/Algebra/Group/Pointwise/Set/BigOperators.lean diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean index 80a073b792385c..d31f9773753a24 100644 --- a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean @@ -3,7 +3,8 @@ Copyright (c) 2024 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ -import Mathlib.Data.Set.Pointwise.Finite +import Mathlib.Algebra.Group.Pointwise.Set.Finite +import Mathlib.Data.Set.Card import Mathlib.SetTheory.Cardinal.Finite /-! @@ -32,12 +33,18 @@ lemma natCard_mul_le : Nat.card (s * t) ≤ Nat.card s * Nat.card t := by refine Cardinal.toNat_le_toNat Cardinal.mk_mul_le ?_ aesop (add simp [Cardinal.mul_lt_aleph0_iff, finite_mul]) -@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_mul_le := natCard_mul_le +@[to_additive] alias card_mul_le := natCard_mul_le + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated natCard_mul_le (since := "2024-09-30")] card_mul_le +attribute [deprecated natCard_add_le (since := "2024-09-30")] card_add_le + end Mul section InvolutiveInv -variable [InvolutiveInv G] {s t : Set G} +variable [InvolutiveInv G] @[to_additive (attr := simp)] lemma _root_.Cardinal.mk_inv (s : Set G) : #↥(s⁻¹) = #s := by @@ -47,7 +54,18 @@ lemma _root_.Cardinal.mk_inv (s : Set G) : #↥(s⁻¹) = #s := by lemma natCard_inv (s : Set G) : Nat.card ↥(s⁻¹) = Nat.card s := by rw [← image_inv, Nat.card_image_of_injective inv_injective] -@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_inv := natCard_inv +@[to_additive] alias card_inv := natCard_inv + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated natCard_inv (since := "2024-09-30")] card_inv +attribute [deprecated natCard_neg (since := "2024-09-30")] card_neg + +@[to_additive (attr := simp)] +lemma encard_inv (s : Set G) : s⁻¹.encard = s.encard := by simp [encard, PartENat.card] + +@[to_additive (attr := simp)] +lemma ncard_inv (s : Set G) : s⁻¹.ncard = s.ncard := by simp [ncard] end InvolutiveInv @@ -67,7 +85,12 @@ variable [Group G] {s t : Set G} lemma natCard_div_le : Nat.card (s / t) ≤ Nat.card s * Nat.card t := by rw [div_eq_mul_inv, ← natCard_inv t]; exact natCard_mul_le -@[to_additive (attr := deprecated (since := "2024-09-30"))] alias card_div_le := natCard_div_le +@[to_additive] alias card_div_le := natCard_div_le + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated natCard_div_le (since := "2024-09-30")] card_div_le +attribute [deprecated natCard_sub_le (since := "2024-09-30")] card_sub_le variable [MulAction G α] @@ -79,8 +102,20 @@ lemma _root_.Cardinal.mk_smul_set (a : G) (s : Set α) : #↥(a • s) = #s := lemma natCard_smul_set (a : G) (s : Set α) : Nat.card ↥(a • s) = Nat.card s := Nat.card_image_of_injective (MulAction.injective a) _ -@[to_additive (attr := deprecated (since := "2024-09-30"))] +@[to_additive] alias card_smul_set := Cardinal.mk_smul_set +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated Cardinal.mk_smul_set (since := "2024-09-30")] card_smul_set +attribute [deprecated Cardinal.mk_vadd_set (since := "2024-09-30")] card_vadd_set + +@[to_additive (attr := simp)] +lemma encard_smul_set (a : G) (s : Set α) : (a • s).encard = s.encard := by + simp [encard, PartENat.card] + +@[to_additive (attr := simp)] +lemma ncard_smul_set (a : G) (s : Set α) : (a • s).ncard = s.ncard := by simp [ncard] + end Group end Set diff --git a/Mathlib/Data/Set/Pointwise/Finite.lean b/Mathlib/Algebra/Group/Pointwise/Set/Finite.lean similarity index 100% rename from Mathlib/Data/Set/Pointwise/Finite.lean rename to Mathlib/Algebra/Group/Pointwise/Set/Finite.lean diff --git a/Mathlib/Data/Set/Pointwise/ListOfFn.lean b/Mathlib/Algebra/Group/Pointwise/Set/ListOfFn.lean similarity index 100% rename from Mathlib/Data/Set/Pointwise/ListOfFn.lean rename to Mathlib/Algebra/Group/Pointwise/Set/ListOfFn.lean diff --git a/Mathlib/Algebra/Group/Prod.lean b/Mathlib/Algebra/Group/Prod.lean index 02781d10d00679..e6e9519ae64833 100644 --- a/Mathlib/Algebra/Group/Prod.lean +++ b/Mathlib/Algebra/Group/Prod.lean @@ -149,6 +149,8 @@ theorem mk_div_mk [Div G] [Div H] (x₁ x₂ : G) (y₁ y₂ : H) : theorem swap_div [Div G] [Div H] (a b : G × H) : (a / b).swap = a.swap / b.swap := rfl +@[to_additive] lemma div_def [Div M] [Div N] (a b : M × N) : a / b = (a.1 / b.1, a.2 / b.2) := rfl + @[to_additive] instance instSemigroup [Semigroup M] [Semigroup N] : Semigroup (M × N) := { mul_assoc := fun _ _ _ => mk.inj_iff.mpr ⟨mul_assoc _ _ _, mul_assoc _ _ _⟩ } diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index 6fc988e05de4bd..c6b11e2b701e3e 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -5,20 +5,13 @@ Authors: Kexing Ying -/ import Mathlib.Algebra.Group.Conj import Mathlib.Algebra.Group.Pi.Lemmas -import Mathlib.Algebra.Group.Submonoid.Operations -import Mathlib.Algebra.Group.Subgroup.Defs -import Mathlib.Data.Set.Image -import Mathlib.Tactic.ApplyFun +import Mathlib.Algebra.Group.Subgroup.Ker /-! -# Subgroups +# Basic results on subgroups -We prove subgroups of a group form a complete lattice, and results about images and preimages of -subgroups under group homomorphisms. The bundled subgroups use bundled monoid homomorphisms. - -There are also theorems about the subgroups generated by an element or a subset of a group, -defined both inductively and as the infimum of the set of subgroups containing a given -element/subset. +We prove basic results on the definitions of subgroups. The bundled subgroups use bundled monoid +homomorphisms. Special thanks goes to Amelia Livingston and Yury Kudryashov for their help and inspiration. @@ -40,31 +33,9 @@ Notation used here: Definitions in the file: -* `CompleteLattice (Subgroup G)` : the subgroups of `G` form a complete lattice - -* `Subgroup.closure k` : the minimal subgroup that includes the set `k` - -* `Subgroup.subtype` : the natural group homomorphism from a subgroup of group `G` to `G` - -* `Subgroup.gi` : `closure` forms a Galois insertion with the coercion to set - -* `Subgroup.comap H f` : the preimage of a subgroup `H` along the group homomorphism `f` is also a - subgroup - -* `Subgroup.map f H` : the image of a subgroup `H` along the group homomorphism `f` is also a - subgroup - * `Subgroup.prod H K` : the product of subgroups `H`, `K` of groups `G`, `N` respectively, `H × K` is a subgroup of `G × N` -* `MonoidHom.range f` : the range of the group homomorphism `f` is a subgroup - -* `MonoidHom.ker f` : the kernel of a group homomorphism `f` is the subgroup of elements `x : G` - such that `f x = 1` - -* `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 Subgroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as @@ -96,43 +67,6 @@ theorem div_mem_comm_iff {a b : G} : a / b ∈ H ↔ b / a ∈ H := end SubgroupClass -/-! -### Conversion to/from `Additive`/`Multiplicative` --/ - - -section mul_add - -/-- Subgroups of a group `G` are isomorphic to additive subgroups of `Additive G`. -/ -@[simps!] -def Subgroup.toAddSubgroup : Subgroup G ≃o AddSubgroup (Additive G) where - toFun S := { Submonoid.toAddSubmonoid S.toSubmonoid with neg_mem' := S.inv_mem' } - invFun S := { AddSubmonoid.toSubmonoid S.toAddSubmonoid with inv_mem' := S.neg_mem' } - left_inv x := by cases x; rfl - right_inv x := by cases x; rfl - map_rel_iff' := Iff.rfl - -/-- Additive subgroup of an additive group `Additive G` are isomorphic to subgroup of `G`. -/ -abbrev AddSubgroup.toSubgroup' : AddSubgroup (Additive G) ≃o Subgroup G := - Subgroup.toAddSubgroup.symm - -/-- Additive subgroups of an additive group `A` are isomorphic to subgroups of `Multiplicative A`. --/ -@[simps!] -def AddSubgroup.toSubgroup : AddSubgroup A ≃o Subgroup (Multiplicative A) where - toFun S := { AddSubmonoid.toSubmonoid S.toAddSubmonoid with inv_mem' := S.neg_mem' } - invFun S := { Submonoid.toAddSubmonoid S.toSubmonoid with neg_mem' := S.inv_mem' } - left_inv x := by cases x; rfl - right_inv x := by cases x; rfl - map_rel_iff' := Iff.rfl - -/-- Subgroups of an additive group `Multiplicative A` are isomorphic to additive subgroups of `A`. --/ -abbrev Subgroup.toAddSubgroup' : Subgroup (Multiplicative A) ≃o AddSubgroup A := - AddSubgroup.toSubgroup.symm - -end mul_add - namespace Subgroup variable (H K : Subgroup G) @@ -141,691 +75,11 @@ variable (H K : Subgroup G) protected theorem div_mem_comm_iff {a b : G} : a / b ∈ H ↔ b / a ∈ H := div_mem_comm_iff -/-- The subgroup `G` of the group `G`. -/ -@[to_additive "The `AddSubgroup G` of the `AddGroup G`."] -instance : Top (Subgroup G) := - ⟨{ (⊤ : Submonoid G) with inv_mem' := fun _ => Set.mem_univ _ }⟩ - -/-- The top subgroup is isomorphic to the group. - -This is the group version of `Submonoid.topEquiv`. -/ -@[to_additive (attr := simps!) - "The top additive subgroup is isomorphic to the additive group. - - This is the additive group version of `AddSubmonoid.topEquiv`."] -def topEquiv : (⊤ : Subgroup G) ≃* G := - Submonoid.topEquiv - -/-- The trivial subgroup `{1}` of a group `G`. -/ -@[to_additive "The trivial `AddSubgroup` `{0}` of an `AddGroup` `G`."] -instance : Bot (Subgroup G) := - ⟨{ (⊥ : Submonoid G) with inv_mem' := by simp}⟩ - -@[to_additive] -instance : Inhabited (Subgroup G) := - ⟨⊥⟩ - -@[to_additive (attr := simp)] -theorem mem_bot {x : G} : x ∈ (⊥ : Subgroup G) ↔ x = 1 := - Iff.rfl - -@[to_additive (attr := simp)] -theorem mem_top (x : G) : x ∈ (⊤ : Subgroup G) := - Set.mem_univ x - -@[to_additive (attr := simp)] -theorem coe_top : ((⊤ : Subgroup G) : Set G) = Set.univ := - rfl - -@[to_additive (attr := simp)] -theorem coe_bot : ((⊥ : Subgroup G) : Set G) = {1} := - rfl - -@[to_additive] -instance : Unique (⊥ : Subgroup G) := - ⟨⟨1⟩, fun g => Subtype.ext g.2⟩ - -@[to_additive (attr := simp)] -theorem top_toSubmonoid : (⊤ : Subgroup G).toSubmonoid = ⊤ := - rfl - -@[to_additive (attr := simp)] -theorem bot_toSubmonoid : (⊥ : Subgroup G).toSubmonoid = ⊥ := - rfl - -@[to_additive] -theorem eq_bot_iff_forall : H = ⊥ ↔ ∀ x ∈ H, x = (1 : G) := - toSubmonoid_injective.eq_iff.symm.trans <| Submonoid.eq_bot_iff_forall _ - -@[to_additive] -theorem eq_bot_of_subsingleton [Subsingleton H] : H = ⊥ := by - rw [Subgroup.eq_bot_iff_forall] - intro y hy - rw [← Subgroup.coe_mk H y hy, Subsingleton.elim (⟨y, hy⟩ : H) 1, Subgroup.coe_one] - -@[to_additive (attr := simp, norm_cast)] -theorem coe_eq_univ {H : Subgroup G} : (H : Set G) = Set.univ ↔ H = ⊤ := - (SetLike.ext'_iff.trans (by rfl)).symm - -@[to_additive] -theorem coe_eq_singleton {H : Subgroup G} : (∃ g : G, (H : Set G) = {g}) ↔ H = ⊥ := - ⟨fun ⟨g, hg⟩ => - haveI : Subsingleton (H : Set G) := by - rw [hg] - infer_instance - H.eq_bot_of_subsingleton, - fun h => ⟨1, SetLike.ext'_iff.mp h⟩⟩ - -@[to_additive] -theorem nontrivial_iff_exists_ne_one (H : Subgroup G) : Nontrivial H ↔ ∃ x ∈ H, x ≠ (1 : G) := by - rw [Subtype.nontrivial_iff_exists_ne (fun x => x ∈ H) (1 : H)] - simp - -@[to_additive] -theorem exists_ne_one_of_nontrivial (H : Subgroup G) [Nontrivial H] : - ∃ x ∈ H, x ≠ 1 := by - rwa [← Subgroup.nontrivial_iff_exists_ne_one] - -@[to_additive] -theorem nontrivial_iff_ne_bot (H : Subgroup G) : Nontrivial H ↔ H ≠ ⊥ := by - rw [nontrivial_iff_exists_ne_one, ne_eq, eq_bot_iff_forall] - simp only [ne_eq, not_forall, exists_prop] - -/-- A subgroup is either the trivial subgroup or nontrivial. -/ -@[to_additive "A subgroup is either the trivial subgroup or nontrivial."] -theorem bot_or_nontrivial (H : Subgroup G) : H = ⊥ ∨ Nontrivial H := by - have := nontrivial_iff_ne_bot H - tauto - -/-- A subgroup is either the trivial subgroup or contains a non-identity element. -/ -@[to_additive "A subgroup is either the trivial subgroup or contains a nonzero element."] -theorem bot_or_exists_ne_one (H : Subgroup G) : H = ⊥ ∨ ∃ x ∈ H, x ≠ (1 : G) := by - convert H.bot_or_nontrivial - rw [nontrivial_iff_exists_ne_one] - -@[to_additive] -lemma ne_bot_iff_exists_ne_one {H : Subgroup G} : H ≠ ⊥ ↔ ∃ a : ↥H, a ≠ 1 := by - rw [← nontrivial_iff_ne_bot, nontrivial_iff_exists_ne_one] - simp only [ne_eq, Subtype.exists, mk_eq_one, exists_prop] - -/-- The inf of two subgroups is their intersection. -/ -@[to_additive "The inf of two `AddSubgroup`s is their intersection."] -instance : Min (Subgroup G) := - ⟨fun H₁ H₂ => - { H₁.toSubmonoid ⊓ H₂.toSubmonoid with - inv_mem' := fun ⟨hx, hx'⟩ => ⟨H₁.inv_mem hx, H₂.inv_mem hx'⟩ }⟩ - -@[to_additive (attr := simp)] -theorem coe_inf (p p' : Subgroup G) : ((p ⊓ p' : Subgroup G) : Set G) = (p : Set G) ∩ p' := - rfl - -@[to_additive (attr := simp)] -theorem mem_inf {p p' : Subgroup G} {x : G} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := - Iff.rfl - -@[to_additive] -instance : InfSet (Subgroup G) := - ⟨fun s => - { (⨅ S ∈ s, Subgroup.toSubmonoid S).copy (⋂ S ∈ s, ↑S) (by simp) with - inv_mem' := fun {x} hx => - Set.mem_biInter fun i h => i.inv_mem (by apply Set.mem_iInter₂.1 hx i h) }⟩ - -@[to_additive (attr := simp, norm_cast)] -theorem coe_sInf (H : Set (Subgroup G)) : ((sInf H : Subgroup G) : Set G) = ⋂ s ∈ H, ↑s := - rfl - -@[to_additive (attr := simp)] -theorem mem_sInf {S : Set (Subgroup G)} {x : G} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p := - Set.mem_iInter₂ - -@[to_additive] -theorem mem_iInf {ι : Sort*} {S : ι → Subgroup G} {x : G} : (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by - simp only [iInf, mem_sInf, Set.forall_mem_range] - -@[to_additive (attr := simp, norm_cast)] -theorem coe_iInf {ι : Sort*} {S : ι → Subgroup G} : (↑(⨅ i, S i) : Set G) = ⋂ i, S i := by - simp only [iInf, coe_sInf, Set.biInter_range] - -/-- Subgroups of a group form a complete lattice. -/ -@[to_additive "The `AddSubgroup`s of an `AddGroup` form a complete lattice."] -instance : CompleteLattice (Subgroup G) := - { completeLatticeOfInf (Subgroup G) fun _s => - IsGLB.of_image SetLike.coe_subset_coe isGLB_biInf with - bot := ⊥ - bot_le := fun S _x hx => (mem_bot.1 hx).symm ▸ S.one_mem - top := ⊤ - le_top := fun _S x _hx => mem_top x - inf := (· ⊓ ·) - le_inf := fun _a _b _c ha hb _x hx => ⟨ha hx, hb hx⟩ - inf_le_left := fun _a _b _x => And.left - inf_le_right := fun _a _b _x => And.right } - -@[to_additive] -theorem mem_sup_left {S T : Subgroup G} : ∀ {x : G}, x ∈ S → x ∈ S ⊔ T := - have : S ≤ S ⊔ T := le_sup_left; fun h ↦ this h - -@[to_additive] -theorem mem_sup_right {S T : Subgroup G} : ∀ {x : G}, x ∈ T → x ∈ S ⊔ T := - have : T ≤ S ⊔ T := le_sup_right; fun h ↦ this h - -@[to_additive] -theorem mul_mem_sup {S T : Subgroup G} {x y : G} (hx : x ∈ S) (hy : y ∈ T) : x * y ∈ S ⊔ T := - (S ⊔ T).mul_mem (mem_sup_left hx) (mem_sup_right hy) - -@[to_additive] -theorem mem_iSup_of_mem {ι : Sort*} {S : ι → Subgroup G} (i : ι) : - ∀ {x : G}, x ∈ S i → x ∈ iSup S := - have : S i ≤ iSup S := le_iSup _ _; fun h ↦ this h - -@[to_additive] -theorem mem_sSup_of_mem {S : Set (Subgroup G)} {s : Subgroup G} (hs : s ∈ S) : - ∀ {x : G}, x ∈ s → x ∈ sSup S := - have : s ≤ sSup S := le_sSup hs; fun h ↦ this h - -@[to_additive (attr := simp)] -theorem subsingleton_iff : Subsingleton (Subgroup G) ↔ Subsingleton G := - ⟨fun _ => - ⟨fun x y => - have : ∀ i : G, i = 1 := fun i => - mem_bot.mp <| Subsingleton.elim (⊤ : Subgroup G) ⊥ ▸ mem_top i - (this x).trans (this y).symm⟩, - fun _ => ⟨fun x y => Subgroup.ext fun i => Subsingleton.elim 1 i ▸ by simp [Subgroup.one_mem]⟩⟩ - -@[to_additive (attr := simp)] -theorem nontrivial_iff : Nontrivial (Subgroup G) ↔ Nontrivial G := - not_iff_not.mp - ((not_nontrivial_iff_subsingleton.trans subsingleton_iff).trans - not_nontrivial_iff_subsingleton.symm) - -@[to_additive] -instance [Subsingleton G] : Unique (Subgroup G) := - ⟨⟨⊥⟩, fun a => @Subsingleton.elim _ (subsingleton_iff.mpr ‹_›) a _⟩ - -@[to_additive] -instance [Nontrivial G] : Nontrivial (Subgroup G) := - nontrivial_iff.mpr ‹_› - -@[to_additive] -theorem eq_top_iff' : H = ⊤ ↔ ∀ x : G, x ∈ H := - eq_top_iff.trans ⟨fun h m => h <| mem_top m, fun h m _ => h m⟩ - -/-- The `Subgroup` generated by a set. -/ -@[to_additive "The `AddSubgroup` generated by a set"] -def closure (k : Set G) : Subgroup G := - sInf { K | k ⊆ K } - variable {k : Set G} -@[to_additive] -theorem mem_closure {x : G} : x ∈ closure k ↔ ∀ K : Subgroup G, k ⊆ K → x ∈ K := - mem_sInf - -/-- The subgroup generated by a set includes the set. -/ -@[to_additive (attr := simp, aesop safe 20 apply (rule_sets := [SetLike])) - "The `AddSubgroup` generated by a set includes the set."] -theorem subset_closure : k ⊆ closure k := fun _ hx => mem_closure.2 fun _ hK => hK hx - -@[to_additive] -theorem not_mem_of_not_mem_closure {P : G} (hP : P ∉ closure k) : P ∉ k := fun h => - hP (subset_closure h) - open Set -/-- A subgroup `K` includes `closure k` if and only if it includes `k`. -/ -@[to_additive (attr := simp) - "An additive subgroup `K` includes `closure k` if and only if it includes `k`"] -theorem closure_le : closure k ≤ K ↔ k ⊆ K := - ⟨Subset.trans subset_closure, fun h => sInf_le h⟩ - -@[to_additive] -theorem closure_eq_of_le (h₁ : k ⊆ K) (h₂ : K ≤ closure k) : closure k = K := - le_antisymm ((closure_le <| K).2 h₁) h₂ - -/-- 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`. - -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`. - - 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 : G) → g ∈ closure k → Prop} - (mem : ∀ x (hx : x ∈ k), p x (subset_closure hx)) (one : p 1 (one_mem _)) - (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) - (inv : ∀ x hx, p x hx → p x⁻¹ (inv_mem hx)) {x} (hx : x ∈ closure k) : p x hx := - let K : Subgroup G := - { carrier := { x | ∃ hx, p x hx } - mul_mem' := fun ⟨_, ha⟩ ⟨_, hb⟩ ↦ ⟨_, mul _ _ _ _ ha hb⟩ - one_mem' := ⟨_, one⟩ - inv_mem' := fun ⟨_, hb⟩ ↦ ⟨_, inv _ _ hb⟩ } - closure_le (K := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id - -@[deprecated closure_induction (since := "2024-10-10")] -alias closure_induction' := closure_induction - -/-- An induction principle for closure membership for predicates with two arguments. -/ -@[to_additive (attr := elab_as_elim) - "An induction principle for additive closure membership, for - predicates with two arguments."] -theorem closure_induction₂ {p : (x y : G) → x ∈ closure k → y ∈ closure k → Prop} - (mem : ∀ (x) (y) (hx : x ∈ k) (hy : y ∈ k), p x y (subset_closure hx) (subset_closure hy)) - (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) - (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) - (mul_right : ∀ y z x hy hz hx, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) - (inv_left : ∀ x y hx hy, p x y hx hy → p x⁻¹ y (inv_mem hx) hy) - (inv_right : ∀ x y hx hy, p x y hx hy → p x y⁻¹ hx (inv_mem hy)) - {x y : G} (hx : x ∈ closure k) (hy : y ∈ closure k) : p x y hx hy := by - induction hy using closure_induction with - | mem z hz => induction hx using closure_induction with - | mem _ h => exact mem _ _ h hz - | one => exact one_left _ (subset_closure hz) - | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ - | inv _ _ h => exact inv_left _ _ _ _ h - | one => exact one_right x hx - | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ hx h₁ h₂ - | inv _ _ h => exact inv_right _ _ _ _ h - -@[to_additive (attr := simp)] -theorem closure_closure_coe_preimage {k : Set G} : closure (((↑) : closure k → G) ⁻¹' k) = ⊤ := - eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ - closure_induction (fun _ h ↦ subset_closure h) (one_mem _) (fun _ _ _ _ ↦ mul_mem) - (fun _ _ ↦ inv_mem) hx' - -variable (G) - -/-- `closure` forms a Galois insertion with the coercion to set. -/ -@[to_additive "`closure` forms a Galois insertion with the coercion to set."] -protected def gi : GaloisInsertion (@closure G _) (↑) where - choice s _ := closure s - gc s t := @closure_le _ _ t s - le_l_u _s := subset_closure - choice_eq _s _h := rfl - -variable {G} - -/-- Subgroup closure of a set is monotone in its argument: if `h ⊆ k`, -then `closure h ≤ closure k`. -/ -@[to_additive - "Additive subgroup closure of a set is monotone in its argument: if `h ⊆ k`, - then `closure h ≤ closure k`"] -theorem closure_mono ⦃h k : Set G⦄ (h' : h ⊆ k) : closure h ≤ closure k := - (Subgroup.gi G).gc.monotone_l h' - -/-- Closure of a subgroup `K` equals `K`. -/ -@[to_additive (attr := simp) "Additive closure of an additive subgroup `K` equals `K`"] -theorem closure_eq : closure (K : Set G) = K := - (Subgroup.gi G).l_u_eq K - -@[to_additive (attr := simp)] -theorem closure_empty : closure (∅ : Set G) = ⊥ := - (Subgroup.gi G).gc.l_bot - -@[to_additive (attr := simp)] -theorem closure_univ : closure (univ : Set G) = ⊤ := - @coe_top G _ ▸ closure_eq ⊤ - -@[to_additive] -theorem closure_union (s t : Set G) : closure (s ∪ t) = closure s ⊔ closure t := - (Subgroup.gi G).gc.l_sup - -@[to_additive] -theorem sup_eq_closure (H H' : Subgroup G) : H ⊔ H' = closure ((H : Set G) ∪ (H' : Set G)) := by - simp_rw [closure_union, closure_eq] - -@[to_additive] -theorem closure_iUnion {ι} (s : ι → Set G) : closure (⋃ i, s i) = ⨆ i, closure (s i) := - (Subgroup.gi G).gc.l_iSup - -@[to_additive (attr := simp)] -theorem closure_eq_bot_iff : closure k = ⊥ ↔ k ⊆ {1} := le_bot_iff.symm.trans <| closure_le _ - -@[to_additive] -theorem iSup_eq_closure {ι : Sort*} (p : ι → Subgroup G) : - ⨆ i, p i = closure (⋃ i, (p i : Set G)) := by simp_rw [closure_iUnion, closure_eq] - -/-- The subgroup generated by an element of a group equals the set of integer number powers of - the element. -/ -@[to_additive - "The `AddSubgroup` generated by an element of an `AddGroup` equals the set of - natural number multiples of the element."] -theorem mem_closure_singleton {x y : G} : y ∈ closure ({x} : Set G) ↔ ∃ n : ℤ, x ^ n = y := by - refine - ⟨fun hy => closure_induction ?_ ?_ ?_ ?_ hy, fun ⟨n, hn⟩ => - hn ▸ zpow_mem (subset_closure <| mem_singleton x) n⟩ - · intro y hy - rw [eq_of_mem_singleton hy] - exact ⟨1, zpow_one x⟩ - · exact ⟨0, zpow_zero x⟩ - · rintro _ _ _ _ ⟨n, rfl⟩ ⟨m, rfl⟩ - exact ⟨n + m, zpow_add x n m⟩ - rintro _ _ ⟨n, rfl⟩ - exact ⟨-n, zpow_neg x n⟩ - -@[to_additive] -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 - -@[to_additive] -theorem closure_eq_top_of_mclosure_eq_top {S : Set G} (h : Submonoid.closure S = ⊤) : - closure S = ⊤ := - (eq_top_iff' _).2 fun _ => le_closure_toSubmonoid _ <| h.symm ▸ trivial - -@[to_additive] -theorem mem_iSup_of_directed {ι} [hι : Nonempty ι] {K : ι → Subgroup G} (hK : Directed (· ≤ ·) K) - {x : G} : x ∈ (iSup K : Subgroup G) ↔ ∃ i, x ∈ K i := by - refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup K i hi⟩ - suffices x ∈ closure (⋃ i, (K i : Set G)) → ∃ i, x ∈ K i by - simpa only [closure_iUnion, closure_eq (K _)] using this - refine fun hx ↦ closure_induction (fun _ ↦ mem_iUnion.1) ?_ ?_ ?_ hx - · exact hι.elim fun i ↦ ⟨i, (K i).one_mem⟩ - · rintro x y _ _ ⟨i, hi⟩ ⟨j, hj⟩ - rcases hK i j with ⟨k, hki, hkj⟩ - exact ⟨k, mul_mem (hki hi) (hkj hj)⟩ - · rintro _ _ ⟨i, hi⟩ - exact ⟨i, inv_mem hi⟩ - -@[to_additive] -theorem coe_iSup_of_directed {ι} [Nonempty ι] {S : ι → Subgroup G} (hS : Directed (· ≤ ·) S) : - ((⨆ i, S i : Subgroup G) : Set G) = ⋃ i, S i := - Set.ext fun x ↦ by simp [mem_iSup_of_directed hS] - -@[to_additive] -theorem mem_sSup_of_directedOn {K : Set (Subgroup G)} (Kne : K.Nonempty) (hK : DirectedOn (· ≤ ·) K) - {x : G} : x ∈ sSup K ↔ ∃ s ∈ K, x ∈ s := by - haveI : Nonempty K := Kne.to_subtype - simp only [sSup_eq_iSup', mem_iSup_of_directed hK.directed_val, SetCoe.exists, Subtype.coe_mk, - exists_prop] - -variable {N : Type*} [Group N] {P : Type*} [Group P] - -/-- The preimage of a subgroup along a monoid homomorphism is a subgroup. -/ -@[to_additive - "The preimage of an `AddSubgroup` along an `AddMonoid` homomorphism - is an `AddSubgroup`."] -def comap {N : Type*} [Group N] (f : G →* N) (H : Subgroup N) : Subgroup G := - { H.toSubmonoid.comap f with - carrier := f ⁻¹' H - inv_mem' := fun {a} ha => show f a⁻¹ ∈ H by rw [f.map_inv]; exact H.inv_mem ha } - -@[to_additive (attr := simp)] -theorem coe_comap (K : Subgroup N) (f : G →* N) : (K.comap f : Set G) = f ⁻¹' K := - rfl - -@[simp] -theorem toAddSubgroup_comap {G₂ : Type*} [Group G₂] (f : G →* G₂) (s : Subgroup G₂) : - s.toAddSubgroup.comap (MonoidHom.toAdditive f) = Subgroup.toAddSubgroup (s.comap f) := rfl - -@[simp] -theorem _root_.AddSubgroup.toSubgroup_comap {A A₂ : Type*} [AddGroup A] [AddGroup A₂] - (f : A →+ A₂) (s : AddSubgroup A₂) : - s.toSubgroup.comap (AddMonoidHom.toMultiplicative f) = AddSubgroup.toSubgroup (s.comap f) := rfl - -@[to_additive (attr := simp)] -theorem mem_comap {K : Subgroup N} {f : G →* N} {x : G} : x ∈ K.comap f ↔ f x ∈ K := - Iff.rfl - -@[to_additive] -theorem comap_mono {f : G →* N} {K K' : Subgroup N} : K ≤ K' → comap f K ≤ comap f K' := - preimage_mono - -@[to_additive] -theorem comap_comap (K : Subgroup P) (g : N →* P) (f : G →* N) : - (K.comap g).comap f = K.comap (g.comp f) := - rfl - -@[to_additive (attr := simp)] -theorem comap_id (K : Subgroup N) : K.comap (MonoidHom.id _) = K := by - ext - rfl - -/-- The image of a subgroup along a monoid homomorphism is a subgroup. -/ -@[to_additive - "The image of an `AddSubgroup` along an `AddMonoid` homomorphism - is an `AddSubgroup`."] -def map (f : G →* N) (H : Subgroup G) : Subgroup N := - { H.toSubmonoid.map f with - carrier := f '' H - inv_mem' := by - rintro _ ⟨x, hx, rfl⟩ - exact ⟨x⁻¹, H.inv_mem hx, f.map_inv x⟩ } - -@[to_additive (attr := simp)] -theorem coe_map (f : G →* N) (K : Subgroup G) : (K.map f : Set N) = f '' K := - rfl - -@[to_additive (attr := simp)] -theorem mem_map {f : G →* N} {K : Subgroup G} {y : N} : y ∈ K.map f ↔ ∃ x ∈ K, f x = y := Iff.rfl - -@[to_additive] -theorem mem_map_of_mem (f : G →* N) {K : Subgroup G} {x : G} (hx : x ∈ K) : f x ∈ K.map f := - mem_image_of_mem f hx - -@[to_additive] -theorem apply_coe_mem_map (f : G →* N) (K : Subgroup G) (x : K) : f x ∈ K.map f := - mem_map_of_mem f x.prop - -@[to_additive] -theorem map_mono {f : G →* N} {K K' : Subgroup G} : K ≤ K' → map f K ≤ map f K' := - image_subset _ - -@[to_additive (attr := simp)] -theorem map_id : K.map (MonoidHom.id G) = K := - SetLike.coe_injective <| image_id _ - -@[to_additive] -theorem map_map (g : N →* P) (f : G →* N) : (K.map f).map g = K.map (g.comp f) := - SetLike.coe_injective <| image_image _ _ _ - -@[to_additive (attr := simp)] -theorem map_one_eq_bot : K.map (1 : G →* N) = ⊥ := - eq_bot_iff.mpr <| by - rintro x ⟨y, _, rfl⟩ - simp - -@[to_additive] -theorem mem_map_equiv {f : G ≃* N} {K : Subgroup G} {x : N} : - x ∈ K.map f.toMonoidHom ↔ f.symm x ∈ K := by - erw [@Set.mem_image_equiv _ _ (↑K) f.toEquiv x]; rfl - --- The simpNF linter says that the LHS can be simplified via `Subgroup.mem_map`. --- However this is a higher priority lemma. --- https://github.com/leanprover/std4/issues/207 -@[to_additive (attr := simp 1100, nolint simpNF)] -theorem mem_map_iff_mem {f : G →* N} (hf : Function.Injective f) {K : Subgroup G} {x : G} : - f x ∈ K.map f ↔ x ∈ K := - hf.mem_set_image - -@[to_additive] -theorem map_equiv_eq_comap_symm' (f : G ≃* N) (K : Subgroup G) : - K.map f.toMonoidHom = K.comap f.symm.toMonoidHom := - SetLike.coe_injective (f.toEquiv.image_eq_preimage K) - -@[to_additive] -theorem map_equiv_eq_comap_symm (f : G ≃* N) (K : Subgroup G) : - K.map f = K.comap (G := N) f.symm := - map_equiv_eq_comap_symm' _ _ - -@[to_additive] -theorem comap_equiv_eq_map_symm (f : N ≃* G) (K : Subgroup G) : - K.comap (G := N) f = K.map f.symm := - (map_equiv_eq_comap_symm f.symm K).symm - -@[to_additive] -theorem comap_equiv_eq_map_symm' (f : N ≃* G) (K : Subgroup G) : - K.comap f.toMonoidHom = K.map f.symm.toMonoidHom := - (map_equiv_eq_comap_symm f.symm K).symm - -@[to_additive] -theorem map_symm_eq_iff_map_eq {H : Subgroup N} {e : G ≃* N} : - H.map ↑e.symm = K ↔ K.map ↑e = H := by - constructor <;> rintro rfl - · rw [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.symm_trans_self, - MulEquiv.coe_monoidHom_refl, map_id] - · rw [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.self_trans_symm, - MulEquiv.coe_monoidHom_refl, map_id] - -@[to_additive] -theorem map_le_iff_le_comap {f : G →* N} {K : Subgroup G} {H : Subgroup N} : - K.map f ≤ H ↔ K ≤ H.comap f := - image_subset_iff - -@[to_additive] -theorem gc_map_comap (f : G →* N) : GaloisConnection (map f) (comap f) := fun _ _ => - map_le_iff_le_comap - -@[to_additive] -theorem map_sup (H K : Subgroup G) (f : G →* N) : (H ⊔ K).map f = H.map f ⊔ K.map f := - (gc_map_comap f).l_sup - -@[to_additive] -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) := - Monotone.le_map_sup (fun _ _ => comap_mono) H K - -@[to_additive] -theorem iSup_comap_le {ι : Sort*} (f : G →* N) (s : ι → Subgroup N) : - ⨆ i, (s i).comap f ≤ (iSup s).comap f := - Monotone.le_map_iSup fun _ _ => comap_mono - -@[to_additive] -theorem comap_inf (H K : Subgroup N) (f : G →* N) : (H ⊓ K).comap f = H.comap f ⊓ K.comap f := - (gc_map_comap f).u_inf - -@[to_additive] -theorem comap_iInf {ι : Sort*} (f : G →* N) (s : ι → Subgroup N) : - (iInf s).comap f = ⨅ i, (s i).comap f := - (gc_map_comap f).u_iInf - -@[to_additive] -theorem map_inf_le (H K : Subgroup G) (f : G →* N) : map f (H ⊓ K) ≤ map f H ⊓ map f K := - le_inf (map_mono inf_le_left) (map_mono inf_le_right) - -@[to_additive] -theorem map_inf_eq (H K : Subgroup G) (f : G →* N) (hf : Function.Injective f) : - map f (H ⊓ K) = map f H ⊓ map f K := by - rw [← SetLike.coe_set_eq] - simp [Set.image_inter hf] - -@[to_additive (attr := simp)] -theorem map_bot (f : G →* N) : (⊥ : Subgroup G).map f = ⊥ := - (gc_map_comap f).l_bot - -@[to_additive (attr := simp)] -theorem map_top_of_surjective (f : G →* N) (h : Function.Surjective f) : Subgroup.map f ⊤ = ⊤ := by - rw [eq_top_iff] - intro x _ - obtain ⟨y, hy⟩ := h x - exact ⟨y, trivial, hy⟩ - -@[to_additive (attr := simp)] -theorem comap_top (f : G →* N) : (⊤ : Subgroup N).comap f = ⊤ := - (gc_map_comap f).u_top - -/-- For any subgroups `H` and `K`, view `H ⊓ K` as a subgroup of `K`. -/ -@[to_additive "For any subgroups `H` and `K`, view `H ⊓ K` as a subgroup of `K`."] -def subgroupOf (H K : Subgroup G) : Subgroup K := - H.comap K.subtype - -/-- If `H ≤ K`, then `H` as a subgroup of `K` is isomorphic to `H`. -/ -@[to_additive (attr := simps) "If `H ≤ K`, then `H` as a subgroup of `K` is isomorphic to `H`."] -def subgroupOfEquivOfLe {G : Type*} [Group G] {H K : Subgroup G} (h : H ≤ K) : - H.subgroupOf K ≃* H where - toFun g := ⟨g.1, g.2⟩ - invFun g := ⟨⟨g.1, h g.2⟩, g.2⟩ - left_inv _g := Subtype.ext (Subtype.ext rfl) - right_inv _g := Subtype.ext rfl - map_mul' _g _h := rfl - -@[to_additive (attr := simp)] -theorem comap_subtype (H K : Subgroup G) : H.comap K.subtype = H.subgroupOf K := - rfl - -@[to_additive (attr := simp)] -theorem comap_inclusion_subgroupOf {K₁ K₂ : Subgroup G} (h : K₁ ≤ K₂) (H : Subgroup G) : - (H.subgroupOf K₂).comap (inclusion h) = H.subgroupOf K₁ := - rfl - -@[to_additive] -theorem coe_subgroupOf (H K : Subgroup G) : (H.subgroupOf K : Set K) = K.subtype ⁻¹' H := - rfl - -@[to_additive] -theorem mem_subgroupOf {H K : Subgroup G} {h : K} : h ∈ H.subgroupOf K ↔ (h : G) ∈ H := - Iff.rfl - --- TODO(kmill): use `K ⊓ H` order for RHS to match `Subtype.image_preimage_coe` -@[to_additive (attr := simp)] -theorem subgroupOf_map_subtype (H K : Subgroup G) : (H.subgroupOf K).map K.subtype = H ⊓ K := - SetLike.ext' <| by refine Subtype.image_preimage_coe _ _ |>.trans ?_; apply Set.inter_comm - -@[to_additive (attr := simp)] -theorem bot_subgroupOf : (⊥ : Subgroup G).subgroupOf H = ⊥ := - Eq.symm (Subgroup.ext fun _g => Subtype.ext_iff) - -@[to_additive (attr := simp)] -theorem top_subgroupOf : (⊤ : Subgroup G).subgroupOf H = ⊤ := - rfl - -@[to_additive] -theorem subgroupOf_bot_eq_bot : H.subgroupOf ⊥ = ⊥ := - Subsingleton.elim _ _ - -@[to_additive] -theorem subgroupOf_bot_eq_top : H.subgroupOf ⊥ = ⊤ := - Subsingleton.elim _ _ - -@[to_additive (attr := simp)] -theorem subgroupOf_self : H.subgroupOf H = ⊤ := - top_unique fun g _hg => g.2 - -@[to_additive (attr := simp)] -theorem subgroupOf_inj {H₁ H₂ K : Subgroup G} : - H₁.subgroupOf K = H₂.subgroupOf K ↔ H₁ ⊓ K = H₂ ⊓ K := by - simpa only [SetLike.ext_iff, mem_inf, mem_subgroupOf, and_congr_left_iff] using Subtype.forall - -@[to_additive (attr := simp)] -theorem inf_subgroupOf_right (H K : Subgroup G) : (H ⊓ K).subgroupOf K = H.subgroupOf K := - subgroupOf_inj.2 (inf_right_idem _ _) - -@[to_additive (attr := simp)] -theorem inf_subgroupOf_left (H K : Subgroup G) : (K ⊓ H).subgroupOf K = H.subgroupOf K := by - rw [inf_comm, inf_subgroupOf_right] - -@[to_additive (attr := simp)] -theorem subgroupOf_eq_bot {H K : Subgroup G} : H.subgroupOf K = ⊥ ↔ Disjoint H K := by - rw [disjoint_iff, ← bot_subgroupOf, subgroupOf_inj, bot_inf_eq] - -@[to_additive (attr := simp)] -theorem subgroupOf_eq_top {H K : Subgroup G} : H.subgroupOf K = ⊤ ↔ K ≤ H := by - rw [← top_subgroupOf, subgroupOf_inj, top_inf_eq, inf_eq_right] +variable {N : Type*} [Group N] {P : Type*} [Group P] /-- Given `Subgroup`s `H`, `K` of groups `G`, `N` respectively, `H × K` as a subgroup of `G × N`. -/ @[to_additive prod @@ -1143,66 +397,8 @@ variable (H) end Normalizer -@[to_additive] -instance map_isCommutative (f : G →* G') [H.IsCommutative] : (H.map f).IsCommutative := - ⟨⟨by - rintro ⟨-, a, ha, rfl⟩ ⟨-, b, hb, rfl⟩ - rw [Subtype.ext_iff, coe_mul, coe_mul, Subtype.coe_mk, Subtype.coe_mk, ← map_mul, ← map_mul] - exact congr_arg f (Subtype.ext_iff.mp (mul_comm (⟨a, ha⟩ : H) ⟨b, hb⟩))⟩⟩ - -@[to_additive] -theorem comap_injective_isCommutative {f : G' →* G} (hf : Injective f) [H.IsCommutative] : - (H.comap f).IsCommutative := - ⟨⟨fun a b => - Subtype.ext - (by - have := mul_comm (⟨f a, a.2⟩ : H) (⟨f b, b.2⟩ : H) - rwa [Subtype.ext_iff, coe_mul, coe_mul, coe_mk, coe_mk, ← map_mul, ← map_mul, - hf.eq_iff] at this)⟩⟩ - -@[to_additive] -instance subgroupOf_isCommutative [H.IsCommutative] : (H.subgroupOf K).IsCommutative := - H.comap_injective_isCommutative Subtype.coe_injective - end Subgroup -namespace MulEquiv -variable {H : Type*} [Group H] - -/-- -An isomorphism of groups gives an order isomorphism between the lattices of subgroups, -defined by sending subgroups to their inverse images. - -See also `MulEquiv.mapSubgroup` which maps subgroups to their forward images. --/ -@[simps] -def comapSubgroup (f : G ≃* H) : Subgroup H ≃o Subgroup G where - toFun := Subgroup.comap f - invFun := Subgroup.comap f.symm - left_inv sg := by simp [Subgroup.comap_comap] - right_inv sh := by simp [Subgroup.comap_comap] - map_rel_iff' {sg1 sg2} := - ⟨fun h => by simpa [Subgroup.comap_comap] using - Subgroup.comap_mono (f := (f.symm : H →* G)) h, Subgroup.comap_mono⟩ - -/-- -An isomorphism of groups gives an order isomorphism between the lattices of subgroups, -defined by sending subgroups to their forward images. - -See also `MulEquiv.comapSubgroup` which maps subgroups to their inverse images. --/ -@[simps] -def mapSubgroup {H : Type*} [Group H] (f : G ≃* H) : Subgroup G ≃o Subgroup H where - toFun := Subgroup.map f - invFun := Subgroup.map f.symm - left_inv sg := by simp [Subgroup.map_map] - right_inv sh := by simp [Subgroup.map_map] - map_rel_iff' {sg1 sg2} := - ⟨fun h => by simpa [Subgroup.map_map] using - Subgroup.map_mono (f := (f.symm : H →* G)) h, Subgroup.map_mono⟩ - -end MulEquiv - namespace Group variable {s : Set G} @@ -1352,243 +548,10 @@ variable {N : Type*} {P : Type*} [Group N] [Group P] (K : Subgroup G) open Subgroup -/-- The range of a monoid homomorphism from a group is a subgroup. -/ -@[to_additive "The range of an `AddMonoidHom` from an `AddGroup` is an `AddSubgroup`."] -def range (f : G →* N) : Subgroup N := - Subgroup.copy ((⊤ : Subgroup G).map f) (Set.range f) (by simp [Set.ext_iff]) - -@[to_additive (attr := simp)] -theorem coe_range (f : G →* N) : (f.range : Set N) = Set.range f := - rfl - -@[to_additive (attr := simp)] -theorem mem_range {f : G →* N} {y : N} : y ∈ f.range ↔ ∃ x, f x = y := - Iff.rfl - -@[to_additive] -theorem range_eq_map (f : G →* N) : f.range = (⊤ : Subgroup G).map f := by ext; simp - -@[to_additive] -instance range_isCommutative {G : Type*} [CommGroup G] {N : Type*} [Group N] (f : G →* N) : - f.range.IsCommutative := - range_eq_map f ▸ Subgroup.map_isCommutative ⊤ f - -@[to_additive (attr := simp)] -theorem restrict_range (f : G →* N) : (f.restrict K).range = K.map f := by - simp_rw [SetLike.ext_iff, mem_range, mem_map, restrict_apply, SetLike.exists, - exists_prop, forall_const] - -/-- The canonical surjective group homomorphism `G →* f(G)` induced by a group -homomorphism `G →* N`. -/ -@[to_additive - "The canonical surjective `AddGroup` homomorphism `G →+ f(G)` induced by a group - homomorphism `G →+ N`."] -def rangeRestrict (f : G →* N) : G →* f.range := - codRestrict f _ fun x => ⟨x, rfl⟩ - -@[to_additive (attr := simp)] -theorem coe_rangeRestrict (f : G →* N) (g : G) : (f.rangeRestrict g : N) = f g := - rfl - -@[to_additive] -theorem coe_comp_rangeRestrict (f : G →* N) : - ((↑) : f.range → N) ∘ (⇑f.rangeRestrict : G → f.range) = f := - rfl - -@[to_additive] -theorem subtype_comp_rangeRestrict (f : G →* N) : f.range.subtype.comp f.rangeRestrict = f := - ext <| f.coe_rangeRestrict - -@[to_additive] -theorem rangeRestrict_surjective (f : G →* N) : Function.Surjective f.rangeRestrict := - fun ⟨_, g, rfl⟩ => ⟨g, rfl⟩ - -@[to_additive (attr := simp)] -lemma rangeRestrict_injective_iff {f : G →* N} : Injective f.rangeRestrict ↔ Injective f := by - convert Set.injective_codRestrict _ - -@[to_additive] -theorem map_range (g : N →* P) (f : G →* N) : f.range.map g = (g.comp f).range := by - rw [range_eq_map, range_eq_map]; exact (⊤ : Subgroup G).map_map g f - -@[to_additive] -theorem range_eq_top {N} [Group N] {f : G →* N} : - f.range = (⊤ : Subgroup N) ↔ Function.Surjective f := - SetLike.ext'_iff.trans <| Iff.trans (by rw [coe_range, coe_top]) Set.range_eq_univ - -@[deprecated (since := "2024-11-11")] alias range_top_iff_surjective := range_eq_top - -/-- The range of a surjective monoid homomorphism is the whole of the codomain. -/ -@[to_additive (attr := simp) - "The range of a surjective `AddMonoid` homomorphism is the whole of the codomain."] -theorem range_eq_top_of_surjective {N} [Group N] (f : G →* N) (hf : Function.Surjective f) : - f.range = (⊤ : Subgroup N) := - range_eq_top.2 hf - -@[deprecated (since := "2024-11-11")] alias range_top_of_surjective := range_eq_top_of_surjective - -@[to_additive (attr := simp)] -theorem range_one : (1 : G →* N).range = ⊥ := - SetLike.ext fun x => by simpa using @comm _ (· = ·) _ 1 x - -@[to_additive (attr := simp)] -theorem _root_.Subgroup.subtype_range (H : Subgroup G) : H.subtype.range = H := by - rw [range_eq_map, ← SetLike.coe_set_eq, coe_map, Subgroup.coeSubtype] - ext - simp - -@[to_additive (attr := simp)] -theorem _root_.Subgroup.inclusion_range {H K : Subgroup G} (h_le : H ≤ K) : - (inclusion h_le).range = H.subgroupOf K := - Subgroup.ext fun g => Set.ext_iff.mp (Set.range_inclusion h_le) g - -@[to_additive] -theorem subgroupOf_range_eq_of_le {G₁ G₂ : Type*} [Group G₁] [Group G₂] {K : Subgroup G₂} - (f : G₁ →* G₂) (h : f.range ≤ K) : - f.range.subgroupOf K = (f.codRestrict K fun x => h ⟨x, rfl⟩).range := by - ext k - refine exists_congr ?_ - simp [Subtype.ext_iff] - -@[simp] -theorem coe_toAdditive_range (f : G →* G') : - (MonoidHom.toAdditive f).range = Subgroup.toAddSubgroup f.range := rfl - -@[simp] -theorem coe_toMultiplicative_range {A A' : Type*} [AddGroup A] [AddGroup A'] (f : A →+ A') : - (AddMonoidHom.toMultiplicative f).range = AddSubgroup.toSubgroup f.range := rfl - -/-- Computable alternative to `MonoidHom.ofInjective`. -/ -@[to_additive "Computable alternative to `AddMonoidHom.ofInjective`."] -def ofLeftInverse {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) : G ≃* f.range := - { f.rangeRestrict with - toFun := f.rangeRestrict - invFun := g ∘ f.range.subtype - left_inv := h - right_inv := by - rintro ⟨x, y, rfl⟩ - apply Subtype.ext - rw [coe_rangeRestrict, Function.comp_apply, Subgroup.coeSubtype, Subtype.coe_mk, h] } - -@[to_additive (attr := simp)] -theorem ofLeftInverse_apply {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) (x : G) : - ↑(ofLeftInverse h x) = f x := - rfl - -@[to_additive (attr := simp)] -theorem ofLeftInverse_symm_apply {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) - (x : f.range) : (ofLeftInverse h).symm x = g x := - rfl - -/-- The range of an injective group homomorphism is isomorphic to its domain. -/ -@[to_additive "The range of an injective additive group homomorphism is isomorphic to its -domain."] -noncomputable def ofInjective {f : G →* N} (hf : Function.Injective f) : G ≃* f.range := - MulEquiv.ofBijective (f.codRestrict f.range fun x => ⟨x, rfl⟩) - ⟨fun _ _ h => hf (Subtype.ext_iff.mp h), by - rintro ⟨x, y, rfl⟩ - exact ⟨y, rfl⟩⟩ - -@[to_additive] -theorem ofInjective_apply {f : G →* N} (hf : Function.Injective f) {x : G} : - ↑(ofInjective hf x) = f x := - rfl - -@[to_additive (attr := simp)] -theorem apply_ofInjective_symm {f : G →* N} (hf : Function.Injective f) (x : f.range) : - f ((ofInjective hf).symm x) = x := - Subtype.ext_iff.1 <| (ofInjective hf).apply_symm_apply x - section Ker variable {M : Type*} [MulOneClass M] -/-- The multiplicative kernel of a monoid homomorphism is the subgroup of elements `x : G` such that -`f x = 1` -/ -@[to_additive - "The additive kernel of an `AddMonoid` homomorphism is the `AddSubgroup` of elements - such that `f x = 0`"] -def ker (f : G →* M) : Subgroup G := - { MonoidHom.mker f with - inv_mem' := fun {x} (hx : f x = 1) => - calc - f x⁻¹ = f x * f x⁻¹ := by rw [hx, one_mul] - _ = 1 := by rw [← map_mul, mul_inv_cancel, map_one] } - -@[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 - -@[to_additive (attr := simp)] -theorem ker_toHomUnits {M} [Monoid M] (f : G →* M) : f.toHomUnits.ker = f.ker := by - ext x - simp [mem_ker, Units.ext_iff] - -@[to_additive] -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, mem_ker.1 h, mul_one] - -@[to_additive] -instance decidableMemKer [DecidableEq M] (f : G →* M) : DecidablePred (· ∈ f.ker) := fun x => - decidable_of_iff (f x = 1) f.mem_ker - -@[to_additive] -theorem comap_ker (g : N →* P) (f : G →* N) : g.ker.comap f = (g.comp f).ker := - rfl - -@[to_additive (attr := simp)] -theorem comap_bot (f : G →* N) : (⊥ : Subgroup N).comap f = f.ker := - rfl - -@[to_additive (attr := simp)] -theorem ker_restrict (f : G →* N) : (f.restrict K).ker = f.ker.subgroupOf K := - rfl - -@[to_additive (attr := simp)] -theorem ker_codRestrict {S} [SetLike S N] [SubmonoidClass S N] (f : G →* N) (s : S) - (h : ∀ x, f x ∈ s) : (f.codRestrict s h).ker = f.ker := - SetLike.ext fun _x => Subtype.ext_iff - -@[to_additive (attr := simp)] -theorem ker_rangeRestrict (f : G →* N) : ker (rangeRestrict f) = ker f := - ker_codRestrict _ _ _ - -@[to_additive (attr := simp)] -theorem ker_one : (1 : G →* M).ker = ⊤ := - SetLike.ext fun _x => eq_self_iff_true _ - -@[to_additive (attr := simp)] -theorem ker_id : (MonoidHom.id G).ker = ⊥ := - rfl - -@[to_additive] -theorem ker_eq_bot_iff (f : G →* M) : f.ker = ⊥ ↔ Function.Injective f := - ⟨fun h x y hxy => by rwa [eq_iff, h, mem_bot, inv_mul_eq_one, eq_comm] at hxy, fun h => - bot_unique fun _ hx => h (hx.trans f.map_one.symm)⟩ - -@[to_additive (attr := simp)] -theorem _root_.Subgroup.ker_subtype (H : Subgroup G) : H.subtype.ker = ⊥ := - H.subtype.ker_eq_bot_iff.mpr Subtype.coe_injective - -@[to_additive (attr := simp)] -theorem _root_.Subgroup.ker_inclusion {H K : Subgroup G} (h : H ≤ K) : (inclusion h).ker = ⊥ := - (inclusion h).ker_eq_bot_iff.mpr (Set.inclusion_injective h) - -@[to_additive] -theorem ker_prod {M N : Type*} [MulOneClass M] [MulOneClass N] (f : G →* M) (g : G →* N) : - (f.prod g).ker = f.ker ⊓ g.ker := - SetLike.ext fun _ => Prod.mk_eq_one - @[to_additive] theorem prodMap_comap_prod {G' : Type*} {N' : Type*} [Group G'] [Group N'] (f : G →* N) (g : G' →* N') (S : Subgroup N) (S' : Subgroup N') : @@ -1600,74 +563,14 @@ theorem ker_prodMap {G' : Type*} {N' : Type*} [Group G'] [Group N'] (f : G →* (prodMap f g).ker = f.ker.prod g.ker := by rw [← comap_bot, ← comap_bot, ← comap_bot, ← prodMap_comap_prod, bot_prod_bot] -@[to_additive] -theorem range_le_ker_iff (f : G →* G') (g : G' →* G'') : f.range ≤ g.ker ↔ g.comp f = 1 := - ⟨fun h => ext fun x => h ⟨x, rfl⟩, by rintro h _ ⟨y, rfl⟩; exact DFunLike.congr_fun h y⟩ - -@[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, 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 _ => (iff_of_eq (and_true _)).symm @[to_additive (attr := simp)] 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') : - (MonoidHom.toAdditive f).ker = Subgroup.toAddSubgroup f.ker := rfl - -@[simp] -theorem coe_toMultiplicative_ker {A A' : Type*} [AddGroup A] [AddGroup A'] (f : A →+ A') : - (AddMonoidHom.toMultiplicative f).ker = AddSubgroup.toSubgroup f.ker := rfl - end Ker -section EqLocus - -variable {M : Type*} [Monoid M] - -/-- The subgroup of elements `x : G` such that `f x = g x` -/ -@[to_additive "The additive subgroup of elements `x : G` such that `f x = g x`"] -def eqLocus (f g : G →* M) : Subgroup G := - { eqLocusM f g with inv_mem' := eq_on_inv f g } - -@[to_additive (attr := simp)] -theorem eqLocus_same (f : G →* N) : f.eqLocus f = ⊤ := - SetLike.ext fun _ => eq_self_iff_true _ - -/-- If two monoid homomorphisms are equal on a set, then they are equal on its subgroup closure. -/ -@[to_additive - "If two monoid homomorphisms are equal on a set, then they are equal on its subgroup - closure."] -theorem eqOn_closure {f g : G →* M} {s : Set G} (h : Set.EqOn f g s) : Set.EqOn f g (closure s) := - show closure s ≤ f.eqLocus g from (closure_le _).2 h - -@[to_additive] -theorem eq_of_eqOn_top {f g : G →* M} (h : Set.EqOn f g (⊤ : Subgroup G)) : f = g := - ext fun _x => h trivial - -@[to_additive] -theorem eq_of_eqOn_dense {s : Set G} (hs : closure s = ⊤) {f g : G →* M} (h : s.EqOn f g) : f = g := - eq_of_eqOn_top <| hs ▸ eqOn_closure h - -end EqLocus - -@[to_additive] -theorem closure_preimage_le (f : G →* N) (s : Set N) : closure (f ⁻¹' s) ≤ (closure s).comap f := - (closure_le _).2 fun x hx => by rw [SetLike.mem_coe, mem_comap]; exact subset_closure hx - -/-- The image under a monoid homomorphism of the subgroup generated by a set equals the subgroup -generated by the image of the set. -/ -@[to_additive - "The image under an `AddMonoid` hom of the `AddSubgroup` generated by a set equals - the `AddSubgroup` generated by the image of the set."] -theorem map_closure (f : G →* N) (s : Set G) : (closure s).map f = closure (f '' s) := - Set.image_preimage.l_comm_of_u_comm (gc_map_comap f) (Subgroup.gi N).gc (Subgroup.gi G).gc - fun _ ↦ rfl - end MonoidHom namespace Subgroup @@ -1681,14 +584,6 @@ theorem Normal.map {H : Subgroup G} (h : H.Normal) (f : G →* N) (hf : Function normalizer_eq_top.2 h] exact le_normalizer_map _ -@[to_additive] -theorem map_eq_bot_iff {f : G →* N} : H.map f = ⊥ ↔ H ≤ f.ker := - (gc_map_comap f).l_eq_bot - -@[to_additive] -theorem map_eq_bot_iff_of_injective {f : G →* N} (hf : Function.Injective f) : - H.map f = ⊥ ↔ H = ⊥ := by rw [map_eq_bot_iff, f.ker_eq_bot_iff.mpr hf, le_bot_iff] - end Subgroup namespace Subgroup @@ -1697,166 +592,6 @@ open MonoidHom variable {N : Type*} [Group N] (f : G →* N) -@[to_additive] -theorem map_le_range (H : Subgroup G) : map f H ≤ f.range := - (range_eq_map f).symm ▸ map_mono le_top - -@[to_additive] -theorem map_subtype_le {H : Subgroup G} (K : Subgroup H) : K.map H.subtype ≤ H := - (K.map_le_range H.subtype).trans (le_of_eq H.subtype_range) - -@[to_additive] -theorem ker_le_comap (H : Subgroup N) : f.ker ≤ comap f H := - comap_bot f ▸ comap_mono bot_le - -@[to_additive] -theorem map_comap_le (H : Subgroup N) : map f (comap f H) ≤ H := - (gc_map_comap f).l_u_le _ - -@[to_additive] -theorem le_comap_map (H : Subgroup G) : H ≤ comap f (map f H) := - (gc_map_comap f).le_u_l _ - -@[to_additive] -theorem map_comap_eq (H : Subgroup N) : map f (comap f H) = f.range ⊓ H := - SetLike.ext' <| by - rw [coe_map, coe_comap, Set.image_preimage_eq_inter_range, coe_inf, coe_range, Set.inter_comm] - -@[to_additive] -theorem comap_map_eq (H : Subgroup G) : comap f (map f H) = H ⊔ f.ker := by - refine le_antisymm ?_ (sup_le (le_comap_map _ _) (ker_le_comap _ _)) - intro x hx; simp only [exists_prop, mem_map, mem_comap] at hx - rcases hx with ⟨y, hy, hy'⟩ - rw [← mul_inv_cancel_left y x] - exact mul_mem_sup hy (by simp [mem_ker, hy']) - -@[to_additive] -theorem map_comap_eq_self {f : G →* N} {H : Subgroup N} (h : H ≤ f.range) : - map f (comap f H) = H := by - rwa [map_comap_eq, inf_eq_right] - -@[to_additive] -theorem map_comap_eq_self_of_surjective {f : G →* N} (h : Function.Surjective f) (H : Subgroup N) : - map f (comap f H) = H := - map_comap_eq_self (range_eq_top.2 h ▸ le_top) - -@[to_additive] -theorem comap_le_comap_of_le_range {f : G →* N} {K L : Subgroup N} (hf : K ≤ f.range) : - K.comap f ≤ L.comap f ↔ K ≤ L := - ⟨(map_comap_eq_self hf).ge.trans ∘ map_le_iff_le_comap.mpr, comap_mono⟩ - -@[to_additive] -theorem comap_le_comap_of_surjective {f : G →* N} {K L : Subgroup N} (hf : Function.Surjective f) : - K.comap f ≤ L.comap f ↔ K ≤ L := - comap_le_comap_of_le_range (range_eq_top.2 hf ▸ le_top) - -@[to_additive] -theorem comap_lt_comap_of_surjective {f : G →* N} {K L : Subgroup N} (hf : Function.Surjective f) : - K.comap f < L.comap f ↔ K < L := by simp_rw [lt_iff_le_not_le, comap_le_comap_of_surjective hf] - -@[to_additive] -theorem comap_injective {f : G →* N} (h : Function.Surjective f) : Function.Injective (comap f) := - fun K L => by simp only [le_antisymm_iff, comap_le_comap_of_surjective h, imp_self] - -@[to_additive] -theorem comap_map_eq_self {f : G →* N} {H : Subgroup G} (h : f.ker ≤ H) : - comap f (map f H) = H := by - rwa [comap_map_eq, sup_eq_left] - -@[to_additive] -theorem comap_map_eq_self_of_injective {f : G →* N} (h : Function.Injective f) (H : Subgroup G) : - comap f (map f H) = H := - comap_map_eq_self (((ker_eq_bot_iff _).mpr h).symm ▸ bot_le) - -@[to_additive] -theorem map_le_map_iff {f : G →* N} {H K : Subgroup G} : H.map f ≤ K.map f ↔ H ≤ K ⊔ f.ker := by - rw [map_le_iff_le_comap, comap_map_eq] - -@[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] - -@[to_additive] -theorem map_eq_map_iff {f : G →* N} {H K : Subgroup G} : - H.map f = K.map f ↔ H ⊔ f.ker = K ⊔ f.ker := by simp only [le_antisymm_iff, map_le_map_iff'] - -@[to_additive] -theorem map_eq_range_iff {f : G →* N} {H : Subgroup G} : - H.map f = f.range ↔ Codisjoint H f.ker := by - rw [f.range_eq_map, map_eq_map_iff, codisjoint_iff, top_sup_eq] - -@[to_additive] -theorem map_le_map_iff_of_injective {f : G →* N} (hf : Function.Injective f) {H K : Subgroup G} : - H.map f ≤ K.map f ↔ H ≤ K := by rw [map_le_iff_le_comap, comap_map_eq_self_of_injective hf] - -@[to_additive (attr := simp)] -theorem map_subtype_le_map_subtype {G' : Subgroup G} {H K : Subgroup G'} : - H.map G'.subtype ≤ K.map G'.subtype ↔ H ≤ K := - map_le_map_iff_of_injective <| by apply Subtype.coe_injective - -@[to_additive] -theorem map_injective {f : G →* N} (h : Function.Injective f) : Function.Injective (map f) := - Function.LeftInverse.injective <| comap_map_eq_self_of_injective h - -@[to_additive] -theorem map_eq_comap_of_inverse {f : G →* N} {g : N →* G} (hl : Function.LeftInverse g f) - (hr : Function.RightInverse g f) (H : Subgroup G) : map f H = comap g H := - SetLike.ext' <| by rw [coe_map, coe_comap, Set.image_eq_preimage_of_inverse hl hr] - -/-- Given `f(A) = f(B)`, `ker f ≤ A`, and `ker f ≤ B`, deduce that `A = B`. -/ -@[to_additive "Given `f(A) = f(B)`, `ker f ≤ A`, and `ker f ≤ B`, deduce that `A = B`."] -theorem map_injective_of_ker_le {H K : Subgroup G} (hH : f.ker ≤ H) (hK : f.ker ≤ K) - (hf : map f H = map f K) : H = K := by - apply_fun comap f at hf - rwa [comap_map_eq, comap_map_eq, sup_of_le_left hH, sup_of_le_left hK] at hf - -@[to_additive] -theorem closure_preimage_eq_top (s : Set G) : closure ((closure s).subtype ⁻¹' s) = ⊤ := by - apply map_injective (closure s).subtype_injective - rw [MonoidHom.map_closure, ← MonoidHom.range_eq_map, subtype_range, - Set.image_preimage_eq_of_subset] - rw [coeSubtype, Subtype.range_coe_subtype] - exact subset_closure - -@[to_additive] -theorem comap_sup_eq_of_le_range {H K : Subgroup N} (hH : H ≤ f.range) (hK : K ≤ f.range) : - comap f H ⊔ comap f K = comap f (H ⊔ K) := - map_injective_of_ker_le f ((ker_le_comap f H).trans le_sup_left) (ker_le_comap f (H ⊔ K)) - (by - rw [map_comap_eq, map_sup, map_comap_eq, map_comap_eq, inf_eq_right.mpr hH, - inf_eq_right.mpr hK, inf_eq_right.mpr (sup_le hH hK)]) - -@[to_additive] -theorem comap_sup_eq (H K : Subgroup N) (hf : Function.Surjective f) : - comap f H ⊔ comap f K = comap f (H ⊔ K) := - comap_sup_eq_of_le_range f (range_eq_top.2 hf ▸ le_top) (range_eq_top.2 hf ▸ le_top) - -@[to_additive] -theorem sup_subgroupOf_eq {H K L : Subgroup G} (hH : H ≤ L) (hK : K ≤ L) : - H.subgroupOf L ⊔ K.subgroupOf L = (H ⊔ K).subgroupOf L := - comap_sup_eq_of_le_range L.subtype (hH.trans L.subtype_range.ge) (hK.trans L.subtype_range.ge) - -@[to_additive] -theorem codisjoint_subgroupOf_sup (H K : Subgroup G) : - Codisjoint (H.subgroupOf (H ⊔ K)) (K.subgroupOf (H ⊔ K)) := by - rw [codisjoint_iff, sup_subgroupOf_eq, subgroupOf_self] - exacts [le_sup_left, le_sup_right] - -/-- A subgroup is isomorphic to its image under an injective function. If you have an isomorphism, -use `MulEquiv.subgroupMap` for better definitional equalities. -/ -@[to_additive - "An additive subgroup is isomorphic to its image under an injective function. If you - have an isomorphism, use `AddEquiv.addSubgroupMap` for better definitional equalities."] -noncomputable def equivMapOfInjective (H : Subgroup G) (f : G →* N) (hf : Function.Injective f) : - H ≃* H.map f := - { Equiv.Set.image f H hf with map_mul' := fun _ _ => Subtype.ext (f.map_mul _ _) } - -@[to_additive (attr := simp)] -theorem coe_equivMapOfInjective_apply (H : Subgroup G) (f : G →* N) (hf : Function.Injective f) - (h : H) : (equivMapOfInjective H f hf h : N) = f h := - rfl - /-- The preimage of the normalizer is equal to the normalizer of the preimage of a surjective function. -/ @[to_additive @@ -2064,103 +799,6 @@ theorem Normal.of_map_subtype {K : Subgroup G} {L : Subgroup K} end Subgroup -namespace MonoidHom - -/-- The `MonoidHom` from the preimage of a subgroup to itself. -/ -@[to_additive (attr := simps!) "the `AddMonoidHom` from the preimage of an -additive subgroup to itself."] -def subgroupComap (f : G →* G') (H' : Subgroup G') : H'.comap f →* H' := - f.submonoidComap H'.toSubmonoid - -/-- The `MonoidHom` from a subgroup to its image. -/ -@[to_additive (attr := simps!) "the `AddMonoidHom` from an additive subgroup to its image"] -def subgroupMap (f : G →* G') (H : Subgroup G) : H →* H.map f := - f.submonoidMap H.toSubmonoid - -@[to_additive] -theorem subgroupMap_surjective (f : G →* G') (H : Subgroup G) : - Function.Surjective (f.subgroupMap H) := - f.submonoidMap_surjective H.toSubmonoid - -end MonoidHom - -namespace MulEquiv - -variable {H K : Subgroup G} - -/-- Makes the identity isomorphism from a proof two subgroups of a multiplicative - group are equal. -/ -@[to_additive - "Makes the identity additive isomorphism from a proof - two subgroups of an additive group are equal."] -def subgroupCongr (h : H = K) : H ≃* K := - { Equiv.setCongr <| congr_arg _ h with map_mul' := fun _ _ => rfl } - -@[to_additive (attr := simp)] -lemma subgroupCongr_apply (h : H = K) (x) : - (MulEquiv.subgroupCongr h x : G) = x := rfl - -@[to_additive (attr := simp)] -lemma subgroupCongr_symm_apply (h : H = K) (x) : - ((MulEquiv.subgroupCongr h).symm x : G) = x := rfl - -/-- A subgroup is isomorphic to its image under an isomorphism. If you only have an injective map, -use `Subgroup.equiv_map_of_injective`. -/ -@[to_additive - "An additive subgroup is isomorphic to its image under an isomorphism. If you only - have an injective map, use `AddSubgroup.equiv_map_of_injective`."] -def subgroupMap (e : G ≃* G') (H : Subgroup G) : H ≃* H.map (e : G →* G') := - MulEquiv.submonoidMap (e : G ≃* G') H.toSubmonoid - -@[to_additive (attr := simp)] -theorem coe_subgroupMap_apply (e : G ≃* G') (H : Subgroup G) (g : H) : - ((subgroupMap e H g : H.map (e : G →* G')) : G') = e g := - rfl - -@[to_additive (attr := simp)] -theorem subgroupMap_symm_apply (e : G ≃* G') (H : Subgroup G) (g : H.map (e : G →* G')) : - (e.subgroupMap H).symm g = ⟨e.symm g, SetLike.mem_coe.1 <| Set.mem_image_equiv.1 g.2⟩ := - rfl - -end MulEquiv - -namespace Subgroup - -@[to_additive (attr := simp)] -theorem equivMapOfInjective_coe_mulEquiv (H : Subgroup G) (e : G ≃* G') : - H.equivMapOfInjective (e : G →* G') (EquivLike.injective e) = e.subgroupMap H := by - ext - rfl - -variable {C : Type*} [CommGroup C] {s t : Subgroup C} {x : C} - -@[to_additive] -theorem mem_sup : x ∈ s ⊔ t ↔ ∃ y ∈ s, ∃ z ∈ t, y * z = x := - ⟨fun h => by - rw [sup_eq_closure] at h - refine Subgroup.closure_induction ?_ ?_ ?_ ?_ h - · rintro y (h | h) - · exact ⟨y, h, 1, t.one_mem, by simp⟩ - · exact ⟨1, s.one_mem, y, h, by simp⟩ - · exact ⟨1, s.one_mem, 1, ⟨t.one_mem, mul_one 1⟩⟩ - · rintro _ _ _ _ ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ - exact ⟨_, mul_mem hy₁ hy₂, _, mul_mem hz₁ hz₂, by simp [mul_assoc, mul_left_comm]⟩ - · rintro _ _ ⟨y, hy, z, hz, rfl⟩ - exact ⟨_, inv_mem hy, _, inv_mem hz, mul_comm z y ▸ (mul_inv_rev z y).symm⟩, by - rintro ⟨y, hy, z, hz, rfl⟩; exact mul_mem_sup hy hz⟩ - -@[to_additive] -theorem mem_sup' : x ∈ s ⊔ t ↔ ∃ (y : s) (z : t), (y : C) * z = x := - mem_sup.trans <| by simp only [SetLike.exists, coe_mk, exists_prop] - -@[to_additive] -theorem mem_closure_pair {x y z : C} : - z ∈ closure ({x, y} : Set C) ↔ ∃ m n : ℤ, x ^ m * y ^ n = z := by - rw [← Set.singleton_union, Subgroup.closure_union, mem_sup] - simp_rw [mem_closure_singleton, exists_exists_eq_and] - -end Subgroup - namespace Subgroup section SubgroupNormal @@ -2208,15 +846,6 @@ theorem inf_subgroupOf_inf_normal_of_left {A' A : Subgroup G} (B : Subgroup G) ( instance normal_inf_normal (H K : Subgroup G) [hH : H.Normal] [hK : K.Normal] : (H ⊓ K).Normal := ⟨fun n hmem g => ⟨hH.conj_mem n hmem.1 g, hK.conj_mem n hmem.2 g⟩⟩ -@[to_additive] -theorem subgroupOf_sup (A A' B : Subgroup G) (hA : A ≤ B) (hA' : A' ≤ B) : - (A ⊔ A').subgroupOf B = A.subgroupOf B ⊔ A'.subgroupOf B := by - refine - map_injective_of_ker_le B.subtype (ker_le_comap _ _) - (le_trans (ker_le_comap B.subtype _) le_sup_left) ?_ - simp only [subgroupOf, map_comap_eq, map_sup, subtype_range] - rw [inf_of_le_right (sup_le hA hA'), inf_of_le_right hA', inf_of_le_right hA] - @[to_additive] theorem SubgroupNormal.mem_comm {H K : Subgroup G} (hK : H ≤ K) [hN : (H.subgroupOf K).Normal] {a b : G} (hb : b ∈ K) (h : a * b ∈ H) : b * a ∈ H := by @@ -2243,33 +872,6 @@ theorem commute_of_normal_of_disjoint (H₁ H₂ : Subgroup G) (hH₁ : H₁.Nor end SubgroupNormal -@[to_additive] -theorem disjoint_def {H₁ H₂ : Subgroup G} : Disjoint H₁ H₂ ↔ ∀ {x : G}, x ∈ H₁ → x ∈ H₂ → x = 1 := - disjoint_iff_inf_le.trans <| by simp only [Disjoint, SetLike.le_def, mem_inf, mem_bot, and_imp] - -@[to_additive] -theorem disjoint_def' {H₁ H₂ : Subgroup G} : - Disjoint H₁ H₂ ↔ ∀ {x y : G}, x ∈ H₁ → y ∈ H₂ → x = y → x = 1 := - disjoint_def.trans ⟨fun h _x _y hx hy hxy ↦ h hx <| hxy.symm ▸ hy, fun h _x hx hx' ↦ h hx hx' rfl⟩ - -@[to_additive] -theorem disjoint_iff_mul_eq_one {H₁ H₂ : Subgroup G} : - Disjoint H₁ H₂ ↔ ∀ {x y : G}, x ∈ H₁ → y ∈ H₂ → x * y = 1 → x = 1 ∧ y = 1 := - disjoint_def'.trans - ⟨fun h x y hx hy hxy => - let hx1 : x = 1 := h hx (H₂.inv_mem hy) (eq_inv_iff_mul_eq_one.mpr hxy) - ⟨hx1, by simpa [hx1] using hxy⟩, - fun h _ _ hx hy hxy => (h hx (H₂.inv_mem hy) (mul_inv_eq_one.mpr hxy)).1⟩ - -@[to_additive] -theorem mul_injective_of_disjoint {H₁ H₂ : Subgroup G} (h : Disjoint H₁ H₂) : - Function.Injective (fun g => g.1 * g.2 : H₁ × H₂ → G) := by - intro x y hxy - rw [← inv_mul_eq_iff_eq_mul, ← mul_assoc, ← mul_inv_eq_one, mul_assoc] at hxy - replace hxy := disjoint_iff_mul_eq_one.mp h (y.1⁻¹ * x.1).prop (x.2 * y.2⁻¹).prop hxy - rwa [coe_mul, coe_mul, coe_inv, coe_inv, inv_mul_eq_one, mul_inv_eq_one, ← Subtype.ext_iff, ← - Subtype.ext_iff, eq_comm, ← Prod.ext_iff] at hxy - end Subgroup namespace IsConj @@ -2310,5 +912,3 @@ def noncenter (G : Type*) [Monoid G] : Set (ConjClasses G) := g ∈ noncenter G ↔ g.carrier.Nontrivial := Iff.rfl end ConjClasses - -set_option linter.style.longFile 2500 diff --git a/Mathlib/Algebra/Group/Subgroup/Ker.lean b/Mathlib/Algebra/Group/Subgroup/Ker.lean new file mode 100644 index 00000000000000..8b9be58076933b --- /dev/null +++ b/Mathlib/Algebra/Group/Subgroup/Ker.lean @@ -0,0 +1,507 @@ +/- +Copyright (c) 2020 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying +-/ +import Mathlib.Algebra.Group.Subgroup.Map +import Mathlib.Tactic.ApplyFun + +/-! +# Kernel and range of group homomorphisms + +We define and prove results about the kernel and range of group homomorphisms. + +Special thanks goes to Amelia Livingston and Yury Kudryashov for their help and inspiration. + +## Main definitions + +Notation used here: + +- `G N` are `Group`s + +- `x` is an element of type `G` + +- `f g : N →* G` are group homomorphisms + +Definitions in the file: + +* `MonoidHom.range f` : the range of the group homomorphism `f` is a subgroup + +* `MonoidHom.ker f` : the kernel of a group homomorphism `f` is the subgroup of elements `x : G` + such that `f x = 1` + +* `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 + +Subgroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a subgroup's underlying set. + +## Tags +subgroup, subgroups +-/ + +assert_not_exists OrderedAddCommMonoid +assert_not_exists Multiset +assert_not_exists Ring + +open Function +open scoped Int + +variable {G G' G'' : Type*} [Group G] [Group G'] [Group G''] +variable {A : Type*} [AddGroup A] + +namespace MonoidHom + +variable {N : Type*} {P : Type*} [Group N] [Group P] (K : Subgroup G) + +open Subgroup + +/-- The range of a monoid homomorphism from a group is a subgroup. -/ +@[to_additive "The range of an `AddMonoidHom` from an `AddGroup` is an `AddSubgroup`."] +def range (f : G →* N) : Subgroup N := + Subgroup.copy ((⊤ : Subgroup G).map f) (Set.range f) (by simp [Set.ext_iff]) + +@[to_additive (attr := simp)] +theorem coe_range (f : G →* N) : (f.range : Set N) = Set.range f := + rfl + +@[to_additive (attr := simp)] +theorem mem_range {f : G →* N} {y : N} : y ∈ f.range ↔ ∃ x, f x = y := + Iff.rfl + +@[to_additive] +theorem range_eq_map (f : G →* N) : f.range = (⊤ : Subgroup G).map f := by ext; simp + +@[to_additive] +instance range_isCommutative {G : Type*} [CommGroup G] {N : Type*} [Group N] (f : G →* N) : + f.range.IsCommutative := + range_eq_map f ▸ Subgroup.map_isCommutative ⊤ f + +@[to_additive (attr := simp)] +theorem restrict_range (f : G →* N) : (f.restrict K).range = K.map f := by + simp_rw [SetLike.ext_iff, mem_range, mem_map, restrict_apply, SetLike.exists, + exists_prop, forall_const] + +/-- The canonical surjective group homomorphism `G →* f(G)` induced by a group +homomorphism `G →* N`. -/ +@[to_additive + "The canonical surjective `AddGroup` homomorphism `G →+ f(G)` induced by a group + homomorphism `G →+ N`."] +def rangeRestrict (f : G →* N) : G →* f.range := + codRestrict f _ fun x => ⟨x, rfl⟩ + +@[to_additive (attr := simp)] +theorem coe_rangeRestrict (f : G →* N) (g : G) : (f.rangeRestrict g : N) = f g := + rfl + +@[to_additive] +theorem coe_comp_rangeRestrict (f : G →* N) : + ((↑) : f.range → N) ∘ (⇑f.rangeRestrict : G → f.range) = f := + rfl + +@[to_additive] +theorem subtype_comp_rangeRestrict (f : G →* N) : f.range.subtype.comp f.rangeRestrict = f := + ext <| f.coe_rangeRestrict + +@[to_additive] +theorem rangeRestrict_surjective (f : G →* N) : Function.Surjective f.rangeRestrict := + fun ⟨_, g, rfl⟩ => ⟨g, rfl⟩ + +@[to_additive (attr := simp)] +lemma rangeRestrict_injective_iff {f : G →* N} : Injective f.rangeRestrict ↔ Injective f := by + convert Set.injective_codRestrict _ + +@[to_additive] +theorem map_range (g : N →* P) (f : G →* N) : f.range.map g = (g.comp f).range := by + rw [range_eq_map, range_eq_map]; exact (⊤ : Subgroup G).map_map g f + +@[to_additive] +theorem range_eq_top {N} [Group N] {f : G →* N} : + f.range = (⊤ : Subgroup N) ↔ Function.Surjective f := + SetLike.ext'_iff.trans <| Iff.trans (by rw [coe_range, coe_top]) Set.range_eq_univ + +@[deprecated (since := "2024-11-11")] alias range_top_iff_surjective := range_eq_top + +/-- The range of a surjective monoid homomorphism is the whole of the codomain. -/ +@[to_additive (attr := simp) + "The range of a surjective `AddMonoid` homomorphism is the whole of the codomain."] +theorem range_eq_top_of_surjective {N} [Group N] (f : G →* N) (hf : Function.Surjective f) : + f.range = (⊤ : Subgroup N) := + range_eq_top.2 hf + +@[deprecated (since := "2024-11-11")] alias range_top_of_surjective := range_eq_top_of_surjective + +@[to_additive (attr := simp)] +theorem range_one : (1 : G →* N).range = ⊥ := + SetLike.ext fun x => by simpa using @comm _ (· = ·) _ 1 x + +@[to_additive (attr := simp)] +theorem _root_.Subgroup.subtype_range (H : Subgroup G) : H.subtype.range = H := by + rw [range_eq_map, ← SetLike.coe_set_eq, coe_map, Subgroup.coeSubtype] + ext + simp + +@[to_additive (attr := simp)] +theorem _root_.Subgroup.inclusion_range {H K : Subgroup G} (h_le : H ≤ K) : + (inclusion h_le).range = H.subgroupOf K := + Subgroup.ext fun g => Set.ext_iff.mp (Set.range_inclusion h_le) g + +@[to_additive] +theorem subgroupOf_range_eq_of_le {G₁ G₂ : Type*} [Group G₁] [Group G₂] {K : Subgroup G₂} + (f : G₁ →* G₂) (h : f.range ≤ K) : + f.range.subgroupOf K = (f.codRestrict K fun x => h ⟨x, rfl⟩).range := by + ext k + refine exists_congr ?_ + simp [Subtype.ext_iff] + +/-- Computable alternative to `MonoidHom.ofInjective`. -/ +@[to_additive "Computable alternative to `AddMonoidHom.ofInjective`."] +def ofLeftInverse {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) : G ≃* f.range := + { f.rangeRestrict with + toFun := f.rangeRestrict + invFun := g ∘ f.range.subtype + left_inv := h + right_inv := by + rintro ⟨x, y, rfl⟩ + apply Subtype.ext + rw [coe_rangeRestrict, Function.comp_apply, Subgroup.coeSubtype, Subtype.coe_mk, h] } + +@[to_additive (attr := simp)] +theorem ofLeftInverse_apply {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) (x : G) : + ↑(ofLeftInverse h x) = f x := + rfl + +@[to_additive (attr := simp)] +theorem ofLeftInverse_symm_apply {f : G →* N} {g : N →* G} (h : Function.LeftInverse g f) + (x : f.range) : (ofLeftInverse h).symm x = g x := + rfl + +/-- The range of an injective group homomorphism is isomorphic to its domain. -/ +@[to_additive "The range of an injective additive group homomorphism is isomorphic to its +domain."] +noncomputable def ofInjective {f : G →* N} (hf : Function.Injective f) : G ≃* f.range := + MulEquiv.ofBijective (f.codRestrict f.range fun x => ⟨x, rfl⟩) + ⟨fun _ _ h => hf (Subtype.ext_iff.mp h), by + rintro ⟨x, y, rfl⟩ + exact ⟨y, rfl⟩⟩ + +@[to_additive] +theorem ofInjective_apply {f : G →* N} (hf : Function.Injective f) {x : G} : + ↑(ofInjective hf x) = f x := + rfl + +@[to_additive (attr := simp)] +theorem apply_ofInjective_symm {f : G →* N} (hf : Function.Injective f) (x : f.range) : + f ((ofInjective hf).symm x) = x := + Subtype.ext_iff.1 <| (ofInjective hf).apply_symm_apply x + +@[simp] +theorem coe_toAdditive_range (f : G →* G') : + (MonoidHom.toAdditive f).range = Subgroup.toAddSubgroup f.range := rfl + +@[simp] +theorem coe_toMultiplicative_range {A A' : Type*} [AddGroup A] [AddGroup A'] (f : A →+ A') : + (AddMonoidHom.toMultiplicative f).range = AddSubgroup.toSubgroup f.range := rfl + +section Ker + +variable {M : Type*} [MulOneClass M] + +/-- The multiplicative kernel of a monoid homomorphism is the subgroup of elements `x : G` such that +`f x = 1` -/ +@[to_additive + "The additive kernel of an `AddMonoid` homomorphism is the `AddSubgroup` of elements + such that `f x = 0`"] +def ker (f : G →* M) : Subgroup G := + { MonoidHom.mker f with + inv_mem' := fun {x} (hx : f x = 1) => + calc + f x⁻¹ = f x * f x⁻¹ := by rw [hx, one_mul] + _ = 1 := by rw [← map_mul, mul_inv_cancel, map_one] } + +@[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 + +@[to_additive (attr := simp)] +theorem ker_toHomUnits {M} [Monoid M] (f : G →* M) : f.toHomUnits.ker = f.ker := by + ext x + simp [mem_ker, Units.ext_iff] + +@[to_additive] +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, mem_ker.1 h, mul_one] + +@[to_additive] +instance decidableMemKer [DecidableEq M] (f : G →* M) : DecidablePred (· ∈ f.ker) := fun x => + decidable_of_iff (f x = 1) f.mem_ker + +@[to_additive] +theorem comap_ker (g : N →* P) (f : G →* N) : g.ker.comap f = (g.comp f).ker := + rfl + +@[to_additive (attr := simp)] +theorem comap_bot (f : G →* N) : (⊥ : Subgroup N).comap f = f.ker := + rfl + +@[to_additive (attr := simp)] +theorem ker_restrict (f : G →* N) : (f.restrict K).ker = f.ker.subgroupOf K := + rfl + +@[to_additive (attr := simp)] +theorem ker_codRestrict {S} [SetLike S N] [SubmonoidClass S N] (f : G →* N) (s : S) + (h : ∀ x, f x ∈ s) : (f.codRestrict s h).ker = f.ker := + SetLike.ext fun _x => Subtype.ext_iff + +@[to_additive (attr := simp)] +theorem ker_rangeRestrict (f : G →* N) : ker (rangeRestrict f) = ker f := + ker_codRestrict _ _ _ + +@[to_additive (attr := simp)] +theorem ker_one : (1 : G →* M).ker = ⊤ := + SetLike.ext fun _x => eq_self_iff_true _ + +@[to_additive (attr := simp)] +theorem ker_id : (MonoidHom.id G).ker = ⊥ := + rfl + +@[to_additive] +theorem ker_eq_bot_iff (f : G →* M) : f.ker = ⊥ ↔ Function.Injective f := + ⟨fun h x y hxy => by rwa [eq_iff, h, mem_bot, inv_mul_eq_one, eq_comm] at hxy, fun h => + bot_unique fun _ hx => h (hx.trans f.map_one.symm)⟩ + +@[to_additive (attr := simp)] +theorem _root_.Subgroup.ker_subtype (H : Subgroup G) : H.subtype.ker = ⊥ := + H.subtype.ker_eq_bot_iff.mpr Subtype.coe_injective + +@[to_additive (attr := simp)] +theorem _root_.Subgroup.ker_inclusion {H K : Subgroup G} (h : H ≤ K) : (inclusion h).ker = ⊥ := + (inclusion h).ker_eq_bot_iff.mpr (Set.inclusion_injective h) + +@[to_additive] +theorem ker_prod {M N : Type*} [MulOneClass M] [MulOneClass N] (f : G →* M) (g : G →* N) : + (f.prod g).ker = f.ker ⊓ g.ker := + SetLike.ext fun _ => Prod.mk_eq_one + +@[to_additive] +theorem range_le_ker_iff (f : G →* G') (g : G' →* G'') : f.range ≤ g.ker ↔ g.comp f = 1 := + ⟨fun h => ext fun x => h ⟨x, rfl⟩, by rintro h _ ⟨y, rfl⟩; exact DFunLike.congr_fun h y⟩ + +@[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, mem_ker.1 hx, mul_one, map_mul_eq_one f (mul_inv_cancel y)]⟩ + +@[simp] +theorem coe_toAdditive_ker (f : G →* G') : + (MonoidHom.toAdditive f).ker = Subgroup.toAddSubgroup f.ker := rfl + +@[simp] +theorem coe_toMultiplicative_ker {A A' : Type*} [AddGroup A] [AddGroup A'] (f : A →+ A') : + (AddMonoidHom.toMultiplicative f).ker = AddSubgroup.toSubgroup f.ker := rfl + +end Ker + +section EqLocus + +variable {M : Type*} [Monoid M] + +/-- The subgroup of elements `x : G` such that `f x = g x` -/ +@[to_additive "The additive subgroup of elements `x : G` such that `f x = g x`"] +def eqLocus (f g : G →* M) : Subgroup G := + { eqLocusM f g with inv_mem' := eq_on_inv f g } + +@[to_additive (attr := simp)] +theorem eqLocus_same (f : G →* N) : f.eqLocus f = ⊤ := + SetLike.ext fun _ => eq_self_iff_true _ + +/-- If two monoid homomorphisms are equal on a set, then they are equal on its subgroup closure. -/ +@[to_additive + "If two monoid homomorphisms are equal on a set, then they are equal on its subgroup + closure."] +theorem eqOn_closure {f g : G →* M} {s : Set G} (h : Set.EqOn f g s) : Set.EqOn f g (closure s) := + show closure s ≤ f.eqLocus g from (closure_le _).2 h + +@[to_additive] +theorem eq_of_eqOn_top {f g : G →* M} (h : Set.EqOn f g (⊤ : Subgroup G)) : f = g := + ext fun _x => h trivial + +@[to_additive] +theorem eq_of_eqOn_dense {s : Set G} (hs : closure s = ⊤) {f g : G →* M} (h : s.EqOn f g) : f = g := + eq_of_eqOn_top <| hs ▸ eqOn_closure h + +end EqLocus + +end MonoidHom + +namespace Subgroup + +variable {N : Type*} [Group N] (H : Subgroup G) + +@[to_additive] +theorem map_eq_bot_iff {f : G →* N} : H.map f = ⊥ ↔ H ≤ f.ker := + (gc_map_comap f).l_eq_bot + +@[to_additive] +theorem map_eq_bot_iff_of_injective {f : G →* N} (hf : Function.Injective f) : + H.map f = ⊥ ↔ H = ⊥ := by rw [map_eq_bot_iff, f.ker_eq_bot_iff.mpr hf, le_bot_iff] + +open MonoidHom + +variable (f : G →* N) + +@[to_additive] +theorem map_le_range (H : Subgroup G) : map f H ≤ f.range := + (range_eq_map f).symm ▸ map_mono le_top + +@[to_additive] +theorem map_subtype_le {H : Subgroup G} (K : Subgroup H) : K.map H.subtype ≤ H := + (K.map_le_range H.subtype).trans (le_of_eq H.subtype_range) + +@[to_additive] +theorem ker_le_comap (H : Subgroup N) : f.ker ≤ comap f H := + comap_bot f ▸ comap_mono bot_le + +@[to_additive] +theorem map_comap_eq (H : Subgroup N) : map f (comap f H) = f.range ⊓ H := + SetLike.ext' <| by + rw [coe_map, coe_comap, Set.image_preimage_eq_inter_range, coe_inf, coe_range, Set.inter_comm] + +@[to_additive] +theorem comap_map_eq (H : Subgroup G) : comap f (map f H) = H ⊔ f.ker := by + refine le_antisymm ?_ (sup_le (le_comap_map _ _) (ker_le_comap _ _)) + intro x hx; simp only [exists_prop, mem_map, mem_comap] at hx + rcases hx with ⟨y, hy, hy'⟩ + rw [← mul_inv_cancel_left y x] + exact mul_mem_sup hy (by simp [mem_ker, hy']) + +@[to_additive] +theorem map_comap_eq_self {f : G →* N} {H : Subgroup N} (h : H ≤ f.range) : + map f (comap f H) = H := by + rwa [map_comap_eq, inf_eq_right] + +@[to_additive] +theorem map_comap_eq_self_of_surjective {f : G →* N} (h : Function.Surjective f) (H : Subgroup N) : + map f (comap f H) = H := + map_comap_eq_self (range_eq_top.2 h ▸ le_top) + +@[to_additive] +theorem comap_le_comap_of_le_range {f : G →* N} {K L : Subgroup N} (hf : K ≤ f.range) : + K.comap f ≤ L.comap f ↔ K ≤ L := + ⟨(map_comap_eq_self hf).ge.trans ∘ map_le_iff_le_comap.mpr, comap_mono⟩ + +@[to_additive] +theorem comap_le_comap_of_surjective {f : G →* N} {K L : Subgroup N} (hf : Function.Surjective f) : + K.comap f ≤ L.comap f ↔ K ≤ L := + comap_le_comap_of_le_range (range_eq_top.2 hf ▸ le_top) + +@[to_additive] +theorem comap_lt_comap_of_surjective {f : G →* N} {K L : Subgroup N} (hf : Function.Surjective f) : + K.comap f < L.comap f ↔ K < L := by simp_rw [lt_iff_le_not_le, comap_le_comap_of_surjective hf] + +@[to_additive] +theorem comap_injective {f : G →* N} (h : Function.Surjective f) : Function.Injective (comap f) := + fun K L => by simp only [le_antisymm_iff, comap_le_comap_of_surjective h, imp_self] + +@[to_additive] +theorem comap_map_eq_self {f : G →* N} {H : Subgroup G} (h : f.ker ≤ H) : + comap f (map f H) = H := by + rwa [comap_map_eq, sup_eq_left] + +@[to_additive] +theorem comap_map_eq_self_of_injective {f : G →* N} (h : Function.Injective f) (H : Subgroup G) : + comap f (map f H) = H := + comap_map_eq_self (((ker_eq_bot_iff _).mpr h).symm ▸ bot_le) + +@[to_additive] +theorem map_le_map_iff {f : G →* N} {H K : Subgroup G} : H.map f ≤ K.map f ↔ H ≤ K ⊔ f.ker := by + rw [map_le_iff_le_comap, comap_map_eq] + +@[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] + +@[to_additive] +theorem map_eq_map_iff {f : G →* N} {H K : Subgroup G} : + H.map f = K.map f ↔ H ⊔ f.ker = K ⊔ f.ker := by simp only [le_antisymm_iff, map_le_map_iff'] + +@[to_additive] +theorem map_eq_range_iff {f : G →* N} {H : Subgroup G} : + H.map f = f.range ↔ Codisjoint H f.ker := by + rw [f.range_eq_map, map_eq_map_iff, codisjoint_iff, top_sup_eq] + +@[to_additive] +theorem map_le_map_iff_of_injective {f : G →* N} (hf : Function.Injective f) {H K : Subgroup G} : + H.map f ≤ K.map f ↔ H ≤ K := by rw [map_le_iff_le_comap, comap_map_eq_self_of_injective hf] + +@[to_additive (attr := simp)] +theorem map_subtype_le_map_subtype {G' : Subgroup G} {H K : Subgroup G'} : + H.map G'.subtype ≤ K.map G'.subtype ↔ H ≤ K := + map_le_map_iff_of_injective <| by apply Subtype.coe_injective + +@[to_additive] +theorem map_injective {f : G →* N} (h : Function.Injective f) : Function.Injective (map f) := + Function.LeftInverse.injective <| comap_map_eq_self_of_injective h + +/-- Given `f(A) = f(B)`, `ker f ≤ A`, and `ker f ≤ B`, deduce that `A = B`. -/ +@[to_additive "Given `f(A) = f(B)`, `ker f ≤ A`, and `ker f ≤ B`, deduce that `A = B`."] +theorem map_injective_of_ker_le {H K : Subgroup G} (hH : f.ker ≤ H) (hK : f.ker ≤ K) + (hf : map f H = map f K) : H = K := by + apply_fun comap f at hf + rwa [comap_map_eq, comap_map_eq, sup_of_le_left hH, sup_of_le_left hK] at hf + +@[to_additive] +theorem closure_preimage_eq_top (s : Set G) : closure ((closure s).subtype ⁻¹' s) = ⊤ := by + apply map_injective (closure s).subtype_injective + rw [MonoidHom.map_closure, ← MonoidHom.range_eq_map, subtype_range, + Set.image_preimage_eq_of_subset] + rw [coeSubtype, Subtype.range_coe_subtype] + exact subset_closure + +@[to_additive] +theorem comap_sup_eq_of_le_range {H K : Subgroup N} (hH : H ≤ f.range) (hK : K ≤ f.range) : + comap f H ⊔ comap f K = comap f (H ⊔ K) := + map_injective_of_ker_le f ((ker_le_comap f H).trans le_sup_left) (ker_le_comap f (H ⊔ K)) + (by + rw [map_comap_eq, map_sup, map_comap_eq, map_comap_eq, inf_eq_right.mpr hH, + inf_eq_right.mpr hK, inf_eq_right.mpr (sup_le hH hK)]) + +@[to_additive] +theorem comap_sup_eq (H K : Subgroup N) (hf : Function.Surjective f) : + comap f H ⊔ comap f K = comap f (H ⊔ K) := + comap_sup_eq_of_le_range f (range_eq_top.2 hf ▸ le_top) (range_eq_top.2 hf ▸ le_top) + +@[to_additive] +theorem sup_subgroupOf_eq {H K L : Subgroup G} (hH : H ≤ L) (hK : K ≤ L) : + H.subgroupOf L ⊔ K.subgroupOf L = (H ⊔ K).subgroupOf L := + comap_sup_eq_of_le_range L.subtype (hH.trans L.subtype_range.ge) (hK.trans L.subtype_range.ge) + +@[to_additive] +theorem codisjoint_subgroupOf_sup (H K : Subgroup G) : + Codisjoint (H.subgroupOf (H ⊔ K)) (K.subgroupOf (H ⊔ K)) := by + rw [codisjoint_iff, sup_subgroupOf_eq, subgroupOf_self] + exacts [le_sup_left, le_sup_right] + +@[to_additive] +theorem subgroupOf_sup (A A' B : Subgroup G) (hA : A ≤ B) (hA' : A' ≤ B) : + (A ⊔ A').subgroupOf B = A.subgroupOf B ⊔ A'.subgroupOf B := by + refine + map_injective_of_ker_le B.subtype (ker_le_comap _ _) + (le_trans (ker_le_comap B.subtype _) le_sup_left) ?_ + simp only [subgroupOf, map_comap_eq, map_sup, subtype_range] + rw [inf_of_le_right (sup_le hA hA'), inf_of_le_right hA', inf_of_le_right hA] + +end Subgroup diff --git a/Mathlib/Algebra/Group/Subgroup/Lattice.lean b/Mathlib/Algebra/Group/Subgroup/Lattice.lean new file mode 100644 index 00000000000000..ea029ac82db4b8 --- /dev/null +++ b/Mathlib/Algebra/Group/Subgroup/Lattice.lean @@ -0,0 +1,558 @@ +/- +Copyright (c) 2020 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying +-/ +import Mathlib.Algebra.Group.Submonoid.Operations +import Mathlib.Algebra.Group.Subgroup.Defs + +/-! +# Lattice structure of subgroups + +We prove subgroups of a group form a complete lattice. + +There are also theorems about the subgroups generated by an element or a subset of a group, +defined both inductively and as the infimum of the set of subgroups containing a given +element/subset. + +Special thanks goes to Amelia Livingston and Yury Kudryashov for their help and inspiration. + +## Main definitions + +Notation used here: + +- `G` is a `Group` + +- `k` is a set of elements of type `G` + +Definitions in the file: + +* `CompleteLattice (Subgroup G)` : the subgroups of `G` form a complete lattice + +* `Subgroup.closure k` : the minimal subgroup that includes the set `k` + +* `Subgroup.gi` : `closure` forms a Galois insertion with the coercion to set + +## Implementation notes + +Subgroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a subgroup's underlying set. + +## Tags +subgroup, subgroups +-/ + +assert_not_exists OrderedAddCommMonoid +assert_not_exists Multiset +assert_not_exists Ring + +open Function +open scoped Int + +variable {G : Type*} [Group G] + +/-! +### Conversion to/from `Additive`/`Multiplicative` +-/ + +section mul_add + +variable {A : Type*} [AddGroup A] + +/-- Subgroups of a group `G` are isomorphic to additive subgroups of `Additive G`. -/ +@[simps!] +def Subgroup.toAddSubgroup : Subgroup G ≃o AddSubgroup (Additive G) where + toFun S := { Submonoid.toAddSubmonoid S.toSubmonoid with neg_mem' := S.inv_mem' } + invFun S := { AddSubmonoid.toSubmonoid S.toAddSubmonoid with inv_mem' := S.neg_mem' } + left_inv x := by cases x; rfl + right_inv x := by cases x; rfl + map_rel_iff' := Iff.rfl + +/-- Additive subgroup of an additive group `Additive G` are isomorphic to subgroup of `G`. -/ +abbrev AddSubgroup.toSubgroup' : AddSubgroup (Additive G) ≃o Subgroup G := + Subgroup.toAddSubgroup.symm + +/-- Additive subgroups of an additive group `A` are isomorphic to subgroups of `Multiplicative A`. +-/ +@[simps!] +def AddSubgroup.toSubgroup : AddSubgroup A ≃o Subgroup (Multiplicative A) where + toFun S := { AddSubmonoid.toSubmonoid S.toAddSubmonoid with inv_mem' := S.neg_mem' } + invFun S := { Submonoid.toAddSubmonoid S.toSubmonoid with neg_mem' := S.inv_mem' } + left_inv x := by cases x; rfl + right_inv x := by cases x; rfl + map_rel_iff' := Iff.rfl + +/-- Subgroups of an additive group `Multiplicative A` are isomorphic to additive subgroups of `A`. +-/ +abbrev Subgroup.toAddSubgroup' : Subgroup (Multiplicative A) ≃o AddSubgroup A := + AddSubgroup.toSubgroup.symm + +end mul_add + +namespace Subgroup + +variable (H K : Subgroup G) + +/-- The subgroup `G` of the group `G`. -/ +@[to_additive "The `AddSubgroup G` of the `AddGroup G`."] +instance : Top (Subgroup G) := + ⟨{ (⊤ : Submonoid G) with inv_mem' := fun _ => Set.mem_univ _ }⟩ + +/-- The top subgroup is isomorphic to the group. + +This is the group version of `Submonoid.topEquiv`. -/ +@[to_additive (attr := simps!) + "The top additive subgroup is isomorphic to the additive group. + + This is the additive group version of `AddSubmonoid.topEquiv`."] +def topEquiv : (⊤ : Subgroup G) ≃* G := + Submonoid.topEquiv + +/-- The trivial subgroup `{1}` of a group `G`. -/ +@[to_additive "The trivial `AddSubgroup` `{0}` of an `AddGroup` `G`."] +instance : Bot (Subgroup G) := + ⟨{ (⊥ : Submonoid G) with inv_mem' := by simp}⟩ + +@[to_additive] +instance : Inhabited (Subgroup G) := + ⟨⊥⟩ + +@[to_additive (attr := simp)] +theorem mem_bot {x : G} : x ∈ (⊥ : Subgroup G) ↔ x = 1 := + Iff.rfl + +@[to_additive (attr := simp)] +theorem mem_top (x : G) : x ∈ (⊤ : Subgroup G) := + Set.mem_univ x + +@[to_additive (attr := simp)] +theorem coe_top : ((⊤ : Subgroup G) : Set G) = Set.univ := + rfl + +@[to_additive (attr := simp)] +theorem coe_bot : ((⊥ : Subgroup G) : Set G) = {1} := + rfl + +@[to_additive] +instance : Unique (⊥ : Subgroup G) := + ⟨⟨1⟩, fun g => Subtype.ext g.2⟩ + +@[to_additive (attr := simp)] +theorem top_toSubmonoid : (⊤ : Subgroup G).toSubmonoid = ⊤ := + rfl + +@[to_additive (attr := simp)] +theorem bot_toSubmonoid : (⊥ : Subgroup G).toSubmonoid = ⊥ := + rfl + +@[to_additive] +theorem eq_bot_iff_forall : H = ⊥ ↔ ∀ x ∈ H, x = (1 : G) := + toSubmonoid_injective.eq_iff.symm.trans <| Submonoid.eq_bot_iff_forall _ + +@[to_additive] +theorem eq_bot_of_subsingleton [Subsingleton H] : H = ⊥ := by + rw [Subgroup.eq_bot_iff_forall] + intro y hy + rw [← Subgroup.coe_mk H y hy, Subsingleton.elim (⟨y, hy⟩ : H) 1, Subgroup.coe_one] + +@[to_additive (attr := simp, norm_cast)] +theorem coe_eq_univ {H : Subgroup G} : (H : Set G) = Set.univ ↔ H = ⊤ := + (SetLike.ext'_iff.trans (by rfl)).symm + +@[to_additive] +theorem coe_eq_singleton {H : Subgroup G} : (∃ g : G, (H : Set G) = {g}) ↔ H = ⊥ := + ⟨fun ⟨g, hg⟩ => + haveI : Subsingleton (H : Set G) := by + rw [hg] + infer_instance + H.eq_bot_of_subsingleton, + fun h => ⟨1, SetLike.ext'_iff.mp h⟩⟩ + +@[to_additive] +theorem nontrivial_iff_exists_ne_one (H : Subgroup G) : Nontrivial H ↔ ∃ x ∈ H, x ≠ (1 : G) := by + rw [Subtype.nontrivial_iff_exists_ne (fun x => x ∈ H) (1 : H)] + simp + +@[to_additive] +theorem exists_ne_one_of_nontrivial (H : Subgroup G) [Nontrivial H] : + ∃ x ∈ H, x ≠ 1 := by + rwa [← Subgroup.nontrivial_iff_exists_ne_one] + +@[to_additive] +theorem nontrivial_iff_ne_bot (H : Subgroup G) : Nontrivial H ↔ H ≠ ⊥ := by + rw [nontrivial_iff_exists_ne_one, ne_eq, eq_bot_iff_forall] + simp only [ne_eq, not_forall, exists_prop] + +/-- A subgroup is either the trivial subgroup or nontrivial. -/ +@[to_additive "A subgroup is either the trivial subgroup or nontrivial."] +theorem bot_or_nontrivial (H : Subgroup G) : H = ⊥ ∨ Nontrivial H := by + have := nontrivial_iff_ne_bot H + tauto + +/-- A subgroup is either the trivial subgroup or contains a non-identity element. -/ +@[to_additive "A subgroup is either the trivial subgroup or contains a nonzero element."] +theorem bot_or_exists_ne_one (H : Subgroup G) : H = ⊥ ∨ ∃ x ∈ H, x ≠ (1 : G) := by + convert H.bot_or_nontrivial + rw [nontrivial_iff_exists_ne_one] + +@[to_additive] +lemma ne_bot_iff_exists_ne_one {H : Subgroup G} : H ≠ ⊥ ↔ ∃ a : ↥H, a ≠ 1 := by + rw [← nontrivial_iff_ne_bot, nontrivial_iff_exists_ne_one] + simp only [ne_eq, Subtype.exists, mk_eq_one, exists_prop] + +/-- The inf of two subgroups is their intersection. -/ +@[to_additive "The inf of two `AddSubgroup`s is their intersection."] +instance : Min (Subgroup G) := + ⟨fun H₁ H₂ => + { H₁.toSubmonoid ⊓ H₂.toSubmonoid with + inv_mem' := fun ⟨hx, hx'⟩ => ⟨H₁.inv_mem hx, H₂.inv_mem hx'⟩ }⟩ + +@[to_additive (attr := simp)] +theorem coe_inf (p p' : Subgroup G) : ((p ⊓ p' : Subgroup G) : Set G) = (p : Set G) ∩ p' := + rfl + +@[to_additive (attr := simp)] +theorem mem_inf {p p' : Subgroup G} {x : G} : x ∈ p ⊓ p' ↔ x ∈ p ∧ x ∈ p' := + Iff.rfl + +@[to_additive] +instance : InfSet (Subgroup G) := + ⟨fun s => + { (⨅ S ∈ s, Subgroup.toSubmonoid S).copy (⋂ S ∈ s, ↑S) (by simp) with + inv_mem' := fun {x} hx => + Set.mem_biInter fun i h => i.inv_mem (by apply Set.mem_iInter₂.1 hx i h) }⟩ + +@[to_additive (attr := simp, norm_cast)] +theorem coe_sInf (H : Set (Subgroup G)) : ((sInf H : Subgroup G) : Set G) = ⋂ s ∈ H, ↑s := + rfl + +@[to_additive (attr := simp)] +theorem mem_sInf {S : Set (Subgroup G)} {x : G} : x ∈ sInf S ↔ ∀ p ∈ S, x ∈ p := + Set.mem_iInter₂ + +@[to_additive] +theorem mem_iInf {ι : Sort*} {S : ι → Subgroup G} {x : G} : (x ∈ ⨅ i, S i) ↔ ∀ i, x ∈ S i := by + simp only [iInf, mem_sInf, Set.forall_mem_range] + +@[to_additive (attr := simp, norm_cast)] +theorem coe_iInf {ι : Sort*} {S : ι → Subgroup G} : (↑(⨅ i, S i) : Set G) = ⋂ i, S i := by + simp only [iInf, coe_sInf, Set.biInter_range] + +/-- Subgroups of a group form a complete lattice. -/ +@[to_additive "The `AddSubgroup`s of an `AddGroup` form a complete lattice."] +instance : CompleteLattice (Subgroup G) := + { completeLatticeOfInf (Subgroup G) fun _s => + IsGLB.of_image SetLike.coe_subset_coe isGLB_biInf with + bot := ⊥ + bot_le := fun S _x hx => (mem_bot.1 hx).symm ▸ S.one_mem + top := ⊤ + le_top := fun _S x _hx => mem_top x + inf := (· ⊓ ·) + le_inf := fun _a _b _c ha hb _x hx => ⟨ha hx, hb hx⟩ + inf_le_left := fun _a _b _x => And.left + inf_le_right := fun _a _b _x => And.right } + +@[to_additive] +theorem mem_sup_left {S T : Subgroup G} : ∀ {x : G}, x ∈ S → x ∈ S ⊔ T := + have : S ≤ S ⊔ T := le_sup_left; fun h ↦ this h + +@[to_additive] +theorem mem_sup_right {S T : Subgroup G} : ∀ {x : G}, x ∈ T → x ∈ S ⊔ T := + have : T ≤ S ⊔ T := le_sup_right; fun h ↦ this h + +@[to_additive] +theorem mul_mem_sup {S T : Subgroup G} {x y : G} (hx : x ∈ S) (hy : y ∈ T) : x * y ∈ S ⊔ T := + (S ⊔ T).mul_mem (mem_sup_left hx) (mem_sup_right hy) + +@[to_additive] +theorem mem_iSup_of_mem {ι : Sort*} {S : ι → Subgroup G} (i : ι) : + ∀ {x : G}, x ∈ S i → x ∈ iSup S := + have : S i ≤ iSup S := le_iSup _ _; fun h ↦ this h + +@[to_additive] +theorem mem_sSup_of_mem {S : Set (Subgroup G)} {s : Subgroup G} (hs : s ∈ S) : + ∀ {x : G}, x ∈ s → x ∈ sSup S := + have : s ≤ sSup S := le_sSup hs; fun h ↦ this h + +@[to_additive (attr := simp)] +theorem subsingleton_iff : Subsingleton (Subgroup G) ↔ Subsingleton G := + ⟨fun _ => + ⟨fun x y => + have : ∀ i : G, i = 1 := fun i => + mem_bot.mp <| Subsingleton.elim (⊤ : Subgroup G) ⊥ ▸ mem_top i + (this x).trans (this y).symm⟩, + fun _ => ⟨fun x y => Subgroup.ext fun i => Subsingleton.elim 1 i ▸ by simp [Subgroup.one_mem]⟩⟩ + +@[to_additive (attr := simp)] +theorem nontrivial_iff : Nontrivial (Subgroup G) ↔ Nontrivial G := + not_iff_not.mp + ((not_nontrivial_iff_subsingleton.trans subsingleton_iff).trans + not_nontrivial_iff_subsingleton.symm) + +@[to_additive] +instance [Subsingleton G] : Unique (Subgroup G) := + ⟨⟨⊥⟩, fun a => @Subsingleton.elim _ (subsingleton_iff.mpr ‹_›) a _⟩ + +@[to_additive] +instance [Nontrivial G] : Nontrivial (Subgroup G) := + nontrivial_iff.mpr ‹_› + +@[to_additive] +theorem eq_top_iff' : H = ⊤ ↔ ∀ x : G, x ∈ H := + eq_top_iff.trans ⟨fun h m => h <| mem_top m, fun h m _ => h m⟩ + +/-- The `Subgroup` generated by a set. -/ +@[to_additive "The `AddSubgroup` generated by a set"] +def closure (k : Set G) : Subgroup G := + sInf { K | k ⊆ K } + +variable {k : Set G} + +@[to_additive] +theorem mem_closure {x : G} : x ∈ closure k ↔ ∀ K : Subgroup G, k ⊆ K → x ∈ K := + mem_sInf + +/-- The subgroup generated by a set includes the set. -/ +@[to_additive (attr := simp, aesop safe 20 apply (rule_sets := [SetLike])) + "The `AddSubgroup` generated by a set includes the set."] +theorem subset_closure : k ⊆ closure k := fun _ hx => mem_closure.2 fun _ hK => hK hx + +@[to_additive] +theorem not_mem_of_not_mem_closure {P : G} (hP : P ∉ closure k) : P ∉ k := fun h => + hP (subset_closure h) + +open Set + +/-- A subgroup `K` includes `closure k` if and only if it includes `k`. -/ +@[to_additive (attr := simp) + "An additive subgroup `K` includes `closure k` if and only if it includes `k`"] +theorem closure_le : closure k ≤ K ↔ k ⊆ K := + ⟨Subset.trans subset_closure, fun h => sInf_le h⟩ + +@[to_additive] +theorem closure_eq_of_le (h₁ : k ⊆ K) (h₂ : K ≤ closure k) : closure k = K := + le_antisymm ((closure_le <| K).2 h₁) h₂ + +/-- 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`. + +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`. + + 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 : G) → g ∈ closure k → Prop} + (mem : ∀ x (hx : x ∈ k), p x (subset_closure hx)) (one : p 1 (one_mem _)) + (mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy)) + (inv : ∀ x hx, p x hx → p x⁻¹ (inv_mem hx)) {x} (hx : x ∈ closure k) : p x hx := + let K : Subgroup G := + { carrier := { x | ∃ hx, p x hx } + mul_mem' := fun ⟨_, ha⟩ ⟨_, hb⟩ ↦ ⟨_, mul _ _ _ _ ha hb⟩ + one_mem' := ⟨_, one⟩ + inv_mem' := fun ⟨_, hb⟩ ↦ ⟨_, inv _ _ hb⟩ } + closure_le (K := K) |>.mpr (fun y hy ↦ ⟨subset_closure hy, mem y hy⟩) hx |>.elim fun _ ↦ id + +@[deprecated closure_induction (since := "2024-10-10")] +alias closure_induction' := closure_induction + +/-- An induction principle for closure membership for predicates with two arguments. -/ +@[to_additive (attr := elab_as_elim) + "An induction principle for additive closure membership, for + predicates with two arguments."] +theorem closure_induction₂ {p : (x y : G) → x ∈ closure k → y ∈ closure k → Prop} + (mem : ∀ (x) (y) (hx : x ∈ k) (hy : y ∈ k), p x y (subset_closure hx) (subset_closure hy)) + (one_left : ∀ x hx, p 1 x (one_mem _) hx) (one_right : ∀ x hx, p x 1 hx (one_mem _)) + (mul_left : ∀ x y z hx hy hz, p x z hx hz → p y z hy hz → p (x * y) z (mul_mem hx hy) hz) + (mul_right : ∀ y z x hy hz hx, p x y hx hy → p x z hx hz → p x (y * z) hx (mul_mem hy hz)) + (inv_left : ∀ x y hx hy, p x y hx hy → p x⁻¹ y (inv_mem hx) hy) + (inv_right : ∀ x y hx hy, p x y hx hy → p x y⁻¹ hx (inv_mem hy)) + {x y : G} (hx : x ∈ closure k) (hy : y ∈ closure k) : p x y hx hy := by + induction hy using closure_induction with + | mem z hz => induction hx using closure_induction with + | mem _ h => exact mem _ _ h hz + | one => exact one_left _ (subset_closure hz) + | mul _ _ _ _ h₁ h₂ => exact mul_left _ _ _ _ _ _ h₁ h₂ + | inv _ _ h => exact inv_left _ _ _ _ h + | one => exact one_right x hx + | mul _ _ _ _ h₁ h₂ => exact mul_right _ _ _ _ _ hx h₁ h₂ + | inv _ _ h => exact inv_right _ _ _ _ h + +@[to_additive (attr := simp)] +theorem closure_closure_coe_preimage {k : Set G} : closure (((↑) : closure k → G) ⁻¹' k) = ⊤ := + eq_top_iff.2 fun x _ ↦ Subtype.recOn x fun _ hx' ↦ + closure_induction (fun _ h ↦ subset_closure h) (one_mem _) (fun _ _ _ _ ↦ mul_mem) + (fun _ _ ↦ inv_mem) hx' + +variable (G) + +/-- `closure` forms a Galois insertion with the coercion to set. -/ +@[to_additive "`closure` forms a Galois insertion with the coercion to set."] +protected def gi : GaloisInsertion (@closure G _) (↑) where + choice s _ := closure s + gc s t := @closure_le _ _ t s + le_l_u _s := subset_closure + choice_eq _s _h := rfl + +variable {G} + +/-- Subgroup closure of a set is monotone in its argument: if `h ⊆ k`, +then `closure h ≤ closure k`. -/ +@[to_additive + "Additive subgroup closure of a set is monotone in its argument: if `h ⊆ k`, + then `closure h ≤ closure k`"] +theorem closure_mono ⦃h k : Set G⦄ (h' : h ⊆ k) : closure h ≤ closure k := + (Subgroup.gi G).gc.monotone_l h' + +/-- Closure of a subgroup `K` equals `K`. -/ +@[to_additive (attr := simp) "Additive closure of an additive subgroup `K` equals `K`"] +theorem closure_eq : closure (K : Set G) = K := + (Subgroup.gi G).l_u_eq K + +@[to_additive (attr := simp)] +theorem closure_empty : closure (∅ : Set G) = ⊥ := + (Subgroup.gi G).gc.l_bot + +@[to_additive (attr := simp)] +theorem closure_univ : closure (univ : Set G) = ⊤ := + @coe_top G _ ▸ closure_eq ⊤ + +@[to_additive] +theorem closure_union (s t : Set G) : closure (s ∪ t) = closure s ⊔ closure t := + (Subgroup.gi G).gc.l_sup + +@[to_additive] +theorem sup_eq_closure (H H' : Subgroup G) : H ⊔ H' = closure ((H : Set G) ∪ (H' : Set G)) := by + simp_rw [closure_union, closure_eq] + +@[to_additive] +theorem closure_iUnion {ι} (s : ι → Set G) : closure (⋃ i, s i) = ⨆ i, closure (s i) := + (Subgroup.gi G).gc.l_iSup + +@[to_additive (attr := simp)] +theorem closure_eq_bot_iff : closure k = ⊥ ↔ k ⊆ {1} := le_bot_iff.symm.trans <| closure_le _ + +@[to_additive] +theorem iSup_eq_closure {ι : Sort*} (p : ι → Subgroup G) : + ⨆ i, p i = closure (⋃ i, (p i : Set G)) := by simp_rw [closure_iUnion, closure_eq] + +/-- The subgroup generated by an element of a group equals the set of integer number powers of + the element. -/ +@[to_additive + "The `AddSubgroup` generated by an element of an `AddGroup` equals the set of + natural number multiples of the element."] +theorem mem_closure_singleton {x y : G} : y ∈ closure ({x} : Set G) ↔ ∃ n : ℤ, x ^ n = y := by + refine + ⟨fun hy => closure_induction ?_ ?_ ?_ ?_ hy, fun ⟨n, hn⟩ => + hn ▸ zpow_mem (subset_closure <| mem_singleton x) n⟩ + · intro y hy + rw [eq_of_mem_singleton hy] + exact ⟨1, zpow_one x⟩ + · exact ⟨0, zpow_zero x⟩ + · rintro _ _ _ _ ⟨n, rfl⟩ ⟨m, rfl⟩ + exact ⟨n + m, zpow_add x n m⟩ + rintro _ _ ⟨n, rfl⟩ + exact ⟨-n, zpow_neg x n⟩ + +@[to_additive] +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 + +@[to_additive] +theorem closure_eq_top_of_mclosure_eq_top {S : Set G} (h : Submonoid.closure S = ⊤) : + closure S = ⊤ := + (eq_top_iff' _).2 fun _ => le_closure_toSubmonoid _ <| h.symm ▸ trivial + +@[to_additive] +theorem mem_iSup_of_directed {ι} [hι : Nonempty ι] {K : ι → Subgroup G} (hK : Directed (· ≤ ·) K) + {x : G} : x ∈ (iSup K : Subgroup G) ↔ ∃ i, x ∈ K i := by + refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup K i hi⟩ + suffices x ∈ closure (⋃ i, (K i : Set G)) → ∃ i, x ∈ K i by + simpa only [closure_iUnion, closure_eq (K _)] using this + refine fun hx ↦ closure_induction (fun _ ↦ mem_iUnion.1) ?_ ?_ ?_ hx + · exact hι.elim fun i ↦ ⟨i, (K i).one_mem⟩ + · rintro x y _ _ ⟨i, hi⟩ ⟨j, hj⟩ + rcases hK i j with ⟨k, hki, hkj⟩ + exact ⟨k, mul_mem (hki hi) (hkj hj)⟩ + · rintro _ _ ⟨i, hi⟩ + exact ⟨i, inv_mem hi⟩ + +@[to_additive] +theorem coe_iSup_of_directed {ι} [Nonempty ι] {S : ι → Subgroup G} (hS : Directed (· ≤ ·) S) : + ((⨆ i, S i : Subgroup G) : Set G) = ⋃ i, S i := + Set.ext fun x ↦ by simp [mem_iSup_of_directed hS] + +@[to_additive] +theorem mem_sSup_of_directedOn {K : Set (Subgroup G)} (Kne : K.Nonempty) (hK : DirectedOn (· ≤ ·) K) + {x : G} : x ∈ sSup K ↔ ∃ s ∈ K, x ∈ s := by + haveI : Nonempty K := Kne.to_subtype + simp only [sSup_eq_iSup', mem_iSup_of_directed hK.directed_val, SetCoe.exists, Subtype.coe_mk, + exists_prop] + +variable {C : Type*} [CommGroup C] {s t : Subgroup C} {x : C} + +@[to_additive] +theorem mem_sup : x ∈ s ⊔ t ↔ ∃ y ∈ s, ∃ z ∈ t, y * z = x := + ⟨fun h => by + rw [sup_eq_closure] at h + refine Subgroup.closure_induction ?_ ?_ ?_ ?_ h + · rintro y (h | h) + · exact ⟨y, h, 1, t.one_mem, by simp⟩ + · exact ⟨1, s.one_mem, y, h, by simp⟩ + · exact ⟨1, s.one_mem, 1, ⟨t.one_mem, mul_one 1⟩⟩ + · rintro _ _ _ _ ⟨y₁, hy₁, z₁, hz₁, rfl⟩ ⟨y₂, hy₂, z₂, hz₂, rfl⟩ + exact ⟨_, mul_mem hy₁ hy₂, _, mul_mem hz₁ hz₂, by simp [mul_assoc, mul_left_comm]⟩ + · rintro _ _ ⟨y, hy, z, hz, rfl⟩ + exact ⟨_, inv_mem hy, _, inv_mem hz, mul_comm z y ▸ (mul_inv_rev z y).symm⟩, by + rintro ⟨y, hy, z, hz, rfl⟩; exact mul_mem_sup hy hz⟩ + +@[to_additive] +theorem mem_sup' : x ∈ s ⊔ t ↔ ∃ (y : s) (z : t), (y : C) * z = x := + mem_sup.trans <| by simp only [SetLike.exists, coe_mk, exists_prop] + +@[to_additive] +theorem mem_closure_pair {x y z : C} : + z ∈ closure ({x, y} : Set C) ↔ ∃ m n : ℤ, x ^ m * y ^ n = z := by + rw [← Set.singleton_union, Subgroup.closure_union, mem_sup] + simp_rw [mem_closure_singleton, exists_exists_eq_and] + +@[to_additive] +theorem disjoint_def {H₁ H₂ : Subgroup G} : Disjoint H₁ H₂ ↔ ∀ {x : G}, x ∈ H₁ → x ∈ H₂ → x = 1 := + disjoint_iff_inf_le.trans <| by simp only [Disjoint, SetLike.le_def, mem_inf, mem_bot, and_imp] + +@[to_additive] +theorem disjoint_def' {H₁ H₂ : Subgroup G} : + Disjoint H₁ H₂ ↔ ∀ {x y : G}, x ∈ H₁ → y ∈ H₂ → x = y → x = 1 := + disjoint_def.trans ⟨fun h _x _y hx hy hxy ↦ h hx <| hxy.symm ▸ hy, fun h _x hx hx' ↦ h hx hx' rfl⟩ + +@[to_additive] +theorem disjoint_iff_mul_eq_one {H₁ H₂ : Subgroup G} : + Disjoint H₁ H₂ ↔ ∀ {x y : G}, x ∈ H₁ → y ∈ H₂ → x * y = 1 → x = 1 ∧ y = 1 := + disjoint_def'.trans + ⟨fun h x y hx hy hxy => + let hx1 : x = 1 := h hx (H₂.inv_mem hy) (eq_inv_iff_mul_eq_one.mpr hxy) + ⟨hx1, by simpa [hx1] using hxy⟩, + fun h _ _ hx hy hxy => (h hx (H₂.inv_mem hy) (mul_inv_eq_one.mpr hxy)).1⟩ + +@[to_additive] +theorem mul_injective_of_disjoint {H₁ H₂ : Subgroup G} (h : Disjoint H₁ H₂) : + Function.Injective (fun g => g.1 * g.2 : H₁ × H₂ → G) := by + intro x y hxy + rw [← inv_mul_eq_iff_eq_mul, ← mul_assoc, ← mul_inv_eq_one, mul_assoc] at hxy + replace hxy := disjoint_iff_mul_eq_one.mp h (y.1⁻¹ * x.1).prop (x.2 * y.2⁻¹).prop hxy + rwa [coe_mul, coe_mul, coe_inv, coe_inv, inv_mul_eq_one, mul_inv_eq_one, ← Subtype.ext_iff, ← + Subtype.ext_iff, eq_comm, ← Prod.ext_iff] at hxy + +end Subgroup diff --git a/Mathlib/Algebra/Group/Subgroup/Map.lean b/Mathlib/Algebra/Group/Subgroup/Map.lean new file mode 100644 index 00000000000000..e1219dcd592033 --- /dev/null +++ b/Mathlib/Algebra/Group/Subgroup/Map.lean @@ -0,0 +1,528 @@ +/- +Copyright (c) 2020 Kexing Ying. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kexing Ying +-/ +import Mathlib.Algebra.Group.Subgroup.Lattice +import Mathlib.Algebra.Group.TypeTags.Hom + +/-! +# `map` and `comap` for subgroups + +We prove results about images and preimages of subgroups under group homomorphisms. The bundled +subgroups use bundled monoid homomorphisms. + +Special thanks goes to Amelia Livingston and Yury Kudryashov for their help and inspiration. + +## Main definitions + +Notation used here: + +- `G N` are `Group`s + +- `H` is a `Subgroup` of `G` + +- `x` is an element of type `G` or type `A` + +- `f g : N →* G` are group homomorphisms + +- `s k` are sets of elements of type `G` + +Definitions in the file: + +* `Subgroup.comap H f` : the preimage of a subgroup `H` along the group homomorphism `f` is also a + subgroup + +* `Subgroup.map f H` : the image of a subgroup `H` along the group homomorphism `f` is also a + subgroup + +## Implementation notes + +Subgroup inclusion is denoted `≤` rather than `⊆`, although `∈` is defined as +membership of a subgroup's underlying set. + +## Tags +subgroup, subgroups +-/ + +assert_not_exists OrderedAddCommMonoid +assert_not_exists Multiset +assert_not_exists Ring + +open Function +open scoped Int + +variable {G G' G'' : Type*} [Group G] [Group G'] [Group G''] +variable {A : Type*} [AddGroup A] + +namespace Subgroup + +variable (H K : Subgroup G) {k : Set G} + +open Set + +variable {N : Type*} [Group N] {P : Type*} [Group P] + +/-- The preimage of a subgroup along a monoid homomorphism is a subgroup. -/ +@[to_additive + "The preimage of an `AddSubgroup` along an `AddMonoid` homomorphism + is an `AddSubgroup`."] +def comap {N : Type*} [Group N] (f : G →* N) (H : Subgroup N) : Subgroup G := + { H.toSubmonoid.comap f with + carrier := f ⁻¹' H + inv_mem' := fun {a} ha => show f a⁻¹ ∈ H by rw [f.map_inv]; exact H.inv_mem ha } + +@[to_additive (attr := simp)] +theorem coe_comap (K : Subgroup N) (f : G →* N) : (K.comap f : Set G) = f ⁻¹' K := + rfl + +@[to_additive (attr := simp)] +theorem mem_comap {K : Subgroup N} {f : G →* N} {x : G} : x ∈ K.comap f ↔ f x ∈ K := + Iff.rfl + +@[to_additive] +theorem comap_mono {f : G →* N} {K K' : Subgroup N} : K ≤ K' → comap f K ≤ comap f K' := + preimage_mono + +@[to_additive] +theorem comap_comap (K : Subgroup P) (g : N →* P) (f : G →* N) : + (K.comap g).comap f = K.comap (g.comp f) := + rfl + +@[to_additive (attr := simp)] +theorem comap_id (K : Subgroup N) : K.comap (MonoidHom.id _) = K := by + ext + rfl + +@[simp] +theorem toAddSubgroup_comap {G₂ : Type*} [Group G₂] (f : G →* G₂) (s : Subgroup G₂) : + s.toAddSubgroup.comap (MonoidHom.toAdditive f) = Subgroup.toAddSubgroup (s.comap f) := rfl + +@[simp] +theorem _root_.AddSubgroup.toSubgroup_comap {A A₂ : Type*} [AddGroup A] [AddGroup A₂] + (f : A →+ A₂) (s : AddSubgroup A₂) : + s.toSubgroup.comap (AddMonoidHom.toMultiplicative f) = AddSubgroup.toSubgroup (s.comap f) := rfl + +/-- The image of a subgroup along a monoid homomorphism is a subgroup. -/ +@[to_additive + "The image of an `AddSubgroup` along an `AddMonoid` homomorphism + is an `AddSubgroup`."] +def map (f : G →* N) (H : Subgroup G) : Subgroup N := + { H.toSubmonoid.map f with + carrier := f '' H + inv_mem' := by + rintro _ ⟨x, hx, rfl⟩ + exact ⟨x⁻¹, H.inv_mem hx, f.map_inv x⟩ } + +@[to_additive (attr := simp)] +theorem coe_map (f : G →* N) (K : Subgroup G) : (K.map f : Set N) = f '' K := + rfl + +@[to_additive (attr := simp)] +theorem mem_map {f : G →* N} {K : Subgroup G} {y : N} : y ∈ K.map f ↔ ∃ x ∈ K, f x = y := Iff.rfl + +@[to_additive] +theorem mem_map_of_mem (f : G →* N) {K : Subgroup G} {x : G} (hx : x ∈ K) : f x ∈ K.map f := + mem_image_of_mem f hx + +@[to_additive] +theorem apply_coe_mem_map (f : G →* N) (K : Subgroup G) (x : K) : f x ∈ K.map f := + mem_map_of_mem f x.prop + +@[to_additive] +theorem map_mono {f : G →* N} {K K' : Subgroup G} : K ≤ K' → map f K ≤ map f K' := + image_subset _ + +@[to_additive (attr := simp)] +theorem map_id : K.map (MonoidHom.id G) = K := + SetLike.coe_injective <| image_id _ + +@[to_additive] +theorem map_map (g : N →* P) (f : G →* N) : (K.map f).map g = K.map (g.comp f) := + SetLike.coe_injective <| image_image _ _ _ + +@[to_additive (attr := simp)] +theorem map_one_eq_bot : K.map (1 : G →* N) = ⊥ := + eq_bot_iff.mpr <| by + rintro x ⟨y, _, rfl⟩ + simp + +@[to_additive] +theorem mem_map_equiv {f : G ≃* N} {K : Subgroup G} {x : N} : + x ∈ K.map f.toMonoidHom ↔ f.symm x ∈ K := by + erw [@Set.mem_image_equiv _ _ (↑K) f.toEquiv x]; rfl + +-- The simpNF linter says that the LHS can be simplified via `Subgroup.mem_map`. +-- However this is a higher priority lemma. +-- https://github.com/leanprover/std4/issues/207 +@[to_additive (attr := simp 1100, nolint simpNF)] +theorem mem_map_iff_mem {f : G →* N} (hf : Function.Injective f) {K : Subgroup G} {x : G} : + f x ∈ K.map f ↔ x ∈ K := + hf.mem_set_image + +@[to_additive] +theorem map_equiv_eq_comap_symm' (f : G ≃* N) (K : Subgroup G) : + K.map f.toMonoidHom = K.comap f.symm.toMonoidHom := + SetLike.coe_injective (f.toEquiv.image_eq_preimage K) + +@[to_additive] +theorem map_equiv_eq_comap_symm (f : G ≃* N) (K : Subgroup G) : + K.map f = K.comap (G := N) f.symm := + map_equiv_eq_comap_symm' _ _ + +@[to_additive] +theorem comap_equiv_eq_map_symm (f : N ≃* G) (K : Subgroup G) : + K.comap (G := N) f = K.map f.symm := + (map_equiv_eq_comap_symm f.symm K).symm + +@[to_additive] +theorem comap_equiv_eq_map_symm' (f : N ≃* G) (K : Subgroup G) : + K.comap f.toMonoidHom = K.map f.symm.toMonoidHom := + (map_equiv_eq_comap_symm f.symm K).symm + +@[to_additive] +theorem map_symm_eq_iff_map_eq {H : Subgroup N} {e : G ≃* N} : + H.map ↑e.symm = K ↔ K.map ↑e = H := by + constructor <;> rintro rfl + · rw [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.symm_trans_self, + MulEquiv.coe_monoidHom_refl, map_id] + · rw [map_map, ← MulEquiv.coe_monoidHom_trans, MulEquiv.self_trans_symm, + MulEquiv.coe_monoidHom_refl, map_id] + +@[to_additive] +theorem map_le_iff_le_comap {f : G →* N} {K : Subgroup G} {H : Subgroup N} : + K.map f ≤ H ↔ K ≤ H.comap f := + image_subset_iff + +@[to_additive] +theorem gc_map_comap (f : G →* N) : GaloisConnection (map f) (comap f) := fun _ _ => + map_le_iff_le_comap + +@[to_additive] +theorem map_sup (H K : Subgroup G) (f : G →* N) : (H ⊔ K).map f = H.map f ⊔ K.map f := + (gc_map_comap f).l_sup + +@[to_additive] +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) := + Monotone.le_map_sup (fun _ _ => comap_mono) H K + +@[to_additive] +theorem iSup_comap_le {ι : Sort*} (f : G →* N) (s : ι → Subgroup N) : + ⨆ i, (s i).comap f ≤ (iSup s).comap f := + Monotone.le_map_iSup fun _ _ => comap_mono + +@[to_additive] +theorem comap_inf (H K : Subgroup N) (f : G →* N) : (H ⊓ K).comap f = H.comap f ⊓ K.comap f := + (gc_map_comap f).u_inf + +@[to_additive] +theorem comap_iInf {ι : Sort*} (f : G →* N) (s : ι → Subgroup N) : + (iInf s).comap f = ⨅ i, (s i).comap f := + (gc_map_comap f).u_iInf + +@[to_additive] +theorem map_inf_le (H K : Subgroup G) (f : G →* N) : map f (H ⊓ K) ≤ map f H ⊓ map f K := + le_inf (map_mono inf_le_left) (map_mono inf_le_right) + +@[to_additive] +theorem map_inf_eq (H K : Subgroup G) (f : G →* N) (hf : Function.Injective f) : + map f (H ⊓ K) = map f H ⊓ map f K := by + rw [← SetLike.coe_set_eq] + simp [Set.image_inter hf] + +@[to_additive (attr := simp)] +theorem map_bot (f : G →* N) : (⊥ : Subgroup G).map f = ⊥ := + (gc_map_comap f).l_bot + +@[to_additive (attr := simp)] +theorem map_top_of_surjective (f : G →* N) (h : Function.Surjective f) : Subgroup.map f ⊤ = ⊤ := by + rw [eq_top_iff] + intro x _ + obtain ⟨y, hy⟩ := h x + exact ⟨y, trivial, hy⟩ + +@[to_additive (attr := simp)] +theorem comap_top (f : G →* N) : (⊤ : Subgroup N).comap f = ⊤ := + (gc_map_comap f).u_top + +/-- For any subgroups `H` and `K`, view `H ⊓ K` as a subgroup of `K`. -/ +@[to_additive "For any subgroups `H` and `K`, view `H ⊓ K` as a subgroup of `K`."] +def subgroupOf (H K : Subgroup G) : Subgroup K := + H.comap K.subtype + +/-- If `H ≤ K`, then `H` as a subgroup of `K` is isomorphic to `H`. -/ +@[to_additive (attr := simps) "If `H ≤ K`, then `H` as a subgroup of `K` is isomorphic to `H`."] +def subgroupOfEquivOfLe {G : Type*} [Group G] {H K : Subgroup G} (h : H ≤ K) : + H.subgroupOf K ≃* H where + toFun g := ⟨g.1, g.2⟩ + invFun g := ⟨⟨g.1, h g.2⟩, g.2⟩ + left_inv _g := Subtype.ext (Subtype.ext rfl) + right_inv _g := Subtype.ext rfl + map_mul' _g _h := rfl + +@[to_additive (attr := simp)] +theorem comap_subtype (H K : Subgroup G) : H.comap K.subtype = H.subgroupOf K := + rfl + +@[to_additive (attr := simp)] +theorem comap_inclusion_subgroupOf {K₁ K₂ : Subgroup G} (h : K₁ ≤ K₂) (H : Subgroup G) : + (H.subgroupOf K₂).comap (inclusion h) = H.subgroupOf K₁ := + rfl + +@[to_additive] +theorem coe_subgroupOf (H K : Subgroup G) : (H.subgroupOf K : Set K) = K.subtype ⁻¹' H := + rfl + +@[to_additive] +theorem mem_subgroupOf {H K : Subgroup G} {h : K} : h ∈ H.subgroupOf K ↔ (h : G) ∈ H := + Iff.rfl + +-- TODO(kmill): use `K ⊓ H` order for RHS to match `Subtype.image_preimage_coe` +@[to_additive (attr := simp)] +theorem subgroupOf_map_subtype (H K : Subgroup G) : (H.subgroupOf K).map K.subtype = H ⊓ K := + SetLike.ext' <| by refine Subtype.image_preimage_coe _ _ |>.trans ?_; apply Set.inter_comm + +@[to_additive (attr := simp)] +theorem bot_subgroupOf : (⊥ : Subgroup G).subgroupOf H = ⊥ := + Eq.symm (Subgroup.ext fun _g => Subtype.ext_iff) + +@[to_additive (attr := simp)] +theorem top_subgroupOf : (⊤ : Subgroup G).subgroupOf H = ⊤ := + rfl + +@[to_additive] +theorem subgroupOf_bot_eq_bot : H.subgroupOf ⊥ = ⊥ := + Subsingleton.elim _ _ + +@[to_additive] +theorem subgroupOf_bot_eq_top : H.subgroupOf ⊥ = ⊤ := + Subsingleton.elim _ _ + +@[to_additive (attr := simp)] +theorem subgroupOf_self : H.subgroupOf H = ⊤ := + top_unique fun g _hg => g.2 + +@[to_additive (attr := simp)] +theorem subgroupOf_inj {H₁ H₂ K : Subgroup G} : + H₁.subgroupOf K = H₂.subgroupOf K ↔ H₁ ⊓ K = H₂ ⊓ K := by + simpa only [SetLike.ext_iff, mem_inf, mem_subgroupOf, and_congr_left_iff] using Subtype.forall + +@[to_additive (attr := simp)] +theorem inf_subgroupOf_right (H K : Subgroup G) : (H ⊓ K).subgroupOf K = H.subgroupOf K := + subgroupOf_inj.2 (inf_right_idem _ _) + +@[to_additive (attr := simp)] +theorem inf_subgroupOf_left (H K : Subgroup G) : (K ⊓ H).subgroupOf K = H.subgroupOf K := by + rw [inf_comm, inf_subgroupOf_right] + +@[to_additive (attr := simp)] +theorem subgroupOf_eq_bot {H K : Subgroup G} : H.subgroupOf K = ⊥ ↔ Disjoint H K := by + rw [disjoint_iff, ← bot_subgroupOf, subgroupOf_inj, bot_inf_eq] + +@[to_additive (attr := simp)] +theorem subgroupOf_eq_top {H K : Subgroup G} : H.subgroupOf K = ⊤ ↔ K ≤ H := by + rw [← top_subgroupOf, subgroupOf_inj, top_inf_eq, inf_eq_right] + +variable (H : Subgroup G) + +@[to_additive] +instance map_isCommutative (f : G →* G') [H.IsCommutative] : (H.map f).IsCommutative := + ⟨⟨by + rintro ⟨-, a, ha, rfl⟩ ⟨-, b, hb, rfl⟩ + rw [Subtype.ext_iff, coe_mul, coe_mul, Subtype.coe_mk, Subtype.coe_mk, ← map_mul, ← map_mul] + exact congr_arg f (Subtype.ext_iff.mp (mul_comm (⟨a, ha⟩ : H) ⟨b, hb⟩))⟩⟩ + +@[to_additive] +theorem comap_injective_isCommutative {f : G' →* G} (hf : Injective f) [H.IsCommutative] : + (H.comap f).IsCommutative := + ⟨⟨fun a b => + Subtype.ext + (by + have := mul_comm (⟨f a, a.2⟩ : H) (⟨f b, b.2⟩ : H) + rwa [Subtype.ext_iff, coe_mul, coe_mul, coe_mk, coe_mk, ← map_mul, ← map_mul, + hf.eq_iff] at this)⟩⟩ + +@[to_additive] +instance subgroupOf_isCommutative [H.IsCommutative] : (H.subgroupOf K).IsCommutative := + H.comap_injective_isCommutative Subtype.coe_injective + +end Subgroup + +namespace MulEquiv +variable {H : Type*} [Group H] + +/-- +An isomorphism of groups gives an order isomorphism between the lattices of subgroups, +defined by sending subgroups to their inverse images. + +See also `MulEquiv.mapSubgroup` which maps subgroups to their forward images. +-/ +@[simps] +def comapSubgroup (f : G ≃* H) : Subgroup H ≃o Subgroup G where + toFun := Subgroup.comap f + invFun := Subgroup.comap f.symm + left_inv sg := by simp [Subgroup.comap_comap] + right_inv sh := by simp [Subgroup.comap_comap] + map_rel_iff' {sg1 sg2} := + ⟨fun h => by simpa [Subgroup.comap_comap] using + Subgroup.comap_mono (f := (f.symm : H →* G)) h, Subgroup.comap_mono⟩ + +/-- +An isomorphism of groups gives an order isomorphism between the lattices of subgroups, +defined by sending subgroups to their forward images. + +See also `MulEquiv.comapSubgroup` which maps subgroups to their inverse images. +-/ +@[simps] +def mapSubgroup {H : Type*} [Group H] (f : G ≃* H) : Subgroup G ≃o Subgroup H where + toFun := Subgroup.map f + invFun := Subgroup.map f.symm + left_inv sg := by simp [Subgroup.map_map] + right_inv sh := by simp [Subgroup.map_map] + map_rel_iff' {sg1 sg2} := + ⟨fun h => by simpa [Subgroup.map_map] using + Subgroup.map_mono (f := (f.symm : H →* G)) h, Subgroup.map_mono⟩ + +end MulEquiv + +namespace Subgroup + +open MonoidHom + +variable {N : Type*} [Group N] (f : G →* N) + +@[to_additive] +theorem map_comap_le (H : Subgroup N) : map f (comap f H) ≤ H := + (gc_map_comap f).l_u_le _ + +@[to_additive] +theorem le_comap_map (H : Subgroup G) : H ≤ comap f (map f H) := + (gc_map_comap f).le_u_l _ + +@[to_additive] +theorem map_eq_comap_of_inverse {f : G →* N} {g : N →* G} (hl : Function.LeftInverse g f) + (hr : Function.RightInverse g f) (H : Subgroup G) : map f H = comap g H := + SetLike.ext' <| by rw [coe_map, coe_comap, Set.image_eq_preimage_of_inverse hl hr] + +/-- A subgroup is isomorphic to its image under an injective function. If you have an isomorphism, +use `MulEquiv.subgroupMap` for better definitional equalities. -/ +@[to_additive + "An additive subgroup is isomorphic to its image under an injective function. If you + have an isomorphism, use `AddEquiv.addSubgroupMap` for better definitional equalities."] +noncomputable def equivMapOfInjective (H : Subgroup G) (f : G →* N) (hf : Function.Injective f) : + H ≃* H.map f := + { Equiv.Set.image f H hf with map_mul' := fun _ _ => Subtype.ext (f.map_mul _ _) } + +@[to_additive (attr := simp)] +theorem coe_equivMapOfInjective_apply (H : Subgroup G) (f : G →* N) (hf : Function.Injective f) + (h : H) : (equivMapOfInjective H f hf h : N) = f h := + rfl + +end Subgroup + +variable {N : Type*} [Group N] + +namespace MonoidHom + +/-- The `MonoidHom` from the preimage of a subgroup to itself. -/ +@[to_additive (attr := simps!) "the `AddMonoidHom` from the preimage of an +additive subgroup to itself."] +def subgroupComap (f : G →* G') (H' : Subgroup G') : H'.comap f →* H' := + f.submonoidComap H'.toSubmonoid + +/-- The `MonoidHom` from a subgroup to its image. -/ +@[to_additive (attr := simps!) "the `AddMonoidHom` from an additive subgroup to its image"] +def subgroupMap (f : G →* G') (H : Subgroup G) : H →* H.map f := + f.submonoidMap H.toSubmonoid + +@[to_additive] +theorem subgroupMap_surjective (f : G →* G') (H : Subgroup G) : + Function.Surjective (f.subgroupMap H) := + f.submonoidMap_surjective H.toSubmonoid + +end MonoidHom + +namespace MulEquiv + +variable {H K : Subgroup G} + +/-- Makes the identity isomorphism from a proof two subgroups of a multiplicative + group are equal. -/ +@[to_additive + "Makes the identity additive isomorphism from a proof + two subgroups of an additive group are equal."] +def subgroupCongr (h : H = K) : H ≃* K := + { Equiv.setCongr <| congr_arg _ h with map_mul' := fun _ _ => rfl } + +@[to_additive (attr := simp)] +lemma subgroupCongr_apply (h : H = K) (x) : + (MulEquiv.subgroupCongr h x : G) = x := rfl + +@[to_additive (attr := simp)] +lemma subgroupCongr_symm_apply (h : H = K) (x) : + ((MulEquiv.subgroupCongr h).symm x : G) = x := rfl + +/-- A subgroup is isomorphic to its image under an isomorphism. If you only have an injective map, +use `Subgroup.equiv_map_of_injective`. -/ +@[to_additive + "An additive subgroup is isomorphic to its image under an isomorphism. If you only + have an injective map, use `AddSubgroup.equiv_map_of_injective`."] +def subgroupMap (e : G ≃* G') (H : Subgroup G) : H ≃* H.map (e : G →* G') := + MulEquiv.submonoidMap (e : G ≃* G') H.toSubmonoid + +@[to_additive (attr := simp)] +theorem coe_subgroupMap_apply (e : G ≃* G') (H : Subgroup G) (g : H) : + ((subgroupMap e H g : H.map (e : G →* G')) : G') = e g := + rfl + +@[to_additive (attr := simp)] +theorem subgroupMap_symm_apply (e : G ≃* G') (H : Subgroup G) (g : H.map (e : G →* G')) : + (e.subgroupMap H).symm g = ⟨e.symm g, SetLike.mem_coe.1 <| Set.mem_image_equiv.1 g.2⟩ := + rfl + +end MulEquiv + +namespace MonoidHom + +open Subgroup + +@[to_additive] +theorem closure_preimage_le (f : G →* N) (s : Set N) : closure (f ⁻¹' s) ≤ (closure s).comap f := + (closure_le _).2 fun x hx => by rw [SetLike.mem_coe, mem_comap]; exact subset_closure hx + +/-- The image under a monoid homomorphism of the subgroup generated by a set equals the subgroup +generated by the image of the set. -/ +@[to_additive + "The image under an `AddMonoid` hom of the `AddSubgroup` generated by a set equals + the `AddSubgroup` generated by the image of the set."] +theorem map_closure (f : G →* N) (s : Set G) : (closure s).map f = closure (f '' s) := + Set.image_preimage.l_comm_of_u_comm (gc_map_comap f) (Subgroup.gi N).gc (Subgroup.gi G).gc + fun _ ↦ rfl + +end MonoidHom + +namespace Subgroup + +@[to_additive (attr := simp)] +theorem equivMapOfInjective_coe_mulEquiv (H : Subgroup G) (e : G ≃* G') : + H.equivMapOfInjective (e : G →* G') (EquivLike.injective e) = e.subgroupMap H := by + ext + rfl + +end Subgroup diff --git a/Mathlib/Algebra/Group/Subgroup/ZPowers/Basic.lean b/Mathlib/Algebra/Group/Subgroup/ZPowers/Basic.lean index cf8febc23281b8..357b32013f3582 100644 --- a/Mathlib/Algebra/Group/Subgroup/ZPowers/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/ZPowers/Basic.lean @@ -3,7 +3,8 @@ Copyright (c) 2020 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Int +import Mathlib.Algebra.Group.Subgroup.Map /-! # Subgroups generated by an element diff --git a/Mathlib/Algebra/Group/Submonoid/Membership.lean b/Mathlib/Algebra/Group/Submonoid/Membership.lean index cc9d5be5714ae4..b48b123c3e191e 100644 --- a/Mathlib/Algebra/Group/Submonoid/Membership.lean +++ b/Mathlib/Algebra/Group/Submonoid/Membership.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.FreeMonoid.Basic import Mathlib.Algebra.Group.Submonoid.MulOpposite import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.GroupWithZero.Divisibility +import Mathlib.Algebra.Ring.Idempotents import Mathlib.Algebra.Ring.Int.Defs import Mathlib.Data.Finset.NoncommProd import Mathlib.Data.Nat.Cast.Basic @@ -420,6 +421,21 @@ lemma powers_le {n : M} {P : Submonoid M} : powers n ≤ P ↔ n ∈ P := by sim lemma powers_one : powers (1 : M) = ⊥ := bot_unique <| powers_le.2 <| one_mem _ +theorem _root_.IsIdempotentElem.coe_powers {a : M} (ha : IsIdempotentElem a) : + (Submonoid.powers a : Set M) = {1, a} := + let S : Submonoid M := + { carrier := {1, a}, + mul_mem' := by + rintro _ _ (rfl|rfl) (rfl|rfl) + · rw [one_mul]; exact .inl rfl + · rw [one_mul]; exact .inr rfl + · rw [mul_one]; exact .inr rfl + · rw [ha]; exact .inr rfl + one_mem' := .inl rfl } + suffices Submonoid.powers a = S from congr_arg _ this + le_antisymm (Submonoid.powers_le.mpr <| .inr rfl) + (by rintro _ (rfl|rfl); exacts [one_mem _, Submonoid.mem_powers _]) + /-- The submonoid generated by an element is a group if that element has finite order. -/ abbrev groupPowers {x : M} {n : ℕ} (hpos : 0 < n) (hx : x ^ n = 1) : Group (powers x) where inv x := x ^ (n - 1) @@ -475,7 +491,7 @@ when it is injective. The inverse is given by the logarithms. -/ @[simps] def powLogEquiv [DecidableEq M] {n : M} (h : Function.Injective fun m : ℕ => n ^ m) : Multiplicative ℕ ≃* powers n where - toFun m := pow n (Multiplicative.toAdd m) + toFun m := pow n m.toAdd invFun m := Multiplicative.ofAdd (log m) left_inv := log_pow_eq_self h right_inv := pow_log_eq_self diff --git a/Mathlib/Algebra/Group/Submonoid/Operations.lean b/Mathlib/Algebra/Group/Submonoid/Operations.lean index 46c96865817f9b..36ee592c01e9df 100644 --- a/Mathlib/Algebra/Group/Submonoid/Operations.lean +++ b/Mathlib/Algebra/Group/Submonoid/Operations.lean @@ -5,9 +5,10 @@ Authors: Johannes Hölzl, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzza Amelia Livingston, Yury Kudryashov -/ import Mathlib.Algebra.Group.Action.Faithful -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.TypeTags.Basic /-! # Operations on `Submonoid`s diff --git a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean index 2c5e53bea3b806..9c5e50a98eb6be 100644 --- a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean +++ b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean @@ -5,6 +5,7 @@ Authors: Eric Wieser -/ import Mathlib.Algebra.Group.Hom.End import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.GroupWithZero.Action.End import Mathlib.Algebra.Order.BigOperators.Group.List import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Order.WellFoundedSet diff --git a/Mathlib/Algebra/Group/Submonoid/Units.lean b/Mathlib/Algebra/Group/Submonoid/Units.lean index 96ce6d155d1e44..111adf47e20ff0 100644 --- a/Mathlib/Algebra/Group/Submonoid/Units.lean +++ b/Mathlib/Algebra/Group/Submonoid/Units.lean @@ -5,7 +5,7 @@ Authors: Wrenna Robson -/ import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.Group.Submonoid.Pointwise -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Lattice /-! diff --git a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean index 8fc45916faae0d..2c782614c04cf2 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean @@ -6,7 +6,7 @@ Amelia Livingston, Yury Kudryashov, Yakov Pechersky, Jireh Loreaux -/ import Mathlib.Algebra.Group.Prod import Mathlib.Algebra.Group.Subsemigroup.Basic -import Mathlib.Algebra.Group.TypeTags +import Mathlib.Algebra.Group.TypeTags.Basic /-! # Operations on `Subsemigroup`s diff --git a/Mathlib/Algebra/Group/TypeTags.lean b/Mathlib/Algebra/Group/TypeTags/Basic.lean similarity index 71% rename from Mathlib/Algebra/Group/TypeTags.lean rename to Mathlib/Algebra/Group/TypeTags/Basic.lean index f6e2f9c2cc9e01..152313ad2ebc6e 100644 --- a/Mathlib/Algebra/Group/TypeTags.lean +++ b/Mathlib/Algebra/Group/TypeTags/Basic.lean @@ -3,8 +3,12 @@ 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.Group.Hom.Defs -import Mathlib.Data.Finite.Defs +import Mathlib.Algebra.Group.Pi.Basic +import Mathlib.Data.FunLike.Basic +import Mathlib.Logic.Function.Iterate +import Mathlib.Logic.Equiv.Defs +import Mathlib.Tactic.Set +import Mathlib.Util.AssertExists import Mathlib.Logic.Nontrivial.Basic /-! @@ -23,15 +27,12 @@ We also define instances `Additive.*` and `Multiplicative.*` that actually trans This file is similar to `Order.Synonym`. -## Porting notes - -- Since bundled morphism applications that rely on `CoeFun` currently don't work, they are ported - as `toFoo a` rather than `a.toFoo` for now. (https://github.com/leanprover/lean4/issues/1910) - -/ assert_not_exists MonoidWithZero assert_not_exists DenselyOrdered +assert_not_exists MonoidHom +assert_not_exists Finite universe u v @@ -71,7 +72,7 @@ protected lemma «exists» {p : Additive α → Prop} : (∃ a, p a) ↔ ∃ a, /-- Recursion principle for `Additive`, supported by `cases` and `induction`. -/ @[elab_as_elim, cases_eliminator, induction_eliminator] def rec {motive : Additive α → Sort*} (ofMul : ∀ a, motive (ofMul a)) : ∀ a, motive a := - fun a => ofMul (toMul a) + fun a => ofMul (a.toMul) end Additive @@ -101,7 +102,7 @@ protected lemma «exists» {p : Multiplicative α → Prop} : (∃ a, p a) ↔ /-- Recursion principle for `Multiplicative`, supported by `cases` and `induction`. -/ @[elab_as_elim, cases_eliminator, induction_eliminator] def rec {motive : Multiplicative α → Sort*} (ofAdd : ∀ a, motive (ofAdd a)) : ∀ a, motive a := - fun a => ofAdd (toAdd a) + fun a => ofAdd (a.toAdd) end Multiplicative @@ -109,19 +110,19 @@ open Additive (ofMul toMul) open Multiplicative (ofAdd toAdd) @[simp] -theorem toAdd_ofAdd (x : α) : toAdd (ofAdd x) = x := +theorem toAdd_ofAdd (x : α) : (ofAdd x).toAdd = x := rfl @[simp] -theorem ofAdd_toAdd (x : Multiplicative α) : ofAdd (toAdd x) = x := +theorem ofAdd_toAdd (x : Multiplicative α) : ofAdd x.toAdd = x := rfl @[simp] -theorem toMul_ofMul (x : α) : toMul (ofMul x) = x := +theorem toMul_ofMul (x : α) : (ofMul x).toMul = x := rfl @[simp] -theorem ofMul_toMul (x : Additive α) : ofMul (toMul x) = x := +theorem ofMul_toMul (x : Additive α) : ofMul x.toMul = x := rfl instance [Subsingleton α] : Subsingleton (Additive α) := toMul.injective.subsingleton @@ -136,16 +137,6 @@ instance [Inhabited α] : Inhabited (Multiplicative α) := instance [Unique α] : Unique (Additive α) := toMul.unique instance [Unique α] : Unique (Multiplicative α) := toAdd.unique -instance [Finite α] : Finite (Additive α) := - Finite.of_equiv α (by rfl) - -instance [Finite α] : Finite (Multiplicative α) := - Finite.of_equiv α (by rfl) - -instance [h : Infinite α] : Infinite (Additive α) := h - -instance [h : Infinite α] : Infinite (Multiplicative α) := h - instance [h : DecidableEq α] : DecidableEq (Multiplicative α) := h instance [h : DecidableEq α] : DecidableEq (Additive α) := h @@ -157,22 +148,22 @@ instance Multiplicative.instNontrivial [Nontrivial α] : Nontrivial (Multiplicat ofAdd.injective.nontrivial instance Additive.add [Mul α] : Add (Additive α) where - add x y := ofMul (toMul x * toMul y) + add x y := ofMul (x.toMul * y.toMul) instance Multiplicative.mul [Add α] : Mul (Multiplicative α) where - mul x y := ofAdd (toAdd x + toAdd y) + mul x y := ofAdd (x.toAdd + y.toAdd) @[simp] theorem ofAdd_add [Add α] (x y : α) : ofAdd (x + y) = ofAdd x * ofAdd y := rfl @[simp] -theorem toAdd_mul [Add α] (x y : Multiplicative α) : toAdd (x * y) = toAdd x + toAdd y := rfl +theorem toAdd_mul [Add α] (x y : Multiplicative α) : (x * y).toAdd = x.toAdd + y.toAdd := rfl @[simp] theorem ofMul_mul [Mul α] (x y : α) : ofMul (x * y) = ofMul x + ofMul y := rfl @[simp] -theorem toMul_add [Mul α] (x y : Additive α) : toMul (x + y) = toMul x * toMul y := rfl +theorem toMul_add [Mul α] (x y : Additive α) : (x + y).toMul = x.toMul * y.toMul := rfl instance Additive.addSemigroup [Semigroup α] : AddSemigroup (Additive α) := { Additive.add with add_assoc := @mul_assoc α _ } @@ -232,11 +223,11 @@ theorem ofMul_one [One α] : @Additive.ofMul α 1 = 0 := rfl theorem ofMul_eq_zero {A : Type*} [One A] {x : A} : Additive.ofMul x = 0 ↔ x = 1 := Iff.rfl @[simp] -theorem toMul_zero [One α] : toMul (0 : Additive α) = 1 := rfl +theorem toMul_zero [One α] : (0 : Additive α).toMul = 1 := rfl @[simp] lemma toMul_eq_one {α : Type*} [One α] {x : Additive α} : - Additive.toMul x = 1 ↔ x = 0 := + x.toMul = 1 ↔ x = 0 := Iff.rfl instance [Zero α] : One (Multiplicative α) := @@ -251,12 +242,12 @@ theorem ofAdd_eq_one {A : Type*} [Zero A] {x : A} : Multiplicative.ofAdd x = 1 Iff.rfl @[simp] -theorem toAdd_one [Zero α] : toAdd (1 : Multiplicative α) = 0 := +theorem toAdd_one [Zero α] : (1 : Multiplicative α).toAdd = 0 := rfl @[simp] lemma toAdd_eq_zero {α : Type*} [Zero α] {x : Multiplicative α} : - Multiplicative.toAdd x = 0 ↔ x = 1 := + x.toAdd = 0 ↔ x = 1 := Iff.rfl instance Additive.addZeroClass [MulOneClass α] : AddZeroClass (Additive α) where @@ -288,7 +279,7 @@ theorem ofMul_pow [Monoid α] (n : ℕ) (a : α) : ofMul (a ^ n) = n • ofMul a rfl @[simp] -theorem toMul_nsmul [Monoid α] (n : ℕ) (a : Additive α) : toMul (n • a) = toMul a ^ n := +theorem toMul_nsmul [Monoid α] (n : ℕ) (a : Additive α) : (n • a).toMul = a.toMul ^ n := rfl @[simp] @@ -296,7 +287,7 @@ theorem ofAdd_nsmul [AddMonoid α] (n : ℕ) (a : α) : ofAdd (n • a) = ofAdd rfl @[simp] -theorem toAdd_pow [AddMonoid α] (a : Multiplicative α) (n : ℕ) : toAdd (a ^ n) = n • toAdd a := +theorem toAdd_pow [AddMonoid α] (a : Multiplicative α) (n : ℕ) : (a ^ n).toAdd = n • a.toAdd := rfl instance Additive.addLeftCancelMonoid [LeftCancelMonoid α] : AddLeftCancelMonoid (Additive α) := @@ -320,39 +311,39 @@ instance Multiplicative.commMonoid [AddCommMonoid α] : CommMonoid (Multiplicati { Multiplicative.monoid, Multiplicative.commSemigroup with } instance Additive.neg [Inv α] : Neg (Additive α) := - ⟨fun x => ofAdd (toMul x)⁻¹⟩ + ⟨fun x => ofAdd x.toMul⁻¹⟩ @[simp] theorem ofMul_inv [Inv α] (x : α) : ofMul x⁻¹ = -ofMul x := rfl @[simp] -theorem toMul_neg [Inv α] (x : Additive α) : toMul (-x) = (toMul x)⁻¹ := +theorem toMul_neg [Inv α] (x : Additive α) : (-x).toMul = x.toMul⁻¹ := rfl instance Multiplicative.inv [Neg α] : Inv (Multiplicative α) := - ⟨fun x => ofMul (-toAdd x)⟩ + ⟨fun x => ofMul (-x.toAdd)⟩ @[simp] theorem ofAdd_neg [Neg α] (x : α) : ofAdd (-x) = (ofAdd x)⁻¹ := rfl @[simp] -theorem toAdd_inv [Neg α] (x : Multiplicative α) : toAdd x⁻¹ = -(toAdd x) := +theorem toAdd_inv [Neg α] (x : Multiplicative α) : x⁻¹.toAdd = -x.toAdd := rfl instance Additive.sub [Div α] : Sub (Additive α) where - sub x y := ofMul (toMul x / toMul y) + sub x y := ofMul (x.toMul / y.toMul) instance Multiplicative.div [Sub α] : Div (Multiplicative α) where - div x y := ofAdd (toAdd x - toAdd y) + div x y := ofAdd (x.toAdd - y.toAdd) @[simp] theorem ofAdd_sub [Sub α] (x y : α) : ofAdd (x - y) = ofAdd x / ofAdd y := rfl @[simp] -theorem toAdd_div [Sub α] (x y : Multiplicative α) : toAdd (x / y) = toAdd x - toAdd y := +theorem toAdd_div [Sub α] (x y : Multiplicative α) : (x / y).toAdd = x.toAdd - y.toAdd := rfl @[simp] @@ -360,7 +351,7 @@ theorem ofMul_div [Div α] (x y : α) : ofMul (x / y) = ofMul x - ofMul y := rfl @[simp] -theorem toMul_sub [Div α] (x y : Additive α) : toMul (x - y) = toMul x / toMul y := +theorem toMul_sub [Div α] (x y : Additive α) : (x - y).toMul = x.toMul / y.toMul := rfl instance Additive.involutiveNeg [InvolutiveInv α] : InvolutiveNeg (Additive α) := @@ -390,7 +381,7 @@ theorem ofMul_zpow [DivInvMonoid α] (z : ℤ) (a : α) : ofMul (a ^ z) = z • rfl @[simp] -theorem toMul_zsmul [DivInvMonoid α] (z : ℤ) (a : Additive α) : toMul (z • a) = toMul a ^ z := +theorem toMul_zsmul [DivInvMonoid α] (z : ℤ) (a : Additive α) : (z • a).toMul = a.toMul ^ z := rfl @[simp] @@ -398,7 +389,7 @@ theorem ofAdd_zsmul [SubNegMonoid α] (z : ℤ) (a : α) : ofAdd (z • a) = ofA rfl @[simp] -theorem toAdd_zpow [SubNegMonoid α] (a : Multiplicative α) (z : ℤ) : toAdd (a ^ z) = z • toAdd a := +theorem toAdd_zpow [SubNegMonoid α] (a : Multiplicative α) (z : ℤ) : (a ^ z).toAdd = z • a.toAdd := rfl instance Additive.subtractionMonoid [DivisionMonoid α] : SubtractionMonoid (Additive α) := @@ -431,110 +422,6 @@ instance Additive.addCommGroup [CommGroup α] : AddCommGroup (Additive α) := instance Multiplicative.commGroup [AddCommGroup α] : CommGroup (Multiplicative α) := { Multiplicative.group, Multiplicative.commMonoid with } -/-- Reinterpret `α →+ β` as `Multiplicative α →* Multiplicative β`. -/ -@[simps] -def AddMonoidHom.toMultiplicative [AddZeroClass α] [AddZeroClass β] : - (α →+ β) ≃ (Multiplicative α →* Multiplicative β) where - toFun f := { - toFun := fun a => ofAdd (f (toAdd a)) - map_mul' := f.map_add - map_one' := f.map_zero - } - invFun f := { - toFun := fun a => toAdd (f (ofAdd a)) - map_add' := f.map_mul - map_zero' := f.map_one - } - left_inv _ := rfl - right_inv _ := rfl - -@[simp, norm_cast] -lemma AddMonoidHom.coe_toMultiplicative [AddZeroClass α] [AddZeroClass β] (f : α →+ β) : - ⇑(toMultiplicative f) = ofAdd ∘ f ∘ toAdd := rfl - -/-- Reinterpret `α →* β` as `Additive α →+ Additive β`. -/ -@[simps] -def MonoidHom.toAdditive [MulOneClass α] [MulOneClass β] : - (α →* β) ≃ (Additive α →+ Additive β) where - toFun f := { - toFun := fun a => ofMul (f (toMul a)) - map_add' := f.map_mul - map_zero' := f.map_one - } - invFun f := { - toFun := fun a => toMul (f (ofMul a)) - map_mul' := f.map_add - map_one' := f.map_zero - } - left_inv _ := rfl - right_inv _ := rfl - -@[simp, norm_cast] -lemma MonoidHom.coe_toMultiplicative [MulOneClass α] [MulOneClass β] (f : α →* β) : - ⇑(toAdditive f) = ofMul ∘ f ∘ toMul := rfl - -/-- Reinterpret `Additive α →+ β` as `α →* Multiplicative β`. -/ -@[simps] -def AddMonoidHom.toMultiplicative' [MulOneClass α] [AddZeroClass β] : - (Additive α →+ β) ≃ (α →* Multiplicative β) where - toFun f := { - toFun := fun a => ofAdd (f (ofMul a)) - map_mul' := f.map_add - map_one' := f.map_zero - } - invFun f := { - toFun := fun a => toAdd (f (toMul a)) - map_add' := f.map_mul - map_zero' := f.map_one - } - left_inv _ := rfl - right_inv _ := rfl - -@[simp, norm_cast] -lemma AddMonoidHom.coe_toMultiplicative' [MulOneClass α] [AddZeroClass β] (f : Additive α →+ β) : - ⇑(toMultiplicative' f) = ofAdd ∘ f ∘ ofMul := rfl - -/-- Reinterpret `α →* Multiplicative β` as `Additive α →+ β`. -/ -@[simps!] -def MonoidHom.toAdditive' [MulOneClass α] [AddZeroClass β] : - (α →* Multiplicative β) ≃ (Additive α →+ β) := - AddMonoidHom.toMultiplicative'.symm - -@[simp, norm_cast] -lemma MonoidHom.coe_toAdditive' [MulOneClass α] [AddZeroClass β] (f : α →* Multiplicative β) : - ⇑(toAdditive' f) = toAdd ∘ f ∘ toMul := rfl - -/-- Reinterpret `α →+ Additive β` as `Multiplicative α →* β`. -/ -@[simps] -def AddMonoidHom.toMultiplicative'' [AddZeroClass α] [MulOneClass β] : - (α →+ Additive β) ≃ (Multiplicative α →* β) where - toFun f := { - toFun := fun a => toMul (f (toAdd a)) - map_mul' := f.map_add - map_one' := f.map_zero - } - invFun f := { - toFun := fun a => ofMul (f (ofAdd a)) - map_add' := f.map_mul - map_zero' := f.map_one - } - left_inv _ := rfl - right_inv _ := rfl - -@[simp, norm_cast] -lemma AddMonoidHom.coe_toMultiplicative'' [AddZeroClass α] [MulOneClass β] (f : α →+ Additive β) : - ⇑(toMultiplicative'' f) = toMul ∘ f ∘ toAdd := rfl - -/-- Reinterpret `Multiplicative α →* β` as `α →+ Additive β`. -/ -@[simps!] -def MonoidHom.toAdditive'' [AddZeroClass α] [MulOneClass β] : - (Multiplicative α →* β) ≃ (α →+ Additive β) := - AddMonoidHom.toMultiplicative''.symm - -@[simp, norm_cast] -lemma MonoidHom.coe_toAdditive'' [AddZeroClass α] [MulOneClass β] (f : Multiplicative α →* β) : - ⇑(toAdditive'' f) = ofMul ∘ f ∘ ofAdd := rfl - /-- If `α` has some multiplicative structure and coerces to a function, then `Additive α` should also coerce to the same function. @@ -542,8 +429,8 @@ This allows `Additive` to be used on bundled function types with a multiplicativ is often used for composition, without affecting the behavior of the function itself. -/ instance Additive.coeToFun {α : Type*} {β : α → Sort*} [CoeFun α β] : - CoeFun (Additive α) fun a => β (toMul a) := - ⟨fun a => CoeFun.coe (toMul a)⟩ + CoeFun (Additive α) fun a => β a.toMul := + ⟨fun a => CoeFun.coe a.toMul⟩ /-- If `α` has some additive structure and coerces to a function, then `Multiplicative α` should also coerce to the same function. @@ -552,8 +439,8 @@ This allows `Multiplicative` to be used on bundled function types with an additi is often used for composition, without affecting the behavior of the function itself. -/ instance Multiplicative.coeToFun {α : Type*} {β : α → Sort*} [CoeFun α β] : - CoeFun (Multiplicative α) fun a => β (toAdd a) := - ⟨fun a => CoeFun.coe (toAdd a)⟩ + CoeFun (Multiplicative α) fun a => β a.toAdd := + ⟨fun a => CoeFun.coe a.toAdd⟩ lemma Pi.mulSingle_multiplicativeOfAdd_eq {ι : Type*} [DecidableEq ι] {M : ι → Type*} [(i : ι) → AddMonoid (M i)] (i : ι) (a : M i) (j : ι) : diff --git a/Mathlib/Algebra/Group/TypeTags/Finite.lean b/Mathlib/Algebra/Group/TypeTags/Finite.lean new file mode 100644 index 00000000000000..e3885696b373b6 --- /dev/null +++ b/Mathlib/Algebra/Group/TypeTags/Finite.lean @@ -0,0 +1,28 @@ +/- +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.Group.TypeTags.Basic +import Mathlib.Data.Finite.Defs + +/-! +# `Finite` and `Infinite` are preserved by `Additive` and `Multiplicative`. +-/ + +assert_not_exists MonoidWithZero +assert_not_exists DenselyOrdered + +universe u v + +variable {α : Type u} + +instance [Finite α] : Finite (Additive α) := + Finite.of_equiv α (by rfl) + +instance [Finite α] : Finite (Multiplicative α) := + Finite.of_equiv α (by rfl) + +instance [h : Infinite α] : Infinite (Additive α) := h + +instance [h : Infinite α] : Infinite (Multiplicative α) := h diff --git a/Mathlib/Algebra/Group/TypeTags/Hom.lean b/Mathlib/Algebra/Group/TypeTags/Hom.lean new file mode 100644 index 00000000000000..909615b47da556 --- /dev/null +++ b/Mathlib/Algebra/Group/TypeTags/Hom.lean @@ -0,0 +1,123 @@ +/- +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.Group.Hom.Defs +import Mathlib.Algebra.Group.TypeTags.Basic + +/-! +# Transport algebra morphisms between additive and multiplicative types. +-/ + + +universe u v + +variable {α : Type u} {β : Type v} + +open Additive (ofMul toMul) +open Multiplicative (ofAdd toAdd) + +/-- Reinterpret `α →+ β` as `Multiplicative α →* Multiplicative β`. -/ +@[simps] +def AddMonoidHom.toMultiplicative [AddZeroClass α] [AddZeroClass β] : + (α →+ β) ≃ (Multiplicative α →* Multiplicative β) where + toFun f := { + toFun := fun a => ofAdd (f a.toAdd) + map_mul' := f.map_add + map_one' := f.map_zero + } + invFun f := { + toFun := fun a => f (ofAdd a) |>.toAdd + map_add' := f.map_mul + map_zero' := f.map_one + } + left_inv _ := rfl + right_inv _ := rfl + +@[simp, norm_cast] +lemma AddMonoidHom.coe_toMultiplicative [AddZeroClass α] [AddZeroClass β] (f : α →+ β) : + ⇑(toMultiplicative f) = ofAdd ∘ f ∘ toAdd := rfl + +/-- Reinterpret `α →* β` as `Additive α →+ Additive β`. -/ +@[simps] +def MonoidHom.toAdditive [MulOneClass α] [MulOneClass β] : + (α →* β) ≃ (Additive α →+ Additive β) where + toFun f := { + toFun := fun a => ofMul (f a.toMul) + map_add' := f.map_mul + map_zero' := f.map_one + } + invFun f := { + toFun := fun a => (f (ofMul a)).toMul + map_mul' := f.map_add + map_one' := f.map_zero + } + left_inv _ := rfl + right_inv _ := rfl + +@[simp, norm_cast] +lemma MonoidHom.coe_toMultiplicative [MulOneClass α] [MulOneClass β] (f : α →* β) : + ⇑(toAdditive f) = ofMul ∘ f ∘ toMul := rfl + +/-- Reinterpret `Additive α →+ β` as `α →* Multiplicative β`. -/ +@[simps] +def AddMonoidHom.toMultiplicative' [MulOneClass α] [AddZeroClass β] : + (Additive α →+ β) ≃ (α →* Multiplicative β) where + toFun f := { + toFun := fun a => ofAdd (f (ofMul a)) + map_mul' := f.map_add + map_one' := f.map_zero + } + invFun f := { + toFun := fun a => (f a.toMul).toAdd + map_add' := f.map_mul + map_zero' := f.map_one + } + left_inv _ := rfl + right_inv _ := rfl + +@[simp, norm_cast] +lemma AddMonoidHom.coe_toMultiplicative' [MulOneClass α] [AddZeroClass β] (f : Additive α →+ β) : + ⇑(toMultiplicative' f) = ofAdd ∘ f ∘ ofMul := rfl + +/-- Reinterpret `α →* Multiplicative β` as `Additive α →+ β`. -/ +@[simps!] +def MonoidHom.toAdditive' [MulOneClass α] [AddZeroClass β] : + (α →* Multiplicative β) ≃ (Additive α →+ β) := + AddMonoidHom.toMultiplicative'.symm + +@[simp, norm_cast] +lemma MonoidHom.coe_toAdditive' [MulOneClass α] [AddZeroClass β] (f : α →* Multiplicative β) : + ⇑(toAdditive' f) = toAdd ∘ f ∘ toMul := rfl + +/-- Reinterpret `α →+ Additive β` as `Multiplicative α →* β`. -/ +@[simps] +def AddMonoidHom.toMultiplicative'' [AddZeroClass α] [MulOneClass β] : + (α →+ Additive β) ≃ (Multiplicative α →* β) where + toFun f := { + toFun := fun a => (f a.toAdd).toMul + map_mul' := f.map_add + map_one' := f.map_zero + } + invFun f := { + toFun := fun a => ofMul (f (ofAdd a)) + map_add' := f.map_mul + map_zero' := f.map_one + } + left_inv _ := rfl + right_inv _ := rfl + +@[simp, norm_cast] +lemma AddMonoidHom.coe_toMultiplicative'' [AddZeroClass α] [MulOneClass β] (f : α →+ Additive β) : + ⇑(toMultiplicative'' f) = toMul ∘ f ∘ toAdd := rfl + +/-- Reinterpret `Multiplicative α →* β` as `α →+ Additive β`. -/ +@[simps!] +def MonoidHom.toAdditive'' [AddZeroClass α] [MulOneClass β] : + (Multiplicative α →* β) ≃ (α →+ Additive β) := + AddMonoidHom.toMultiplicative''.symm + +@[simp, norm_cast] +lemma MonoidHom.coe_toAdditive'' [AddZeroClass α] [MulOneClass β] (f : Multiplicative α →* β) : + ⇑(toAdditive'' f) = ofMul ∘ f ∘ ofAdd := rfl diff --git a/Mathlib/Algebra/Group/WithOne/Basic.lean b/Mathlib/Algebra/Group/WithOne/Basic.lean index 3dca5ba0dab777..b9d87ce1b04af7 100644 --- a/Mathlib/Algebra/Group/WithOne/Basic.lean +++ b/Mathlib/Algebra/Group/WithOne/Basic.lean @@ -73,8 +73,7 @@ variable (f : α →ₙ* β) theorem lift_coe (x : α) : lift f x = f x := rfl --- Porting note (#11119): removed `simp` attribute to appease `simpNF` linter. -@[to_additive] +@[to_additive (attr := simp)] theorem lift_one : lift f 1 = 1 := rfl diff --git a/Mathlib/Algebra/GroupPower/IterateHom.lean b/Mathlib/Algebra/GroupPower/IterateHom.lean index 1a3170e11ac093..ae097ed297d67b 100644 --- a/Mathlib/Algebra/GroupPower/IterateHom.lean +++ b/Mathlib/Algebra/GroupPower/IterateHom.lean @@ -5,7 +5,6 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Action.Opposite import Mathlib.Algebra.Group.Int -import Mathlib.Algebra.Group.Nat import Mathlib.Logic.Function.Iterate import Mathlib.Tactic.Common diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index c09c2c9f7742f7..f242f9558df452 100644 --- a/Mathlib/Algebra/GroupWithZero/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Basic.lean @@ -244,11 +244,11 @@ section GroupWithZero variable [GroupWithZero G₀] {a b x : G₀} -theorem GroupWithZero.mul_left_injective (h : x ≠ 0) : +theorem GroupWithZero.mul_right_injective (h : x ≠ 0) : Function.Injective fun y => x * y := fun y y' w => by simpa only [← mul_assoc, inv_mul_cancel₀ h, one_mul] using congr_arg (fun y => x⁻¹ * y) w -theorem GroupWithZero.mul_right_injective (h : x ≠ 0) : +theorem GroupWithZero.mul_left_injective (h : x ≠ 0) : Function.Injective fun y => y * x := fun y y' w => by simpa only [mul_assoc, mul_inv_cancel₀ h, mul_one] using congr_arg (fun y => y * x⁻¹) w diff --git a/Mathlib/Algebra/GroupWithZero/Conj.lean b/Mathlib/Algebra/GroupWithZero/Conj.lean index 17ccffc430192f..6aea4c22972a72 100644 --- a/Mathlib/Algebra/GroupWithZero/Conj.lean +++ b/Mathlib/Algebra/GroupWithZero/Conj.lean @@ -14,9 +14,17 @@ assert_not_exists Multiset -- TODO -- assert_not_exists DenselyOrdered +namespace GroupWithZero + variable {α : Type*} [GroupWithZero α] {a b : α} @[simp] lemma isConj_iff₀ : IsConj a b ↔ ∃ c : α, c ≠ 0 ∧ c * a * c⁻¹ = b := by rw [IsConj, Units.exists_iff_ne_zero (p := (SemiconjBy · a b))] congr! 2 with c exact and_congr_right (mul_inv_eq_iff_eq_mul₀ · |>.symm) + +lemma conj_pow₀ {s : ℕ} {a d : α} (ha : a ≠ 0) : (a⁻¹ * d * a) ^ s = a⁻¹ * d ^ s * a := + let u : αˣ := ⟨a, a⁻¹, mul_inv_cancel₀ ha, inv_mul_cancel₀ ha⟩ + Units.conj_pow' u d s + +end GroupWithZero diff --git a/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean index 8466c8876f1c1c..4e144b113a816f 100644 --- a/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean +++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Card.lean @@ -13,7 +13,7 @@ import Mathlib.SetTheory.Cardinal.Finite open scoped Cardinal Pointwise -variable {G G₀ M M₀ : Type*} +variable {G₀ M₀ : Type*} namespace Set variable [GroupWithZero G₀] [Zero M₀] [MulActionWithZero G₀ M₀] {a : G₀} diff --git a/Mathlib/Algebra/GroupWithZero/Units/Basic.lean b/Mathlib/Algebra/GroupWithZero/Units/Basic.lean index 4eed1a7034205a..be6aebca0a7760 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Basic.lean @@ -422,9 +422,9 @@ instance (priority := 100) CommGroupWithZero.toDivisionCommMonoid : lemma div_mul_cancel_left₀ (ha : a ≠ 0) (b : G₀) : a / (a * b) = b⁻¹ := ha.isUnit.div_mul_cancel_left _ -set_option linter.deprecated false in @[deprecated div_mul_cancel_left₀ (since := "2024-03-22")] -lemma div_mul_right (b : G₀) (ha : a ≠ 0) : a / (a * b) = 1 / b := ha.isUnit.div_mul_right _ +lemma div_mul_right (b : G₀) (ha : a ≠ 0) : a / (a * b) = 1 / b := by + simp [div_mul_cancel_left₀ ha] lemma mul_div_cancel_left_of_imp (h : a = 0 → b = 0) : a * b / a = b := by rw [mul_comm, mul_div_cancel_of_imp h] diff --git a/Mathlib/Algebra/Homology/Additive.lean b/Mathlib/Algebra/Homology/Additive.lean index 5fbebb2c8beb91..1b14c45bf5b006 100644 --- a/Mathlib/Algebra/Homology/Additive.lean +++ b/Mathlib/Algebra/Homology/Additive.lean @@ -23,8 +23,8 @@ variable {ι : Type*} variable {V : Type u} [Category.{v} V] [Preadditive V] variable {W : Type*} [Category W] [Preadditive W] variable {W₁ W₂ : Type*} [Category W₁] [Category W₂] [HasZeroMorphisms W₁] [HasZeroMorphisms W₂] -variable {c : ComplexShape ι} {C D E : HomologicalComplex V c} -variable (f g : C ⟶ D) (h k : D ⟶ E) (i : ι) +variable {c : ComplexShape ι} {C D : HomologicalComplex V c} +variable (f : C ⟶ D) (i : ι) namespace HomologicalComplex diff --git a/Mathlib/Algebra/Homology/Monoidal.lean b/Mathlib/Algebra/Homology/Monoidal.lean new file mode 100644 index 00000000000000..e0e185b0f0becd --- /dev/null +++ b/Mathlib/Algebra/Homology/Monoidal.lean @@ -0,0 +1,325 @@ +/- +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, Kim Morrison +-/ +import Mathlib.Algebra.Homology.BifunctorAssociator +import Mathlib.Algebra.Homology.Single +import Mathlib.CategoryTheory.GradedObject.Monoidal +import Mathlib.CategoryTheory.Monoidal.Transport + +/-! +# The monoidal category structure on homological complexes + +Let `c : ComplexShape I` with `I` an additive monoid. If `c` is equipped +with the data and axioms `c.TensorSigns`, then the category +`HomologicalComplex C c` can be equipped with a monoidal category +structure if `C` is a monoidal category such that `C` has certain +coproducts and both left/right tensoring commute with these. + +In particular, we obtain a monoidal category structure on +`ChainComplex C ℕ` when `C` is an additive monoidal category. + +-/ + +open CategoryTheory Limits MonoidalCategory Category + +namespace HomologicalComplex + +variable {C : Type*} [Category C] [MonoidalCategory C] [Preadditive C] [HasZeroObject C] + [(curriedTensor C).Additive] [∀ (X₁ : C), ((curriedTensor C).obj X₁).Additive] + {I : Type*} [AddMonoid I] {c : ComplexShape I} [c.TensorSigns] + +/-- If `K₁` and `K₂` are two homological complexes, this is the property that +for all `j`, the coproduct of `K₁ i₁ ⊗ K₂ i₂` for `i₁ + i₂ = j` exists. -/ +abbrev HasTensor (K₁ K₂ : HomologicalComplex C c) := HasMapBifunctor K₁ K₂ (curriedTensor C) c + +section + +variable [DecidableEq I] + +/-- The tensor product of two homological complexes. -/ +noncomputable abbrev tensorObj (K₁ K₂ : HomologicalComplex C c) [HasTensor K₁ K₂] : + HomologicalComplex C c := + mapBifunctor K₁ K₂ (curriedTensor C) c + +/-- The inclusion `K₁.X i₁ ⊗ K₂.X i₂ ⟶ (tensorObj K₁ K₂).X j` of a summand in +the tensor product of the homological complexes. -/ +noncomputable abbrev ιTensorObj (K₁ K₂ : HomologicalComplex C c) [HasTensor K₁ K₂] + (i₁ i₂ j : I) (h : i₁ + i₂ = j) : + K₁.X i₁ ⊗ K₂.X i₂ ⟶ (tensorObj K₁ K₂).X j := + ιMapBifunctor K₁ K₂ (curriedTensor C) c i₁ i₂ j h + +/-- The tensor product of two morphisms of homological complexes. -/ +noncomputable abbrev tensorHom {K₁ K₂ L₁ L₂ : HomologicalComplex C c} + (f : K₁ ⟶ L₁) (g : K₂ ⟶ L₂) [HasTensor K₁ K₂] [HasTensor L₁ L₂] : + tensorObj K₁ K₂ ⟶ tensorObj L₁ L₂ := + mapBifunctorMap f g _ _ + +/-- Given three homological complexes `K₁`, `K₂`, and `K₃`, this asserts that for +all `j`, the functor `- ⊗ K₃.X i₃` commutes with the coproduct of +the `K₁.X i₁ ⊗ K₂.X i₂` such that `i₁ + i₂ = j`. -/ +abbrev HasGoodTensor₁₂ (K₁ K₂ K₃ : HomologicalComplex C c) := + HasGoodTrifunctor₁₂Obj (curriedTensor C) (curriedTensor C) K₁ K₂ K₃ c c + +/-- Given three homological complexes `K₁`, `K₂`, and `K₃`, this asserts that for +all `j`, the functor `K₁.X i₁` commutes with the coproduct of +the `K₂.X i₂ ⊗ K₃.X i₃` such that `i₂ + i₃ = j`. -/ +abbrev HasGoodTensor₂₃ (K₁ K₂ K₃ : HomologicalComplex C c) := + HasGoodTrifunctor₂₃Obj (curriedTensor C) (curriedTensor C) K₁ K₂ K₃ c c c + +/-- The associator isomorphism for the tensor product of homological complexes. -/ +noncomputable abbrev associator (K₁ K₂ K₃ : HomologicalComplex C c) + [HasTensor K₁ K₂] [HasTensor K₂ K₃] + [HasTensor (tensorObj K₁ K₂) K₃] [HasTensor K₁ (tensorObj K₂ K₃)] + [HasGoodTensor₁₂ K₁ K₂ K₃] [HasGoodTensor₂₃ K₁ K₂ K₃] : + tensorObj (tensorObj K₁ K₂) K₃ ≅ tensorObj K₁ (tensorObj K₂ K₃) := + mapBifunctorAssociator (curriedAssociatorNatIso C) K₁ K₂ K₃ c c c + +variable (C c) in +/-- The unit of the tensor product of homological complexes. -/ +noncomputable abbrev tensorUnit : HomologicalComplex C c := (single C c 0).obj (𝟙_ C) + +variable (C c) in +/-- As a graded object, the single complex `(single C c 0).obj (𝟙_ C)` identifies +to the unit `(GradedObject.single₀ I).obj (𝟙_ C)` of the tensor product of graded objects. -/ +noncomputable def tensorUnitIso : + (GradedObject.single₀ I).obj (𝟙_ C) ≅ (tensorUnit C c).X := + GradedObject.isoMk _ _ (fun i ↦ + if hi : i = 0 then + (GradedObject.singleObjApplyIsoOfEq (0 : I) (𝟙_ C) i hi).trans + (singleObjXIsoOfEq c 0 (𝟙_ C) i hi).symm + else + { hom := 0 + inv := 0 + hom_inv_id := (GradedObject.isInitialSingleObjApply 0 (𝟙_ C) i hi).hom_ext _ _ + inv_hom_id := (isZero_single_obj_X c 0 (𝟙_ C) i hi).eq_of_src _ _ }) + +end + +instance (K₁ K₂ : HomologicalComplex C c) [GradedObject.HasTensor K₁.X K₂.X] : + HasTensor K₁ K₂ := by + assumption + +instance (K₁ K₂ K₃ : HomologicalComplex C c) + [GradedObject.HasGoodTensor₁₂Tensor K₁.X K₂.X K₃.X] : + HasGoodTensor₁₂ K₁ K₂ K₃ := + inferInstanceAs (GradedObject.HasGoodTensor₁₂Tensor K₁.X K₂.X K₃.X) + +instance (K₁ K₂ K₃ : HomologicalComplex C c) + [GradedObject.HasGoodTensorTensor₂₃ K₁.X K₂.X K₃.X] : + HasGoodTensor₂₃ K₁ K₂ K₃ := + inferInstanceAs (GradedObject.HasGoodTensorTensor₂₃ K₁.X K₂.X K₃.X) + +section + +variable (K : HomologicalComplex C c) [DecidableEq I] + +section + +variable [∀ X₂, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).flip.obj X₂)] + +instance : GradedObject.HasTensor (tensorUnit C c).X K.X := + GradedObject.hasTensor_of_iso (tensorUnitIso C c) (Iso.refl _) + +instance : HasTensor (tensorUnit C c) K := + inferInstanceAs (GradedObject.HasTensor (tensorUnit C c).X K.X) + +@[simp] +lemma unit_tensor_d₁ (i₁ i₂ j : I) : + mapBifunctor.d₁ (tensorUnit C c) K (curriedTensor C) c i₁ i₂ j = 0 := by + 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₂, single_obj_d, Functor.map_zero, + zero_app, zero_comp, smul_zero] + · rw [mapBifunctor.d₁_eq_zero' _ _ _ _ h₁ _ _ h₂] + · rw [mapBifunctor.d₁_eq_zero _ _ _ _ _ _ _ h₁] + +end + +section + +variable [∀ X₁, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).obj X₁)] + +instance : GradedObject.HasTensor K.X (tensorUnit C c).X := + GradedObject.hasTensor_of_iso (Iso.refl _) (tensorUnitIso C c) + +instance : HasTensor K (tensorUnit C c) := + inferInstanceAs (GradedObject.HasTensor K.X (tensorUnit C c).X) + +@[simp] +lemma tensor_unit_d₂ (i₁ i₂ j : I) : + mapBifunctor.d₂ K (tensorUnit C c) (curriedTensor C) c i₁ i₂ j = 0 := by + by_cases h₁ : c.Rel i₂ (c.next i₂) + · by_cases h₂ : ComplexShape.π c c c (i₁, c.next i₂) = j + · rw [mapBifunctor.d₂_eq _ _ _ _ _ h₁ _ h₂, single_obj_d, Functor.map_zero, + zero_comp, smul_zero] + · rw [mapBifunctor.d₂_eq_zero' _ _ _ _ _ h₁ _ h₂] + · rw [mapBifunctor.d₂_eq_zero _ _ _ _ _ _ _ h₁] + +end + +end + +section Unitor + +variable (K : HomologicalComplex C c) [DecidableEq I] + +section LeftUnitor + +variable [∀ X₂, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).flip.obj X₂)] + +/-- Auxiliary definition for `leftUnitor`. -/ +noncomputable def leftUnitor' : + (tensorObj (tensorUnit C c) K).X ≅ K.X := + GradedObject.Monoidal.tensorIso ((tensorUnitIso C c).symm) (Iso.refl _) ≪≫ + GradedObject.Monoidal.leftUnitor K.X + +lemma leftUnitor'_inv (i : I) : + (leftUnitor' K).inv i = (λ_ (K.X i)).inv ≫ ((singleObjXSelf c 0 (𝟙_ C)).inv ▷ (K.X i)) ≫ + ιTensorObj (tensorUnit C c) K 0 i i (zero_add i) := by + dsimp [leftUnitor'] + rw [GradedObject.Monoidal.leftUnitor_inv_apply, assoc, assoc, Iso.cancel_iso_inv_left, + GradedObject.Monoidal.ι_tensorHom] + dsimp + rw [tensorHom_id, ← comp_whiskerRight_assoc] + congr 2 + rw [← cancel_epi (GradedObject.Monoidal.tensorUnit₀ (I := I)).hom, Iso.hom_inv_id_assoc] + dsimp [tensorUnitIso] + rw [dif_pos rfl] + rfl + +@[reassoc] +lemma leftUnitor'_inv_comm (i j : I) : + (leftUnitor' K).inv i ≫ (tensorObj (tensorUnit C c) K).d i j = + K.d i j ≫ (leftUnitor' K).inv j := by + by_cases hij : c.Rel i j + · simp only [leftUnitor'_inv, assoc, mapBifunctor.d_eq, + Preadditive.comp_add, mapBifunctor.ι_D₁, mapBifunctor.ι_D₂, + unit_tensor_d₁, comp_zero, zero_add] + rw [mapBifunctor.d₂_eq _ _ _ _ _ hij _ (by simp)] + dsimp + simp only [ComplexShape.ε_zero, one_smul, ← whisker_exchange_assoc, + id_whiskerLeft, assoc, Iso.inv_hom_id_assoc] + · simp only [shape _ _ _ hij, comp_zero, zero_comp] + +/-- The left unitor for the tensor product of homological complexes. -/ +noncomputable def leftUnitor : + tensorObj (tensorUnit C c) K ≅ K := + Iso.symm (Hom.isoOfComponents (fun i ↦ (GradedObject.eval i).mapIso (leftUnitor' K).symm) + (fun _ _ _ ↦ leftUnitor'_inv_comm _ _ _)) + +end LeftUnitor + +section RightUnitor + +variable [∀ X₁, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).obj X₁)] + +/-- Auxiliary definition for `rightUnitor`. -/ +noncomputable def rightUnitor' : + (tensorObj K (tensorUnit C c)).X ≅ K.X := + GradedObject.Monoidal.tensorIso (Iso.refl _) ((tensorUnitIso C c).symm) ≪≫ + GradedObject.Monoidal.rightUnitor K.X + +lemma rightUnitor'_inv (i : I) : + (rightUnitor' K).inv i = (ρ_ (K.X i)).inv ≫ ((K.X i) ◁ (singleObjXSelf c 0 (𝟙_ C)).inv) ≫ + ιTensorObj K (tensorUnit C c) i 0 i (add_zero i) := by + dsimp [rightUnitor'] + rw [GradedObject.Monoidal.rightUnitor_inv_apply, assoc, assoc, Iso.cancel_iso_inv_left, + GradedObject.Monoidal.ι_tensorHom] + dsimp + rw [id_tensorHom, ← MonoidalCategory.whiskerLeft_comp_assoc] + congr 2 + rw [← cancel_epi (GradedObject.Monoidal.tensorUnit₀ (I := I)).hom, Iso.hom_inv_id_assoc] + dsimp [tensorUnitIso] + rw [dif_pos rfl] + rfl + +lemma rightUnitor'_inv_comm (i j : I) : + (rightUnitor' K).inv i ≫ (tensorObj K (tensorUnit C c)).d i j = + K.d i j ≫ (rightUnitor' K).inv j := by + by_cases hij : c.Rel i j + · simp only [rightUnitor'_inv, assoc, mapBifunctor.d_eq, + Preadditive.comp_add, mapBifunctor.ι_D₁, mapBifunctor.ι_D₂, + tensor_unit_d₂, comp_zero, add_zero] + rw [mapBifunctor.d₁_eq _ _ _ _ hij _ _ (by simp)] + dsimp + simp only [one_smul, whisker_exchange_assoc, + MonoidalCategory.whiskerRight_id, assoc, Iso.inv_hom_id_assoc] + · simp only [shape _ _ _ hij, comp_zero, zero_comp] + +/-- The right unitor for the tensor product of homological complexes. -/ +noncomputable def rightUnitor : + tensorObj K (tensorUnit C c) ≅ K := + Iso.symm (Hom.isoOfComponents (fun i ↦ (GradedObject.eval i).mapIso (rightUnitor' K).symm) + (fun _ _ _ ↦ rightUnitor'_inv_comm _ _ _)) + +end RightUnitor + +end Unitor + +variable (C c) [∀ (X₁ X₂ : GradedObject I C), GradedObject.HasTensor X₁ X₂] + [∀ X₁, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).obj X₁)] + [∀ X₂, PreservesColimit (Functor.empty.{0} C) ((curriedTensor C).flip.obj X₂)] + [∀ (X₁ X₂ X₃ X₄ : GradedObject I C), GradedObject.HasTensor₄ObjExt X₁ X₂ X₃ X₄] + [∀ (X₁ X₂ X₃ : GradedObject I C), GradedObject.HasGoodTensor₁₂Tensor X₁ X₂ X₃] + [∀ (X₁ X₂ X₃ : GradedObject I C), GradedObject.HasGoodTensorTensor₂₃ X₁ X₂ X₃] + [DecidableEq I] + +noncomputable instance monoidalCategoryStruct : + MonoidalCategoryStruct (HomologicalComplex C c) where + tensorObj K₁ K₂ := tensorObj K₁ K₂ + whiskerLeft _ _ _ g := tensorHom (𝟙 _) g + whiskerRight f _ := tensorHom f (𝟙 _) + tensorHom f g := tensorHom f g + tensorUnit := tensorUnit C c + associator K₁ K₂ K₃ := associator K₁ K₂ K₃ + leftUnitor K := leftUnitor K + rightUnitor K := rightUnitor K + +/-- The structure which allows to construct the monoidal category structure +on `HomologicalComplex C c` from the monoidal category structure on +graded objects. -/ +noncomputable def Monoidal.inducingFunctorData : + Monoidal.InducingFunctorData (forget C c) where + μIso _ _ := Iso.refl _ + εIso := tensorUnitIso C c + whiskerLeft_eq K₁ K₂ L₂ g := by + dsimp [forget] + erw [comp_id, id_comp] + rfl + whiskerRight_eq {K₁ L₁} f K₂ := by + dsimp [forget] + erw [comp_id, id_comp] + rfl + tensorHom_eq {K₁ L₁ K₂ L₂} f g := by + dsimp [forget] + erw [comp_id, id_comp] + rfl + associator_eq K₁ K₂ K₃ := by + dsimp [forget] + simp only [tensorHom_id, whiskerRight_tensor, id_whiskerRight, + id_comp, Iso.inv_hom_id, comp_id, assoc] + erw [id_whiskerRight, id_comp, id_comp] + rfl + leftUnitor_eq K := by + dsimp + erw [id_comp] + rfl + rightUnitor_eq K := by + dsimp + rw [assoc] + erw [id_comp] + rfl + +noncomputable instance monoidalCategory : MonoidalCategory (HomologicalComplex C c) := + Monoidal.induced _ (Monoidal.inducingFunctorData C c) + +noncomputable example {D : Type*} [Category D] [Preadditive D] [MonoidalCategory D] + [HasZeroObject D] [HasFiniteCoproducts D] [((curriedTensor D).Additive)] + [∀ (X : D), (((curriedTensor D).obj X).Additive)] + [∀ (X : D), PreservesFiniteCoproducts ((curriedTensor D).obj X)] + [∀ (X : D), PreservesFiniteCoproducts ((curriedTensor D).flip.obj X)] : + MonoidalCategory (ChainComplex D ℕ) := inferInstance + +end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/ShortComplex/Homology.lean b/Mathlib/Algebra/Homology/ShortComplex/Homology.lean index 25854245e340ca..0c416a49f4df57 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Homology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Homology.lean @@ -70,8 +70,6 @@ structure HomologyMapData where namespace HomologyMapData -attribute [nolint simpNF] mk.injEq - variable {φ h₁ h₂} @[reassoc] diff --git a/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean index 1022a52c7ab903..a8abcedd4972c3 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean @@ -266,7 +266,6 @@ structure LeftHomologyMapData where namespace LeftHomologyMapData attribute [reassoc (attr := simp)] commi commf' commπ -attribute [nolint simpNF] mk.injEq /-- The left homology map data associated to the zero morphism between two short complexes. -/ @[simps] diff --git a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean index 865ffa00b94fb3..35922895338930 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean @@ -356,7 +356,6 @@ structure RightHomologyMapData where namespace RightHomologyMapData attribute [reassoc (attr := simp)] commp commg' commι -attribute [nolint simpNF] mk.injEq /-- The right homology map data associated to the zero morphism between two short complexes. -/ @[simps] diff --git a/Mathlib/Algebra/Homology/TotalComplex.lean b/Mathlib/Algebra/Homology/TotalComplex.lean index 645d747de064fd..15137d2628a9bb 100644 --- a/Mathlib/Algebra/Homology/TotalComplex.lean +++ b/Mathlib/Algebra/Homology/TotalComplex.lean @@ -6,6 +6,7 @@ Authors: Joël Riou import Mathlib.CategoryTheory.Linear.Basic import Mathlib.Algebra.Homology.ComplexShapeSigns import Mathlib.Algebra.Homology.HomologicalBicomplex +import Mathlib.Algebra.Module.Basic /-! # The total complex of a bicomplex diff --git a/Mathlib/Algebra/Lie/IdealOperations.lean b/Mathlib/Algebra/Lie/IdealOperations.lean index 75e9facacd878c..459dce3dfdbf00 100644 --- a/Mathlib/Algebra/Lie/IdealOperations.lean +++ b/Mathlib/Algebra/Lie/IdealOperations.lean @@ -192,12 +192,10 @@ theorem sup_lie : ⁅I ⊔ J, N⁆ = ⁅I, N⁆ ⊔ ⁅J, N⁆ := by use ⁅((⟨x₂, hx₂⟩ : J) : L), (n : N)⁆; constructor; · apply lie_coe_mem_lie simp [← h, ← hx'] --- @[simp] -- Porting note: not in simpNF theorem lie_inf : ⁅I, N ⊓ N'⁆ ≤ ⁅I, N⁆ ⊓ ⁅I, N'⁆ := by rw [le_inf_iff]; constructor <;> apply mono_lie_right <;> [exact inf_le_left; exact inf_le_right] --- @[simp] -- Porting note: not in simpNF theorem inf_lie : ⁅I ⊓ J, N⁆ ≤ ⁅I, N⁆ ⊓ ⁅J, N⁆ := by rw [le_inf_iff]; constructor <;> apply mono_lie_left <;> [exact inf_le_left; exact inf_le_right] diff --git a/Mathlib/Algebra/Lie/Semisimple/Basic.lean b/Mathlib/Algebra/Lie/Semisimple/Basic.lean index 12b30d31de1c28..50b8820a1addcc 100644 --- a/Mathlib/Algebra/Lie/Semisimple/Basic.lean +++ b/Mathlib/Algebra/Lie/Semisimple/Basic.lean @@ -147,7 +147,7 @@ lemma isSimple_of_isAtom (I : LieIdeal R L) (hI : IsAtom I) : IsSimple R I where -- Finally `⁅b, y⁆ = 0`, by the independence of the atoms. · 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] + ← (IsSemisimple.sSupIndep_isAtom hI).eq_bot] exact ⟨lie_mem_right R L I b y y.2, lie_mem_left _ _ _ _ _ hb⟩ } -- Now that we know that `J` is an ideal of `L`, -- we start with the proof that `I` is a simple Lie algebra. @@ -240,7 +240,7 @@ lemma finitelyAtomistic : ∀ s : Finset (LieIdeal R L), ↑s ⊆ {I : LieIdeal constructor -- `j` brackets to `0` with `z`, since `⁅j, z⁆` is contained in `⁅J, K⁆ ≤ J ⊓ K`, -- and `J ⊓ K = ⊥` by the independence of the atoms. - · apply (setIndependent_isAtom.disjoint_sSup (hs hJs) hs'S (Finset.not_mem_erase _ _)).le_bot + · apply (sSupIndep_isAtom.disjoint_sSup (hs hJs) hs'S (Finset.not_mem_erase _ _)).le_bot apply LieSubmodule.lie_le_inf apply LieSubmodule.lie_mem_lie j.2 simpa only [K, Finset.sup_id_eq_sSup] using hz @@ -292,7 +292,7 @@ instance (priority := 100) IsSimple.instIsSemisimple [IsSimple R L] : IsSemisimple R L := by constructor · simp - · simpa using CompleteLattice.setIndependent_singleton _ + · simpa using sSupIndep_singleton _ · intro I hI₁ hI₂ apply IsSimple.non_abelian (R := R) (L := L) rw [IsSimple.isAtom_iff_eq_top] at hI₁ diff --git a/Mathlib/Algebra/Lie/Semisimple/Defs.lean b/Mathlib/Algebra/Lie/Semisimple/Defs.lean index 018f07cacb964c..74db546a946433 100644 --- a/Mathlib/Algebra/Lie/Semisimple/Defs.lean +++ b/Mathlib/Algebra/Lie/Semisimple/Defs.lean @@ -72,7 +72,7 @@ class IsSemisimple : Prop where /-- In a semisimple Lie algebra, the supremum of the atoms is the whole Lie algebra. -/ sSup_atoms_eq_top : sSup {I : LieIdeal R L | IsAtom I} = ⊤ /-- In a semisimple Lie algebra, the atoms are independent. -/ - setIndependent_isAtom : CompleteLattice.SetIndependent {I : LieIdeal R L | IsAtom I} + sSupIndep_isAtom : sSupIndep {I : LieIdeal R L | IsAtom I} /-- In a semisimple Lie algebra, the atoms are non-abelian. -/ non_abelian_of_isAtom : ∀ I : LieIdeal R L, IsAtom I → ¬ IsLieAbelian I diff --git a/Mathlib/Algebra/Lie/Submodule.lean b/Mathlib/Algebra/Lie/Submodule.lean index c6fc1d659955f8..12012327878628 100644 --- a/Mathlib/Algebra/Lie/Submodule.lean +++ b/Mathlib/Algebra/Lie/Submodule.lean @@ -514,9 +514,12 @@ theorem isCompl_iff_coe_toSubmodule : IsCompl N N' ↔ IsCompl (N : Submodule R M) (N' : Submodule R M) := by simp only [isCompl_iff, disjoint_iff_coe_toSubmodule, codisjoint_iff_coe_toSubmodule] -theorem independent_iff_coe_toSubmodule {ι : Type*} {N : ι → LieSubmodule R L M} : - CompleteLattice.Independent N ↔ CompleteLattice.Independent fun i ↦ (N i : Submodule R M) := by - simp [CompleteLattice.independent_def, disjoint_iff_coe_toSubmodule] +theorem iSupIndep_iff_coe_toSubmodule {ι : Type*} {N : ι → LieSubmodule R L M} : + iSupIndep N ↔ iSupIndep fun i ↦ (N i : Submodule R M) := by + simp [iSupIndep_def, disjoint_iff_coe_toSubmodule] + +@[deprecated (since := "2024-11-24")] +alias independent_iff_coe_toSubmodule := iSupIndep_iff_coe_toSubmodule theorem iSup_eq_top_iff_coe_toSubmodule {ι : Sort*} {N : ι → LieSubmodule R L M} : ⨆ i, N i = ⊤ ↔ ⨆ i, (N i : Submodule R M) = ⊤ := by diff --git a/Mathlib/Algebra/Lie/TraceForm.lean b/Mathlib/Algebra/Lie/TraceForm.lean index 2d1253e2b18c9a..55ee3be037f296 100644 --- a/Mathlib/Algebra/Lie/TraceForm.lean +++ b/Mathlib/Algebra/Lie/TraceForm.lean @@ -227,8 +227,8 @@ lemma traceForm_eq_sum_genWeightSpaceOf convert finite_genWeightSpaceOf_ne_bot R L M z exact LieSubmodule.coeSubmodule_eq_bot_iff (genWeightSpaceOf M _ _) classical - 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 + have h := LieSubmodule.iSupIndep_iff_coe_toSubmodule.mp <| iSupIndep_genWeightSpaceOf R L M z + have hds := DirectSum.isInternal_submodule_of_iSupIndep_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] @@ -407,8 +407,8 @@ lemma traceForm_eq_sum_finrank_nsmul_mul (x y : L) : (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_genWeightSpace' K L M) + have hds := DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top + (LieSubmodule.iSupIndep_iff_coe_toSubmodule.mp <| iSupIndep_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_genWeightSpace_eq K L M _ x y] diff --git a/Mathlib/Algebra/Lie/Weights/Basic.lean b/Mathlib/Algebra/Lie/Weights/Basic.lean index ce2e34ec7f66ef..8ddf44e6372c75 100644 --- a/Mathlib/Algebra/Lie/Weights/Basic.lean +++ b/Mathlib/Algebra/Lie/Weights/Basic.lean @@ -33,7 +33,7 @@ Basic definitions and properties of the above ideas are provided in this file. * `LieModule.iSup_ucs_eq_genWeightSpace_zero` * `LieModule.iInf_lowerCentralSeries_eq_posFittingComp` * `LieModule.isCompl_genWeightSpace_zero_posFittingComp` - * `LieModule.independent_genWeightSpace` + * `LieModule.iSupIndep_genWeightSpace` * `LieModule.iSup_genWeightSpace_eq_top` ## References @@ -666,32 +666,39 @@ lemma injOn_genWeightSpace [NoZeroSMulDivisors R M] : /-- Lie module weight spaces are independent. -See also `LieModule.independent_genWeightSpace'`. -/ -lemma independent_genWeightSpace [NoZeroSMulDivisors R M] : - CompleteLattice.Independent fun χ : L → R ↦ genWeightSpace M χ := by - simp only [LieSubmodule.independent_iff_coe_toSubmodule, genWeightSpace, +See also `LieModule.iSupIndep_genWeightSpace'`. -/ +lemma iSupIndep_genWeightSpace [NoZeroSMulDivisors R M] : + iSupIndep fun χ : L → R ↦ genWeightSpace M χ := by + simp only [LieSubmodule.iSupIndep_iff_coe_toSubmodule, genWeightSpace, LieSubmodule.iInf_coe_toSubmodule] exact Module.End.independent_iInf_maxGenEigenspace_of_forall_mapsTo (toEnd R L M) (fun x y φ z ↦ (genWeightSpaceOf M φ y).lie_mem) -lemma independent_genWeightSpace' [NoZeroSMulDivisors R M] : - CompleteLattice.Independent fun χ : Weight R L M ↦ genWeightSpace M χ := - (independent_genWeightSpace R L M).comp <| +@[deprecated (since := "2024-11-24")] alias independent_genWeightSpace := iSupIndep_genWeightSpace + +lemma iSupIndep_genWeightSpace' [NoZeroSMulDivisors R M] : + iSupIndep fun χ : Weight R L M ↦ genWeightSpace M χ := + (iSupIndep_genWeightSpace R L M).comp <| Subtype.val_injective.comp (Weight.equivSetOf R L M).injective -lemma independent_genWeightSpaceOf [NoZeroSMulDivisors R M] (x : L) : - CompleteLattice.Independent fun (χ : R) ↦ genWeightSpaceOf M χ x := by - rw [LieSubmodule.independent_iff_coe_toSubmodule] +@[deprecated (since := "2024-11-24")] alias independent_genWeightSpace' := iSupIndep_genWeightSpace' + +lemma iSupIndep_genWeightSpaceOf [NoZeroSMulDivisors R M] (x : L) : + iSupIndep fun (χ : R) ↦ genWeightSpaceOf M χ x := by + rw [LieSubmodule.iSupIndep_iff_coe_toSubmodule] dsimp [genWeightSpaceOf] exact (toEnd R L M x).independent_genEigenspace _ +@[deprecated (since := "2024-11-24")] +alias independent_genWeightSpaceOf := iSupIndep_genWeightSpaceOf + 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) + WellFoundedGT.finite_ne_bot_of_iSupIndep (iSupIndep_genWeightSpaceOf R L M x) 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) + WellFoundedGT.finite_ne_bot_of_iSupIndep (iSupIndep_genWeightSpace R L M) instance Weight.instFinite [NoZeroSMulDivisors R M] [IsNoetherian R M] : Finite (Weight R L M) := by diff --git a/Mathlib/Algebra/Lie/Weights/Chain.lean b/Mathlib/Algebra/Lie/Weights/Chain.lean index 4107e1e4cd27ff..1acfd102224c76 100644 --- a/Mathlib/Algebra/Lie/Weights/Chain.lean +++ b/Mathlib/Algebra/Lie/Weights/Chain.lean @@ -204,9 +204,9 @@ lemma exists_forall_mem_corootSpace_smul_add_eq_zero exact finrank_pos refine ⟨a, b, Int.ofNat_pos.mpr hb, fun x hx ↦ ?_⟩ 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_genWeightSpace R H M).comp fun i j hij ↦ ?_ + have h₁ : iSupIndep fun (i : Finset.Ioo p q) ↦ N i := by + rw [← LieSubmodule.iSupIndep_iff_coe_toSubmodule] + refine (iSupIndep_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₃ : genWeightSpaceChain M α χ p q = ⨆ i ∈ Finset.Ioo p q, N i := by diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean index 3fe00e4149748a..7c2b6ece5a6b50 100644 --- a/Mathlib/Algebra/Lie/Weights/Killing.lean +++ b/Mathlib/Algebra/Lie/Weights/Killing.lean @@ -112,8 +112,8 @@ lemma killingForm_apply_eq_zero_of_mem_rootSpace_of_add_ne_zero {α β : H → K (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_genWeightSpace K H L) + have hds := DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top + (LieSubmodule.iSupIndep_iff_coe_toSubmodule.mp <| iSupIndep_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 diff --git a/Mathlib/Algebra/Module/Basic.lean b/Mathlib/Algebra/Module/Basic.lean index 0eeee9934e3d30..b653c02aa9f6ca 100644 --- a/Mathlib/Algebra/Module/Basic.lean +++ b/Mathlib/Algebra/Module/Basic.lean @@ -6,7 +6,8 @@ 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.GroupWithZero.Action.Units +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.NoZeroSMulDivisors.Defs /-! @@ -23,6 +24,11 @@ universe u v variable {α R M M₂ : Type*} +@[simp] +theorem Units.neg_smul [Ring R] [AddCommGroup M] [Module R M] (u : Rˣ) (x : M) : + -u • x = -(u • x) := by + rw [Units.smul_def, Units.val_neg, _root_.neg_smul, Units.smul_def] + @[simp] theorem invOf_two_smul_add_invOf_two_smul (R) [Semiring R] [AddCommMonoid M] [Module R M] [Invertible (2 : R)] (x : M) : diff --git a/Mathlib/Algebra/Module/Defs.lean b/Mathlib/Algebra/Module/Defs.lean index c614c036f09772..ebc9ab4254580e 100644 --- a/Mathlib/Algebra/Module/Defs.lean +++ b/Mathlib/Algebra/Module/Defs.lean @@ -3,10 +3,11 @@ 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.GroupWithZero.Action.End -import Mathlib.Algebra.GroupWithZero.Action.Units +import Mathlib.Algebra.Group.Action.End +import Mathlib.Algebra.Group.Equiv.Basic +import Mathlib.Algebra.GroupWithZero.Action.Defs +import Mathlib.Algebra.Ring.Defs import Mathlib.Algebra.SMulWithZero -import Mathlib.Data.Int.Cast.Lemmas /-! # Modules over a ring @@ -39,7 +40,9 @@ assert_not_exists Field assert_not_exists Invertible assert_not_exists Multiset assert_not_exists Pi.single_smul₀ +assert_not_exists RingHom assert_not_exists Set.indicator +assert_not_exists Units open Function Set @@ -72,14 +75,6 @@ instance (priority := 100) Module.toMulActionWithZero smul_zero := smul_zero zero_smul := Module.zero_smul } -instance AddCommGroup.toNatModule : Module ℕ M where - one_smul := one_nsmul - mul_smul m n a := mul_nsmul' a m n - smul_add n a b := nsmul_add a b n - smul_zero := nsmul_zero - zero_smul := zero_nsmul - add_smul r s x := add_nsmul x r s - theorem add_smul : (r + s) • x = r • x + s • x := Module.add_smul r s x @@ -111,31 +106,7 @@ protected abbrev Function.Surjective.module [AddCommMonoid M₂] [SMul R M₂] ( rcases hf x with ⟨x, rfl⟩ rw [← f.map_zero, ← smul, zero_smul] } -/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →+* S`. - -See also `Function.Surjective.mulActionLeft` and `Function.Surjective.distribMulActionLeft`. --/ -abbrev Function.Surjective.moduleLeft {R S M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] - [Semiring S] [SMul S M] (f : R →+* S) (hf : Function.Surjective f) - (hsmul : ∀ (c) (x : M), f c • x = c • x) : Module S M := - { hf.distribMulActionLeft f.toMonoidHom hsmul with - zero_smul := fun x => by rw [← f.map_zero, hsmul, zero_smul] - add_smul := hf.forall₂.mpr fun a b x => by simp only [← f.map_add, hsmul, add_smul] } - -variable {R} (M) - -/-- Compose a `Module` with a `RingHom`, with action `f s • m`. - -See note [reducible non-instances]. -/ -abbrev Module.compHom [Semiring S] (f : S →+* R) : Module S M := - { MulActionWithZero.compHom M f.toMonoidWithZeroHom, DistribMulAction.compHom M (f : S →* R) with - -- Porting note: the `show f (r + s) • x = f r • x + f s • x` wasn't needed in mathlib3. - -- Somehow, now that `SMul` is heterogeneous, it can't unfold earlier fields of a definition for - -- use in later fields. See - -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Heterogeneous.20scalar.20multiplication - add_smul := fun r s x => show f (r + s) • x = f r • x + f s • x by simp [add_smul] } - -variable {M} +variable {R} theorem Module.eq_zero_of_zero_eq_one (zero_eq_one : (0 : R) = 1) : x = 0 := by rw [← one_smul R x, ← zero_eq_one, zero_smul] @@ -146,20 +117,9 @@ theorem smul_add_one_sub_smul {R : Type*} [Ring R] [Module R M] {r : R} {m : M} end AddCommMonoid - section AddCommGroup -variable (R M) [Semiring R] [AddCommGroup M] - -instance AddCommGroup.toIntModule : Module ℤ M where - one_smul := one_zsmul - mul_smul m n a := mul_zsmul a m n - smul_add n a b := zsmul_add a b n - smul_zero := zsmul_zero - zero_smul := zero_zsmul - add_smul r s x := add_zsmul x r s - -variable {R M} +variable [Semiring R] [AddCommGroup M] theorem Convex.combo_eq_smul_sub_add [Module R M] {x y : M} {a b : R} (h : a + b = 1) : a • x + b • y = b • (y - x) + x := @@ -187,10 +147,6 @@ theorem neg_smul : -r • x = -(r • x) := theorem neg_smul_neg : -r • -x = r • x := by rw [neg_smul, smul_neg, neg_neg] -@[simp] -theorem Units.neg_smul (u : Rˣ) (x : M) : -u • x = -(u • x) := by - rw [Units.smul_def, Units.val_neg, _root_.neg_smul, Units.smul_def] - variable (R) theorem neg_one_smul (x : M) : (-1 : R) • x = -x := by simp @@ -202,26 +158,6 @@ theorem sub_smul (r s : R) (y : M) : (r - s) • y = r • y - s • y := by end Module -variable (R) - -/-- An `AddCommMonoid` that is a `Module` over a `Ring` carries a natural `AddCommGroup` -structure. -See note [reducible non-instances]. -/ -abbrev Module.addCommMonoidToAddCommGroup - [Ring R] [AddCommMonoid M] [Module R M] : AddCommGroup M := - { (inferInstance : AddCommMonoid M) with - neg := fun a => (-1 : R) • a - neg_add_cancel := fun a => - show (-1 : R) • a + a = 0 by - nth_rw 2 [← one_smul R a] - rw [← add_smul, neg_add_cancel, zero_smul] - zsmul := fun z a => (z : R) • a - zsmul_zero' := fun a => by simpa only [Int.cast_zero] using zero_smul R a - zsmul_succ' := fun z a => by simp [add_comm, add_smul] - zsmul_neg' := fun z a => by simp [← smul_assoc, neg_one_smul] } - -variable {R} - /-- A module over a `Subsingleton` semiring is a `Subsingleton`. We cannot register this as an instance because Lean has no way to guess `R`. -/ protected theorem Module.subsingleton (R M : Type*) [Semiring R] [Subsingleton R] [AddCommMonoid M] @@ -242,87 +178,3 @@ instance (priority := 910) Semiring.toModule [Semiring R] : Module R R where instance [NonUnitalNonAssocSemiring R] : DistribSMul R R where smul_add := left_distrib - -/-- A ring homomorphism `f : R →+* M` defines a module structure by `r • x = f r * x`. -/ -def RingHom.toModule [Semiring R] [Semiring S] (f : R →+* S) : Module R S := - Module.compHom S f - -/-- If the module action of `R` on `S` is compatible with multiplication on `S`, then -`fun x ↦ x • 1` is a ring homomorphism from `R` to `S`. - -This is the `RingHom` version of `MonoidHom.smulOneHom`. - -When `R` is commutative, usually `algebraMap` should be preferred. -/ -@[simps!] def RingHom.smulOneHom - [Semiring R] [NonAssocSemiring S] [Module R S] [IsScalarTower R S S] : R →+* S where - __ := MonoidHom.smulOneHom - map_zero' := zero_smul R 1 - map_add' := (add_smul · · 1) - -/-- A homomorphism between semirings R and S can be equivalently specified by a R-module -structure on S such that S/S/R is a scalar tower. -/ -def ringHomEquivModuleIsScalarTower [Semiring R] [Semiring S] : - (R →+* S) ≃ {_inst : Module R S // IsScalarTower R S S} where - toFun f := ⟨Module.compHom S f, SMul.comp.isScalarTower _⟩ - invFun := fun ⟨_, _⟩ ↦ RingHom.smulOneHom - left_inv f := RingHom.ext fun r ↦ mul_one (f r) - right_inv := fun ⟨_, _⟩ ↦ Subtype.ext <| Module.ext <| funext₂ <| smul_one_smul S - -section AddCommMonoid - -variable [Semiring R] [AddCommMonoid M] [Module R M] - -section - -variable (R) - -/-- `nsmul` is equal to any other module structure via a cast. -/ -lemma Nat.cast_smul_eq_nsmul (n : ℕ) (b : M) : (n : R) • b = n • b := by - induction n with - | zero => rw [Nat.cast_zero, zero_smul, zero_smul] - | succ n ih => rw [Nat.cast_succ, add_smul, add_smul, one_smul, ih, one_smul] - -/-- `nsmul` is equal to any other module structure via a cast. -/ --- See note [no_index around OfNat.ofNat] -lemma ofNat_smul_eq_nsmul (n : ℕ) [n.AtLeastTwo] (b : M) : - (no_index (OfNat.ofNat n) : R) • b = OfNat.ofNat n • b := Nat.cast_smul_eq_nsmul .. - -/-- `nsmul` is equal to any other module structure via a cast. -/ -@[deprecated Nat.cast_smul_eq_nsmul (since := "2024-07-23")] -lemma nsmul_eq_smul_cast (n : ℕ) (b : M) : n • b = (n : R) • b := (Nat.cast_smul_eq_nsmul ..).symm - -end - -/-- Convert back any exotic `ℕ`-smul to the canonical instance. This should not be needed since in -mathlib all `AddCommMonoid`s should normally have exactly one `ℕ`-module structure by design. --/ -theorem nat_smul_eq_nsmul (h : Module ℕ M) (n : ℕ) (x : M) : @SMul.smul ℕ M h.toSMul n x = n • x := - Nat.cast_smul_eq_nsmul .. - -/-- All `ℕ`-module structures are equal. Not an instance since in mathlib all `AddCommMonoid` -should normally have exactly one `ℕ`-module structure by design. -/ -def AddCommMonoid.uniqueNatModule : Unique (Module ℕ M) where - default := by infer_instance - 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 := by - induction n with - | zero => simp only [zero_smul] - | succ n ih => simp only [add_smul, one_smul, ih] - -end AddCommMonoid - -theorem map_natCast_smul [AddCommMonoid M] [AddCommMonoid M₂] {F : Type*} [FunLike F M M₂] - [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [Semiring R] [Semiring S] [Module R M] - [Module S M₂] (x : ℕ) (a : M) : f ((x : R) • a) = (x : S) • f a := by - simp only [Nat.cast_smul_eq_nsmul, AddMonoidHom.map_nsmul, map_nsmul] - -theorem Nat.smul_one_eq_cast {R : Type*} [NonAssocSemiring R] (m : ℕ) : m • (1 : R) = ↑m := by - rw [nsmul_eq_mul, mul_one] - -theorem Int.smul_one_eq_cast {R : Type*} [NonAssocRing R] (m : ℤ) : m • (1 : R) = ↑m := by - rw [zsmul_eq_mul, mul_one] - -@[deprecated (since := "2024-05-03")] alias Nat.smul_one_eq_coe := Nat.smul_one_eq_cast -@[deprecated (since := "2024-05-03")] alias Int.smul_one_eq_coe := Int.smul_one_eq_cast diff --git a/Mathlib/Algebra/Module/End.lean b/Mathlib/Algebra/Module/End.lean index b1269c071ad3da..405cb931c87f9b 100644 --- a/Mathlib/Algebra/Module/End.lean +++ b/Mathlib/Algebra/Module/End.lean @@ -5,6 +5,7 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro -/ import Mathlib.Algebra.Group.Hom.End import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.NatInt /-! # Module structure and endomorphisms diff --git a/Mathlib/Algebra/Module/FinitePresentation.lean b/Mathlib/Algebra/Module/FinitePresentation.lean index a4d6e21f875765..b5737ac1b8e492 100644 --- a/Mathlib/Algebra/Module/FinitePresentation.lean +++ b/Mathlib/Algebra/Module/FinitePresentation.lean @@ -4,10 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.LinearAlgebra.FreeModule.Finite.Basic +import Mathlib.LinearAlgebra.TensorProduct.RightExactness import Mathlib.LinearAlgebra.Isomorphisms import Mathlib.RingTheory.Finiteness.Projective -import Mathlib.RingTheory.Localization.Module -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Finiteness.TensorProduct +import Mathlib.RingTheory.Localization.BaseChange +import Mathlib.RingTheory.Noetherian.Basic + /-! # Finitely Presented Modules @@ -232,6 +235,36 @@ section CommRing variable {R M N N'} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] variable [AddCommGroup N'] [Module R N'] (S : Submonoid R) (f : N →ₗ[R] N') [IsLocalizedModule S f] +open TensorProduct in +instance {A} [CommRing A] [Algebra R A] [Module.FinitePresentation R M] : + Module.FinitePresentation A (A ⊗[R] M) := by + classical + obtain ⟨n, f, hf⟩ := Module.Finite.exists_fin' R M + have inst := Module.finitePresentation_of_projective A (A ⊗[R] (Fin n → R)) + apply Module.finitePresentation_of_surjective (f.baseChange A) + (LinearMap.lTensor_surjective A hf) + have : Function.Exact ((LinearMap.ker f).subtype.baseChange A) (f.baseChange A) := + lTensor_exact A f.exact_subtype_ker_map hf + rw [LinearMap.exact_iff] at this + rw [this, ← Submodule.map_top] + apply Submodule.FG.map + have : Module.Finite R (LinearMap.ker f) := + ⟨(Submodule.fg_top _).mpr (Module.FinitePresentation.fg_ker f hf)⟩ + exact Module.Finite.out (R := A) (M := A ⊗[R] LinearMap.ker f) + +open TensorProduct in +lemma FinitePresentation.of_isBaseChange + {A} [CommRing A] [Algebra R A] [Module A N] [IsScalarTower R A N] + (f : M →ₗ[R] N) (h : IsBaseChange A f) [Module.FinitePresentation R M] : + Module.FinitePresentation A N := + Module.finitePresentation_of_surjective + h.equiv.toLinearMap h.equiv.surjective (by simpa using Submodule.fg_bot) + +open TensorProduct in +instance (S : Submonoid R) [Module.FinitePresentation R M] : + Module.FinitePresentation (Localization S) (LocalizedModule S M) := + FinitePresentation.of_isBaseChange (LocalizedModule.mkLinearMap S M) + ((isLocalizedModule_iff_isBaseChange S _ _).mp inferInstance) lemma Module.FinitePresentation.exists_lift_of_isLocalizedModule [h : Module.FinitePresentation R M] (g : M →ₗ[R] N') : diff --git a/Mathlib/Algebra/Module/FreeLocus.lean b/Mathlib/Algebra/Module/FreeLocus.lean new file mode 100644 index 00000000000000..9f42786132f02f --- /dev/null +++ b/Mathlib/Algebra/Module/FreeLocus.lean @@ -0,0 +1,227 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.PrimeSpectrum.Basic +import Mathlib.RingTheory.Flat.Stability +import Mathlib.RingTheory.LocalProperties.Projective +import Mathlib.RingTheory.LocalRing.Module +import Mathlib.RingTheory.Localization.Free +import Mathlib.RingTheory.Localization.LocalizationLocalization +import Mathlib.Topology.LocallyConstant.Basic + +/-! + +# The free locus of a module + +## Main definitions and results + +Let `M` be a finitely presented `R`-module. +- `Module.freeLocus`: The set of points `x` in `Spec R` such that `Mₓ` is free over `Rₓ`. +- `Module.freeLocus_eq_univ_iff`: + The free locus is the whole `Spec R` if and only if `M` is projective. +- `Module.basicOpen_subset_freeLocus_iff`: `D(f)` is contained in the free locus if and only if + `M_f` is projective over `R_f`. +- `Module.rankAtStalk`: The function `Spec R → ℕ` sending `x` to `rank_{Rₓ} Mₓ`. +- `Module.isLocallyConstant_rankAtStalk`: + If `M` is flat over `R`, then `rankAtStalk` is locally constant. + +-/ + +universe uR uM + +variable (R : Type uR) (M : Type uM) [CommRing R] [AddCommGroup M] [Module R M] + +namespace Module + +open PrimeSpectrum TensorProduct + +/-- The free locus of a module, i.e. the set of primes `p` such that `Mₚ` is free over `Rₚ`. -/ +def freeLocus : Set (PrimeSpectrum R) := + { p | Module.Free (Localization.AtPrime p.asIdeal) (LocalizedModule p.asIdeal.primeCompl M) } + +variable {R M} + +lemma mem_freeLocus {p} : p ∈ freeLocus R M ↔ + Module.Free (Localization.AtPrime p.asIdeal) (LocalizedModule p.asIdeal.primeCompl M) := + Iff.rfl + +attribute [local instance] RingHomInvPair.of_ringEquiv in +lemma mem_freeLocus_of_isLocalization (p : PrimeSpectrum R) + (Rₚ Mₚ) [CommRing Rₚ] [Algebra R Rₚ] [IsLocalization.AtPrime Rₚ p.asIdeal] + [AddCommGroup Mₚ] [Module R Mₚ] (f : M →ₗ[R] Mₚ) [IsLocalizedModule p.asIdeal.primeCompl f] + [Module Rₚ Mₚ] [IsScalarTower R Rₚ Mₚ] : + p ∈ freeLocus R M ↔ Module.Free Rₚ Mₚ := by + apply Module.Free.iff_of_ringEquiv (IsLocalization.algEquiv p.asIdeal.primeCompl + (Localization.AtPrime p.asIdeal) Rₚ).toRingEquiv + refine { __ := IsLocalizedModule.iso p.asIdeal.primeCompl f, map_smul' := ?_ } + intro r x + obtain ⟨r, s, rfl⟩ := IsLocalization.mk'_surjective p.asIdeal.primeCompl r + apply ((Module.End_isUnit_iff _).mp (IsLocalizedModule.map_units f s)).1 + simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, LinearEquiv.coe_coe, + algebraMap_end_apply, AlgEquiv.toRingEquiv_eq_coe, + AlgEquiv.toRingEquiv_toRingHom, RingHom.coe_coe, IsLocalization.algEquiv_apply, + IsLocalization.map_id_mk'] + simp only [← map_smul, ← smul_assoc, IsLocalization.smul_mk'_self, algebraMap_smul, + IsLocalization.map_id_mk'] + +attribute [local instance] RingHomInvPair.of_ringEquiv in +lemma mem_freeLocus_iff_tensor (p : PrimeSpectrum R) + (Rₚ) [CommRing Rₚ] [Algebra R Rₚ] [IsLocalization.AtPrime Rₚ p.asIdeal] : + p ∈ freeLocus R M ↔ Module.Free Rₚ (Rₚ ⊗[R] M) := by + have := (isLocalizedModule_iff_isBaseChange p.asIdeal.primeCompl _ _).mpr + (TensorProduct.isBaseChange R M Rₚ) + exact mem_freeLocus_of_isLocalization p Rₚ (f := TensorProduct.mk R Rₚ M 1) + +lemma freeLocus_congr {M'} [AddCommGroup M'] [Module R M'] (e : M ≃ₗ[R] M') : + freeLocus R M = freeLocus R M' := by + ext p + exact mem_freeLocus_of_isLocalization _ _ _ + (LocalizedModule.mkLinearMap p.asIdeal.primeCompl M' ∘ₗ e.toLinearMap) + +open TensorProduct in +lemma comap_freeLocus_le {A} [CommRing A] [Algebra R A] : + comap (algebraMap R A) ⁻¹' freeLocus R M ≤ freeLocus A (A ⊗[R] M) := by + intro p hp + let Rₚ := Localization.AtPrime (comap (algebraMap R A) p).asIdeal + let Aₚ := Localization.AtPrime p.asIdeal + rw [Set.mem_preimage, mem_freeLocus_iff_tensor _ Rₚ] at hp + rw [mem_freeLocus_iff_tensor _ Aₚ] + letI : Algebra Rₚ Aₚ := (Localization.localRingHom + (comap (algebraMap R A) p).asIdeal p.asIdeal (algebraMap R A) rfl).toAlgebra + have : IsScalarTower R Rₚ Aₚ := IsScalarTower.of_algebraMap_eq' + (by simp [RingHom.algebraMap_toAlgebra, Localization.localRingHom, + ← IsScalarTower.algebraMap_eq]) + let e := AlgebraTensorModule.cancelBaseChange R Rₚ Aₚ Aₚ M ≪≫ₗ + (AlgebraTensorModule.cancelBaseChange R A Aₚ Aₚ M).symm + exact .of_equiv e + +lemma freeLocus_localization (S : Submonoid R) : + freeLocus (Localization S) (LocalizedModule S M) = + comap (algebraMap R _) ⁻¹' freeLocus R M := by + ext p + simp only [Set.mem_preimage] + let p' := p.asIdeal.comap (algebraMap R _) + have hp' : S ≤ p'.primeCompl := fun x hx H ↦ + p.isPrime.ne_top (Ideal.eq_top_of_isUnit_mem _ H (IsLocalization.map_units _ ⟨x, hx⟩)) + let Rₚ := Localization.AtPrime p' + let Mₚ := LocalizedModule p'.primeCompl M + letI : Algebra (Localization S) Rₚ := + IsLocalization.localizationAlgebraOfSubmonoidLe _ _ S p'.primeCompl hp' + have : IsScalarTower R (Localization S) Rₚ := + IsLocalization.localization_isScalarTower_of_submonoid_le .. + have : IsLocalization.AtPrime Rₚ p.asIdeal := by + have := IsLocalization.isLocalization_of_submonoid_le (Localization S) Rₚ _ _ hp' + apply IsLocalization.isLocalization_of_is_exists_mul_mem _ + (Submonoid.map (algebraMap R (Localization S)) p'.primeCompl) + · rintro _ ⟨x, hx, rfl⟩; exact hx + · rintro ⟨x, hx⟩ + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective S x + refine ⟨algebraMap _ _ s.1, x, fun H ↦ hx ?_, by simp⟩ + rw [IsLocalization.mk'_eq_mul_mk'_one] + exact Ideal.mul_mem_right _ _ H + letI : Module (Localization S) Mₚ := Module.compHom Mₚ (algebraMap _ Rₚ) + have : IsScalarTower R (Localization S) Mₚ := + ⟨fun r r' m ↦ show algebraMap _ Rₚ (r • r') • m = _ by + simp [Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ + have : IsScalarTower (Localization S) Rₚ Mₚ := + ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • _ by rw [← mul_smul, ← Algebra.smul_def]⟩ + let l := (IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap S M) + (LocalizedModule.mkLinearMap p'.primeCompl M)).extendScalarsOfIsLocalization S + (Localization S) + have : IsLocalizedModule p.asIdeal.primeCompl l := by + have : IsLocalizedModule p'.primeCompl (l.restrictScalars R) := + inferInstanceAs (IsLocalizedModule p'.primeCompl + (IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap S M) + (LocalizedModule.mkLinearMap p'.primeCompl M))) + have : IsLocalizedModule (Algebra.algebraMapSubmonoid (Localization S) p'.primeCompl) l := + IsLocalizedModule.of_restrictScalars p'.primeCompl .. + apply IsLocalizedModule.of_exists_mul_mem + (Algebra.algebraMapSubmonoid (Localization S) p'.primeCompl) + · rintro _ ⟨x, hx, rfl⟩; exact hx + · rintro ⟨x, hx⟩ + obtain ⟨x, s, rfl⟩ := IsLocalization.mk'_surjective S x + refine ⟨algebraMap _ _ s.1, x, fun H ↦ hx ?_, by simp⟩ + rw [IsLocalization.mk'_eq_mul_mk'_one] + exact Ideal.mul_mem_right _ _ H + rw [mem_freeLocus_of_isLocalization (R := Localization S) p Rₚ Mₚ l] + rfl + +lemma freeLocus_eq_univ_iff [Module.FinitePresentation R M] : + freeLocus R M = Set.univ ↔ Module.Projective R M := by + simp_rw [Set.eq_univ_iff_forall, mem_freeLocus] + exact ⟨fun H ↦ Module.projective_of_localization_maximal fun I hI ↦ + have := H ⟨I, hI.isPrime⟩; .of_free, fun H x ↦ Module.free_of_flat_of_isLocalRing⟩ + +lemma freeLocus_eq_univ [Module.FinitePresentation R M] [Module.Flat R M] : + freeLocus R M = Set.univ := by + simp_rw [Set.eq_univ_iff_forall, mem_freeLocus] + exact fun x ↦ Module.free_of_flat_of_isLocalRing + +lemma basicOpen_subset_freeLocus_iff [Module.FinitePresentation R M] {f : R} : + (basicOpen f : Set (PrimeSpectrum R)) ⊆ freeLocus R M ↔ + Module.Projective (Localization.Away f) (LocalizedModule (.powers f) M) := by + rw [← freeLocus_eq_univ_iff, freeLocus_localization, + Set.preimage_eq_univ_iff, localization_away_comap_range _ f] + +lemma isOpen_freeLocus [Module.FinitePresentation R M] : + IsOpen (freeLocus R M) := by + refine isOpen_iff_forall_mem_open.mpr fun x hx ↦ ?_ + have : Module.Free _ _ := hx + obtain ⟨r, hr, hr', _⟩ := Module.FinitePresentation.exists_free_localizedModule_powers + x.asIdeal.primeCompl (LocalizedModule.mkLinearMap x.asIdeal.primeCompl M) + (Localization.AtPrime x.asIdeal) + exact ⟨basicOpen r, basicOpen_subset_freeLocus_iff.mpr inferInstance, (basicOpen r).2, hr⟩ + +variable (M) in +/-- The rank of `M` at the stalk of `p` is the rank of `Mₚ` as a `Rₚ`-module. -/ +noncomputable +def rankAtStalk (p : PrimeSpectrum R) : ℕ := + Module.finrank (Localization.AtPrime p.asIdeal) (LocalizedModule p.asIdeal.primeCompl M) + +lemma isLocallyConstant_rankAtStalk_freeLocus [Module.FinitePresentation R M] : + IsLocallyConstant (fun x : freeLocus R M ↦ rankAtStalk M x.1) := by + refine (IsLocallyConstant.iff_exists_open _).mpr fun ⟨x, hx⟩ ↦ ?_ + have : Module.Free _ _ := hx + obtain ⟨f, hf, hf', hf''⟩ := Module.FinitePresentation.exists_free_localizedModule_powers + x.asIdeal.primeCompl (LocalizedModule.mkLinearMap x.asIdeal.primeCompl M) + (Localization.AtPrime x.asIdeal) + refine ⟨Subtype.val ⁻¹' basicOpen f, (basicOpen f).2.preimage continuous_subtype_val, hf, ?_⟩ + rintro ⟨p, hp''⟩ hp + let p' := Algebra.algebraMapSubmonoid (Localization (.powers f)) p.asIdeal.primeCompl + have hp' : Submonoid.powers f ≤ p.asIdeal.primeCompl := by + simpa [Submonoid.powers_le, Ideal.primeCompl] + let Rₚ := Localization.AtPrime p.asIdeal + let Mₚ := LocalizedModule p.asIdeal.primeCompl M + letI : Algebra (Localization.Away f) Rₚ := + IsLocalization.localizationAlgebraOfSubmonoidLe _ _ (.powers f) p.asIdeal.primeCompl hp' + have : IsScalarTower R (Localization.Away f) Rₚ := + IsLocalization.localization_isScalarTower_of_submonoid_le .. + letI : Module (Localization.Away f) Mₚ := Module.compHom Mₚ (algebraMap _ Rₚ) + have : IsScalarTower R (Localization.Away f) Mₚ := + ⟨fun r r' m ↦ show algebraMap _ Rₚ (r • r') • m = _ by + simp [Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ + have : IsScalarTower (Localization.Away f) Rₚ Mₚ := + ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • _ by rw [← mul_smul, ← Algebra.smul_def]⟩ + let l := (IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap (.powers f) M) + (LocalizedModule.mkLinearMap p.asIdeal.primeCompl M)).extendScalarsOfIsLocalization (.powers f) + (Localization.Away f) + have : IsLocalization p' Rₚ := + IsLocalization.isLocalization_of_submonoid_le (Localization.Away f) Rₚ _ _ hp' + have : IsLocalizedModule p.asIdeal.primeCompl (l.restrictScalars R) := + inferInstanceAs (IsLocalizedModule p.asIdeal.primeCompl + ((IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap (.powers f) M) + (LocalizedModule.mkLinearMap p.asIdeal.primeCompl M)))) + have : IsLocalizedModule (Algebra.algebraMapSubmonoid _ p.asIdeal.primeCompl) l := + IsLocalizedModule.of_restrictScalars p.asIdeal.primeCompl .. + have := Module.finrank_of_isLocalizedModule_of_free Rₚ p' l + simp [rankAtStalk, this, hf''] + +lemma isLocallyConstant_rankAtStalk [Module.FinitePresentation R M] [Module.Flat R M] : + IsLocallyConstant (rankAtStalk (R := R) M) := by + let e : freeLocus R M ≃ₜ PrimeSpectrum R := + (Homeomorph.setCongr freeLocus_eq_univ).trans (Homeomorph.Set.univ (PrimeSpectrum R)) + convert isLocallyConstant_rankAtStalk_freeLocus.comp_continuous e.symm.continuous + +end Module diff --git a/Mathlib/Algebra/Module/GradedModule.lean b/Mathlib/Algebra/Module/GradedModule.lean index 8adb7c6ada0a57..8797f2bbdd7b54 100644 --- a/Mathlib/Algebra/Module/GradedModule.lean +++ b/Mathlib/Algebra/Module/GradedModule.lean @@ -93,11 +93,9 @@ theorem smulAddMonoidHom_apply_of_of [DecidableEq ιA] [DecidableEq ιB] [GMonoi smulAddMonoidHom A M (DirectSum.of A i x) (of M j y) = of M (i +ᵥ j) (GSMul.smul x y) := by simp [smulAddMonoidHom] --- @[simp] -- Porting note: simpNF lint theorem of_smul_of [DecidableEq ιA] [DecidableEq ιB] [GMonoid A] [Gmodule A M] {i j} (x : A i) (y : M j) : - DirectSum.of A i x • of M j y = of M (i +ᵥ j) (GSMul.smul x y) := - smulAddMonoidHom_apply_of_of _ _ _ _ + DirectSum.of A i x • of M j y = of M (i +ᵥ j) (GSMul.smul x y) := by simp open AddMonoidHom diff --git a/Mathlib/Algebra/Module/Hom.lean b/Mathlib/Algebra/Module/Hom.lean index 66bdfade35658a..8149ac54e6b584 100644 --- a/Mathlib/Algebra/Module/Hom.lean +++ b/Mathlib/Algebra/Module/Hom.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ import Mathlib.Algebra.Group.Hom.Instances +import Mathlib.Algebra.GroupWithZero.Action.End import Mathlib.Algebra.Module.End import Mathlib.Algebra.Ring.Opposite import Mathlib.GroupTheory.GroupAction.DomAct.Basic diff --git a/Mathlib/Algebra/Module/LinearMap/Defs.lean b/Mathlib/Algebra/Module/LinearMap/Defs.lean index 893c0c84ca3702..d4c25f58c52fbc 100644 --- a/Mathlib/Algebra/Module/LinearMap/Defs.lean +++ b/Mathlib/Algebra/Module/LinearMap/Defs.lean @@ -5,6 +5,8 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro, Anne Frédéric Dupuis, Heather Macbeth -/ import Mathlib.Algebra.Group.Hom.Instances +import Mathlib.Algebra.Module.NatInt +import Mathlib.Algebra.Module.RingHom import Mathlib.Algebra.Ring.CompTypeclasses import Mathlib.GroupTheory.GroupAction.Hom @@ -594,14 +596,14 @@ variable [Semiring R] [Module R M] [Semiring S] [Module S M₂] [Module R M₃] variable {σ : R →+* S} /-- A `DistribMulActionHom` between two modules is a linear map. -/ -@[deprecated (since := "2024-11-08")] +@[deprecated "No deprecation message was provided." (since := "2024-11-08")] def toSemilinearMap (fₗ : M →ₑ+[σ.toMonoidHom] M₂) : M →ₛₗ[σ] M₂ := { fₗ with } instance : SemilinearMapClass (M →ₑ+[σ.toMonoidHom] M₂) σ M M₂ where /-- A `DistribMulActionHom` between two modules is a linear map. -/ -@[deprecated (since := "2024-11-08")] +@[deprecated "No deprecation message was provided." (since := "2024-11-08")] def toLinearMap (fₗ : M →+[R] M₃) : M →ₗ[R] M₃ := { fₗ with } diff --git a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean index cd73b52dd3c655..efe62ee72caee0 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean @@ -560,7 +560,7 @@ lemma IsLocalizedModule.eq_iff_exists [IsLocalizedModule S f] {x₁ x₂} : simp_rw [f.map_smul_of_tower, Submonoid.smul_def, ← Module.algebraMap_end_apply R R] at h exact ((Module.End_isUnit_iff _).mp <| map_units f c).1 h -theorem IsLocalizedModule.of_linearEquiv (e : M' ≃ₗ[R] M'') [hf : IsLocalizedModule S f] : +instance IsLocalizedModule.of_linearEquiv (e : M' ≃ₗ[R] M'') [hf : IsLocalizedModule S f] : IsLocalizedModule S (e ∘ₗ f : M →ₗ[R] M'') where map_units s := by rw [show algebraMap R (Module.End R M'') s = e ∘ₗ (algebraMap R (Module.End R M') s) ∘ₗ e.symm @@ -576,6 +576,18 @@ theorem IsLocalizedModule.of_linearEquiv (e : M' ≃ₗ[R] M'') [hf : IsLocalize EmbeddingLike.apply_eq_iff_eq] at h exact hf.exists_of_eq h +instance IsLocalizedModule.of_linearEquiv_right (e : M'' ≃ₗ[R] M) [hf : IsLocalizedModule S f] : + IsLocalizedModule S (f ∘ₗ e : M'' →ₗ[R] M') where + map_units s := hf.map_units s + surj' x := by + obtain ⟨⟨p, s⟩, h⟩ := hf.surj' x + exact ⟨⟨e.symm p, s⟩, by simpa using h⟩ + exists_of_eq h := by + simp_rw [LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply] at h + obtain ⟨c, hc⟩ := hf.exists_of_eq h + exact ⟨c, by simpa only [Submonoid.smul_def, map_smul, e.symm_apply_apply] + using congr(e.symm $hc)⟩ + variable (M) in lemma isLocalizedModule_id (R') [CommSemiring R'] [Algebra R R'] [IsLocalization S R'] [Module R' M] [IsScalarTower R R' M] : IsLocalizedModule S (.id : M →ₗ[R] M) where @@ -703,6 +715,39 @@ instance localizedModuleIsLocalizedModule : LocalizedModule.mk_cancel t] exists_of_eq eq1 := by simpa only [eq_comm, one_smul] using LocalizedModule.mk_eq.mp eq1 +lemma IsLocalizedModule.of_restrictScalars (S : Submonoid R) + {N : Type*} [AddCommGroup N] [Module R N] [Module A M] [Module A N] + [IsScalarTower R A M] [IsScalarTower R A N] + (f : M →ₗ[A] N) [IsLocalizedModule S (f.restrictScalars R)] : + IsLocalizedModule (Algebra.algebraMapSubmonoid A S) f where + map_units x := by + obtain ⟨_, x, hx, rfl⟩ := x + have := IsLocalizedModule.map_units (f.restrictScalars R) ⟨x, hx⟩ + simp only [← IsScalarTower.algebraMap_apply, Module.End_isUnit_iff] at this ⊢ + exact this + surj' y := by + obtain ⟨⟨x, t⟩, e⟩ := IsLocalizedModule.surj S (f.restrictScalars R) y + exact ⟨⟨x, ⟨_, t, t.2, rfl⟩⟩, by simpa [Submonoid.smul_def] using e⟩ + exists_of_eq {x₁ x₂} e := by + obtain ⟨c, hc⟩ := IsLocalizedModule.exists_of_eq (S := S) (f := f.restrictScalars R) e + refine ⟨⟨_, c, c.2, rfl⟩, by simpa [Submonoid.smul_def]⟩ + +lemma IsLocalizedModule.of_exists_mul_mem {N : Type*} [AddCommGroup N] [Module R N] + (S T : Submonoid R) (h : S ≤ T) (h' : ∀ x : T, ∃ m : R, m * x ∈ S) + (f : M →ₗ[R] N) [IsLocalizedModule S f] : + IsLocalizedModule T f where + map_units x := by + obtain ⟨m, mx⟩ := h' x + have := IsLocalizedModule.map_units f ⟨_, mx⟩ + rw [map_mul, (Algebra.commute_algebraMap_left _ _).isUnit_mul_iff] at this + exact this.2 + surj' y := by + obtain ⟨⟨x, t⟩, e⟩ := IsLocalizedModule.surj S f y + exact ⟨⟨x, ⟨t, h t.2⟩⟩, e⟩ + exists_of_eq {x₁ x₂} e := by + obtain ⟨c, hc⟩ := IsLocalizedModule.exists_of_eq (S := S) (f := f) e + exact ⟨⟨c, h c.2⟩, hc⟩ + namespace IsLocalizedModule variable [IsLocalizedModule S f] diff --git a/Mathlib/Algebra/Module/LocalizedModule/Submodule.lean b/Mathlib/Algebra/Module/LocalizedModule/Submodule.lean index 786335636ddb07..0ec7f25bf02d75 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Submodule.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Submodule.lean @@ -28,49 +28,73 @@ Results about localizations of submodules and quotient modules are provided in t open nonZeroDivisors -universe u u' v v' w w' - -variable {R : Type u} (S : Type u') {M : Type v} {N : Type v'} -variable [CommRing R] [CommRing S] [AddCommGroup M] [AddCommGroup N] +variable {R S M N : Type*} +variable (S) [CommSemiring R] [CommSemiring S] [AddCommMonoid M] [AddCommMonoid N] variable [Module R M] [Module R N] [Algebra R S] [Module S N] [IsScalarTower R S N] variable (p : Submonoid R) [IsLocalization p S] (f : M →ₗ[R] N) [IsLocalizedModule p f] variable (M' : Submodule R M) -/-- Let `S` be the localization of `R` at `p` and `N` be the localization of `M` at `p`. -This is the localization of an `R`-submodule of `M` viewed as an `S`-submodule of `N`. -/ -def Submodule.localized' : Submodule S N where +namespace Submodule + +/-- Let `N` be a localization of an `R`-module `M` at `p`. +This is the localization of an `R`-submodule of `M` viewed as an `R`-submodule of `N`. -/ +def localized₀ : Submodule R N where carrier := { x | ∃ m ∈ M', ∃ s : p, IsLocalizedModule.mk' f m s = x } - add_mem' := fun {x} {y} ⟨m, hm, s, hx⟩ ⟨n, hn, t, hy⟩ ↦ ⟨t • m + s • n, add_mem (M'.smul_mem t hm) + add_mem' := fun {x y} ⟨m, hm, s, hx⟩ ⟨n, hn, t, hy⟩ ↦ ⟨t • m + s • n, add_mem (M'.smul_mem t hm) (M'.smul_mem s hn), s * t, by rw [← hx, ← hy, IsLocalizedModule.mk'_add_mk']⟩ zero_mem' := ⟨0, zero_mem _, 1, by simp⟩ - smul_mem' := fun r x h ↦ by - have ⟨m, hm, s, hx⟩ := h + smul_mem' r x := by + rintro ⟨m, hm, s, hx⟩ + exact ⟨r • m, smul_mem M' _ hm, s, by rw [IsLocalizedModule.mk'_smul, hx]⟩ + +/-- Let `S` be the localization of `R` at `p` and `N` be a localization of `M` at `p`. +This is the localization of an `R`-submodule of `M` viewed as an `S`-submodule of `N`. -/ +def localized' : Submodule S N where + __ := localized₀ p f M' + smul_mem' := fun r x ⟨m, hm, s, hx⟩ ↦ by have ⟨y, t, hyt⟩ := IsLocalization.mk'_surjective p r exact ⟨y • m, M'.smul_mem y hm, t * s, by simp [← hyt, ← hx, IsLocalizedModule.mk'_smul_mk']⟩ -lemma Submodule.mem_localized' (x : N) : - x ∈ Submodule.localized' S p f M' ↔ ∃ m ∈ M', ∃ s : p, IsLocalizedModule.mk' f m s = x := +lemma mem_localized₀ (x : N) : + x ∈ localized₀ p f M' ↔ ∃ m ∈ M', ∃ s : p, IsLocalizedModule.mk' f m s = x := + Iff.rfl + +lemma mem_localized' (x : N) : + x ∈ localized' S p f M' ↔ ∃ m ∈ M', ∃ s : p, IsLocalizedModule.mk' f m s = x := Iff.rfl +/-- `localized₀` is the same as `localized'` considered as a submodule over the base ring. -/ +lemma restrictScalars_localized' : + (localized' S p f M').restrictScalars R = localized₀ p f M' := + rfl + /-- The localization of an `R`-submodule of `M` at `p` viewed as an `Rₚ`-submodule of `Mₚ`. -/ -abbrev Submodule.localized : Submodule (Localization p) (LocalizedModule p M) := +abbrev localized : Submodule (Localization p) (LocalizedModule p M) := M'.localized' (Localization p) p (LocalizedModule.mkLinearMap p M) @[simp] -lemma Submodule.localized'_bot : (⊥ : Submodule R M).localized' S p f = ⊥ := by +lemma localized₀_bot : (⊥ : Submodule R M).localized₀ p f = ⊥ := by rw [← le_bot_iff] rintro _ ⟨_, rfl, s, rfl⟩ simp only [IsLocalizedModule.mk'_zero, mem_bot] @[simp] -lemma Submodule.localized'_top : (⊤ : Submodule R M).localized' S p f = ⊤ := by +lemma localized'_bot : (⊥ : Submodule R M).localized' S p f = ⊥ := + SetLike.ext' (by apply SetLike.ext'_iff.mp <| Submodule.localized₀_bot p f) + +@[simp] +lemma localized₀_top : (⊤ : Submodule R M).localized₀ p f = ⊤ := by rw [← top_le_iff] rintro x _ obtain ⟨⟨x, s⟩, rfl⟩ := IsLocalizedModule.mk'_surjective p f x exact ⟨x, trivial, s, rfl⟩ @[simp] -lemma Submodule.localized'_span (s : Set M) : (span R s).localized' S p f = span S (f '' s) := by +lemma localized'_top : (⊤ : Submodule R M).localized' S p f = ⊤ := + SetLike.ext' (by apply SetLike.ext'_iff.mp <| Submodule.localized₀_top p f) + +@[simp] +lemma localized'_span (s : Set M) : (span R s).localized' S p f = span S (f '' s) := by apply le_antisymm · rintro _ ⟨x, hx, t, rfl⟩ have := IsLocalizedModule.mk'_smul_mk' S f 1 x t 1 @@ -87,29 +111,45 @@ lemma Submodule.localized'_span (s : Set M) : (span R s).localized' S p f = span /-- The localization map of a submodule. -/ @[simps!] -def Submodule.toLocalized' : M' →ₗ[R] M'.localized' S p f := - f.restrict (q := (M'.localized' S p f).restrictScalars R) (fun x hx ↦ ⟨x, hx, 1, by simp⟩) +def toLocalized₀ : M' →ₗ[R] M'.localized₀ p f := f.restrict fun x hx ↦ ⟨x, hx, 1, by simp⟩ + +/-- The localization map of a submodule. -/ +@[simps!] +def toLocalized' : M' →ₗ[R] M'.localized' S p f := toLocalized₀ p f M' /-- The localization map of a submodule. -/ -abbrev Submodule.toLocalized : M' →ₗ[R] M'.localized p := +abbrev toLocalized : M' →ₗ[R] M'.localized p := M'.toLocalized' (Localization p) p (LocalizedModule.mkLinearMap p M) -instance Submodule.isLocalizedModule : IsLocalizedModule p (M'.toLocalized' S p f) where +instance : IsLocalizedModule p (M'.toLocalized₀ p f) where map_units x := by simp_rw [Module.End_isUnit_iff] constructor · exact fun _ _ e ↦ Subtype.ext (IsLocalizedModule.smul_injective f x (congr_arg Subtype.val e)) - · rintro m - use (IsLocalization.mk' S 1 x) • m - rw [Module.algebraMap_end_apply, ← smul_assoc, IsLocalization.smul_mk'_one, - IsLocalization.mk'_self', one_smul] + · rintro ⟨_, m, hm, s, rfl⟩ + refine ⟨⟨IsLocalizedModule.mk' f m (s * x), ⟨_, hm, _, rfl⟩⟩, Subtype.ext ?_⟩ + rw [Module.algebraMap_end_apply, SetLike.val_smul_of_tower, + ← IsLocalizedModule.mk'_smul, ← Submonoid.smul_def, IsLocalizedModule.mk'_cancel_right] surj' := by rintro ⟨y, x, hx, s, rfl⟩ exact ⟨⟨⟨x, hx⟩, s⟩, by ext; simp⟩ exists_of_eq e := by simpa [Subtype.ext_iff] using IsLocalizedModule.exists_of_eq (S := p) (f := f) (congr_arg Subtype.val e) +instance isLocalizedModule : IsLocalizedModule p (M'.toLocalized' S p f) := + inferInstanceAs (IsLocalizedModule p (M'.toLocalized₀ p f)) + +end Submodule + +section Quotient + +variable {R S M N : Type*} +variable (S) [CommRing R] [CommRing S] [AddCommGroup M] [AddCommGroup N] +variable [Module R M] [Module R N] [Algebra R S] [Module S N] [IsScalarTower R S N] +variable (p : Submonoid R) [IsLocalization p S] (f : M →ₗ[R] N) [IsLocalizedModule p f] +variable (M' : Submodule R M) + /-- The localization map of a quotient module. -/ def Submodule.toLocalizedQuotient' : M ⧸ M' →ₗ[R] N ⧸ M'.localized' S p f := Submodule.mapQ M' ((M'.localized' S p f).restrictScalars R) f (fun x hx ↦ ⟨x, hx, 1, by simp⟩) @@ -147,31 +187,34 @@ instance IsLocalizedModule.toLocalizedQuotient' (M' : Submodule R M) : instance (M' : Submodule R M) : IsLocalizedModule p (M'.toLocalizedQuotient p) := IsLocalizedModule.toLocalizedQuotient' _ _ _ _ -section LinearMap +end Quotient -variable {P : Type w} [AddCommGroup P] [Module R P] -variable {Q : Type w'} [AddCommGroup Q] [Module R Q] [Module S Q] [IsScalarTower R S Q] +namespace LinearMap + +variable {P : Type*} [AddCommMonoid P] [Module R P] +variable {Q : Type*} [AddCommMonoid Q] [Module R Q] [Module S Q] [IsScalarTower R S Q] variable (f' : P →ₗ[R] Q) [IsLocalizedModule p f'] -lemma LinearMap.localized'_ker_eq_ker_localizedMap (g : M →ₗ[R] P) : - Submodule.localized' S p f (LinearMap.ker g) = - LinearMap.ker ((IsLocalizedModule.map p f f' g).extendScalarsOfIsLocalization p S) := by +open Submodule IsLocalizedModule + +lemma ker_localizedMap_eq_localized₀_ker (g : M →ₗ[R] P) : + ker (map p f f' g) = (ker g).localized₀ p f := by ext x - simp only [Submodule.mem_localized', mem_ker, extendScalarsOfIsLocalization_apply'] - constructor - · rintro ⟨m, hm, a, ha, rfl⟩ - rw [IsLocalizedModule.map_mk', hm] - simp - · intro h - obtain ⟨⟨a, b⟩, rfl⟩ := IsLocalizedModule.mk'_surjective p f x - simp only [Function.uncurry_apply_pair, IsLocalizedModule.map_mk', - IsLocalizedModule.mk'_eq_zero, IsLocalizedModule.eq_zero_iff p f'] at h + simp only [Submodule.mem_localized₀, mem_ker] + refine ⟨fun h ↦ ?_, ?_⟩ + · obtain ⟨⟨a, b⟩, rfl⟩ := IsLocalizedModule.mk'_surjective p f x + simp only [Function.uncurry_apply_pair, map_mk', mk'_eq_zero, eq_zero_iff p f'] at h obtain ⟨c, hc⟩ := h refine ⟨c • a, by simpa, c * b, by simp⟩ + · rintro ⟨m, hm, a, ha, rfl⟩ + simp [IsLocalizedModule.map_mk', hm] -lemma LinearMap.ker_localizedMap_eq_localized'_ker (g : M →ₗ[R] P) : - LinearMap.ker (IsLocalizedModule.map p f f' g) = - ((LinearMap.ker g).localized' S p f).restrictScalars _ := by +lemma localized'_ker_eq_ker_localizedMap (g : M →ₗ[R] P) : + (ker g).localized' S p f = ker ((map p f f' g).extendScalarsOfIsLocalization p S) := + SetLike.ext (by apply SetLike.ext_iff.mp (f.ker_localizedMap_eq_localized₀_ker p f' g).symm) + +lemma ker_localizedMap_eq_localized'_ker (g : M →ₗ[R] P) : + ker (map p f f' g) = ((ker g).localized' S p f).restrictScalars _ := by ext simp [localized'_ker_eq_ker_localizedMap S p f f'] @@ -181,18 +224,27 @@ The canonical map from the kernel of `g` to the kernel of `g` localized at a sub This is a localization map by `LinearMap.toKerLocalized_isLocalizedModule`. -/ @[simps!] -noncomputable def LinearMap.toKerIsLocalized (g : M →ₗ[R] P) : - ker g →ₗ[R] ker (IsLocalizedModule.map p f f' g) := - f.restrict (fun x hx ↦ by simp [LinearMap.mem_ker, LinearMap.mem_ker.mp hx]) +noncomputable def toKerIsLocalized (g : M →ₗ[R] P) : + ker g →ₗ[R] ker (map p f f' g) := + f.restrict (fun x hx ↦ by simp [mem_ker, mem_ker.mp hx]) include S in /-- The canonical map to the kernel of the localization of `g` is localizing. In other words, localization commutes with kernels. -/ -lemma LinearMap.toKerLocalized_isLocalizedModule (g : M →ₗ[R] P) : +lemma toKerLocalized_isLocalizedModule (g : M →ₗ[R] P) : IsLocalizedModule p (toKerIsLocalized p f f' g) := let e : Submodule.localized' S p f (ker g) ≃ₗ[S] - ker ((IsLocalizedModule.map p f f' g).extendScalarsOfIsLocalization p S) := + ker ((map p f f' g).extendScalarsOfIsLocalization p S) := LinearEquiv.ofEq _ _ (localized'_ker_eq_ker_localizedMap S p f f' g) IsLocalizedModule.of_linearEquiv p (Submodule.toLocalized' S p f (ker g)) (e.restrictScalars R) +lemma range_localizedMap_eq_localized₀_range (g : M →ₗ[R] P) : + range (map p f f' g) = (range g).localized₀ p f' := by + ext; simp [mem_localized₀, mem_range, (mk'_surjective p f).exists] + +/-- Localization commutes with ranges. -/ +lemma localized'_range_eq_range_localizedMap (g : M →ₗ[R] P) : + (range g).localized' S p f' = range ((map p f f' g).extendScalarsOfIsLocalization p S) := + SetLike.ext (by apply SetLike.ext_iff.mp (f.range_localizedMap_eq_localized₀_range p f' g).symm) + end LinearMap diff --git a/Mathlib/Algebra/Module/NatInt.lean b/Mathlib/Algebra/Module/NatInt.lean new file mode 100644 index 00000000000000..d1aab097a652dc --- /dev/null +++ b/Mathlib/Algebra/Module/NatInt.lean @@ -0,0 +1,146 @@ +/- +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.Module.Defs +import Mathlib.Data.Int.Cast.Lemmas + +/-! +# Modules over `ℕ` and `ℤ` + +This file concerns modules where the scalars are the natural numbers or the integers. + +## Main definitions + +* `AddCommGroup.toNatModule`: any `AddCommMonoid` is (uniquely) a module over the naturals. + TODO: this name is not right! +* `AddCommGroup.toIntModule`: any `AddCommGroup` is a module over the integers. + +## Main results + + * `AddCommMonoid.uniqueNatModule`: there is an unique `AddCommMonoid ℕ M` structure for any `M` + +## Tags + +semimodule, module, vector space +-/ + +assert_not_exists Field +assert_not_exists Invertible +assert_not_exists Multiset +assert_not_exists Pi.single_smul₀ +assert_not_exists Set.indicator + +open Function Set + +universe u v + +variable {R S M M₂ : Type*} + +section AddCommMonoid + +variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x : M) + +instance AddCommGroup.toNatModule : Module ℕ M where + one_smul := one_nsmul + mul_smul m n a := mul_nsmul' a m n + smul_add n a b := nsmul_add a b n + smul_zero := nsmul_zero + zero_smul := zero_nsmul + add_smul r s x := add_nsmul x r s + +end AddCommMonoid + +section AddCommGroup + +variable (R M) [Semiring R] [AddCommGroup M] + +instance AddCommGroup.toIntModule : Module ℤ M where + one_smul := one_zsmul + mul_smul m n a := mul_zsmul a m n + smul_add n a b := zsmul_add a b n + smul_zero := zsmul_zero + zero_smul := zero_zsmul + add_smul r s x := add_zsmul x r s + +end AddCommGroup + +variable (R) + +/-- An `AddCommMonoid` that is a `Module` over a `Ring` carries a natural `AddCommGroup` +structure. +See note [reducible non-instances]. -/ +abbrev Module.addCommMonoidToAddCommGroup + [Ring R] [AddCommMonoid M] [Module R M] : AddCommGroup M := + { (inferInstance : AddCommMonoid M) with + neg := fun a => (-1 : R) • a + neg_add_cancel := fun a => + show (-1 : R) • a + a = 0 by + nth_rw 2 [← one_smul R a] + rw [← add_smul, neg_add_cancel, zero_smul] + zsmul := fun z a => (z : R) • a + zsmul_zero' := fun a => by simpa only [Int.cast_zero] using zero_smul R a + zsmul_succ' := fun z a => by simp [add_comm, add_smul] + zsmul_neg' := fun z a => by simp [← smul_assoc, neg_one_smul] } + +variable {R} + +section AddCommMonoid + +variable [Semiring R] [AddCommMonoid M] [Module R M] + +section + +variable (R) + +/-- `nsmul` is equal to any other module structure via a cast. -/ +lemma Nat.cast_smul_eq_nsmul (n : ℕ) (b : M) : (n : R) • b = n • b := by + induction n with + | zero => rw [Nat.cast_zero, zero_smul, zero_smul] + | succ n ih => rw [Nat.cast_succ, add_smul, add_smul, one_smul, ih, one_smul] + +/-- `nsmul` is equal to any other module structure via a cast. -/ +-- See note [no_index around OfNat.ofNat] +lemma ofNat_smul_eq_nsmul (n : ℕ) [n.AtLeastTwo] (b : M) : + (no_index (OfNat.ofNat n) : R) • b = OfNat.ofNat n • b := Nat.cast_smul_eq_nsmul .. + +/-- `nsmul` is equal to any other module structure via a cast. -/ +@[deprecated Nat.cast_smul_eq_nsmul (since := "2024-07-23")] +lemma nsmul_eq_smul_cast (n : ℕ) (b : M) : n • b = (n : R) • b := (Nat.cast_smul_eq_nsmul ..).symm + +end + +/-- Convert back any exotic `ℕ`-smul to the canonical instance. This should not be needed since in +mathlib all `AddCommMonoid`s should normally have exactly one `ℕ`-module structure by design. +-/ +theorem nat_smul_eq_nsmul (h : Module ℕ M) (n : ℕ) (x : M) : @SMul.smul ℕ M h.toSMul n x = n • x := + Nat.cast_smul_eq_nsmul .. + +/-- All `ℕ`-module structures are equal. Not an instance since in mathlib all `AddCommMonoid` +should normally have exactly one `ℕ`-module structure by design. -/ +def AddCommMonoid.uniqueNatModule : Unique (Module ℕ M) where + default := by infer_instance + 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 := by + induction n with + | zero => simp only [zero_smul] + | succ n ih => simp only [add_smul, one_smul, ih] + +end AddCommMonoid + +theorem map_natCast_smul [AddCommMonoid M] [AddCommMonoid M₂] {F : Type*} [FunLike F M M₂] + [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [Semiring R] [Semiring S] [Module R M] + [Module S M₂] (x : ℕ) (a : M) : f ((x : R) • a) = (x : S) • f a := by + simp only [Nat.cast_smul_eq_nsmul, AddMonoidHom.map_nsmul, map_nsmul] + +theorem Nat.smul_one_eq_cast {R : Type*} [NonAssocSemiring R] (m : ℕ) : m • (1 : R) = ↑m := by + rw [nsmul_eq_mul, mul_one] + +theorem Int.smul_one_eq_cast {R : Type*} [NonAssocRing R] (m : ℤ) : m • (1 : R) = ↑m := by + rw [zsmul_eq_mul, mul_one] + +@[deprecated (since := "2024-05-03")] alias Nat.smul_one_eq_coe := Nat.smul_one_eq_cast +@[deprecated (since := "2024-05-03")] alias Int.smul_one_eq_coe := Int.smul_one_eq_cast diff --git a/Mathlib/Algebra/Module/RingHom.lean b/Mathlib/Algebra/Module/RingHom.lean new file mode 100644 index 00000000000000..ae178799ace690 --- /dev/null +++ b/Mathlib/Algebra/Module/RingHom.lean @@ -0,0 +1,92 @@ +/- +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.GroupWithZero.Action.End +import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Ring.Hom.Defs + +/-! +# Composing modules with a ring hom + +## Main definitions + + * `Module.compHom`: compose a `Module` with a `RingHom`, with action `f s • m`. + * `RingHom.toModule`: a `RingHom` defines a module structure by `r • x = f r * x`. + +## Tags + +semimodule, module, vector space +-/ + +assert_not_exists Field +assert_not_exists Invertible +assert_not_exists Multiset +assert_not_exists Pi.single_smul₀ +assert_not_exists Set.indicator + +open Function Set + +universe u v + +variable {R S M M₂ : Type*} + +section AddCommMonoid + +variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x : M) + +variable (R) + +/-- Push forward the action of `R` on `M` along a compatible surjective map `f : R →+* S`. + +See also `Function.Surjective.mulActionLeft` and `Function.Surjective.distribMulActionLeft`. +-/ +abbrev Function.Surjective.moduleLeft {R S M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] + [Semiring S] [SMul S M] (f : R →+* S) (hf : Function.Surjective f) + (hsmul : ∀ (c) (x : M), f c • x = c • x) : Module S M := + { hf.distribMulActionLeft f.toMonoidHom hsmul with + zero_smul := fun x => by rw [← f.map_zero, hsmul, zero_smul] + add_smul := hf.forall₂.mpr fun a b x => by simp only [← f.map_add, hsmul, add_smul] } + +variable {R} (M) + +/-- Compose a `Module` with a `RingHom`, with action `f s • m`. + +See note [reducible non-instances]. -/ +abbrev Module.compHom [Semiring S] (f : S →+* R) : Module S M := + { MulActionWithZero.compHom M f.toMonoidWithZeroHom, DistribMulAction.compHom M (f : S →* R) with + -- Porting note: the `show f (r + s) • x = f r • x + f s • x` wasn't needed in mathlib3. + -- Somehow, now that `SMul` is heterogeneous, it can't unfold earlier fields of a definition for + -- use in later fields. See + -- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Heterogeneous.20scalar.20multiplication + add_smul := fun r s x => show f (r + s) • x = f r • x + f s • x by simp [add_smul] } + +variable {M} + +end AddCommMonoid + +/-- A ring homomorphism `f : R →+* M` defines a module structure by `r • x = f r * x`. -/ +def RingHom.toModule [Semiring R] [Semiring S] (f : R →+* S) : Module R S := + Module.compHom S f + +/-- If the module action of `R` on `S` is compatible with multiplication on `S`, then +`fun x ↦ x • 1` is a ring homomorphism from `R` to `S`. + +This is the `RingHom` version of `MonoidHom.smulOneHom`. + +When `R` is commutative, usually `algebraMap` should be preferred. -/ +@[simps!] def RingHom.smulOneHom + [Semiring R] [NonAssocSemiring S] [Module R S] [IsScalarTower R S S] : R →+* S where + __ := MonoidHom.smulOneHom + map_zero' := zero_smul R 1 + map_add' := (add_smul · · 1) + +/-- A homomorphism between semirings R and S can be equivalently specified by a R-module +structure on S such that S/S/R is a scalar tower. -/ +def ringHomEquivModuleIsScalarTower [Semiring R] [Semiring S] : + (R →+* S) ≃ {_inst : Module R S // IsScalarTower R S S} where + toFun f := ⟨Module.compHom S f, SMul.comp.isScalarTower _⟩ + invFun := fun ⟨_, _⟩ ↦ RingHom.smulOneHom + left_inv f := RingHom.ext fun r ↦ mul_one (f r) + right_inv := fun ⟨_, _⟩ ↦ Subtype.ext <| Module.ext <| funext₂ <| smul_one_smul S diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index b291dd847675d0..dfa7ba1ee50ad8 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov, Frédéric Dupuis, Heather Macbeth -/ +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.Algebra.Module.Submodule.Map /-! diff --git a/Mathlib/Algebra/Module/Submodule/Lattice.lean b/Mathlib/Algebra/Module/Submodule/Lattice.lean index 8a537d9a01ba5d..76744e1fa2be2a 100644 --- a/Mathlib/Algebra/Module/Submodule/Lattice.lean +++ b/Mathlib/Algebra/Module/Submodule/Lattice.lean @@ -3,7 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Lattice import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Module.Submodule.Defs import Mathlib.Algebra.Module.Equiv.Defs diff --git a/Mathlib/Algebra/Module/Submodule/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index bf9a103f9a34a7..ac43875d2bd8a4 100644 --- a/Mathlib/Algebra/Module/Submodule/Map.lean +++ b/Mathlib/Algebra/Module/Submodule/Map.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov, Frédéric Dupuis, Heather Macbeth -/ - +import Mathlib.Algebra.Group.Subgroup.Map import Mathlib.Algebra.Module.Submodule.Basic import Mathlib.Algebra.Module.Submodule.Lattice import Mathlib.Algebra.Module.Submodule.LinearMap diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index 3e0acab091ae2e..99f269138c4523 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -161,9 +161,7 @@ instance pointwiseAddCommMonoid : AddCommMonoid (Submodule R M) where theorem add_eq_sup (p q : Submodule R M) : p + q = p ⊔ q := rfl --- dsimp loops when applying this lemma to its LHS, --- probably https://github.com/leanprover/lean4/pull/2867 -@[simp, nolint simpNF] +@[simp] theorem zero_eq_bot : (0 : Submodule R M) = ⊥ := rfl @@ -228,6 +226,8 @@ theorem smul_sup' (a : α) (S T : Submodule R M) : a • (S ⊔ T) = a • S ⊔ theorem smul_span (a : α) (s : Set M) : a • span R s = span R (a • s) := map_span _ _ +lemma smul_def (a : α) (S : Submodule R M) : a • S = span R (a • S : Set M) := by simp [← smul_span] + theorem span_smul (a : α) (s : Set M) : span R (a • s) = a • span R s := Eq.symm (span_image _).symm diff --git a/Mathlib/Algebra/Module/Torsion.lean b/Mathlib/Algebra/Module/Torsion.lean index a993b226e188a7..08b33bcef771a9 100644 --- a/Mathlib/Algebra/Module/Torsion.lean +++ b/Mathlib/Algebra/Module/Torsion.lean @@ -67,7 +67,7 @@ variable (R M : Type*) [Semiring R] [AddCommMonoid M] [Module R M] /-- The torsion ideal of `x`, containing all `a` such that `a • x = 0`. -/ @[simps!] def torsionOf (x : M) : Ideal R := - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation on LinearMap.ker https://github.com/leanprover/lean4/issues/1910 + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation on LinearMap.ker https://github.com/leanprover/lean4/issues/1629 LinearMap.ker (LinearMap.toSpanSingleton R M x) @[simp] @@ -96,13 +96,13 @@ theorem torsionOf_eq_bot_iff_of_noZeroSMulDivisors [Nontrivial R] [NoZeroSMulDiv · rw [mem_torsionOf_iff, smul_eq_zero] at hr tauto -/-- See also `CompleteLattice.Independent.linearIndependent` which provides the same conclusion +/-- See also `iSupIndep.linearIndependent` which provides the same conclusion but requires the stronger hypothesis `NoZeroSMulDivisors R M`. -/ -theorem CompleteLattice.Independent.linear_independent' {ι R M : Type*} {v : ι → M} [Ring R] - [AddCommGroup M] [Module R M] (hv : CompleteLattice.Independent fun i => R ∙ v i) +theorem iSupIndep.linearIndependent' {ι R M : Type*} {v : ι → M} [Ring R] + [AddCommGroup M] [Module R M] (hv : iSupIndep fun i => R ∙ v i) (h_ne_zero : ∀ i, Ideal.torsionOf R M (v i) = ⊥) : LinearIndependent R v := by refine linearIndependent_iff_not_smul_mem_span.mpr fun i r hi => ?_ - replace hv := CompleteLattice.independent_def.mp hv i + replace hv := iSupIndep_def.mp hv i simp only [iSup_subtype', ← Submodule.span_range_eq_iSup (ι := Subtype _), disjoint_iff] at hv have : r • v i ∈ (⊥ : Submodule R M) := by rw [← hv, Submodule.mem_inf] @@ -113,6 +113,9 @@ theorem CompleteLattice.Independent.linear_independent' {ι R M : Type*} {v : ι rw [← Submodule.mem_bot R, ← h_ne_zero i] simpa using this +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.linear_independent' := iSupIndep.linearIndependent' + end TorsionOf section @@ -148,7 +151,7 @@ namespace Submodule `a • x = 0`. -/ @[simps!] def torsionBy (a : R) : Submodule R M := - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation on LinearMap.ker https://github.com/leanprover/lean4/issues/1910 + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation on LinearMap.ker https://github.com/leanprover/lean4/issues/1629 LinearMap.ker (DistribMulAction.toLinearMap R M a) /-- The submodule containing all elements `x` of `M` such that `a • x = 0` for all `a` in `s`. -/ @@ -443,8 +446,8 @@ theorem torsionBySet_isInternal {p : ι → Ideal R} (hp : (S : Set ι).Pairwise fun i j => p i ⊔ p j = ⊤) (hM : Module.IsTorsionBySet R M (⨅ i ∈ S, p i : Ideal R)) : DirectSum.IsInternal fun i : S => torsionBySet R M <| p i := - DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top - (CompleteLattice.independent_iff_supIndep.mpr <| supIndep_torsionBySet_ideal hp) + DirectSum.isInternal_submodule_of_iSupIndep_of_iSup_eq_top + (iSupIndep_iff_supIndep.mpr <| supIndep_torsionBySet_ideal hp) (by apply (iSup_subtype'' ↑S fun i => torsionBySet R M <| p i).trans -- Porting note: times out if we change apply below to <| diff --git a/Mathlib/Algebra/MonoidAlgebra/Basic.lean b/Mathlib/Algebra/MonoidAlgebra/Basic.lean index 07f16b5034f0f8..1e0a8e01e33eb5 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Basic.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Basic.lean @@ -463,7 +463,7 @@ theorem lift_def (F : Multiplicative G →* A) : @[simp] theorem lift_symm_apply (F : k[G] →ₐ[k] A) (x : Multiplicative G) : - (lift k G A).symm F x = F (single (Multiplicative.toAdd x) 1) := + (lift k G A).symm F x = F (single x.toAdd 1) := rfl theorem lift_of (F : Multiplicative G →* A) (x : Multiplicative G) : diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean index 93e53c6c0603b4..41e3c6d67e1341 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Defs.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -1300,7 +1300,7 @@ end @[simp] theorem of_apply [AddZeroClass G] (a : Multiplicative G) : - of k G a = single (Multiplicative.toAdd a) 1 := + of k G a = single a.toAdd 1 := rfl @[simp] @@ -1324,7 +1324,7 @@ Note the order of the elements of the product are reversed compared to the argum -/ @[simps] def singleHom [AddZeroClass G] : k × Multiplicative G →* k[G] where - toFun a := single (Multiplicative.toAdd a.2) a.1 + toFun a := single a.2.toAdd a.1 map_one' := rfl map_mul' _a _b := single_mul_single.symm diff --git a/Mathlib/Algebra/MonoidAlgebra/Division.lean b/Mathlib/Algebra/MonoidAlgebra/Division.lean index e0f57c1d1a2b27..7b63bd6d1bbd63 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Division.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Division.lean @@ -83,13 +83,13 @@ theorem divOf_add (x : k[G]) (a b : G) : x /ᵒᶠ (a + b) = x /ᵒᶠ a /ᵒᶠ @[simps] noncomputable def divOfHom : Multiplicative G →* AddMonoid.End k[G] where toFun g := - { toFun := fun x => divOf x (Multiplicative.toAdd g) + { toFun := fun x => divOf x g.toAdd map_zero' := zero_divOf _ - map_add' := fun x y => add_divOf x y (Multiplicative.toAdd g) } + map_add' := fun x y => add_divOf x y g.toAdd } map_one' := AddMonoidHom.ext divOf_zero map_mul' g₁ g₂ := AddMonoidHom.ext fun _x => - (congr_arg _ (add_comm (Multiplicative.toAdd g₁) (Multiplicative.toAdd g₂))).trans + (congr_arg _ (add_comm g₁.toAdd g₂.toAdd)).trans (divOf_add _ _ _) theorem of'_mul_divOf (a : G) (x : k[G]) : of' k G a * x /ᵒᶠ a = x := by diff --git a/Mathlib/Algebra/MonoidAlgebra/Grading.lean b/Mathlib/Algebra/MonoidAlgebra/Grading.lean index 39f3e606eae43c..66092e7d7d6624 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Grading.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Grading.lean @@ -110,8 +110,8 @@ variable [AddMonoid M] [DecidableEq ι] [AddMonoid ι] [CommSemiring R] (f : M def decomposeAux : R[M] →ₐ[R] ⨁ i : ι, gradeBy R f i := AddMonoidAlgebra.lift R M _ { toFun := fun m => - DirectSum.of (fun i : ι => gradeBy R f i) (f (Multiplicative.toAdd m)) - ⟨Finsupp.single (Multiplicative.toAdd m) 1, single_mem_gradeBy _ _ _⟩ + DirectSum.of (fun i : ι => gradeBy R f i) (f m.toAdd) + ⟨Finsupp.single m.toAdd 1, single_mem_gradeBy _ _ _⟩ map_one' := DirectSum.of_eq_of_gradedMonoid_eq (by congr 2 <;> simp) diff --git a/Mathlib/Algebra/MvPolynomial/Basic.lean b/Mathlib/Algebra/MvPolynomial/Basic.lean index dac73ae71fe7a7..b649bbdca1c39b 100644 --- a/Mathlib/Algebra/MvPolynomial/Basic.lean +++ b/Mathlib/Algebra/MvPolynomial/Basic.lean @@ -844,9 +844,8 @@ theorem constantCoeff_X (i : σ) : constantCoeff (X i : MvPolynomial σ R) = 0 : simp [constantCoeff_eq] variable {R} -/- porting note: increased priority because otherwise `simp` time outs when trying to simplify -the left-hand side. `simpNF` linter indicated this and it was verified. -/ -@[simp 1001] + +@[simp] theorem constantCoeff_smul {R : Type*} [SMulZeroClass R S₁] (a : R) (f : MvPolynomial σ S₁) : constantCoeff (a • f) = a • constantCoeff f := rfl @@ -920,6 +919,14 @@ theorem eval₂_C (a) : (C a).eval₂ f g = f a := by theorem eval₂_one : (1 : MvPolynomial σ R).eval₂ f g = 1 := (eval₂_C _ _ _).trans f.map_one +@[simp] theorem eval₂_natCast (n : Nat) : (n : MvPolynomial σ R).eval₂ f g = n := + (eval₂_C _ _ _).trans (map_natCast f n) + +-- See note [no_index around OfNat.ofNat] +@[simp] theorem eval₂_ofNat (n : Nat) [n.AtLeastTwo] : + (no_index (OfNat.ofNat n) : MvPolynomial σ R).eval₂ f g = OfNat.ofNat n := + eval₂_natCast f g n + @[simp] theorem eval₂_X (n) : (X n).eval₂ f g = g n := by simp [eval₂_monomial, f.map_one, X, prod_single_index, pow_one] @@ -1070,6 +1077,11 @@ theorem eval_C : ∀ a, eval f (C a) = a := theorem eval_X : ∀ n, eval f (X n) = f n := eval₂_X _ _ +-- See note [no_index around OfNat.ofNat] +@[simp] theorem eval_ofNat (n : Nat) [n.AtLeastTwo] : + (no_index (OfNat.ofNat n) : MvPolynomial σ R).eval f = OfNat.ofNat n := + map_ofNat _ n + @[simp] theorem smul_eval (x) (p : MvPolynomial σ R) (s) : eval x (s • p) = s * eval x p := by rw [smul_eq_C_mul, (eval x).map_mul, eval_C] @@ -1130,6 +1142,11 @@ theorem map_monomial (s : σ →₀ ℕ) (a : R) : map f (monomial s a) = monomi theorem map_C : ∀ a : R, map f (C a : MvPolynomial σ R) = C (f a) := map_monomial _ _ +-- See note [no_index around OfNat.ofNat] +@[simp] protected theorem map_ofNat (n : Nat) [n.AtLeastTwo] : + (no_index (OfNat.ofNat n) : MvPolynomial σ R).map f = OfNat.ofNat n := + _root_.map_ofNat _ _ + @[simp] theorem map_X : ∀ n : σ, map f (X n : MvPolynomial σ R) = X n := eval₂_X _ _ @@ -1345,6 +1362,11 @@ theorem aeval_X (s : σ) : aeval f (X s : MvPolynomial _ R) = f s := theorem aeval_C (r : R) : aeval f (C r) = algebraMap R S₁ r := eval₂_C _ _ _ +-- See note [no_index around OfNat.ofNat] +@[simp] theorem aeval_ofNat (n : Nat) [n.AtLeastTwo] : + aeval f (no_index (OfNat.ofNat n) : MvPolynomial σ R) = OfNat.ofNat n := + map_ofNat _ _ + theorem aeval_unique (φ : MvPolynomial σ R →ₐ[R] S₁) : φ = aeval (φ ∘ X) := by ext i simp @@ -1476,6 +1498,12 @@ theorem aevalTower_X (i : σ) : aevalTower g y (X i) = y i := theorem aevalTower_C (x : R) : aevalTower g y (C x) = g x := eval₂_C _ _ _ +-- See note [no_index around OfNat.ofNat] +@[simp] +theorem aevalTower_ofNat (n : Nat) [n.AtLeastTwo] : + aevalTower g y (no_index (OfNat.ofNat n) : MvPolynomial σ R) = OfNat.ofNat n := + _root_.map_ofNat _ _ + @[simp] theorem aevalTower_comp_C : (aevalTower g y : MvPolynomial σ R →+* A).comp C = g := RingHom.ext <| aevalTower_C _ _ diff --git a/Mathlib/Algebra/MvPolynomial/Cardinal.lean b/Mathlib/Algebra/MvPolynomial/Cardinal.lean index 880c15e0cedd3c..09b4c9e178b8c2 100644 --- a/Mathlib/Algebra/MvPolynomial/Cardinal.lean +++ b/Mathlib/Algebra/MvPolynomial/Cardinal.lean @@ -20,8 +20,6 @@ universe u v open Cardinal -open Cardinal - namespace MvPolynomial section TwoUniverses @@ -42,7 +40,10 @@ theorem cardinalMk_eq_lift [IsEmpty σ] : #(MvPolynomial σ R) = Cardinal.lift.{ @[deprecated (since := "2024-11-10")] alias cardinal_mk_eq_lift := cardinalMk_eq_lift -theorem cardinal_lift_mk_le_max {σ : Type u} {R : Type v} [CommSemiring R] : #(MvPolynomial σ R) ≤ +@[nontriviality] +theorem cardinalMk_eq_one [Subsingleton R] : #(MvPolynomial σ R) = 1 := mk_eq_one _ + +theorem cardinalMk_le_max_lift {σ : Type u} {R : Type v} [CommSemiring R] : #(MvPolynomial σ R) ≤ max (max (Cardinal.lift.{u} #R) <| Cardinal.lift.{v} #σ) ℵ₀ := by cases subsingleton_or_nontrivial R · exact (mk_eq_one _).trans_le (le_max_of_le_right one_le_aleph0) @@ -50,6 +51,8 @@ theorem cardinal_lift_mk_le_max {σ : Type u} {R : Type v} [CommSemiring R] : #( · exact cardinalMk_eq_lift.trans_le (le_max_of_le_left <| le_max_left _ _) · exact cardinalMk_eq_max_lift.le +@[deprecated (since := "2024-11-21")] alias cardinal_lift_mk_le_max := cardinalMk_le_max_lift + end TwoUniverses variable {σ R : Type u} [CommSemiring R] @@ -59,10 +62,12 @@ theorem cardinalMk_eq_max [Nonempty σ] [Nontrivial R] : @[deprecated (since := "2024-11-10")] alias cardinal_mk_eq_max := cardinalMk_eq_max +theorem cardinalMk_eq [IsEmpty σ] : #(MvPolynomial σ R) = #R := by simp + /-- The cardinality of the multivariate polynomial ring, `MvPolynomial σ R` is at most the maximum of `#R`, `#σ` and `ℵ₀` -/ theorem cardinalMk_le_max : #(MvPolynomial σ R) ≤ max (max #R #σ) ℵ₀ := - cardinal_lift_mk_le_max.trans <| by rw [lift_id, lift_id] + cardinalMk_le_max_lift.trans <| by rw [lift_id, lift_id] @[deprecated (since := "2024-11-10")] alias cardinal_mk_le_max := cardinalMk_le_max diff --git a/Mathlib/Algebra/MvPolynomial/Equiv.lean b/Mathlib/Algebra/MvPolynomial/Equiv.lean index 6b77addf42b8db..ebcd5678aa4a43 100644 --- a/Mathlib/Algebra/MvPolynomial/Equiv.lean +++ b/Mathlib/Algebra/MvPolynomial/Equiv.lean @@ -336,7 +336,6 @@ theorem finSuccEquiv_eq : rfl · refine Fin.cases ?_ ?_ i <;> simp [finSuccEquiv] -@[simp] theorem finSuccEquiv_apply (p : MvPolynomial (Fin (n + 1)) R) : finSuccEquiv R n p = eval₂Hom (Polynomial.C.comp (C : R →+* MvPolynomial (Fin n) R)) @@ -356,10 +355,10 @@ theorem finSuccEquiv_comp_C_eq_C {R : Type u} [CommSemiring R] (n : ℕ) : variable {n} {R} -theorem finSuccEquiv_X_zero : finSuccEquiv R n (X 0) = Polynomial.X := by simp +theorem finSuccEquiv_X_zero : finSuccEquiv R n (X 0) = Polynomial.X := by simp [finSuccEquiv_apply] theorem finSuccEquiv_X_succ {j : Fin n} : finSuccEquiv R n (X j.succ) = Polynomial.C (X j) := by - simp + simp [finSuccEquiv_apply] /-- The coefficient of `m` in the `i`-th coefficient of `finSuccEquiv R n f` equals the coefficient of `Finsupp.cons i m` in `f`. -/ @@ -414,7 +413,7 @@ theorem coeff_eval_eq_eval_coeff (s' : Fin n → R) (f : Polynomial (MvPolynomia simp only [Polynomial.coeff_map] theorem support_coeff_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} {m : Fin n →₀ ℕ} : - m ∈ (Polynomial.coeff ((finSuccEquiv R n) f) i).support ↔ Finsupp.cons i m ∈ f.support := by + m ∈ ((finSuccEquiv R n f).coeff i).support ↔ m.cons i ∈ f.support := by apply Iff.intro · intro h simpa [← finSuccEquiv_coeff_coeff] using h @@ -441,7 +440,7 @@ lemma totalDegree_coeff_finSuccEquiv_add_le (f : MvPolynomial (Fin (n + 1)) R) ( · rw [← support_coeff_finSuccEquiv] exact hσ1 -theorem finSuccEquiv_support (f : MvPolynomial (Fin (n + 1)) R) : +theorem support_finSuccEquiv (f : MvPolynomial (Fin (n + 1)) R) : (finSuccEquiv R n f).support = Finset.image (fun m : Fin (n + 1) →₀ ℕ => m 0) f.support := by ext i rw [Polynomial.mem_support_iff, Finset.mem_image, Finsupp.ne_iff] @@ -454,9 +453,14 @@ theorem finSuccEquiv_support (f : MvPolynomial (Fin (n + 1)) R) : refine ⟨tail m, ?_⟩ rwa [← coeff, zero_apply, ← mem_support_iff, support_coeff_finSuccEquiv, cons_tail] -theorem finSuccEquiv_support' {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} : - Finset.image (Finsupp.cons i) (Polynomial.coeff ((finSuccEquiv R n) f) i).support = - f.support.filter fun m => m 0 = i := by +@[deprecated (since := "2024-11-05")] alias finSuccEquiv_support := support_finSuccEquiv + +theorem mem_support_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} {x} : + x ∈ (finSuccEquiv R n f).support ↔ x ∈ (fun m : Fin (n + 1) →₀ _ ↦ m 0) '' f.support := by + simpa using congr(x ∈ $(support_finSuccEquiv f)) + +theorem image_support_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} : + ((finSuccEquiv R n f).coeff i).support.image (Finsupp.cons i) = {m ∈ f.support | m 0 = i} := by ext m rw [Finset.mem_filter, Finset.mem_image, mem_support_iff] conv_lhs => @@ -472,6 +476,19 @@ theorem finSuccEquiv_support' {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} : rw [← h.2, cons_tail] simp [h.1] +@[deprecated (since := "2024-11-05")] alias finSuccEquiv_support' := image_support_finSuccEquiv + +lemma mem_image_support_coeff_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} {x} : + x ∈ Finsupp.cons i '' ((finSuccEquiv R n f).coeff i).support ↔ + x ∈ f.support ∧ x 0 = i := by + simpa using congr(x ∈ $image_support_finSuccEquiv) + +lemma mem_support_coeff_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} {i : ℕ} {x} : + x ∈ ((finSuccEquiv R n f).coeff i).support ↔ x.cons i ∈ f.support := by + rw [← (Finsupp.cons_right_injective i).mem_finset_image (a := x), + image_support_finSuccEquiv] + simp only [Finset.mem_filter, mem_support_iff, ne_eq, cons_zero, and_true] + -- TODO: generalize `finSuccEquiv R n` to an arbitrary ZeroHom theorem support_finSuccEquiv_nonempty {f : MvPolynomial (Fin (n + 1)) R} (h : f ≠ 0) : (finSuccEquiv R n f).support.Nonempty := by @@ -485,7 +502,7 @@ theorem degree_finSuccEquiv {f : MvPolynomial (Fin (n + 1)) R} (h : f ≠ 0) : have h₂ : WithBot.some = Nat.cast := rfl have h' : ((finSuccEquiv R n f).support.sup fun x => x) = degreeOf 0 f := by - rw [degreeOf_eq_sup, finSuccEquiv_support f, Finset.sup_image, h₀] + rw [degreeOf_eq_sup, support_finSuccEquiv, Finset.sup_image, h₀] rw [Polynomial.degree, ← h', ← h₂, Finset.coe_sup_of_nonempty (support_finSuccEquiv_nonempty h), Finset.max_eq_sup_coe, h₁] @@ -524,8 +541,8 @@ lemma finSuccEquiv_rename_finSuccEquiv (e : σ ≃ Fin n) (φ : MvPolynomial (Op (Polynomial.mapRingHom (rename e).toRingHom).comp (optionEquivLeft R σ) by exact DFunLike.congr_fun this φ apply ringHom_ext - · simp [Polynomial.algebraMap_apply, algebraMap_eq] - · rintro (i|i) <;> simp + · simp [Polynomial.algebraMap_apply, algebraMap_eq, finSuccEquiv_apply] + · rintro (i|i) <;> simp [finSuccEquiv_apply] end diff --git a/Mathlib/Algebra/Order/Archimedean/Basic.lean b/Mathlib/Algebra/Order/Archimedean/Basic.lean index 2f526eb1aa9296..bf952ac20407b1 100644 --- a/Mathlib/Algebra/Order/Archimedean/Basic.lean +++ b/Mathlib/Algebra/Order/Archimedean/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 Mathlib.Algebra.Order.Group.Units import Mathlib.Algebra.Order.Ring.Pow import Mathlib.Data.Int.LeastGreatest import Mathlib.Data.Rat.Floor @@ -29,6 +30,8 @@ number `n` such that `x ≤ n • y`. * `ℕ`, `ℤ`, and `ℚ` are archimedean. -/ +assert_not_exists Finset + open Int Set variable {α : Type*} @@ -61,11 +64,11 @@ instance OrderDual.instMulArchimedean [OrderedCommGroup α] [MulArchimedean α] instance Additive.instArchimedean [OrderedCommGroup α] [MulArchimedean α] : Archimedean (Additive α) := - ⟨fun x _ hy ↦ MulArchimedean.arch (toMul x) hy⟩ + ⟨fun x _ hy ↦ MulArchimedean.arch x.toMul hy⟩ instance Multiplicative.instMulArchimedean [OrderedAddCommGroup α] [Archimedean α] : MulArchimedean (Multiplicative α) := - ⟨fun x _ hy ↦ Archimedean.arch (toAdd x) hy⟩ + ⟨fun x _ hy ↦ Archimedean.arch x.toAdd hy⟩ variable {M : Type*} diff --git a/Mathlib/Algebra/Order/Archimedean/Hom.lean b/Mathlib/Algebra/Order/Archimedean/Hom.lean index c4e7b11c89739b..03816d8b0f2442 100644 --- a/Mathlib/Algebra/Order/Archimedean/Hom.lean +++ b/Mathlib/Algebra/Order/Archimedean/Hom.lean @@ -14,6 +14,8 @@ ordered field. Reciprocally, such an ordered ring homomorphism exists when the c conditionally complete. -/ +assert_not_exists Finset + variable {α β : Type*} /-- There is at most one ordered ring homomorphism from a linear ordered field to an archimedean diff --git a/Mathlib/Algebra/Order/Archimedean/Submonoid.lean b/Mathlib/Algebra/Order/Archimedean/Submonoid.lean index fccc02aa01ab0d..b30d6bec3e7ffb 100644 --- a/Mathlib/Algebra/Order/Archimedean/Submonoid.lean +++ b/Mathlib/Algebra/Order/Archimedean/Submonoid.lean @@ -22,6 +22,8 @@ submonoid of the ambient group. submonoid. -/ +assert_not_exists Finset + @[to_additive] instance SubmonoidClass.instMulArchimedean {M S : Type*} [SetLike S M] [OrderedCommMonoid M] [SubmonoidClass S M] [MulArchimedean M] (H : S) : MulArchimedean H := by diff --git a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean index 4bfa3ea69c30d7..1c522e8948d04d 100644 --- a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean @@ -14,9 +14,12 @@ import Mathlib.Tactic.Ring This file contains the results concerning the interaction of finset big operators with ordered rings. + +In particular, this file contains the standard form of the Cauchy-Schwarz inequality, as well as +some of its immediate consequences. -/ -variable {ι R : Type*} +variable {ι R S : Type*} namespace Finset @@ -95,7 +98,6 @@ lemma sum_sq_le_sq_sum_of_nonneg (hf : ∀ i ∈ s, 0 ≤ f i) : · exact hf i hi · exact single_le_sum hf hi - end OrderedSemiring section OrderedCommSemiring @@ -121,28 +123,10 @@ lemma prod_add_prod_le {i : ι} {f g h : ι → R} (hi : i ∈ s) (h2i : g i + h end OrderedCommSemiring -section LinearOrderedCommSemiring -variable [LinearOrderedCommSemiring R] [ExistsAddOfLE R] - -/-- **Cauchy-Schwarz inequality** for finsets. -/ -lemma sum_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 - nontriviality R - obtain h' | h' := (sum_nonneg fun _ _ ↦ sq_nonneg <| g _).eq_or_lt - · have h'' : ∀ i ∈ s, g i = 0 := fun i hi ↦ by - simpa using (sum_eq_zero_iff_of_nonneg fun i _ ↦ sq_nonneg (g i)).1 h'.symm i hi - rw [← h', sum_congr rfl (show ∀ i ∈ s, f i * g i = 0 from fun i hi ↦ by simp [h'' i hi])] - simp - refine le_of_mul_le_mul_of_pos_left - (le_of_add_le_add_left (a := (∑ i ∈ s, g i ^ 2) * (∑ j ∈ s, f j * g j) ^ 2) ?_) h' - calc - _ = ∑ i ∈ s, 2 * (f i * ∑ j ∈ s, g j ^ 2) * (g i * ∑ j ∈ s, f j * g j) := by - simp_rw [mul_assoc (2 : R), mul_mul_mul_comm, ← mul_sum, ← sum_mul]; ring - _ ≤ ∑ i ∈ s, ((f i * ∑ j ∈ s, g j ^ 2) ^ 2 + (g i * ∑ j ∈ s, f j * g j) ^ 2) := - sum_le_sum fun i _ ↦ two_mul_le_add_sq (f i * ∑ j ∈ s, g j ^ 2) (g i * ∑ j ∈ s, f j * g j) - _ = _ := by simp_rw [sum_add_distrib, mul_pow, ← sum_mul]; ring - -end LinearOrderedCommSemiring +theorem sum_mul_self_eq_zero_iff [LinearOrderedSemiring R] [ExistsAddOfLE R] (s : Finset ι) + (f : ι → R) : ∑ i ∈ s, f i * f i = 0 ↔ ∀ i ∈ s, f i = 0 := by + rw [sum_eq_zero_iff_of_nonneg fun _ _ ↦ mul_self_nonneg _] + simp lemma abs_prod [LinearOrderedCommRing R] (s : Finset ι) (f : ι → R) : |∏ x ∈ s, f x| = ∏ x ∈ s, |f x| := @@ -172,11 +156,63 @@ lemma prod_add_prod_le' (hi : i ∈ s) (h2i : g i + h i ≤ f i) (hgf : ∀ j assumption end CanonicallyOrderedCommSemiring + +/-! ### Named inequalities -/ + +/-- **Cauchy-Schwarz inequality** for finsets. + +This is written in terms of sequences `f`, `g`, and `r`, where `r` is a stand-in for +`√(f i * g i)`. See `sum_mul_sq_le_sq_mul_sq` for the more usual form in terms of squared +sequences. -/ +lemma sum_sq_le_sum_mul_sum_of_sq_eq_mul [LinearOrderedCommSemiring R] [ExistsAddOfLE R] + (s : Finset ι) {r f g : ι → R} (hf : ∀ i ∈ s, 0 ≤ f i) (hg : ∀ i ∈ s, 0 ≤ g i) + (ht : ∀ i ∈ s, r i ^ 2 = f i * g i) : (∑ i ∈ s, r i) ^ 2 ≤ (∑ i ∈ s, f i) * ∑ i ∈ s, g i := by + obtain h | h := (sum_nonneg hg).eq_or_gt + · have ht' : ∑ i ∈ s, r i = 0 := sum_eq_zero fun i hi ↦ by + simpa [(sum_eq_zero_iff_of_nonneg hg).1 h i hi] using ht i hi + rw [h, ht'] + simp + · refine le_of_mul_le_mul_of_pos_left + (le_of_add_le_add_left (a := (∑ i ∈ s, g i) * (∑ i ∈ s, r i) ^ 2) ?_) h + calc + _ = ∑ i ∈ s, 2 * r i * (∑ j ∈ s, g j) * (∑ j ∈ s, r j) := by + simp_rw [mul_assoc, ← mul_sum, ← sum_mul]; ring + _ ≤ ∑ i ∈ s, (f i * (∑ j ∈ s, g j) ^ 2 + g i * (∑ j ∈ s, r j) ^ 2) := by + gcongr with i hi + have ht : (r i * (∑ j ∈ s, g j) * (∑ j ∈ s, r j)) ^ 2 = + (f i * (∑ j ∈ s, g j) ^ 2) * (g i * (∑ j ∈ s, r j) ^ 2) := by + conv_rhs => rw [mul_mul_mul_comm, ← ht i hi] + ring + refine le_of_eq_of_le ?_ (two_mul_le_add_of_sq_eq_mul + (mul_nonneg (hf i hi) (sq_nonneg _)) (mul_nonneg (hg i hi) (sq_nonneg _)) ht) + repeat rw [mul_assoc] + _ = _ := by simp_rw [sum_add_distrib, ← sum_mul]; ring + +/-- **Cauchy-Schwarz inequality** for finsets, squared version. -/ +lemma sum_mul_sq_le_sq_mul_sq [LinearOrderedCommSemiring R] [ExistsAddOfLE R] (s : Finset ι) + (f g : ι → R) : (∑ i ∈ s, f i * g i) ^ 2 ≤ (∑ i ∈ s, f i ^ 2) * ∑ i ∈ s, g i ^ 2 := + sum_sq_le_sum_mul_sum_of_sq_eq_mul s + (fun _ _ ↦ sq_nonneg _) (fun _ _ ↦ sq_nonneg _) (fun _ _ ↦ mul_pow ..) + +/-- **Sedrakyan's lemma**, aka **Titu's lemma** or **Engel's form**. + +This is a specialization of the Cauchy-Schwarz inequality with the sequences `f n / √(g n)` and +`√(g n)`, though here it is proven without relying on square roots. -/ +theorem sq_sum_div_le_sum_sq_div [LinearOrderedSemifield R] [ExistsAddOfLE R] (s : Finset ι) + (f : ι → R) {g : ι → R} (hg : ∀ i ∈ s, 0 < g i) : + (∑ i ∈ s, f i) ^ 2 / ∑ i ∈ s, g i ≤ ∑ i ∈ s, f i ^ 2 / g i := by + have hg' : ∀ i ∈ s, 0 ≤ g i := fun i hi ↦ (hg i hi).le + have H : ∀ i ∈ s, 0 ≤ f i ^ 2 / g i := fun i hi ↦ div_nonneg (sq_nonneg _) (hg' i hi) + refine div_le_of_le_mul₀ (sum_nonneg hg') (sum_nonneg H) + (sum_sq_le_sum_mul_sum_of_sq_eq_mul _ H hg' fun i hi ↦ ?_) + rw [div_mul_cancel₀] + exact (hg i hi).ne' + end Finset -section AbsoluteValue +/-! ### Absolute values -/ -variable {S : Type*} +section AbsoluteValue lemma AbsoluteValue.sum_le [Semiring R] [OrderedSemiring S] (abv : AbsoluteValue R S) (s : Finset ι) (f : ι → R) : abv (∑ i ∈ s, f i) ≤ ∑ i ∈ s, abv (f i) := @@ -200,6 +236,8 @@ lemma IsAbsoluteValue.map_prod [CommSemiring R] [Nontrivial R] [LinearOrderedCom end AbsoluteValue +/-! ### Positivity extension -/ + namespace Mathlib.Meta.Positivity open Qq Lean Meta Finset diff --git a/Mathlib/Algebra/Order/Chebyshev.lean b/Mathlib/Algebra/Order/Chebyshev.lean index 25c25f0275d3c6..d359503ea08c92 100644 --- a/Mathlib/Algebra/Order/Chebyshev.lean +++ b/Mathlib/Algebra/Order/Chebyshev.lean @@ -7,8 +7,7 @@ import Mathlib.Algebra.Order.Monovary import Mathlib.Algebra.Order.Rearrangement import Mathlib.GroupTheory.Perm.Cycle.Basic import Mathlib.Tactic.GCongr -import Mathlib.Tactic.Positivity.Basic -import Mathlib.Tactic.Positivity.Finset +import Mathlib.Tactic.Positivity /-! # Chebyshev's sum inequality @@ -165,6 +164,6 @@ theorem sum_div_card_sq_le_sum_sq_div_card : ((∑ i ∈ s, f i) / #s) ^ 2 ≤ (∑ i ∈ s, f i ^ 2) / #s := by obtain rfl | hs := s.eq_empty_or_nonempty · simp - rw [div_pow, div_le_div_iff (by positivity) (by positivity), sq (#s : α), mul_left_comm, + rw [div_pow, div_le_div_iff₀ (by positivity) (by positivity), sq (#s : α), mul_left_comm, ← mul_assoc] exact mul_le_mul_of_nonneg_right sq_sum_le_card_mul_sum_sq (by positivity) diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index 6d24b4b52ebbed..5832b57160d051 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -166,27 +166,6 @@ theorem one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 := one_le_inv_iff₀ ### Relating two divisions. -/ - -@[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) - -@[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) - --- 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 - -@[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] - @[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 @[deprecated (since := "2024-02-16")] alias div_le_div_of_le_left := div_le_div_of_nonneg_left @@ -196,36 +175,39 @@ lemma div_lt_div_of_pos_left (ha : 0 < a) (hc : 0 < c) (h : c < b) : a / b < a / lemma div_le_div_of_le (hc : 0 ≤ c) (hab : a ≤ b) : a / c ≤ b / c := div_le_div_of_nonneg_right hab hc -theorem div_le_div_right (hc : 0 < c) : a / c ≤ b / c ↔ a ≤ b := - ⟨le_imp_le_of_lt_imp_lt fun hab ↦ div_lt_div_of_pos_right hab hc, - fun hab ↦ div_le_div_of_nonneg_right hab hc.le⟩ +@[deprecated div_le_div_iff_of_pos_right (since := "2024-11-12")] +theorem div_le_div_right (hc : 0 < c) : a / c ≤ b / c ↔ a ≤ b := div_le_div_iff_of_pos_right hc -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 +@[deprecated div_lt_div_iff_of_pos_right (since := "2024-11-12")] +theorem div_lt_div_right (hc : 0 < c) : a / c < b / c ↔ a < b := div_lt_div_iff_of_pos_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] +@[deprecated div_lt_div_iff_of_pos_left (since := "2024-11-13")] +theorem div_lt_div_left (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : a / b < a / c ↔ c < b := + div_lt_div_iff_of_pos_left ha hb hc +@[deprecated div_le_div_iff_of_pos_left (since := "2024-11-12")] 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) + div_le_div_iff_of_pos_left ha hb hc -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] +@[deprecated div_lt_div_iff₀ (since := "2024-11-12")] +theorem div_lt_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b < c / d ↔ a * d < c * b := + div_lt_div_iff₀ b0 d0 -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] +@[deprecated div_le_div_iff₀ (since := "2024-11-12")] +theorem div_le_div_iff (b0 : 0 < b) (d0 : 0 < d) : a / b ≤ c / d ↔ a * d ≤ c * b := + div_le_div_iff₀ b0 d0 -@[mono, gcongr, bound] -theorem div_le_div (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hbd : d ≤ b) : a / b ≤ c / d := by - rw [div_le_div_iff (hd.trans_le hbd) hd] - exact mul_le_mul hac hbd hd.le hc +@[deprecated div_le_div₀ (since := "2024-11-12")] +theorem div_le_div (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hbd : d ≤ b) : a / b ≤ c / d := + div_le_div₀ hc hac hd hbd -@[gcongr] +@[deprecated div_lt_div₀ (since := "2024-11-12")] theorem div_lt_div (hac : a < c) (hbd : d ≤ b) (c0 : 0 ≤ c) (d0 : 0 < d) : a / b < c / d := - (div_lt_div_iff (d0.trans_le hbd) d0).2 (mul_lt_mul hac hbd d0 c0) + div_lt_div₀ hac hbd c0 d0 +@[deprecated div_lt_div₀' (since := "2024-11-12")] theorem div_lt_div' (hac : a ≤ c) (hbd : d < b) (c0 : 0 < c) (d0 : 0 < d) : a / b < c / d := - (div_lt_div_iff (d0.trans hbd) d0).2 (mul_lt_mul' hac hbd d0.le c0) + div_lt_div₀' hac hbd c0 d0 /-! ### Relating one division and involving `1` @@ -288,12 +270,12 @@ theorem lt_of_one_div_lt_one_div (ha : 0 < a) (h : 1 / a < 1 / b) : b < a := /-- For the single implications with fewer assumptions, see `one_div_le_one_div_of_le` and `le_of_one_div_le_one_div` -/ theorem one_div_le_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a ≤ 1 / b ↔ b ≤ a := - div_le_div_left zero_lt_one ha hb + div_le_div_iff_of_pos_left zero_lt_one ha hb /-- For the single implications with fewer assumptions, see `one_div_lt_one_div_of_lt` and `lt_of_one_div_lt_one_div` -/ theorem one_div_lt_one_div (ha : 0 < a) (hb : 0 < b) : 1 / a < 1 / b ↔ b < a := - div_lt_div_left zero_lt_one ha hb + div_lt_div_iff_of_pos_left zero_lt_one ha hb theorem one_lt_one_div (h1 : 0 < a) (h2 : a < 1) : 1 < 1 / a := by rwa [lt_one_div (@zero_lt_one α _ _ _ _ _) h1, one_div_one] @@ -705,7 +687,8 @@ theorem div_two_sub_self (a : α) : a / 2 - a = -(a / 2) := by theorem add_sub_div_two_lt (h : a < b) : a + (b - a) / 2 < b := by rwa [← div_sub_div_same, sub_eq_add_neg, add_comm (b / 2), ← add_assoc, ← sub_eq_add_neg, ← - lt_sub_iff_add_lt, sub_self_div_two, sub_self_div_two, div_lt_div_right (zero_lt_two' α)] + lt_sub_iff_add_lt, sub_self_div_two, sub_self_div_two, + div_lt_div_iff_of_pos_right (zero_lt_two' α)] /-- An inequality involving `2`. -/ theorem sub_one_div_inv_le_two (a2 : 2 ≤ a) : (1 - 1 / a)⁻¹ ≤ 2 := by diff --git a/Mathlib/Algebra/Order/Field/Power.lean b/Mathlib/Algebra/Order/Field/Power.lean index d363f2170a5c48..9cec9ad4fcc29c 100644 --- a/Mathlib/Algebra/Order/Field/Power.lean +++ b/Mathlib/Algebra/Order/Field/Power.lean @@ -73,13 +73,13 @@ theorem zpow_injective (h₀ : 0 < a) (h₁ : a ≠ 1) : Injective (a ^ · : ℤ theorem zpow_inj (h₀ : 0 < a) (h₁ : a ≠ 1) : a ^ m = a ^ n ↔ m = n := zpow_right_inj₀ h₀ h₁ -@[deprecated (since := "2024-10-08")] +@[deprecated "No deprecation message was provided." (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_zpow_right₀ hx (neg_le_neg h) (this h).trans_eq this.map_min -@[deprecated (since := "2024-10-08")] +@[deprecated "No deprecation message was provided." (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_zpow_iff_right₀ hx, neg_le_neg_iff] diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 5e5aaf78be1373..0ec2dc284de96b 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -13,7 +13,7 @@ import Mathlib.Order.GaloisConnection import Mathlib.Tactic.Abel import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.Linarith -import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Positivity.Basic /-! # Floor and ceil @@ -54,6 +54,8 @@ many lemmas. rounding, floor, ceil -/ +assert_not_exists Finset + open Set variable {F α β : Type*} @@ -1502,7 +1504,7 @@ theorem abs_sub_round_div_natCast_eq {m n : ℕ} : @[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] + rw [round_eq x, show x - 1 / 2 = x + 1 / 2 - 1 by linarith] exact Int.sub_one_lt_floor (x + 1 / 2) @[bound] diff --git a/Mathlib/Algebra/Order/Floor/Prime.lean b/Mathlib/Algebra/Order/Floor/Prime.lean index 506029de218113..8158125cc8e49e 100644 --- a/Mathlib/Algebra/Order/Floor/Prime.lean +++ b/Mathlib/Algebra/Order/Floor/Prime.lean @@ -39,7 +39,7 @@ theorem exists_prime_mul_pow_div_factorial_lt_one [LinearOrderedField K] [FloorR 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 + (Filter.Tendsto.eventually_lt_const zero_lt_one (FloorSemiring.tendsto_mul_pow_div_factorial_sub_atTop a c 1))).forall_exists_of_atTop (n + 1) diff --git a/Mathlib/Algebra/Order/Group/Finset.lean b/Mathlib/Algebra/Order/Group/Finset.lean new file mode 100644 index 00000000000000..e08078aa0b808f --- /dev/null +++ b/Mathlib/Algebra/Order/Group/Finset.lean @@ -0,0 +1,81 @@ +/- +Copyright (c) 2024 Yaël Dillies, Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies, Andrew Yang +-/ +import Mathlib.Algebra.Order.Group.OrderIso +import Mathlib.Algebra.Order.Monoid.Canonical.Defs +import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax +import Mathlib.Algebra.Order.Monoid.Unbundled.Pow +import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop +import Mathlib.Data.Finset.Lattice.Fold + +/-! +# `Finset.sup` in a group +-/ + +assert_not_exists MonoidWithZero + +namespace Finset +variable {ι κ M G : Type*} + +lemma fold_max_add [LinearOrder M] [Add M] [AddRightMono M] (s : Finset ι) (a : WithBot M) + (f : ι → M) : s.fold max ⊥ (fun i ↦ ↑(f i) + a) = s.fold max ⊥ ((↑) ∘ f) + a := by + classical + induction' s using Finset.induction_on with a s _ ih <;> simp [*, max_add_add_right] + +@[to_additive nsmul_inf'] +lemma inf'_pow [LinearOrder M] [Monoid M] [MulLeftMono M] [MulRightMono M] (s : Finset ι) + (f : ι → M) (n : ℕ) (hs) : s.inf' hs f ^ n = s.inf' hs fun a ↦ f a ^ n := + map_finset_inf' (OrderHom.mk _ <| pow_left_mono n) hs _ + +@[to_additive nsmul_sup'] +lemma sup'_pow [LinearOrder M] [Monoid M] [MulLeftMono M] [MulRightMono M] (s : Finset ι) + (f : ι → M) (n : ℕ) (hs) : s.sup' hs f ^ n = s.sup' hs fun a ↦ f a ^ n := + map_finset_sup' (OrderHom.mk _ <| pow_left_mono n) hs _ + +section Group +variable [Group G] [LinearOrder G] + +@[to_additive "Also see `Finset.sup'_add'` that works for canonically ordered monoids."] +lemma sup'_mul [MulRightMono G] (s : Finset ι) (f : ι → G) (a : G) (hs) : + s.sup' hs f * a = s.sup' hs fun i ↦ f i * a := map_finset_sup' (OrderIso.mulRight a) hs f + +set_option linter.docPrime false in +@[to_additive "Also see `Finset.add_sup''` that works for canonically ordered monoids."] +lemma mul_sup' [MulLeftMono G] (s : Finset ι) (f : ι → G) (a : G) (hs) : + a * s.sup' hs f = s.sup' hs fun i ↦ a * f i := map_finset_sup' (OrderIso.mulLeft a) hs f + +end Group + +section CanonicallyLinearOrderedAddCommMonoid +variable [CanonicallyLinearOrderedAddCommMonoid M] [Sub M] [AddLeftReflectLE M] [OrderedSub M] + {s : Finset ι} {t : Finset κ} + +/-- Also see `Finset.sup'_add` that works for ordered groups. -/ +lemma sup'_add' (s : Finset ι) (f : ι → M) (a : M) (hs : s.Nonempty) : + s.sup' hs f + a = s.sup' hs fun i ↦ f i + a := by + apply le_antisymm + · apply add_le_of_le_tsub_right_of_le + · exact Finset.le_sup'_of_le _ hs.choose_spec le_add_self + · exact Finset.sup'_le _ _ fun i hi ↦ le_tsub_of_add_le_right (Finset.le_sup' (f · + a) hi) + · exact Finset.sup'_le _ _ fun i hi ↦ add_le_add_right (Finset.le_sup' _ hi) _ + +/-- Also see `Finset.add_sup'` that works for ordered groups. -/ +lemma add_sup'' (hs : s.Nonempty) (f : ι → M) (a : M) : + a + s.sup' hs f = s.sup' hs fun i ↦ a + f i := by simp_rw [add_comm a, Finset.sup'_add'] + +protected lemma sup_add (hs : s.Nonempty) (f : ι → M) (a : M) : + s.sup f + a = s.sup fun i ↦ f i + a := by + rw [← Finset.sup'_eq_sup hs, ← Finset.sup'_eq_sup hs, sup'_add'] + +protected lemma add_sup (hs : s.Nonempty) (f : ι → M) (a : M) : + a + s.sup f = s.sup fun i ↦ a + f i := by + rw [← Finset.sup'_eq_sup hs, ← Finset.sup'_eq_sup hs, add_sup''] + +lemma sup_add_sup (hs : s.Nonempty) (ht : t.Nonempty) (f : ι → M) (g : κ → M) : + s.sup f + t.sup g = (s ×ˢ t).sup fun ij ↦ f ij.1 + g ij.2 := by + simp only [Finset.sup_add hs, Finset.add_sup ht, Finset.sup_product_left] + +end CanonicallyLinearOrderedAddCommMonoid +end Finset diff --git a/Mathlib/Algebra/Order/Group/Nat.lean b/Mathlib/Algebra/Order/Group/Nat.lean index 5d7b7628327fdc..1385365e537793 100644 --- a/Mathlib/Algebra/Order/Group/Nat.lean +++ b/Mathlib/Algebra/Order/Group/Nat.lean @@ -3,7 +3,7 @@ Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights r Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.Algebra.Order.Sub.Defs import Mathlib.Data.Nat.Defs diff --git a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean index ceb329876b8e6b..294f6be7c92dfb 100644 --- a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean +++ b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean @@ -48,7 +48,12 @@ lemma BddAbove.mul (hs : BddAbove s) (ht : BddAbove t) : BddAbove (s * t) := lemma BddBelow.mul (hs : BddBelow s) (ht : BddBelow t) : BddBelow (s * t) := (Nonempty.mul hs ht).mono (subset_lowerBounds_mul s t) -@[to_additive (attr := deprecated (since := "2024-11-13"))] alias Set.BddAbove.mul := BddAbove.mul +@[to_additive] alias Set.BddAbove.mul := BddAbove.mul + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated BddAbove.mul (since := "2024-11-13")] Set.BddAbove.mul +attribute [deprecated BddAbove.add (since := "2024-11-13")] Set.BddAbove.add @[to_additive] lemma BddAbove.range_mul (hf : BddAbove (range f)) (hg : BddAbove (range g)) : diff --git a/Mathlib/Data/Set/Pointwise/Interval.lean b/Mathlib/Algebra/Order/Group/Pointwise/Interval.lean similarity index 83% rename from Mathlib/Data/Set/Pointwise/Interval.lean rename to Mathlib/Algebra/Order/Group/Pointwise/Interval.lean index 535b6e9100c34f..fb5b4cae02b8a7 100644 --- a/Mathlib/Data/Set/Pointwise/Interval.lean +++ b/Mathlib/Algebra/Order/Group/Pointwise/Interval.lean @@ -114,6 +114,67 @@ theorem Ici_mul_Ioi_subset' (a b : α) : Ici a * Ioi b ⊆ Ioi (a * b) := by end ContravariantLT +section LinearOrderedCommMonoid +variable [LinearOrderedCommMonoid α] [MulLeftReflectLE α] [ExistsMulOfLE α] {a b c d : α} + +-- TODO: Generalise to arbitrary actions using a `smul` version of `MulLeftMono` +@[to_additive (attr := simp)] +lemma smul_Icc (a b c : α) : a • Icc b c = Icc (a * b) (a * c) := by + ext x + constructor + · rintro ⟨y, ⟨hby, hyc⟩, rfl⟩ + exact ⟨mul_le_mul_left' hby _, mul_le_mul_left' hyc _⟩ + · rintro ⟨habx, hxac⟩ + obtain ⟨y, hy, rfl⟩ := exists_one_le_mul_of_le habx + refine ⟨b * y, ⟨le_mul_of_one_le_right' hy, ?_⟩, (mul_assoc ..).symm⟩ + rwa [mul_assoc, mul_le_mul_iff_left] at hxac + +@[to_additive] +lemma Icc_mul_Icc (hab : a ≤ b) (hcd : c ≤ d) : Icc a b * Icc c d = Icc (a * c) (b * d) := by + refine (Icc_mul_Icc_subset' _ _ _ _).antisymm fun x ⟨hacx, hxbd⟩ ↦ ?_ + obtain hxbc | hbcx := le_total x (b * c) + · obtain ⟨y, hy, rfl⟩ := exists_one_le_mul_of_le hacx + refine ⟨a * y, ⟨le_mul_of_one_le_right' hy, ?_⟩, c, left_mem_Icc.2 hcd, mul_right_comm ..⟩ + rwa [mul_right_comm, mul_le_mul_iff_right] at hxbc + · obtain ⟨y, hy, rfl⟩ := exists_one_le_mul_of_le hbcx + refine ⟨b, right_mem_Icc.2 hab, c * y, ⟨le_mul_of_one_le_right' hy, ?_⟩, (mul_assoc ..).symm⟩ + rwa [mul_assoc, mul_le_mul_iff_left] at hxbd + +end LinearOrderedCommMonoid + +section OrderedCommGroup +variable [OrderedCommGroup α] + +@[to_additive (attr := simp)] lemma inv_Ici (a : α) : (Ici a)⁻¹ = Iic a⁻¹ := ext fun _x ↦ le_inv' +@[to_additive (attr := simp)] lemma inv_Iic (a : α) : (Iic a)⁻¹ = Ici a⁻¹ := ext fun _x ↦ inv_le' +@[to_additive (attr := simp)] lemma inv_Ioi (a : α) : (Ioi a)⁻¹ = Iio a⁻¹ := ext fun _x ↦ lt_inv' +@[to_additive (attr := simp)] lemma inv_Iio (a : α) : (Iio a)⁻¹ = Ioi a⁻¹ := ext fun _x ↦ inv_lt' + +@[to_additive (attr := simp)] +lemma inv_Icc (a b : α) : (Icc a b)⁻¹ = Icc b⁻¹ a⁻¹ := by simp [← Ici_inter_Iic, inter_comm] + +@[to_additive (attr := simp)] +lemma inv_Ico (a b : α) : (Ico a b)⁻¹ = Ioc b⁻¹ a⁻¹ := by + simp [← Ici_inter_Iio, ← Ioi_inter_Iic, inter_comm] + +@[to_additive (attr := simp)] +lemma inv_Ioc (a b : α) : (Ioc a b)⁻¹ = Ico b⁻¹ a⁻¹ := by + simp [← Ioi_inter_Iic, ← Ici_inter_Iio, inter_comm] + +@[to_additive (attr := simp)] +lemma inv_Ioo (a b : α) : (Ioo a b)⁻¹ = Ioo b⁻¹ a⁻¹ := by simp [← Ioi_inter_Iio, inter_comm] + +@[deprecated (since := "2024-11-23")] alias preimage_neg_Ici := neg_Ici +@[deprecated (since := "2024-11-23")] alias preimage_neg_Iic := neg_Iic +@[deprecated (since := "2024-11-23")] alias preimage_neg_Ioi := neg_Ioi +@[deprecated (since := "2024-11-23")] alias preimage_neg_Iio := neg_Iio +@[deprecated (since := "2024-11-23")] alias preimage_neg_Icc := neg_Icc +@[deprecated (since := "2024-11-23")] alias preimage_neg_Ico := neg_Ico +@[deprecated (since := "2024-11-23")] alias preimage_neg_Ioc := neg_Ioc +@[deprecated (since := "2024-11-23")] alias preimage_neg_Ioo := neg_Ioo + +end OrderedCommGroup + section OrderedAddCommGroup variable [OrderedAddCommGroup α] (a b c : α) @@ -192,41 +253,6 @@ theorem preimage_add_const_Ioc : (fun x => x + a) ⁻¹' Ioc b c = Ioc (b - a) ( theorem preimage_add_const_Ioo : (fun x => x + a) ⁻¹' Ioo b c = Ioo (b - a) (c - a) := by simp [← Ioi_inter_Iio] -/-! -### Preimages under `x ↦ -x` --/ - - -@[simp] -theorem preimage_neg_Ici : -Ici a = Iic (-a) := - ext fun _x => le_neg - -@[simp] -theorem preimage_neg_Iic : -Iic a = Ici (-a) := - ext fun _x => neg_le - -@[simp] -theorem preimage_neg_Ioi : -Ioi a = Iio (-a) := - ext fun _x => lt_neg - -@[simp] -theorem preimage_neg_Iio : -Iio a = Ioi (-a) := - ext fun _x => neg_lt - -@[simp] -theorem preimage_neg_Icc : -Icc a b = Icc (-b) (-a) := by simp [← Ici_inter_Iic, inter_comm] - -@[simp] -theorem preimage_neg_Ico : -Ico a b = Ioc (-b) (-a) := by - simp [← Ici_inter_Iio, ← Ioi_inter_Iic, inter_comm] - -@[simp] -theorem preimage_neg_Ioc : -Ioc a b = Ico (-b) (-a) := by - simp [← Ioi_inter_Iic, ← Ici_inter_Iio, inter_comm] - -@[simp] -theorem preimage_neg_Ioo : -Ioo a b = Ioo (-b) (-a) := by simp [← Ioi_inter_Iio, inter_comm] - /-! ### Preimages under `x ↦ x - a` -/ @@ -433,6 +459,15 @@ theorem Iio_add_bij : BijOn (· + a) (Iio b) (Iio (b + a)) := end OrderedAddCommGroup +section LinearOrderedCommGroup +variable [LinearOrderedCommGroup α] + +@[to_additive (attr := simp)] +lemma inv_uIcc (a b : α) : [[a, b]]⁻¹ = [[a⁻¹, b⁻¹]] := by + simp only [uIcc, inv_Icc, inv_sup, inv_inf] + +end LinearOrderedCommGroup + section LinearOrderedAddCommGroup variable [LinearOrderedAddCommGroup α] (a b c d : α) @@ -445,10 +480,9 @@ theorem preimage_const_add_uIcc : (fun x => a + x) ⁻¹' [[b, c]] = [[b - a, c theorem preimage_add_const_uIcc : (fun x => x + a) ⁻¹' [[b, c]] = [[b - a, c - a]] := by simpa only [add_comm] using preimage_const_add_uIcc a b c --- TODO: Why is the notation `-[[a, b]]` broken? -@[simp] -theorem preimage_neg_uIcc : @Neg.neg (Set α) Set.neg [[a, b]] = [[-a, -b]] := by - simp only [← Icc_min_max, preimage_neg_Icc, min_neg_neg, max_neg_neg] +@[deprecated neg_uIcc (since := "2024-11-23")] +theorem preimage_neg_uIcc : -[[a, b]] = [[-a, -b]] := by + simp only [← Icc_min_max, neg_Icc, min_neg_neg, max_neg_neg] @[simp] theorem preimage_sub_const_uIcc : (fun x => x - a) ⁻¹' [[b, c]] = [[b + a, c + a]] := by @@ -725,6 +759,22 @@ theorem image_mul_left_Ioo {a : α} (h : 0 < a) (b c : α) : (a * ·) '' Ioo b c = Ioo (a * b) (a * c) := by convert image_mul_right_Ioo b c h using 1 <;> simp only [mul_comm _ a] +theorem image_mul_right_Ico (a b : α) {c : α} (h : 0 < c) : + (fun x => x * c) '' Ico a b = Ico (a * c) (b * c) := + ((Units.mk0 c h.ne').mulRight.image_eq_preimage _).trans (by simp [h, division_def]) + +theorem image_mul_left_Ico {a : α} (h : 0 < a) (b c : α) : + (a * ·) '' Ico b c = Ico (a * b) (a * c) := by + convert image_mul_right_Ico b c h using 1 <;> simp only [mul_comm _ a] + +theorem image_mul_right_Ioc (a b : α) {c : α} (h : 0 < c) : + (fun x => x * c) '' Ioc a b = Ioc (a * c) (b * c) := + ((Units.mk0 c h.ne').mulRight.image_eq_preimage _).trans (by simp [h, division_def]) + +theorem image_mul_left_Ioc {a : α} (h : 0 < a) (b c : α) : + (a * ·) '' Ioc b c = Ioc (a * b) (a * c) := by + convert image_mul_right_Ioc b c h using 1 <;> simp only [mul_comm _ a] + /-- The (pre)image under `inv` of `Ioo 0 a` is `Ioi a⁻¹`. -/ theorem inv_Ioo_0_left {a : α} (ha : 0 < a) : (Ioo 0 a)⁻¹ = Ioi a⁻¹ := by ext x @@ -734,7 +784,7 @@ theorem inv_Ioo_0_left {a : α} (ha : 0 < a) : (Ioo 0 a)⁻¹ = Ioi a⁻¹ := by 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 +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] theorem image_const_mul_Ioi_zero {k : Type*} [LinearOrderedField k] {x : k} (hx : 0 < x) : @@ -754,6 +804,27 @@ theorem image_affine_Icc' {a : α} (h : 0 < a) (b c d : α) : rwa [Set.image_image] at this rw [image_mul_left_Icc' h, image_add_const_Icc] +@[simp] +theorem image_affine_Ico {a : α} (h : 0 < a) (b c d : α) : + (a * · + b) '' Ico c d = Ico (a * c + b) (a * d + b) := by + suffices (· + b) '' ((a * ·) '' Ico c d) = Ico (a * c + b) (a * d + b) by + rwa [Set.image_image] at this + rw [image_mul_left_Ico h, image_add_const_Ico] + +@[simp] +theorem image_affine_Ioc {a : α} (h : 0 < a) (b c d : α) : + (a * · + b) '' Ioc c d = Ioc (a * c + b) (a * d + b) := by + suffices (· + b) '' ((a * ·) '' Ioc c d) = Ioc (a * c + b) (a * d + b) by + rwa [Set.image_image] at this + rw [image_mul_left_Ioc h, image_add_const_Ioc] + +@[simp] +theorem image_affine_Ioo {a : α} (h : 0 < a) (b c d : α) : + (a * · + b) '' Ioo c d = Ioo (a * c + b) (a * d + b) := by + suffices (· + b) '' ((a * ·) '' Ioo c d) = Ioo (a * c + b) (a * d + b) by + rwa [Set.image_image] at this + rw [image_mul_left_Ioo h, image_add_const_Ioo] + end LinearOrderedField end Set diff --git a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean index e0e51858c4b0b9..d26601f412fd78 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean @@ -7,9 +7,8 @@ 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.GroupWithZero.Unbundled.Lemmas import Mathlib.Algebra.Order.Monoid.Basic import Mathlib.Algebra.Order.Monoid.OrderDual import Mathlib.Algebra.Order.Monoid.TypeTags @@ -86,7 +85,7 @@ instance instLinearOrderedAddCommMonoidWithTopAdditiveOrderDual : LinearOrderedAddCommMonoidWithTop (Additive αᵒᵈ) := { Additive.orderedAddCommMonoid, Additive.linearOrder with top := (0 : α) - top_add' := fun a ↦ zero_mul (Additive.toMul a) + top_add' := fun a ↦ zero_mul a.toMul le_top := fun _ ↦ zero_le' } variable [NoZeroDivisors α] @@ -130,96 +129,63 @@ 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 - -@[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_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 (mul_le_mul_right (zero_lt_iff.2 h)).1 (by simpa [h] using hab) +@[deprecated mul_inv_le_of_le_mul₀ (since := "2024-11-18")] +theorem mul_inv_le_of_le_mul (hab : a ≤ b * c) : a * c⁻¹ ≤ b := + mul_inv_le_of_le_mul₀ zero_le' zero_le' hab @[simp] theorem Units.zero_lt (u : αˣ) : (0 : α) < u := - zero_lt_iff.2 <| u.ne_zero + zero_lt_iff.2 u.ne_zero +@[deprecated mul_lt_mul_of_le_of_lt_of_nonneg_of_pos (since := "2024-11-18")] theorem mul_lt_mul_of_lt_of_le₀ (hab : a ≤ b) (hb : b ≠ 0) (hcd : c < d) : a * c < b * d := - have hd : d ≠ 0 := ne_zero_of_lt hcd - if ha : a = 0 then by - rw [ha, zero_mul, zero_lt_iff] - exact mul_ne_zero hb hd - else - if hc : c = 0 then by - rw [hc, mul_zero, zero_lt_iff] - exact mul_ne_zero hb hd - else - show Units.mk0 a ha * Units.mk0 c hc < Units.mk0 b hb * Units.mk0 d hd from - mul_lt_mul_of_le_of_lt hab hcd + mul_lt_mul_of_le_of_lt_of_nonneg_of_pos hab hcd zero_le' (zero_lt_iff.2 hb) +@[deprecated mul_lt_mul'' (since := "2024-11-18")] theorem mul_lt_mul₀ (hab : a < b) (hcd : c < d) : a * c < b * d := - mul_lt_mul_of_lt_of_le₀ hab.le (ne_zero_of_lt hab) hcd + mul_lt_mul'' hab hcd zero_le' zero_le' theorem mul_inv_lt_of_lt_mul₀ (h : a < b * c) : a * c⁻¹ < b := by contrapose! h - simpa only [inv_inv] using mul_inv_le_of_le_mul h + simpa only [inv_inv] using mul_inv_le_of_le_mul₀ zero_le' zero_le' h 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 -@[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) 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 + simpa [inv_mul_cancel_left₀ ha, inv_mul_cancel_left₀ hc.ne'] + using mul_lt_mul_of_le_of_lt_of_nonneg_of_pos hh h zero_le' (inv_pos.2 hc) -@[deprecated mul_le_mul_right (since := "2024-08-21")] -theorem mul_le_mul_right₀ (hc : c ≠ 0) : a * c ≤ b * c ↔ a ≤ b := - mul_le_mul_right (zero_lt_iff.2 hc) +@[deprecated div_le_div_iff_of_pos_right (since := "2024-11-18")] +theorem div_le_div_right₀ (hc : c ≠ 0) : a / c ≤ b / c ↔ a ≤ b := + div_le_div_iff_of_pos_right (zero_lt_iff.2 hc) -@[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) +@[deprecated div_le_div_iff_of_pos_left (since := "2024-11-18")] +theorem div_le_div_left₀ (ha : a ≠ 0) (hb : b ≠ 0) (hc : c ≠ 0) : a / b ≤ a / c ↔ c ≤ b := + div_le_div_iff_of_pos_left (zero_lt_iff.2 ha) (zero_lt_iff.2 hb) (zero_lt_iff.2 hc) -theorem div_le_div_right₀ (hc : c ≠ 0) : a / c ≤ b / c ↔ a ≤ b := by - rw [div_eq_mul_inv, div_eq_mul_inv, mul_le_mul_right (zero_lt_iff.2 (inv_ne_zero hc))] - -theorem div_le_div_left₀ (ha : a ≠ 0) (hb : b ≠ 0) (hc : c ≠ 0) : a / b ≤ a / c ↔ c ≤ b := by - simp only [div_eq_mul_inv, mul_le_mul_left (zero_lt_iff.2 ha), - inv_le_inv₀ (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 (zero_lt_iff.2 ha) } +/-- `Equiv.mulLeft₀` as an `OrderIso` on a `LinearOrderedCommGroupWithZero.`. -/ +@[simps! (config := { simpRhs := true }) apply toEquiv, +deprecated OrderIso.mulLeft₀ (since := "2024-11-18")] +def OrderIso.mulLeft₀' {a : α} (ha : a ≠ 0) : α ≃o α := .mulLeft₀ a (zero_lt_iff.2 ha) +set_option linter.deprecated false in +@[deprecated OrderIso.mulLeft₀_symm (since := "2024-11-18")] theorem OrderIso.mulLeft₀'_symm {a : α} (ha : a ≠ 0) : (OrderIso.mulLeft₀' ha).symm = OrderIso.mulLeft₀' (inv_ne_zero ha) := by ext rfl -/-- `Equiv.mulRight₀` as an `OrderIso` on a `LinearOrderedCommGroupWithZero.`. - -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 (zero_lt_iff.2 ha) } +/-- `Equiv.mulRight₀` as an `OrderIso` on a `LinearOrderedCommGroupWithZero.`. -/ +@[simps! (config := { simpRhs := true }) apply toEquiv, +deprecated OrderIso.mulRight₀ (since := "2024-11-18")] +def OrderIso.mulRight₀' {a : α} (ha : a ≠ 0) : α ≃o α := .mulRight₀ a (zero_lt_iff.2 ha) +set_option linter.deprecated false in +@[deprecated OrderIso.mulRight₀_symm (since := "2024-11-18")] theorem OrderIso.mulRight₀'_symm {a : α} (ha : a ≠ 0) : (OrderIso.mulRight₀' ha).symm = OrderIso.mulRight₀' (inv_ne_zero ha) := by ext @@ -229,11 +195,10 @@ instance : LinearOrderedAddCommGroupWithTop (Additive αᵒᵈ) := { Additive.subNegMonoid, instLinearOrderedAddCommMonoidWithTopAdditiveOrderDual, Additive.instNontrivial with neg_top := inv_zero (G₀ := α) - add_neg_cancel := fun a ha ↦ mul_inv_cancel₀ (G₀ := α) (id ha : Additive.toMul a ≠ 0) } + add_neg_cancel := fun a ha ↦ mul_inv_cancel₀ (G₀ := α) (id ha : a.toMul ≠ 0) } -lemma pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := by - rw [← one_mul (a ^ n), pow_succ'] - exact mul_lt_mul_of_pos_right ha (pow_pos (zero_lt_one.trans ha) _) +@[deprecated pow_lt_pow_right₀ (since := "2024-11-18")] +lemma pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := pow_lt_pow_right₀ ha n.lt_succ_self end LinearOrderedCommGroupWithZero @@ -254,7 +219,7 @@ theorem ofAdd_toDual_eq_zero_iff [LinearOrderedAddCommMonoidWithTop α] @[simp] theorem ofDual_toAdd_eq_top_iff [LinearOrderedAddCommMonoidWithTop α] - (x : Multiplicative αᵒᵈ) : OrderDual.ofDual (Multiplicative.toAdd x) = ⊤ ↔ x = 0 := Iff.rfl + (x : Multiplicative αᵒᵈ) : OrderDual.ofDual x.toAdd = ⊤ ↔ x = 0 := Iff.rfl @[simp] theorem ofAdd_bot [LinearOrderedAddCommMonoidWithTop α] : @@ -262,7 +227,7 @@ theorem ofAdd_bot [LinearOrderedAddCommMonoidWithTop α] : @[simp] theorem ofDual_toAdd_zero [LinearOrderedAddCommMonoidWithTop α] : - OrderDual.ofDual (Multiplicative.toAdd (0 : Multiplicative αᵒᵈ)) = ⊤ := rfl + OrderDual.ofDual (0 : Multiplicative αᵒᵈ).toAdd = ⊤ := rfl instance [LinearOrderedAddCommGroupWithTop α] : LinearOrderedCommGroupWithZero (Multiplicative αᵒᵈ) := diff --git a/Mathlib/Algebra/Order/GroupWithZero/Finset.lean b/Mathlib/Algebra/Order/GroupWithZero/Finset.lean new file mode 100644 index 00000000000000..0047881217ebfd --- /dev/null +++ b/Mathlib/Algebra/Order/GroupWithZero/Finset.lean @@ -0,0 +1,64 @@ +/- +Copyright (c) 2022 Eric Wieser. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Eric Wieser, Yaël Dillies, Andrew Yang +-/ +import Mathlib.Algebra.Order.GroupWithZero.Canonical +import Mathlib.Algebra.Order.GroupWithZero.Unbundled.Lemmas +import Mathlib.Data.Finset.Lattice.Fold + +/-! +# `Finset.sup` in a group with zero +-/ + +namespace Finset +variable {ι M₀ G₀ : Type*} + +section MonoidWithZero +variable [MonoidWithZero M₀] {s : Finset ι} {a b : ι → M₀} + +lemma sup_mul_le_mul_sup_of_nonneg [SemilatticeSup M₀] [OrderBot M₀] [PosMulMono M₀] [MulPosMono M₀] + (ha : ∀ i ∈ s, 0 ≤ a i) (hb : ∀ i ∈ s, 0 ≤ b i) : s.sup (a * b) ≤ s.sup a * s.sup b := + Finset.sup_le fun _i hi ↦ + mul_le_mul (le_sup hi) (le_sup hi) (hb _ hi) ((ha _ hi).trans <| le_sup hi) + +lemma mul_inf_le_inf_mul_of_nonneg [SemilatticeInf M₀] [OrderTop M₀] [PosMulMono M₀] [MulPosMono M₀] + (ha : ∀ i ∈ s, 0 ≤ a i) (hb : ∀ i ∈ s, 0 ≤ b i) : s.inf a * s.inf b ≤ s.inf (a * b) := + Finset.le_inf fun i hi ↦ mul_le_mul (inf_le hi) (inf_le hi) (Finset.le_inf hb) (ha i hi) + +lemma sup'_mul_le_mul_sup'_of_nonneg [SemilatticeSup M₀] [PosMulMono M₀] [MulPosMono M₀] + (ha : ∀ i ∈ s, 0 ≤ a i) (hb : ∀ i ∈ s, 0 ≤ b i) (hs) : + s.sup' hs (a * b) ≤ s.sup' hs a * s.sup' hs b := + sup'_le _ _ fun _i hi ↦ + mul_le_mul (le_sup' _ hi) (le_sup' _ hi) (hb _ hi) ((ha _ hi).trans <| le_sup' _ hi) + +lemma inf'_mul_le_mul_inf'_of_nonneg [SemilatticeInf M₀] [PosMulMono M₀] [MulPosMono M₀] + (ha : ∀ i ∈ s, 0 ≤ a i) (hb : ∀ i ∈ s, 0 ≤ b i) (hs) : + s.inf' hs a * s.inf' hs b ≤ s.inf' hs (a * b) := + le_inf' _ _ fun _i hi ↦ mul_le_mul (inf'_le _ hi) (inf'_le _ hi) (le_inf' _ _ hb) (ha _ hi) + +end MonoidWithZero + +section GroupWithZero +variable [GroupWithZero G₀] [SemilatticeSup G₀] {s : Finset ι} {a : G₀} + +lemma sup'_mul₀ [MulPosMono G₀] [MulPosReflectLE G₀] (ha : 0 < a) (f : ι → G₀) (s : Finset ι) (hs) : + s.sup' hs f * a = s.sup' hs fun i ↦ f i * a := map_finset_sup' (OrderIso.mulRight₀ _ ha) hs f + +set_option linter.docPrime false in +lemma mul₀_sup' [PosMulMono G₀] [PosMulReflectLE G₀] (ha : 0 < a) (f : ι → G₀) (s : Finset ι) (hs) : + a * s.sup' hs f = s.sup' hs fun i ↦ a * f i := map_finset_sup' (OrderIso.mulLeft₀ _ ha) hs f + +lemma sup'_div₀ [ZeroLEOneClass G₀] [MulPosStrictMono G₀] [MulPosReflectLE G₀] [PosMulReflectLT G₀] + (ha : 0 < a) (f : ι → G₀) (s : Finset ι) (hs) : s.sup' hs f / a = s.sup' hs fun i ↦ f i / a := + map_finset_sup' (OrderIso.divRight₀ _ ha) hs f + +end GroupWithZero + +lemma sup_div₀ [LinearOrderedCommGroupWithZero G₀] [OrderBot G₀] {a : G₀} (ha : 0 < a) + (s : Finset ι) (f : ι → G₀) : s.sup f / a = s.sup fun i ↦ f i / a := by + obtain rfl | hs := s.eq_empty_or_nonempty + · simp [← show (0 : G₀) = ⊥ from bot_unique zero_le'] + rw [← Finset.sup'_eq_sup hs, ← Finset.sup'_eq_sup hs, sup'_div₀ (ha := ha)] + +end Finset diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean index f11dc3c1af7545..488d67de45348d 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean @@ -983,6 +983,11 @@ lemma mul_lt_one_of_nonneg_of_lt_one_right [MulPosMono M₀] (ha : a ≤ 1) (hb section variable [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] +@[bound] +protected lemma Bound.one_lt_mul : 1 ≤ a ∧ 1 < b ∨ 1 < a ∧ 1 ≤ b → 1 < a * b := by + rintro (⟨ha, hb⟩ | ⟨ha, hb⟩); exacts [one_lt_mul ha hb, one_lt_mul_of_lt_of_le ha hb] + +@[bound] 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 @@ -1358,6 +1363,8 @@ lemma inv_le_iff_one_le_mul₀' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b := b 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] alias ⟨_, Bound.one_le_inv₀⟩ := one_le_inv₀ + @[bound] lemma inv_le_one_of_one_le₀ (ha : 1 ≤ a) : a⁻¹ ≤ 1 := (inv_le_one₀ <| zero_lt_one.trans_le ha).2 ha @@ -1472,6 +1479,11 @@ lemma mul_inv_le_one_of_le₀ (h : a ≤ b) (hb : 0 ≤ b) : a * b⁻¹ ≤ 1 := 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] +@[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) + @[deprecated (since := "2024-08-21")] alias le_div_iff := le_div_iff₀ @[deprecated (since := "2024-08-21")] alias div_le_iff := div_le_iff₀ @@ -1498,6 +1510,12 @@ lemma le_inv_comm₀ (ha : 0 < a) (hb : 0 < b) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ : 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 +-- 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 + end MulPosMono section PosMulStrictMono @@ -1599,6 +1617,11 @@ lemma div_lt_iff₀ (hc : 0 < c) : b / c < a ↔ b < a * c := by lemma inv_lt_iff_one_lt_mul₀ (ha : 0 < a) : a⁻¹ < b ↔ 1 < b * a := by rw [← mul_inv_lt_iff₀ ha, one_mul] +@[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) + variable [PosMulStrictMono G₀] /-- See `inv_strictAnti₀` for the implication from right-to-left with one fewer assumption. -/ @@ -1623,11 +1646,16 @@ lemma lt_inv_comm₀ (ha : 0 < a) (hb : 0 < b) : a < b⁻¹ ↔ b < a⁻¹ := by 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 +@[gcongr, bound] +lemma div_lt_div_of_pos_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_lt_mul_of_pos_left ((inv_lt_inv₀ (hc.trans h) hc).2 h) ha + end MulPosStrictMono end PartialOrder section LinearOrder -variable [LinearOrder G₀] [ZeroLEOneClass G₀] {a b : G₀} +variable [LinearOrder G₀] [ZeroLEOneClass G₀] {a b c d : G₀} section PosMulMono variable [PosMulMono G₀] @@ -1677,6 +1705,37 @@ lemma zpow_eq_one_iff_right₀ (ha₀ : 0 ≤ a) (ha₁ : a ≠ 1) {n : ℤ} : a · exact zero_zpow_eq_one₀ simpa using zpow_right_inj₀ ha₀ ha₁ (n := 0) +variable [MulPosStrictMono G₀] + +lemma div_le_div_iff_of_pos_right (hc : 0 < c) : a / c ≤ b / c ↔ a ≤ b where + mp := le_imp_le_of_lt_imp_lt fun hab ↦ div_lt_div_of_pos_right hab hc + mpr hab := div_le_div_of_nonneg_right hab hc.le + +lemma div_lt_div_iff_of_pos_right (hc : 0 < c) : a / c < b / c ↔ a < b := + lt_iff_lt_of_le_iff_le <| div_le_div_iff_of_pos_right hc + +lemma div_lt_div_iff_of_pos_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] + +lemma div_le_div_iff_of_pos_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_iff_of_pos_left ha hc hb) + +@[mono, gcongr, bound] +lemma div_le_div₀ (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hdb : d ≤ b) : a / b ≤ c / d := by + rw [div_eq_mul_inv, div_eq_mul_inv] + exact mul_le_mul hac ((inv_le_inv₀ (hd.trans_le hdb) hd).2 hdb) + (inv_nonneg.2 <| hd.le.trans hdb) hc + +@[gcongr] +lemma div_lt_div₀ (hac : a < c) (hdb : d ≤ b) (hc : 0 ≤ c) (hd : 0 < d) : a / b < c / d := by + rw [div_eq_mul_inv, div_eq_mul_inv] + exact mul_lt_mul hac ((inv_le_inv₀ (hd.trans_le hdb) hd).2 hdb) (inv_pos.2 <| hd.trans_le hdb) hc + +lemma div_lt_div₀' (hac : a ≤ c) (hdb : d < b) (hc : 0 < c) (hd : 0 < d) : a / b < c / d := by + rw [div_eq_mul_inv, div_eq_mul_inv] + exact mul_lt_mul' hac ((inv_lt_inv₀ (hd.trans hdb) hd).2 hdb) + (inv_nonneg.2 <| hd.le.trans hdb.le) hc + end GroupWithZero.LinearOrder section CommSemigroupHasZero @@ -1722,8 +1781,7 @@ 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 +lemma div_le_div_iff₀ (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] @@ -1751,7 +1809,7 @@ lemma div_le_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b ≤ c ↔ a / c ≤ b := end PosMulMono section PosMulStrictMono -variable [PosMulStrictMono G₀] {a b c : G₀} +variable [PosMulStrictMono G₀] {a b c d : 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 @@ -1771,6 +1829,10 @@ 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] +lemma div_lt_div_iff₀ (hb : 0 < b) (hd : 0 < d) : a / b < c / d ↔ a * d < c * b := by + have := posMulStrictMono_iff_mulPosStrictMono.1 ‹_› + rw [div_lt_iff₀ hb, ← mul_div_right_comm, lt_div_iff₀ hd] + /-- 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 ‹_› diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean index 15331ca9c673ab..daa1991832ae71 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled/Lemmas.lean @@ -12,26 +12,48 @@ import Mathlib.Order.Hom.Basic # Multiplication by a positive element as an order isomorphism -/ -variable {G₀} [GroupWithZero G₀] [Preorder G₀] {a : G₀} +namespace OrderIso +variable {G₀} [GroupWithZero G₀] [PartialOrder G₀] + +section left +variable [PosMulMono G₀] [PosMulReflectLE 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 +def mulLeft₀ (a : G₀) (ha : 0 < a) : G₀ ≃o G₀ where toEquiv := .mulLeft₀ a ha.ne' map_rel_iff' := mul_le_mul_left ha +variable [ZeroLEOneClass G₀] + +lemma mulLeft₀_symm (a : G₀) (ha : 0 < a) : (mulLeft₀ a ha).symm = mulLeft₀ a⁻¹ (inv_pos.2 ha) := by + ext; rfl + +end left + +section right +variable [MulPosMono G₀] [MulPosReflectLE G₀] + /-- `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 +def mulRight₀ (a : G₀) (ha : 0 < a) : G₀ ≃o G₀ where toEquiv := .mulRight₀ a ha.ne' map_rel_iff' := mul_le_mul_right ha +variable [ZeroLEOneClass G₀] [PosMulReflectLT G₀] + +lemma mulRight₀_symm (a : G₀) (ha : 0 < a) : + (mulRight₀ a ha).symm = mulRight₀ a⁻¹ (inv_pos.2 ha) := by ext; rfl + +end right + /-- `Equiv.divRight₀` as an order isomorphism. -/ @[simps! (config := { simpRhs := true })] -def OrderIso.divRight₀ {G₀} [GroupWithZero G₀] [PartialOrder G₀] [ZeroLEOneClass G₀] - [MulPosStrictMono G₀] [MulPosReflectLE G₀] [PosMulReflectLT G₀] +def divRight₀ [ZeroLEOneClass G₀] [MulPosStrictMono G₀] [MulPosReflectLE G₀] [PosMulReflectLT G₀] (a : G₀) (ha : 0 < a) : G₀ ≃o G₀ where toEquiv := .divRight₀ a ha.ne' map_rel_iff' {b c} := by simp only [Equiv.divRight₀_apply, div_eq_mul_inv] exact mul_le_mul_right (a := a⁻¹) (inv_pos.mpr ha) + +end OrderIso diff --git a/Mathlib/Algebra/Order/Hom/Monoid.lean b/Mathlib/Algebra/Order/Hom/Monoid.lean index 5fa19423317a28..b40dacaccb13e5 100644 --- a/Mathlib/Algebra/Order/Hom/Monoid.lean +++ b/Mathlib/Algebra/Order/Hom/Monoid.lean @@ -6,6 +6,7 @@ Authors: Yaël Dillies import Mathlib.Algebra.GroupWithZero.Hom import Mathlib.Algebra.Order.Group.Instances import Mathlib.Algebra.Order.GroupWithZero.Canonical +import Mathlib.Algebra.Order.Monoid.Units import Mathlib.Order.Hom.Basic /-! diff --git a/Mathlib/Algebra/Order/Monoid/ToMulBot.lean b/Mathlib/Algebra/Order/Monoid/ToMulBot.lean index ab578ee5f849e1..79f4fd7e4a1072 100644 --- a/Mathlib/Algebra/Order/Monoid/ToMulBot.lean +++ b/Mathlib/Algebra/Order/Monoid/ToMulBot.lean @@ -33,7 +33,7 @@ theorem toMulBot_zero : toMulBot (0 : WithZero (Multiplicative α)) = Multiplica @[simp] theorem toMulBot_coe (x : Multiplicative α) : - toMulBot ↑x = Multiplicative.ofAdd (↑(Multiplicative.toAdd x) : WithBot α) := + toMulBot ↑x = Multiplicative.ofAdd (↑x.toAdd : WithBot α) := rfl @[simp] diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean index 274bb53619f6fb..0a60e09d11d81a 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean @@ -163,6 +163,10 @@ theorem Monotone.pow_const {f : β → M} (hf : Monotone f) : ∀ n : ℕ, Monot @[to_additive nsmul_right_mono] theorem pow_left_mono (n : ℕ) : Monotone fun a : M => a ^ n := monotone_id.pow_const _ +@[to_additive (attr := gcongr)] +lemma pow_le_pow {a b : M} (hab : a ≤ b) (ht : 1 ≤ b) {m n : ℕ} (hmn : m ≤ n) : a ^ m ≤ b ^ n := + (pow_le_pow_left' hab _).trans (pow_le_pow_right' ht hmn) + end CovariantLESwap end Preorder diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean index 1647d43c6a4342..8a7c336d6901c6 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean @@ -3,9 +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, Johannes Hölzl -/ -import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE import Mathlib.Order.BoundedOrder +import Mathlib.Algebra.Group.TypeTags.Basic /-! # Ordered monoid structures on `Multiplicative α` and `Additive α`. -/ @@ -79,11 +79,11 @@ theorem ofMul_lt {a b : α} : ofMul a < ofMul b ↔ a < b := Iff.rfl @[simp] -theorem toMul_le {a b : Additive α} : toMul a ≤ toMul b ↔ a ≤ b := +theorem toMul_le {a b : Additive α} : a.toMul ≤ b.toMul ↔ a ≤ b := Iff.rfl @[simp] -theorem toMul_lt {a b : Additive α} : toMul a < toMul b ↔ a < b := +theorem toMul_lt {a b : Additive α} : a.toMul < b.toMul ↔ a < b := Iff.rfl end Additive @@ -101,11 +101,11 @@ theorem ofAdd_lt {a b : α} : ofAdd a < ofAdd b ↔ a < b := Iff.rfl @[simp] -theorem toAdd_le {a b : Multiplicative α} : toAdd a ≤ toAdd b ↔ a ≤ b := +theorem toAdd_le {a b : Multiplicative α} : a.toAdd ≤ b.toAdd ↔ a ≤ b := Iff.rfl @[simp] -theorem toAdd_lt {a b : Multiplicative α} : toAdd a < toAdd b ↔ a < b := +theorem toAdd_lt {a b : Multiplicative α} : a.toAdd < b.toAdd ↔ a < b := Iff.rfl end Multiplicative diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index ebf26eae2fbc35..9ad0b00b7fa4d6 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -3,7 +3,6 @@ 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.Field.Basic import Mathlib.Algebra.Order.Group.Instances import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Algebra.Order.Module.Synonym @@ -291,19 +290,19 @@ alias ⟨Antivary.of_inv₀, Antivary.inv₀⟩ := antivary_inv₀ lemma MonovaryOn.div_left₀ (hf₁ : ∀ i ∈ s, 0 ≤ f₁ i) (hf₂ : ∀ i ∈ s, 0 < f₂ i) (h₁ : MonovaryOn f₁ g s) (h₂ : AntivaryOn f₂ g s) : MonovaryOn (f₁ / f₂) g s := - fun _i hi _j hj hij ↦ div_le_div (hf₁ _ hj) (h₁ hi hj hij) (hf₂ _ hj) <| h₂ hi hj hij + fun _i hi _j hj hij ↦ div_le_div₀ (hf₁ _ hj) (h₁ hi hj hij) (hf₂ _ hj) <| h₂ hi hj hij lemma AntivaryOn.div_left₀ (hf₁ : ∀ i ∈ s, 0 ≤ f₁ i) (hf₂ : ∀ i ∈ s, 0 < f₂ i) (h₁ : AntivaryOn f₁ g s) (h₂ : MonovaryOn f₂ g s) : AntivaryOn (f₁ / f₂) g s := - fun _i hi _j hj hij ↦ div_le_div (hf₁ _ hi) (h₁ hi hj hij) (hf₂ _ hi) <| h₂ hi hj hij + fun _i hi _j hj hij ↦ div_le_div₀ (hf₁ _ hi) (h₁ hi hj hij) (hf₂ _ hi) <| h₂ hi hj hij lemma Monovary.div_left₀ (hf₁ : 0 ≤ f₁) (hf₂ : StrongLT 0 f₂) (h₁ : Monovary f₁ g) (h₂ : Antivary f₂ g) : Monovary (f₁ / f₂) g := - fun _i _j hij ↦ div_le_div (hf₁ _) (h₁ hij) (hf₂ _) <| h₂ hij + fun _i _j hij ↦ div_le_div₀ (hf₁ _) (h₁ hij) (hf₂ _) <| h₂ hij lemma Antivary.div_left₀ (hf₁ : 0 ≤ f₁) (hf₂ : StrongLT 0 f₂) (h₁ : Antivary f₁ g) (h₂ : Monovary f₂ g) : Antivary (f₁ / f₂) g := - fun _i _j hij ↦ div_le_div (hf₁ _) (h₁ hij) (hf₂ _) <| h₂ hij + fun _i _j hij ↦ div_le_div₀ (hf₁ _) (h₁ hij) (hf₂ _) <| h₂ hij lemma MonovaryOn.div_right₀ (hg₁ : ∀ i ∈ s, 0 ≤ g₁ i) (hg₂ : ∀ i ∈ s, 0 < g₂ i) (h₁ : MonovaryOn f g₁ s) (h₂ : AntivaryOn f g₂ s) : MonovaryOn f (g₁ / g₂) s := diff --git a/Mathlib/Algebra/Order/Nonneg/Floor.lean b/Mathlib/Algebra/Order/Nonneg/Floor.lean index a3472c9dde95b6..1fdd9eefd18926 100644 --- a/Mathlib/Algebra/Order/Nonneg/Floor.lean +++ b/Mathlib/Algebra/Order/Nonneg/Floor.lean @@ -19,6 +19,8 @@ This is used to derive algebraic structures on `ℝ≥0` and `ℚ≥0` automatic * `{x : α // 0 ≤ x}` is a `FloorSemiring` if `α` is. -/ +assert_not_exists Finset + namespace Nonneg variable {α : Type*} diff --git a/Mathlib/Algebra/Order/Nonneg/Module.lean b/Mathlib/Algebra/Order/Nonneg/Module.lean index 1a388a67825b3f..fb4548137a724a 100644 --- a/Mathlib/Algebra/Order/Nonneg/Module.lean +++ b/Mathlib/Algebra/Order/Nonneg/Module.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Apurva Nakade. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Apurva Nakade -/ -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.RingHom import Mathlib.Algebra.Order.Module.OrderedSMul import Mathlib.Algebra.Order.Nonneg.Ring diff --git a/Mathlib/Algebra/Order/Quantale.lean b/Mathlib/Algebra/Order/Quantale.lean new file mode 100644 index 00000000000000..96bfa1624aa35b --- /dev/null +++ b/Mathlib/Algebra/Order/Quantale.lean @@ -0,0 +1,179 @@ +/- +Copyright (c) 2024 Pieter Cuijpers. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Pieter Cuijpers +-/ +import Mathlib.Algebra.Group.Defs +import Mathlib.Algebra.Order.Monoid.Unbundled.Basic +import Mathlib.Order.CompleteLattice + +/-! +# Theory of quantales + +Quantales are the non-commutative generalization of locales/frames and as such are linked +to point-free topology and order theory. Applications are found throughout logic, +quantum mechanics, and computer science (see e.g. [Vickers1989] and [Mulvey1986]). + +The most general definition of quantale occurring in literature, is that a quantale is a semigroup +distributing over a complete sup-semilattice. In our definition below, we use the fact that +every complete sup-semilattice is in fact a complete lattice, and make constructs defined for +those immediately available. Another view could be to define a quantale as a complete idempotent +semiring, i.e. a complete semiring in which + and sup coincide. However, we will often encounter +additive quantales, i.e. quantales in which the semigroup operator is thought of as addition, in +which case the link with semirings will lead to confusion notationally. + +In this file, we follow the basic definition set out on the wikipedia page on quantales, +using a mixin typeclass to make the special cases of unital, commutative, idempotent, +integral, and involutive quantales easier to add on later. + +## Main definitions + +* `IsQuantale` and `IsAddQuantale` : Typeclass mixin for a (additive) semigroup distributing + over a complete lattice, i.e satisfying `x * (sSup s) = ⨆ y ∈ s, x * y` and + `(sSup s) * y = ⨆ x ∈ s, x * y`; + +* `leftMulResiduation`, `rightMulResiduation`, `leftAddResiduation`, `rightAddResiduation` : + Defining the left- and right- residuations of the semigroup (see notation below). + +* Finally, we provide basic distributivity laws for sSup into iSup and sup, monotonicity of + the semigroup operator, and basic equivalences for left- and right-residuation. + +## Notation + +* `x ⇨ₗ y` : `sSup {z | z * x ≤ y}`, the `leftMulResiduation` of `y` over `x`; + +* `x ⇨ᵣ y` : `sSup {z | x * z ≤ y}`, the `rightMulResiduation` of `y` over `x`; + +## References + + + + + +-/ + +open Function + +/-- An additive quantale is an additive semigroup distributing over a complete lattice. -/ +class IsAddQuantale (α : Type*) [AddSemigroup α] [CompleteLattice α] where + /-- Addition is distributive over join in a quantale -/ + protected add_sSup_distrib (x : α) (s : Set α) : x + sSup s = ⨆ y ∈ s, x + y + /-- Addition is distributive over join in a quantale -/ + protected sSup_add_distrib (s : Set α) (y : α) : sSup s + y = ⨆ x ∈ s, x + y + +/-- A quantale is a semigroup distributing over a complete lattice. -/ +@[to_additive] +class IsQuantale (α : Type*) [Semigroup α] [CompleteLattice α] where + /-- Multiplication is distributive over join in a quantale -/ + protected mul_sSup_distrib (x : α) (s : Set α) : x * sSup s = ⨆ y ∈ s, x * y + /-- Multiplication is distributive over join in a quantale -/ + protected sSup_mul_distrib (s : Set α) (y : α) : sSup s * y = ⨆ x ∈ s, x * y + +section + +variable {α : Type*} {ι : Type*} {x y z : α} {s : Set α} {f : ι → α} +variable [Semigroup α] [CompleteLattice α] [IsQuantale α] + +@[to_additive] +theorem mul_sSup_distrib : x * sSup s = ⨆ y ∈ s, x * y := IsQuantale.mul_sSup_distrib _ _ + +@[to_additive] +theorem sSup_mul_distrib : sSup s * x = ⨆ y ∈ s, y * x := IsQuantale.sSup_mul_distrib _ _ + +end + +namespace IsAddQuantale + +variable {α : Type*} {ι : Type*} {x y z : α} {s : Set α} {f : ι → α} +variable [AddSemigroup α] [CompleteLattice α] [IsAddQuantale α] + +/-- Left- and right- residuation operators on an additive quantale are similar +to the Heyting operator on complete lattices, but for a non-commutative logic. +I.e. `x ≤ y ⇨ₗ z ↔ x + y ≤ z` or alternatively `x ⇨ₗ y = sSup { z | z + x ≤ y }`. -/ +def leftAddResiduation (x y : α) := sSup {z | z + x ≤ y} + +/-- Left- and right- residuation operators on an additive quantale are similar +to the Heyting operator on complete lattices, but for a non-commutative logic. +I.e. `x ≤ y ⇨ᵣ z ↔ y + x ≤ z` or alternatively `x ⇨ₗ y = sSup { z | x + z ≤ y }`." -/ +def rightAddResiduation (x y : α) := sSup {z | x + z ≤ y} + +@[inherit_doc] +scoped infixr:60 " ⇨ₗ " => leftAddResiduation + +@[inherit_doc] +scoped infixr:60 " ⇨ᵣ " => rightAddResiduation + +end IsAddQuantale + +namespace IsQuantale + +variable {α : Type*} {ι : Type*} {x y z : α} {s : Set α} {f : ι → α} +variable [Semigroup α] [CompleteLattice α] [IsQuantale α] + +/-- Left- and right-residuation operators on an additive quantale are similar to the Heyting +operator on complete lattices, but for a non-commutative logic. +I.e. `x ≤ y ⇨ₗ z ↔ x * y ≤ z` or alternatively `x ⇨ₗ y = sSup { z | z * x ≤ y }`. +-/ +@[to_additive existing] +def leftMulResiduation (x y : α) := sSup {z | z * x ≤ y} + +/-- Left- and right- residuation operators on an additive quantale are similar to the Heyting +operator on complete lattices, but for a non-commutative logic. +I.e. `x ≤ y ⇨ᵣ z ↔ y * x ≤ z` or alternatively `x ⇨ₗ y = sSup { z | x * z ≤ y }`. +-/ +@[to_additive existing] +def rightMulResiduation (x y : α) := sSup {z | x * z ≤ y} + +@[inherit_doc, to_additive existing] +scoped infixr:60 " ⇨ₗ " => leftMulResiduation + +@[inherit_doc, to_additive existing] +scoped infixr:60 " ⇨ᵣ " => rightMulResiduation + +@[to_additive] +theorem mul_iSup_distrib : x * ⨆ i, f i = ⨆ i, x * f i := by + rw [iSup, mul_sSup_distrib, iSup_range] + +@[to_additive] +theorem iSup_mul_distrib : (⨆ i, f i) * x = ⨆ i, f i * x := by + rw [iSup, sSup_mul_distrib, iSup_range] + +@[to_additive] +theorem mul_sup_distrib : x * (y ⊔ z) = (x * y) ⊔ (x * z) := by + rw [← iSup_pair, ← sSup_pair, mul_sSup_distrib] + +@[to_additive] +theorem sup_mul_distrib : (x ⊔ y) * z = (x * z) ⊔ (y * z) := by + rw [← (@iSup_pair _ _ _ (fun _? => _? * z) _ _), ← sSup_pair, sSup_mul_distrib] + +@[to_additive] +instance : MulLeftMono α where + elim := by + intro _ _ _; simp only; intro + rw [← left_eq_sup, ← mul_sup_distrib, sup_of_le_left] + trivial + +@[to_additive] +instance : MulRightMono α where + elim := by + intro _ _ _; simp only; intro + rw [← left_eq_sup, ← sup_mul_distrib, sup_of_le_left] + trivial + +@[to_additive] +theorem leftMulResiduation_le_iff_mul_le : x ≤ y ⇨ₗ z ↔ x * y ≤ z where + mp h1 := by + apply le_trans (mul_le_mul_right' h1 _) + simp_all only [leftMulResiduation, sSup_mul_distrib, Set.mem_setOf_eq, + iSup_le_iff, implies_true] + mpr h1 := le_sSup h1 + +@[to_additive] +theorem rightMulResiduation_le_iff_mul_le : x ≤ y ⇨ᵣ z ↔ y * x ≤ z where + mp h1 := by + apply le_trans (mul_le_mul_left' h1 _) + simp_all only [rightMulResiduation, mul_sSup_distrib, Set.mem_setOf_eq, + iSup_le_iff, implies_true] + mpr h1 := le_sSup h1 + +end IsQuantale diff --git a/Mathlib/Algebra/Order/Ring/Abs.lean b/Mathlib/Algebra/Order/Ring/Abs.lean index 9948d23da4d4be..5552705b81dff0 100644 --- a/Mathlib/Algebra/Order/Ring/Abs.lean +++ b/Mathlib/Algebra/Order/Ring/Abs.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Order.Group.Abs import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Algebra.Order.Ring.Int import Mathlib.Algebra.Ring.Divisibility.Basic +import Mathlib.Algebra.Ring.Int.Units import Mathlib.Data.Nat.Cast.Order.Ring /-! @@ -151,6 +152,9 @@ theorem abs_sub_sq (a b : α) : |a - b| * |a - b| = a * a + b * b - (1 + 1) * a simp only [mul_add, add_comm, add_left_comm, mul_comm, sub_eq_add_neg, mul_one, mul_neg, neg_add_rev, neg_neg, add_assoc] +lemma abs_unit_intCast (a : ℤˣ) : |((a : ℤ) : α)| = 1 := by + cases Int.units_eq_one_or a <;> simp_all + end LinearOrderedCommRing section diff --git a/Mathlib/Algebra/Order/Ring/Basic.lean b/Mathlib/Algebra/Order/Ring/Basic.lean index 65844e24d7f301..6f6a50a96337c1 100644 --- a/Mathlib/Algebra/Order/Ring/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2015 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis -/ +import Mathlib.Algebra.Group.Nat.Units import Mathlib.Algebra.Order.Monoid.Unbundled.Pow import Mathlib.Algebra.Order.Ring.Defs import Mathlib.Algebra.Ring.Parity diff --git a/Mathlib/Algebra/Order/Ring/Finset.lean b/Mathlib/Algebra/Order/Ring/Finset.lean deleted file mode 100644 index dd490e170eff42..00000000000000 --- a/Mathlib/Algebra/Order/Ring/Finset.lean +++ /dev/null @@ -1,34 +0,0 @@ -/- -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.Order.Ring.Defs -import Mathlib.Data.Finset.Lattice.Fold - -/-! -# Algebraic properties of finitary supremum --/ - -namespace Finset -variable {ι R : Type*} [LinearOrderedSemiring R] {a b : ι → R} - -theorem sup_mul_le_mul_sup_of_nonneg [OrderBot R] (s : Finset ι) (ha : ∀ i ∈ s, 0 ≤ a i) - (hb : ∀ i ∈ s, 0 ≤ b i) : s.sup (a * b) ≤ s.sup a * s.sup b := - Finset.sup_le fun _i hi ↦ - mul_le_mul (le_sup hi) (le_sup hi) (hb _ hi) ((ha _ hi).trans <| le_sup hi) - -theorem mul_inf_le_inf_mul_of_nonneg [OrderTop R] (s : Finset ι) (ha : ∀ i ∈ s, 0 ≤ a i) - (hb : ∀ i ∈ s, 0 ≤ b i) : s.inf a * s.inf b ≤ s.inf (a * b) := - Finset.le_inf fun i hi ↦ mul_le_mul (inf_le hi) (inf_le hi) (Finset.le_inf hb) (ha i hi) - -theorem sup'_mul_le_mul_sup'_of_nonneg (s : Finset ι) (H : s.Nonempty) (ha : ∀ i ∈ s, 0 ≤ a i) - (hb : ∀ i ∈ s, 0 ≤ b i) : s.sup' H (a * b) ≤ s.sup' H a * s.sup' H b := - (sup'_le _ _) fun _i hi ↦ - mul_le_mul (le_sup' _ hi) (le_sup' _ hi) (hb _ hi) ((ha _ hi).trans <| le_sup' _ hi) - -theorem inf'_mul_le_mul_inf'_of_nonneg (s : Finset ι) (H : s.Nonempty) (ha : ∀ i ∈ s, 0 ≤ a i) - (hb : ∀ i ∈ s, 0 ≤ b i) : s.inf' H a * s.inf' H b ≤ s.inf' H (a * b) := - (le_inf' _ _) fun _i hi ↦ mul_le_mul (inf'_le _ hi) (inf'_le _ hi) (le_inf' _ _ hb) (ha _ hi) - -end Finset diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean index 06cc0315f08b0e..99bd1f2cfd31c7 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean @@ -764,7 +764,7 @@ alias two_mul_le_add_pow_two := two_mul_le_add_sq /-- Binary, squared, and division-free **arithmetic mean-geometric mean inequality** (aka AM-GM inequality) for linearly ordered commutative semirings. -/ lemma four_mul_le_sq_add [ExistsAddOfLE α] [MulPosStrictMono α] - [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)] + [AddLeftReflectLE α] [AddLeftMono α] (a b : α) : 4 * a * b ≤ (a + b) ^ 2 := by calc 4 * a * b _ = 2 * a * b + 2 * a * b := by rw [mul_assoc, two_add_two_eq_four.symm, add_mul, mul_assoc] @@ -774,6 +774,16 @@ lemma four_mul_le_sq_add [ExistsAddOfLE α] [MulPosStrictMono α] alias four_mul_le_pow_two_add := four_mul_le_sq_add +/-- Binary and division-free **arithmetic mean-geometric mean inequality** +(aka AM-GM inequality) for linearly ordered commutative semirings. -/ +lemma two_mul_le_add_of_sq_eq_mul [ExistsAddOfLE α] [MulPosStrictMono α] [PosMulStrictMono α] + [AddLeftReflectLE α] [AddLeftMono α] {a b r : α} + (ha : 0 ≤ a) (hb : 0 ≤ b) (ht : r ^ 2 = a * b) : 2 * r ≤ a + b := by + apply nonneg_le_nonneg_of_sq_le_sq (Left.add_nonneg ha hb) + conv_rhs => rw [← pow_two] + convert four_mul_le_sq_add a b using 1 + rw [mul_mul_mul_comm, two_mul, two_add_two_eq_four, ← pow_two, ht, mul_assoc] + end LinearOrderedCommSemiring section LinearOrderedRing diff --git a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean index 7c69e6dc40162b..4ee0095a26d7c0 100644 --- a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean +++ b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean @@ -36,15 +36,19 @@ 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_toMul [Preorder X] [SuccOrder X] (x : Additive X) : + succ x.toMul = (succ x).toMul := 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 succ_toAdd [Preorder X] [SuccOrder X] (x : Multiplicative X) : + succ x.toAdd = (succ x).toAdd := 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_toMul [Preorder X] [PredOrder X] (x : Additive X) : + pred x.toMul = (pred x).toMul := 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 +@[simp] lemma pred_toAdd [Preorder X] [PredOrder X] (x : Multiplicative X) : + pred x.toAdd = (pred x).toAdd := rfl end Order diff --git a/Mathlib/Algebra/Polynomial/Basic.lean b/Mathlib/Algebra/Polynomial/Basic.lean index 56c5d26cab71c4..72765a3a6e65aa 100644 --- a/Mathlib/Algebra/Polynomial/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Basic.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker -/ import Mathlib.Algebra.GroupWithZero.Divisibility -import Mathlib.Data.Finset.Sort import Mathlib.Algebra.MonoidAlgebra.Defs +import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop +import Mathlib.Data.Finset.Sort import Mathlib.Order.OmegaCompletePartialOrder /-! diff --git a/Mathlib/Algebra/Polynomial/Bivariate.lean b/Mathlib/Algebra/Polynomial/Bivariate.lean index a78e8ffa4e2c86..d9feee54b8b5c4 100644 --- a/Mathlib/Algebra/Polynomial/Bivariate.lean +++ b/Mathlib/Algebra/Polynomial/Bivariate.lean @@ -17,10 +17,12 @@ the abbreviation `CC` to view a constant in the base ring `R` as a bivariate pol -/ /-- The notation `Y` for `X` in the `Polynomial` scope. -/ -scoped[Polynomial] notation3:max "Y" => Polynomial.X (R := Polynomial _) +scoped[Polynomial.Bivariate] notation3:max "Y" => Polynomial.X (R := Polynomial _) /-- The notation `R[X][Y]` for `R[X][X]` in the `Polynomial` scope. -/ -scoped[Polynomial] notation3:max R "[X][Y]" => Polynomial (Polynomial R) +scoped[Polynomial.Bivariate] notation3:max R "[X][Y]" => Polynomial (Polynomial R) + +open scoped Polynomial.Bivariate namespace Polynomial diff --git a/Mathlib/Algebra/Polynomial/Degree/Operations.lean b/Mathlib/Algebra/Polynomial/Degree/Operations.lean index b64a85909e8053..21d80bcb9d741e 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Operations.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Operations.lean @@ -29,7 +29,7 @@ variable {R : Type u} {S : Type v} {a b c d : R} {n m : ℕ} section Semiring -variable [Semiring R] {p q r : R[X]} +variable [Semiring R] [Semiring S] {p q r : R[X]} theorem supDegree_eq_degree (p : R[X]) : p.toFinsupp.supDegree WithBot.some = p.degree := max_eq_sup_coe @@ -65,12 +65,15 @@ theorem natDegree_eq_of_le_of_coeff_ne_zero (pn : p.natDegree ≤ n) (p1 : p.coe p.natDegree = n := pn.antisymm (le_natDegree_of_ne_zero p1) -theorem natDegree_lt_natDegree {p q : R[X]} (hp : p ≠ 0) (hpq : p.degree < q.degree) : +theorem natDegree_lt_natDegree {q : S[X]} (hp : p ≠ 0) (hpq : p.degree < q.degree) : p.natDegree < q.natDegree := by by_cases hq : q = 0 · exact (not_lt_bot <| hq ▸ hpq).elim rwa [degree_eq_natDegree hp, degree_eq_natDegree hq, Nat.cast_lt] at hpq +lemma natDegree_eq_natDegree {q : S[X]} (hpq : p.degree = q.degree) : + p.natDegree = q.natDegree := by simp [natDegree, hpq] + theorem coeff_eq_zero_of_degree_lt (h : degree p < n) : coeff p n = 0 := Classical.not_not.1 (mt le_degree_of_ne_zero (not_le_of_gt h)) diff --git a/Mathlib/Algebra/Polynomial/DenomsClearable.lean b/Mathlib/Algebra/Polynomial/DenomsClearable.lean index 3cbcf3684ebd36..1f3c6c6b23d0ca 100644 --- a/Mathlib/Algebra/Polynomial/DenomsClearable.lean +++ b/Mathlib/Algebra/Polynomial/DenomsClearable.lean @@ -3,8 +3,9 @@ Copyright (c) 2020 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ -import Mathlib.Algebra.Polynomial.EraseLead import Mathlib.Algebra.Algebra.Basic +import Mathlib.Algebra.Order.Ring.Abs +import Mathlib.Algebra.Polynomial.EraseLead /-! # Denominators of evaluation of polynomials at ratios diff --git a/Mathlib/Algebra/Polynomial/Identities.lean b/Mathlib/Algebra/Polynomial/Identities.lean index d33dfaf9c29238..3aa9df0fe8d2a7 100644 --- a/Mathlib/Algebra/Polynomial/Identities.lean +++ b/Mathlib/Algebra/Polynomial/Identities.lean @@ -18,8 +18,6 @@ noncomputable section namespace Polynomial -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} diff --git a/Mathlib/Algebra/Polynomial/Mirror.lean b/Mathlib/Algebra/Polynomial/Mirror.lean index 9f3b754cd0a0a8..804488801b7dca 100644 --- a/Mathlib/Algebra/Polynomial/Mirror.lean +++ b/Mathlib/Algebra/Polynomial/Mirror.lean @@ -27,8 +27,6 @@ divisible by `X`. namespace Polynomial -open Polynomial - section Semiring variable {R : Type*} [Semiring R] (p q : R[X]) diff --git a/Mathlib/Algebra/Polynomial/Monomial.lean b/Mathlib/Algebra/Polynomial/Monomial.lean index 535103330d899a..f994bf2057858d 100644 --- a/Mathlib/Algebra/Polynomial/Monomial.lean +++ b/Mathlib/Algebra/Polynomial/Monomial.lean @@ -16,8 +16,6 @@ noncomputable section namespace Polynomial -open Polynomial - universe u variable {R : Type u} {a b : R} {m n : ℕ} diff --git a/Mathlib/Algebra/Polynomial/Reverse.lean b/Mathlib/Algebra/Polynomial/Reverse.lean index 505b6a0ea5d5a3..a5ba40706e958f 100644 --- a/Mathlib/Algebra/Polynomial/Reverse.lean +++ b/Mathlib/Algebra/Polynomial/Reverse.lean @@ -19,9 +19,9 @@ coefficients of `f` and `g` do not multiply to zero. namespace Polynomial -open Polynomial Finsupp Finset +open Finsupp Finset -open Polynomial +open scoped Polynomial section Semiring @@ -143,6 +143,14 @@ theorem reflect_monomial (N n : ℕ) : reflect N ((X : R[X]) ^ n) = X ^ revAt N @[simp] lemma reflect_one_X : reflect 1 (X : R[X]) = 1 := by simpa using reflect_monomial 1 1 (R := R) +lemma reflect_map {S : Type*} [Semiring S] (f : R →+* S) (p : R[X]) (n : ℕ) : + (p.map f).reflect n = (p.reflect n).map f := by + ext; simp + +@[simp] +lemma reflect_one (n : ℕ) : (1 : R[X]).reflect n = Polynomial.X ^ n := by + rw [← C.map_one, reflect_C, map_one, one_mul] + theorem reflect_mul_induction (cf cg : ℕ) : ∀ N O : ℕ, ∀ f g : R[X], diff --git a/Mathlib/Algebra/Polynomial/Splits.lean b/Mathlib/Algebra/Polynomial/Splits.lean index 918c15651b4a48..211e8294de3714 100644 --- a/Mathlib/Algebra/Polynomial/Splits.lean +++ b/Mathlib/Algebra/Polynomial/Splits.lean @@ -33,8 +33,6 @@ variable {R : Type*} {F : Type u} {K : Type v} {L : Type w} namespace Polynomial -open Polynomial - section Splits section CommRing diff --git a/Mathlib/Algebra/Polynomial/Taylor.lean b/Mathlib/Algebra/Polynomial/Taylor.lean index 805deafc3c1c78..f3f2c2b9b9fd77 100644 --- a/Mathlib/Algebra/Polynomial/Taylor.lean +++ b/Mathlib/Algebra/Polynomial/Taylor.lean @@ -26,8 +26,6 @@ noncomputable section namespace Polynomial -open Polynomial - variable {R : Type*} [Semiring R] (r : R) (f : R[X]) /-- The Taylor expansion of a polynomial `f` at `r`. -/ diff --git a/Mathlib/Algebra/Prime/Lemmas.lean b/Mathlib/Algebra/Prime/Lemmas.lean index 96ee461f3831f3..0211c3bbc8c5e3 100644 --- a/Mathlib/Algebra/Prime/Lemmas.lean +++ b/Mathlib/Algebra/Prime/Lemmas.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Group.Even import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Algebra.GroupWithZero.Hom import Mathlib.Algebra.Prime.Defs -import Mathlib.Order.Lattice +import Mathlib.Order.Monotone.Basic /-! # Associated, prime, and irreducible elements. diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index 69ce497aff36a7..1ee91c3592cc2b 100644 --- a/Mathlib/Algebra/Quaternion.lean +++ b/Mathlib/Algebra/Quaternion.lean @@ -93,7 +93,7 @@ theorem equivTuple_apply {R : Type*} (c₁ c₂ : R) (x : ℍ[R,c₁,c₂]) : @[simp] theorem mk.eta {R : Type*} {c₁ c₂} (a : ℍ[R,c₁,c₂]) : mk a.1 a.2 a.3 a.4 = a := rfl -variable {S T R : Type*} {c₁ c₂ : R} (r x y z : R) (a b c : ℍ[R,c₁,c₂]) +variable {S T R : Type*} {c₁ c₂ : R} (r x y : R) (a b : ℍ[R,c₁,c₂]) instance [Subsingleton R] : Subsingleton ℍ[R, c₁, c₂] := (equivTuple c₁ c₂).subsingleton instance [Nontrivial R] : Nontrivial ℍ[R, c₁, c₂] := (equivTuple c₁ c₂).surjective.nontrivial @@ -742,7 +742,7 @@ instance {R : Type*} [One R] [Neg R] [Nontrivial R] : Nontrivial ℍ[R] := namespace Quaternion -variable {S T R : Type*} [CommRing R] (r x y z : R) (a b c : ℍ[R]) +variable {S T R : Type*} [CommRing R] (r x y : R) (a b : ℍ[R]) export QuaternionAlgebra (re imI imJ imK) diff --git a/Mathlib/Algebra/Ring/Idempotents.lean b/Mathlib/Algebra/Ring/Idempotents.lean index 80a2c2e0be568e..8b7ce4e91aadd4 100644 --- a/Mathlib/Algebra/Ring/Idempotents.lean +++ b/Mathlib/Algebra/Ring/Idempotents.lean @@ -67,6 +67,17 @@ theorem one_sub {p : R} (h : IsIdempotentElem p) : IsIdempotentElem (1 - p) := b theorem one_sub_iff {p : R} : IsIdempotentElem (1 - p) ↔ IsIdempotentElem p := ⟨fun h => sub_sub_cancel 1 p ▸ h.one_sub, IsIdempotentElem.one_sub⟩ +theorem add_sub_mul_of_commute {R} [Ring R] {p q : R} (h : Commute p q) + (hp : IsIdempotentElem p) (hq : IsIdempotentElem q) : + IsIdempotentElem (p + q - p * q) := by + convert (hp.one_sub.mul_of_commute ?_ hq.one_sub).one_sub using 1 + · simp_rw [sub_mul, mul_sub, one_mul, mul_one, sub_sub, sub_sub_cancel, add_sub, add_comm] + · simp_rw [commute_iff_eq, sub_mul, mul_sub, one_mul, mul_one, sub_sub, add_sub, add_comm, h.eq] + +theorem add_sub_mul {R} [CommRing R] {p q : R} (hp : IsIdempotentElem p) (hq : IsIdempotentElem q) : + IsIdempotentElem (p + q - p * q) := + add_sub_mul_of_commute (mul_comm p q) hp hq + theorem pow {p : N} (n : ℕ) (h : IsIdempotentElem p) : IsIdempotentElem (p ^ n) := Nat.recOn n ((pow_zero p).symm ▸ one) fun n _ => show p ^ n.succ * p ^ n.succ = p ^ n.succ by diff --git a/Mathlib/Algebra/Ring/Nat.lean b/Mathlib/Algebra/Ring/Nat.lean index 9b456d31dec8a0..e2c57fc380685c 100644 --- a/Mathlib/Algebra/Ring/Nat.lean +++ b/Mathlib/Algebra/Ring/Nat.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Algebra.CharZero.Defs -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Algebra.Ring.Defs /-! @@ -15,8 +15,6 @@ This file contains the commutative semiring instance on the natural numbers. See note [foundational algebra order theory]. -/ -open Multiplicative - namespace Nat /-! ### Instances -/ diff --git a/Mathlib/Algebra/Ring/Parity.lean b/Mathlib/Algebra/Ring/Parity.lean index 72fdec393def47..7b3959696657a9 100644 --- a/Mathlib/Algebra/Ring/Parity.lean +++ b/Mathlib/Algebra/Ring/Parity.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Algebra.Group.Nat.Even import Mathlib.Data.Nat.Cast.Basic import Mathlib.Data.Nat.Cast.Commute import Mathlib.Data.Set.Operations @@ -88,7 +89,6 @@ lemma Even.pow_of_ne_zero (ha : Even a) : ∀ {n : ℕ}, n ≠ 0 → Even (a ^ n /-- An element `a` of a semiring is odd if there exists `k` such `a = 2*k + 1`. -/ def Odd (a : α) : Prop := ∃ k, a = 2 * k + 1 -set_option linter.deprecated false in lemma odd_iff_exists_bit1 : Odd a ↔ ∃ b, a = 2 * b + 1 := exists_congr fun b ↦ by rw [two_mul] alias ⟨Odd.exists_bit1, _⟩ := odd_iff_exists_bit1 @@ -113,6 +113,8 @@ lemma Odd.add_odd : Odd a → Odd b → Even (a + b) := by @[simp] lemma Even.add_one (h : Even a) : Odd (a + 1) := h.add_odd odd_one @[simp] lemma Even.one_add (h : Even a) : Odd (1 + a) := h.odd_add odd_one +@[simp] lemma Odd.add_one (h : Odd a) : Even (a + 1) := h.add_odd odd_one +@[simp] lemma Odd.one_add (h : Odd a) : Even (1 + a) := odd_one.add_odd h lemma odd_two_mul_add_one (a : α) : Odd (2 * a + 1) := ⟨_, rfl⟩ @@ -244,7 +246,6 @@ lemma mod_two_add_add_odd_mod_two (m : ℕ) {n : ℕ} (hn : Odd n) : m % 2 + (m lemma even_add' : Even (m + n) ↔ (Odd m ↔ Odd n) := by 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) := diff --git a/Mathlib/Algebra/Ring/Semiconj.lean b/Mathlib/Algebra/Ring/Semiconj.lean index 8b20e68a71a066..0ec9636ddebc67 100644 --- a/Mathlib/Algebra/Ring/Semiconj.lean +++ b/Mathlib/Algebra/Ring/Semiconj.lean @@ -61,13 +61,9 @@ section variable [MulOneClass R] [HasDistribNeg R] --- Porting note: `simpNF` told me to remove `simp` attribute -theorem neg_one_right (a : R) : SemiconjBy a (-1) (-1) := - (one_right a).neg_right +theorem neg_one_right (a : R) : SemiconjBy a (-1) (-1) := by simp --- Porting note: `simpNF` told me to remove `simp` attribute -theorem neg_one_left (x : R) : SemiconjBy (-1) x x := - (SemiconjBy.one_left x).neg_left +theorem neg_one_left (x : R) : SemiconjBy (-1) x x := by simp end diff --git a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean index d955416892c367..bcd9bb5829c17b 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Submonoid.Membership -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.RingHom import Mathlib.Algebra.Ring.Action.Subobjects import Mathlib.Algebra.Ring.Equiv import Mathlib.Algebra.Ring.Prod diff --git a/Mathlib/Algebra/Squarefree/Basic.lean b/Mathlib/Algebra/Squarefree/Basic.lean index 284bc77d8edec2..9d68d11fc173a2 100644 --- a/Mathlib/Algebra/Squarefree/Basic.lean +++ b/Mathlib/Algebra/Squarefree/Basic.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ import Mathlib.RingTheory.Nilpotent.Basic -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.GCDMonoid +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicity /-! # Squarefree elements of monoids diff --git a/Mathlib/Algebra/Star/Basic.lean b/Mathlib/Algebra/Star/Basic.lean index 7e3efcae9d6b34..04f2f59e38df23 100644 --- a/Mathlib/Algebra/Star/Basic.lean +++ b/Mathlib/Algebra/Star/Basic.lean @@ -3,7 +3,6 @@ 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.Field.Defs import Mathlib.Algebra.Group.Invertible.Defs import Mathlib.Algebra.GroupWithZero.Units.Lemmas import Mathlib.Algebra.Regular.Basic @@ -38,7 +37,6 @@ assert_not_exists Rat.instField universe u v w open MulOpposite -open scoped NNRat /-- Notation typeclass (with no default notation!) for an algebraic structure with a star operation. -/ @@ -365,18 +363,22 @@ open scoped ComplexConjugate end CommSemiring @[simp] -theorem star_inv' [DivisionSemiring R] [StarRing R] (x : R) : star x⁻¹ = (star x)⁻¹ := - op_injective <| (map_inv₀ (starRingEquiv : R ≃+* Rᵐᵒᵖ) x).trans (op_inv (star x)).symm +theorem star_inv₀ [GroupWithZero R] [StarMul R] (x : R) : star x⁻¹ = (star x)⁻¹ := + op_injective <| (map_inv₀ (starMulEquiv : R ≃* Rᵐᵒᵖ) x).trans (op_inv (star x)).symm + +@[deprecated (since := "2024-11-18")] alias star_inv' := star_inv₀ @[simp] -theorem star_zpow₀ [DivisionSemiring R] [StarRing R] (x : R) (z : ℤ) : star (x ^ z) = star x ^ z := - op_injective <| (map_zpow₀ (starRingEquiv : R ≃+* Rᵐᵒᵖ) x z).trans (op_zpow (star x) z).symm +theorem star_zpow₀ [GroupWithZero R] [StarMul R] (x : R) (z : ℤ) : star (x ^ z) = star x ^ z := + op_injective <| (map_zpow₀ (starMulEquiv : R ≃* Rᵐᵒᵖ) x z).trans (op_zpow (star x) z).symm /-- When multiplication is commutative, `star` preserves division. -/ @[simp] -theorem star_div' [Semifield R] [StarRing R] (x y : R) : star (x / y) = star x / star y := by +theorem star_div₀ [CommGroupWithZero R] [StarMul R] (x y : R) : star (x / y) = star x / star y := by apply op_injective - rw [division_def, op_div, mul_comm, star_mul, star_inv', op_mul, op_inv] + rw [division_def, op_div, mul_comm, star_mul, star_inv₀, op_mul, op_inv] + +@[deprecated (since := "2024-11-18")] alias star_div' := star_div₀ /-- Any commutative semiring admits the trivial `*`-structure. diff --git a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean index 86f059f7cf0fea..0f0476488ad546 100644 --- a/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Star/NonUnitalSubalgebra.lean @@ -6,6 +6,7 @@ Authors: Jireh Loreaux import Mathlib.Algebra.Algebra.NonUnitalSubalgebra import Mathlib.Algebra.Star.StarAlgHom import Mathlib.Algebra.Star.Center +import Mathlib.Algebra.Star.SelfAdjoint /-! # Non-unital Star Subalgebras @@ -1130,6 +1131,77 @@ theorem centralizer_le (s t : Set A) (h : s ⊆ t) : centralizer R t ≤ central theorem centralizer_univ : centralizer R Set.univ = center R A := SetLike.ext' <| by rw [coe_centralizer, Set.univ_union, coe_center, Set.centralizer_univ] +theorem centralizer_toNonUnitalSubalgebra (s : Set A) : + (centralizer R s).toNonUnitalSubalgebra = NonUnitalSubalgebra.centralizer R (s ∪ star s):= + rfl + +theorem coe_centralizer_centralizer (s : Set A) : + (centralizer R (centralizer R s : Set A)) = (s ∪ star s).centralizer.centralizer := by + rw [coe_centralizer, StarMemClass.star_coe_eq, Set.union_self, coe_centralizer] + end Centralizer end NonUnitalStarSubalgebra + +namespace NonUnitalStarAlgebra + +open NonUnitalStarSubalgebra + +variable [CommSemiring R] [StarRing R] +variable [NonUnitalSemiring A] [StarRing A] [Module R A] +variable [IsScalarTower R A A] [SMulCommClass R A A] [StarModule R A] + +variable (R) in +lemma adjoin_le_centralizer_centralizer (s : Set A) : + adjoin R s ≤ centralizer R (centralizer R s) := by + rw [← toNonUnitalSubalgebra_le_iff, centralizer_toNonUnitalSubalgebra, + adjoin_toNonUnitalSubalgebra] + convert NonUnitalAlgebra.adjoin_le_centralizer_centralizer R (s ∪ star s) + rw [StarMemClass.star_coe_eq] + simp + +lemma commute_of_mem_adjoin_of_forall_mem_commute {a b : A} {s : Set A} + (hb : b ∈ adjoin R s) (h : ∀ b ∈ s, Commute a b) (h_star : ∀ b ∈ s, Commute a (star b)) : + Commute a b := + NonUnitalAlgebra.commute_of_mem_adjoin_of_forall_mem_commute hb fun b hb ↦ + hb.elim (h b) (by simpa using h_star (star b)) + +lemma commute_of_mem_adjoin_singleton_of_commute {a b c : A} + (hc : c ∈ adjoin R {b}) (h : Commute a b) (h_star : Commute a (star b)) : + Commute a c := + commute_of_mem_adjoin_of_forall_mem_commute hc (by simpa) (by simpa) + +lemma commute_of_mem_adjoin_self {a b : A} [IsStarNormal a] (hb : b ∈ adjoin R {a}) : + Commute a b := + commute_of_mem_adjoin_singleton_of_commute hb rfl (isStarNormal_iff a |>.mp inferInstance).symm + +variable (R) in +/-- If all elements of `s : Set A` commute pairwise and with elements of `star s`, then `adjoin R s` +is a non-unital commutative semiring. + +See note [reducible non-instances]. -/ +abbrev adjoinNonUnitalCommSemiringOfComm {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) + (hcomm_star : ∀ a ∈ s, ∀ b ∈ s, a * star b = star b * a) : + NonUnitalCommSemiring (adjoin R s) := + { (adjoin R s).toNonUnitalSemiring with + mul_comm := fun ⟨_, h₁⟩ ⟨_, h₂⟩ ↦ by + have hcomm : ∀ a ∈ s ∪ star s, ∀ b ∈ s ∪ star s, a * b = b * a := fun a ha b hb ↦ + Set.union_star_self_comm (fun _ ha _ hb ↦ hcomm _ hb _ ha) + (fun _ ha _ hb ↦ hcomm_star _ hb _ ha) b hb a ha + have := adjoin_le_centralizer_centralizer R s + apply this at h₁ + apply this at h₂ + rw [← SetLike.mem_coe, coe_centralizer_centralizer] at h₁ h₂ + exact Subtype.ext <| Set.centralizer_centralizer_comm_of_comm hcomm _ h₁ _ h₂ } + +/-- If all elements of `s : Set A` commute pairwise and with elements of `star s`, then `adjoin R s` +is a non-unital commutative ring. + +See note [reducible non-instances]. -/ +abbrev adjoinNonUnitalCommRingOfComm (R : Type*) {A : Type*} [CommRing R] [StarRing R] + [NonUnitalRing A] [StarRing A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A] + [StarModule R A] {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) + (hcomm_star : ∀ a ∈ s, ∀ b ∈ s, a * star b = star b * a) : NonUnitalCommRing (adjoin R s) := + { (adjoin R s).toNonUnitalRing, adjoinNonUnitalCommSemiringOfComm R hcomm hcomm_star with } + +end NonUnitalStarAlgebra diff --git a/Mathlib/Algebra/Star/Pointwise.lean b/Mathlib/Algebra/Star/Pointwise.lean index 75524536ac45c0..ee506f2c6f0372 100644 --- a/Mathlib/Algebra/Star/Pointwise.lean +++ b/Mathlib/Algebra/Star/Pointwise.lean @@ -6,6 +6,7 @@ Authors: Jireh Loreaux import Mathlib.Algebra.Group.Pointwise.Set.Basic import Mathlib.Algebra.Star.Basic import Mathlib.Data.Set.Finite.Basic +import Mathlib.Algebra.Field.Defs /-! # Pointwise star operation on sets @@ -118,7 +119,7 @@ protected theorem star_inv [Group α] [StarMul α] (s : Set α) : s⁻¹⋆ = s protected theorem star_inv' [DivisionSemiring α] [StarRing α] (s : Set α) : s⁻¹⋆ = s⋆⁻¹ := by ext - simp only [mem_star, mem_inv, star_inv'] + simp only [mem_star, mem_inv, star_inv₀] end Set diff --git a/Mathlib/Algebra/Star/SelfAdjoint.lean b/Mathlib/Algebra/Star/SelfAdjoint.lean index ff351d45081585..db9fa87db3a504 100644 --- a/Mathlib/Algebra/Star/SelfAdjoint.lean +++ b/Mathlib/Algebra/Star/SelfAdjoint.lean @@ -235,22 +235,38 @@ protected theorem intCast (z : ℤ) : IsSelfAdjoint (z : R) := end Ring -section DivisionSemiring +section Group -variable [DivisionSemiring R] [StarRing R] +variable [Group R] [StarMul R] @[aesop safe apply] theorem inv {x : R} (hx : IsSelfAdjoint x) : IsSelfAdjoint x⁻¹ := by - simp only [isSelfAdjoint_iff, star_inv', hx.star_eq] + simp only [isSelfAdjoint_iff, star_inv, hx.star_eq] @[aesop safe apply] theorem zpow {x : R} (hx : IsSelfAdjoint x) (n : ℤ) : IsSelfAdjoint (x ^ n) := by + simp only [isSelfAdjoint_iff, star_zpow, hx.star_eq] + +end Group + +section GroupWithZero + +variable [GroupWithZero R] [StarMul R] + +@[aesop safe apply] +theorem inv₀ {x : R} (hx : IsSelfAdjoint x) : IsSelfAdjoint x⁻¹ := by + simp only [isSelfAdjoint_iff, star_inv₀, hx.star_eq] + +@[aesop safe apply] +theorem zpow₀ {x : R} (hx : IsSelfAdjoint x) (n : ℤ) : IsSelfAdjoint (x ^ n) := by simp only [isSelfAdjoint_iff, star_zpow₀, hx.star_eq] -@[simp] -protected lemma nnratCast (q : ℚ≥0) : IsSelfAdjoint (q : R) := star_nnratCast _ +end GroupWithZero -end DivisionSemiring +@[simp] +protected lemma nnratCast [DivisionSemiring R] [StarRing R] (q : ℚ≥0) : + IsSelfAdjoint (q : R) := + star_nnratCast _ section DivisionRing @@ -267,17 +283,26 @@ section Semifield variable [Semifield R] [StarRing R] theorem div {x y : R} (hx : IsSelfAdjoint x) (hy : IsSelfAdjoint y) : IsSelfAdjoint (x / y) := by - simp only [isSelfAdjoint_iff, star_div', hx.star_eq, hy.star_eq] + simp only [isSelfAdjoint_iff, star_div₀, hx.star_eq, hy.star_eq] end Semifield section SMul -variable [Star R] [AddMonoid A] [StarAddMonoid A] [SMul R A] [StarModule R A] - @[aesop safe apply] -theorem smul {r : R} (hr : IsSelfAdjoint r) {x : A} (hx : IsSelfAdjoint x) : - IsSelfAdjoint (r • x) := by simp only [isSelfAdjoint_iff, star_smul, hr.star_eq, hx.star_eq] +theorem smul [Star R] [AddMonoid A] [StarAddMonoid A] [SMul R A] [StarModule R A] + {r : R} (hr : IsSelfAdjoint r) {x : A} (hx : IsSelfAdjoint x) : + IsSelfAdjoint (r • x) := by + simp only [isSelfAdjoint_iff, star_smul, hr.star_eq, hx.star_eq] + +theorem smul_iff [Monoid R] [StarMul R] [AddMonoid A] [StarAddMonoid A] + [MulAction R A] [StarModule R A] {r : R} (hr : IsSelfAdjoint r) (hu : IsUnit r) {x : A} : + IsSelfAdjoint (r • x) ↔ IsSelfAdjoint x := by + refine ⟨fun hrx ↦ ?_, .smul hr⟩ + lift r to Rˣ using hu + rw [← inv_smul_smul r x] + replace hr : IsSelfAdjoint r := Units.ext hr.star_eq + exact hr.inv.smul hrx end SMul @@ -384,7 +409,7 @@ section Field variable [Field R] [StarRing R] instance : Inv (selfAdjoint R) where - inv x := ⟨x.val⁻¹, x.prop.inv⟩ + inv x := ⟨x.val⁻¹, x.prop.inv₀⟩ @[simp, norm_cast] theorem val_inv (x : selfAdjoint R) : ↑x⁻¹ = (x : R)⁻¹ := @@ -398,7 +423,7 @@ theorem val_div (x y : selfAdjoint R) : ↑(x / y) = (x / y : R) := rfl instance : Pow (selfAdjoint R) ℤ where - pow x z := ⟨(x : R) ^ z, x.prop.zpow z⟩ + pow x z := ⟨(x : R) ^ z, x.prop.zpow₀ z⟩ @[simp, norm_cast] theorem val_zpow (x : selfAdjoint R) (z : ℤ) : ↑(x ^ z) = (x : R) ^ z := diff --git a/Mathlib/Algebra/Star/Subsemiring.lean b/Mathlib/Algebra/Star/Subsemiring.lean index 8ef2bdd8fdd39f..707ac11a068a8d 100644 --- a/Mathlib/Algebra/Star/Subsemiring.lean +++ b/Mathlib/Algebra/Star/Subsemiring.lean @@ -53,7 +53,6 @@ instance starRing (s : StarSubsemiring R) : StarRing s := instance semiring (s : StarSubsemiring R) : NonAssocSemiring s := s.toSubsemiring.toNonAssocSemiring -@[simp, nolint simpNF] theorem mem_carrier {s : StarSubsemiring R} {x : R} : x ∈ s.carrier ↔ x ∈ s := Iff.rfl diff --git a/Mathlib/Algebra/Symmetrized.lean b/Mathlib/Algebra/Symmetrized.lean index 00c398aaf91ddc..45a69d07685663 100644 --- a/Mathlib/Algebra/Symmetrized.lean +++ b/Mathlib/Algebra/Symmetrized.lean @@ -48,7 +48,7 @@ def sym : α ≃ αˢʸᵐ := /-- The element of `α` represented by `x : αˢʸᵐ`. -/ -- Porting note (kmill): `pp_nodot` has no affect here --- unless RFC https://github.com/leanprover/lean4/issues/1910 leads to dot notation for CoeFun +-- unless RFC https://github.com/leanprover/lean4/issues/6178 leads to dot notation pp for CoeFun @[pp_nodot] def unsym : αˢʸᵐ ≃ α := Equiv.refl _ diff --git a/Mathlib/Algebra/TrivSqZeroExt.lean b/Mathlib/Algebra/TrivSqZeroExt.lean index c40ab975c18d7d..cc4239ab85e256 100644 --- a/Mathlib/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Algebra/TrivSqZeroExt.lean @@ -870,10 +870,9 @@ section Algebra variable (S : Type*) (R R' : Type u) (M : Type v) variable [CommSemiring S] [Semiring R] [CommSemiring R'] [AddCommMonoid M] -variable [Algebra S R] [Algebra S R'] [Module S M] -variable [Module R M] [Module Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] +variable [Algebra S R] [Module S M] [Module R M] [Module Rᵐᵒᵖ M] [SMulCommClass R Rᵐᵒᵖ M] variable [IsScalarTower S R M] [IsScalarTower S Rᵐᵒᵖ M] -variable [Module R' M] [Module R'ᵐᵒᵖ M] [IsCentralScalar R' M] [IsScalarTower S R' M] +variable [Module R' M] [Module R'ᵐᵒᵖ M] [IsCentralScalar R' M] instance algebra' : Algebra S (tsze R M) := { (TrivSqZeroExt.inlHom R M).comp (algebraMap S R) with diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index a83addf8247e54..96002facc9d472 100644 --- a/Mathlib/AlgebraicGeometry/AffineScheme.lean +++ b/Mathlib/AlgebraicGeometry/AffineScheme.lean @@ -67,12 +67,12 @@ def Scheme.isoSpec (X : Scheme) [IsAffine X] : X ≅ Spec Γ(X, ⊤) := @[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 + X.isoSpec.hom ≫ Spec.map (f.appTop) = f ≫ Y.isoSpec.hom := by 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 + Spec.map (f.appTop) ≫ Y.isoSpec.inv = X.isoSpec.inv ≫ f := by rw [Iso.eq_inv_comp, isoSpec, asIso_hom, ← Scheme.toSpecΓ_naturality_assoc, isoSpec, asIso_inv, IsIso.hom_inv_id, Category.comp_id] @@ -112,13 +112,13 @@ theorem isAffine_of_isIso {X Y : Scheme} (f : X ⟶ Y) [IsIso f] [h : IsAffine Y to the arrow of the morphism on prime spectra induced by the map on global sections. -/ noncomputable def arrowIsoSpecΓOfIsAffine {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Y) : - Arrow.mk f ≅ Arrow.mk (Spec.map (Scheme.Γ.map f.op)) := + Arrow.mk f ≅ Arrow.mk (Spec.map f.appTop) := 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.mk f ≅ Arrow.mk ((Spec.map f).appTop) := Arrow.isoMk (Scheme.ΓSpecIso _).symm (Scheme.ΓSpecIso _).symm (Scheme.ΓSpecIso_inv_naturality f).symm @@ -134,7 +134,7 @@ theorem Scheme.isoSpec_Spec (R : CommRingCat.{u}) : (Spec R).isoSpec.inv = Spec.map (Scheme.ΓSpecIso R).inv := congr($(isoSpec_Spec R).inv) -lemma ext_of_isAffine {X Y : Scheme} [IsAffine Y] {f g : X ⟶ Y} (e : f.app ⊤ = g.app ⊤) : +lemma ext_of_isAffine {X Y : Scheme} [IsAffine Y] {f g : X ⟶ Y} (e : f.appTop = g.appTop) : f = g := by rw [← cancel_mono Y.toSpecΓ, Scheme.toSpecΓ_naturality, Scheme.toSpecΓ_naturality, e] @@ -315,21 +315,24 @@ lemma isoSpec_hom_base_apply (x : U) : congr 1 exact IsLocalRing.comap_closedPoint (U.stalkIso x).inv -lemma isoSpec_inv_app_top : - hU.isoSpec.inv.app ⊤ = U.topIso.hom ≫ (Scheme.ΓSpecIso Γ(X, U)).inv := by +lemma isoSpec_inv_appTop : + hU.isoSpec.inv.appTop = U.topIso.hom ≫ (Scheme.ΓSpecIso Γ(X, U)).inv := by simp only [Scheme.Opens.toScheme_presheaf_obj, isoSpec_inv, Scheme.isoSpec, asIso_inv, - Scheme.comp_coeBase, Opens.map_comp_obj, Opens.map_top, Scheme.comp_app, Scheme.inv_app_top, + Scheme.comp_coeBase, Opens.map_comp_obj, Opens.map_top, Scheme.comp_app, Scheme.inv_appTop, Scheme.Opens.topIso_hom, Scheme.ΓSpecIso_inv_naturality, IsIso.inv_comp_eq] - rw [Scheme.toSpecΓ_app_top] + rw [Scheme.toSpecΓ_appTop] erw [Iso.hom_inv_id_assoc] -lemma isoSpec_hom_app_top : - hU.isoSpec.hom.app ⊤ = (Scheme.ΓSpecIso Γ(X, U)).hom ≫ U.topIso.inv := by - have := congr(inv $hU.isoSpec_inv_app_top) +lemma isoSpec_hom_appTop : + hU.isoSpec.hom.appTop = (Scheme.ΓSpecIso Γ(X, U)).hom ≫ U.topIso.inv := by + have := congr(inv $hU.isoSpec_inv_appTop) rw [IsIso.inv_comp, IsIso.Iso.inv_inv, IsIso.Iso.inv_hom] at this have := (Scheme.Γ.map_inv hU.isoSpec.inv.op).trans this rwa [← op_inv, IsIso.Iso.inv_inv] at this +@[deprecated (since := "2024-11-16")] alias isoSpec_inv_app_top := isoSpec_inv_appTop +@[deprecated (since := "2024-11-16")] alias isoSpec_hom_app_top := isoSpec_hom_appTop + /-- The open immersion `Spec Γ(X, U) ⟶ X` for an affine `U`. -/ def fromSpec : Spec Γ(X, U) ⟶ X := @@ -364,7 +367,7 @@ theorem map_fromSpec {V : X.Opens} (hV : IsAffineOpen V) (f : op U ⟶ op V) : conv_rhs => rw [fromSpec, ← X.homOfLE_ι (V := U) f.unop.le, isoSpec_inv, Category.assoc, ← Scheme.isoSpec_inv_naturality_assoc, - ← Spec.map_comp_assoc, Scheme.homOfLE_app, ← Functor.map_comp] + ← Spec.map_comp_assoc, Scheme.homOfLE_appTop, ← Functor.map_comp] rw [fromSpec, isoSpec_inv, Category.assoc, ← Spec.map_comp_assoc, ← Functor.map_comp] rfl @@ -377,21 +380,22 @@ lemma Spec_map_appLE_fromSpec (f : X ⟶ Y) {V : X.Opens} {U : Y.Opens} simp_rw [← Scheme.homOfLE_ι _ i] rw [Category.assoc, ← morphismRestrict_ι, ← Category.assoc _ (f ∣_ U) U.ι, ← @Scheme.isoSpec_inv_naturality_assoc, - ← Spec.map_comp_assoc, ← Spec.map_comp_assoc, Scheme.comp_app, morphismRestrict_app, - Scheme.homOfLE_app, Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map, + ← Spec.map_comp_assoc, ← Spec.map_comp_assoc, Scheme.comp_appTop, morphismRestrict_appTop, + Scheme.homOfLE_appTop, Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map, Scheme.Hom.appLE_map, Scheme.Hom.appLE_map, Scheme.Hom.map_appLE] lemma fromSpec_top [IsAffine X] : (isAffineOpen_top X).fromSpec = X.isoSpec.inv := by - rw [fromSpec, isoSpec_inv, Category.assoc, ← @Scheme.isoSpec_inv_naturality, Scheme.Opens.ι_app, - ← Spec.map_comp_assoc, ← X.presheaf.map_comp, ← op_comp, eqToHom_comp_homOfLE, - ← eqToHom_eq_homOfLE rfl, eqToHom_refl, op_id, X.presheaf.map_id, Spec.map_id, Category.id_comp] + rw [fromSpec, isoSpec_inv, Category.assoc, ← @Scheme.isoSpec_inv_naturality, + ← Spec.map_comp_assoc, Scheme.Opens.ι_appTop, ← X.presheaf.map_comp, ← op_comp, + eqToHom_comp_homOfLE, ← eqToHom_eq_homOfLE rfl, eqToHom_refl, op_id, X.presheaf.map_id, + Spec.map_id, Category.id_comp] lemma fromSpec_app_of_le (V : X.Opens) (h : U ≤ V) : hU.fromSpec.app V = X.presheaf.map (homOfLE h).op ≫ (Scheme.ΓSpecIso Γ(X, U)).inv ≫ (Spec _).presheaf.map (homOfLE le_top).op := by have : U.ι ⁻¹ᵁ V = ⊤ := eq_top_iff.mpr fun x _ ↦ h x.2 rw [IsAffineOpen.fromSpec, Scheme.comp_app, Scheme.Opens.ι_app, Scheme.app_eq _ this, - IsAffineOpen.isoSpec_inv_app_top] + ← Scheme.Hom.appTop, IsAffineOpen.isoSpec_inv_appTop] simp only [Scheme.Opens.toScheme_presheaf_map, Scheme.Opens.topIso_hom, Category.assoc, ← X.presheaf.map_comp_assoc] rfl @@ -470,7 +474,7 @@ theorem ΓSpecIso_hom_fromSpec_app : simp only [fromSpec, Scheme.comp_coeBase, Opens.map_comp_obj, Scheme.comp_app, Scheme.Opens.ι_app_self, eqToHom_op, Scheme.app_eq _ U.ι_preimage_self, Scheme.Opens.toScheme_presheaf_map, eqToHom_unop, eqToHom_map U.ι.opensFunctor, Opens.map_top, - isoSpec_inv_app_top, Scheme.Opens.topIso_hom, Category.assoc, ← Functor.map_comp_assoc, + isoSpec_inv_appTop, Scheme.Opens.topIso_hom, Category.assoc, ← Functor.map_comp_assoc, eqToHom_trans, eqToHom_refl, X.presheaf.map_id, Category.id_comp, Iso.hom_inv_id_assoc] @[elementwise] @@ -953,10 +957,10 @@ lemma specTargetImageRingHom_surjective : Function.Surjective (specTargetImageRi Ideal.Quotient.mk_surjective lemma specTargetImageFactorization_app_injective : - Function.Injective <| (specTargetImageFactorization f).app ⊤ := by + Function.Injective <| (specTargetImageFactorization f).appTop := 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 ⊤ + show Function.Injective <| ((ΓSpec.adjunction.homEquiv X _) φ'.op).appTop rw [ΓSpec_adjunction_homEquiv_eq] apply (RingHom.kerLift_injective φ).comp exact ((ConcreteCategory.isIso_iff_bijective (Scheme.ΓSpecIso _).hom).mp inferInstance).injective @@ -993,7 +997,7 @@ 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 + Function.Surjective <| (affineTargetImageInclusion f).appTop := by simp only [Scheme.comp_coeBase, Opens.map_comp_obj, Opens.map_top, Scheme.comp_app, CommRingCat.coe_comp, affineTargetImageInclusion] apply Function.Surjective.comp @@ -1013,7 +1017,7 @@ def affineTargetImageFactorization (f : X ⟶ Y) : X ⟶ affineTargetImage f := specTargetImageFactorization (f ≫ Y.isoSpec.hom) lemma affineTargetImageFactorization_app_injective : - Function.Injective <| (affineTargetImageFactorization f).app ⊤ := + Function.Injective <| (affineTargetImageFactorization f).appTop := specTargetImageFactorization_app_injective (f ≫ Y.isoSpec.hom) @[reassoc (attr := simp)] diff --git a/Mathlib/AlgebraicGeometry/AffineSpace.lean b/Mathlib/AlgebraicGeometry/AffineSpace.lean index 6374a6564ad9fc..805e43c4928d27 100644 --- a/Mathlib/AlgebraicGeometry/AffineSpace.lean +++ b/Mathlib/AlgebraicGeometry/AffineSpace.lean @@ -71,7 +71,7 @@ Use `homOverEquiv` instead. -/ @[simps] def toSpecMvPolyIntEquiv : (X ⟶ Spec ℤ[n]) ≃ (n → Γ(X, ⊤)) where - toFun f i := f.app ⊤ ((Scheme.ΓSpecIso ℤ[n]).inv (.X i)) + toFun f i := f.appTop ((Scheme.ΓSpecIso ℤ[n]).inv (.X i)) invFun v := X.toSpecΓ ≫ Spec.map (MvPolynomial.eval₂Hom ((algebraMap ℤ _).comp ULift.ringEquiv.toRingHom) v) left_inv f := by @@ -80,7 +80,7 @@ def toSpecMvPolyIntEquiv : (X ⟶ Spec ℤ[n]) ≃ (n → Γ(X, ⊤)) where rw [Adjunction.homEquiv_symm_apply, Adjunction.homEquiv_symm_apply] simp only [Functor.rightOp_obj, Scheme.Γ_obj, Scheme.Spec_obj, algebraMap_int_eq, RingEquiv.toRingHom_eq_coe, TopologicalSpace.Opens.map_top, Functor.rightOp_map, op_comp, - Scheme.Γ_map, unop_comp, Quiver.Hom.unop_op, Scheme.comp_app, Scheme.toSpecΓ_app_top, + Scheme.Γ_map, unop_comp, Quiver.Hom.unop_op, Scheme.comp_app, Scheme.toSpecΓ_appTop, Scheme.ΓSpecIso_naturality, ΓSpec.adjunction_counit_app, Category.assoc, Iso.cancel_iso_inv_left, ← Iso.eq_inv_comp] apply of_mvPolynomial_int_ext @@ -91,13 +91,13 @@ def toSpecMvPolyIntEquiv : (X ⟶ Spec ℤ[n]) ≃ (n → Γ(X, ⊤)) where ext i simp only [algebraMap_int_eq, RingEquiv.toRingHom_eq_coe, Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, TopologicalSpace.Opens.map_top, Scheme.comp_app, - Scheme.toSpecΓ_app_top, Scheme.ΓSpecIso_naturality, CommRingCat.comp_apply, + Scheme.toSpecΓ_appTop, Scheme.ΓSpecIso_naturality, CommRingCat.comp_apply, CommRingCat.coe_of] erw [Iso.hom_inv_id_apply] rw [coe_eval₂Hom, eval₂_X] lemma toSpecMvPolyIntEquiv_comp {X Y : Scheme} (f : X ⟶ Y) (g : Y ⟶ Spec ℤ[n]) (i) : - toSpecMvPolyIntEquiv n (f ≫ g) i = f.app ⊤ (toSpecMvPolyIntEquiv n g i) := rfl + toSpecMvPolyIntEquiv n (f ≫ g) i = f.appTop (toSpecMvPolyIntEquiv n g i) := rfl variable {n} in /-- The standard coordinates of `𝔸(n; S)`. -/ @@ -122,16 +122,16 @@ lemma homOfVector_toSpecMvPoly : homOfVector f v ≫ toSpecMvPoly n S = (toSpecMvPolyIntEquiv n).symm v := pullback.lift_snd _ _ _ -@[local simp] -lemma homOfVector_app_top_coord (i) : - (homOfVector f v).app ⊤ (coord S i) = v i := by +@[simp] +lemma homOfVector_appTop_coord (i) : + (homOfVector f v).appTop (coord S i) = v i := by rw [coord, ← toSpecMvPolyIntEquiv_comp, homOfVector_toSpecMvPoly, Equiv.apply_symm_apply] @[ext 1100] lemma hom_ext {f g : X ⟶ 𝔸(n; S)} (h₁ : f ≫ 𝔸(n; S) ↘ S = g ≫ 𝔸(n; S) ↘ S) - (h₂ : ∀ i, f.app ⊤ (coord S i) = g.app ⊤ (coord S i)) : f = g := by + (h₂ : ∀ i, f.appTop (coord S i) = g.appTop (coord S i)) : f = g := by apply pullback.hom_ext h₁ show f ≫ toSpecMvPoly _ _ = g ≫ toSpecMvPoly _ _ apply (toSpecMvPolyIntEquiv n).injective @@ -141,8 +141,8 @@ lemma hom_ext {f g : X ⟶ 𝔸(n; S)} @[reassoc] lemma comp_homOfVector {X Y : Scheme} (v : n → Γ(Y, ⊤)) (f : X ⟶ Y) (g : Y ⟶ S) : - f ≫ homOfVector g v = homOfVector (f ≫ g) (f.app ⊤ ∘ v) := by - ext1 <;> simp [-TopologicalSpace.Opens.map_top]; rfl + f ≫ homOfVector g v = homOfVector (f ≫ g) (f.appTop ∘ v) := by + ext1 <;> simp end homOfVector @@ -155,13 +155,13 @@ instance (v : n → Γ(X, ⊤)) : (homOfVector (X ↘ S) v).IsOver S where /-- `S`-morphisms into `Spec 𝔸(n; S)` are equivalent to the choice of `n` global sections. -/ @[simps] def homOverEquiv : { f : X ⟶ 𝔸(n; S) // f.IsOver S } ≃ (n → Γ(X, ⊤)) where - toFun f i := f.1.app ⊤ (coord S i) + toFun f i := f.1.appTop (coord S i) invFun v := ⟨homOfVector (X ↘ S) v, inferInstance⟩ left_inv f := by ext : 2 · simp [f.2.1] - · rw [homOfVector_app_top_coord] - right_inv v := by ext i; simp [-TopologicalSpace.Opens.map_top, homOfVector_app_top_coord] + · rw [homOfVector_appTop_coord] + right_inv v := by ext i; simp [-TopologicalSpace.Opens.map_top, homOfVector_appTop_coord] variable (n) in /-- @@ -171,7 +171,7 @@ Also see `AffineSpace.SpecIso`. @[simps (config := .lemmasOnly) hom inv] def isoOfIsAffine [IsAffine S] : 𝔸(n; S) ≅ Spec (.of (MvPolynomial n Γ(S, ⊤))) where - hom := 𝔸(n; S).toSpecΓ ≫ Spec.map (eval₂Hom ((𝔸(n; S) ↘ S).app ⊤) (coord S)) + hom := 𝔸(n; S).toSpecΓ ≫ Spec.map (eval₂Hom ((𝔸(n; S) ↘ S).appTop) (coord S)) inv := homOfVector (Spec.map C ≫ S.isoSpec.inv) ((Scheme.ΓSpecIso (.of (MvPolynomial n Γ(S, ⊤)))).inv ∘ MvPolynomial.X) hom_inv_id := by @@ -180,48 +180,43 @@ def isoOfIsAffine [IsAffine S] : rw [← Spec.map_comp_assoc, CommRingCat.comp_eq_ring_hom_comp, eval₂Hom_comp_C, ← Scheme.toSpecΓ_naturality_assoc] simp [Scheme.isoSpec] - · simp only [Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, Scheme.comp_app, - CommRingCat.coe_comp_of, RingHom.coe_comp, Function.comp_apply, Scheme.id.base, - Scheme.id_app] - -- note: `rw [homOfVector_app_top_coord]` works but takes 3 more seconds - conv => enter [1, 2, 2]; rw [homOfVector_app_top_coord] - simp only [TopologicalSpace.Opens.map_top, Scheme.toSpecΓ_app_top, Function.comp_apply, + · simp only [Category.assoc, Scheme.comp_app, Scheme.comp_coeBase, + TopologicalSpace.Opens.map_comp_obj, TopologicalSpace.Opens.map_top, + Scheme.toSpecΓ_appTop, Scheme.ΓSpecIso_naturality, CommRingCat.comp_apply, + homOfVector_appTop_coord, Function.comp_apply, CommRingCat.coe_of, Scheme.id_app, CommRingCat.id_apply] - erw [elementwise_of% Scheme.ΓSpecIso_naturality, Iso.hom_inv_id_apply] + erw [Iso.hom_inv_id_apply] exact eval₂_X _ _ _ inv_hom_id := by apply ext_of_isAffine simp only [Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, - TopologicalSpace.Opens.map_top, Scheme.comp_app, Scheme.toSpecΓ_app_top, + TopologicalSpace.Opens.map_top, Scheme.comp_app, Scheme.toSpecΓ_appTop, Scheme.ΓSpecIso_naturality, Category.assoc, Scheme.id_app, ← Iso.eq_inv_comp, Category.comp_id] apply ringHom_ext' · show _ = CommRingCat.ofHom C ≫ _ rw [CommRingCat.comp_eq_ring_hom_comp, RingHom.comp_assoc, eval₂Hom_comp_C, ← CommRingCat.comp_eq_ring_hom_comp, ← cancel_mono (Scheme.ΓSpecIso _).hom] - erw [← Scheme.comp_app] - rw [homOfVector_over, Scheme.comp_app] - simp only [TopologicalSpace.Opens.map_top, Category.assoc, Scheme.ΓSpecIso_naturality, ← - Scheme.toSpecΓ_app_top] - erw [← Scheme.comp_app_assoc] - rw [Scheme.isoSpec, asIso_inv, IsIso.hom_inv_id] + rw [← Scheme.comp_appTop, homOfVector_over, Scheme.comp_appTop] + simp only [Category.assoc, Scheme.ΓSpecIso_naturality, ← Scheme.toSpecΓ_appTop] + rw [← Scheme.comp_appTop_assoc, Scheme.isoSpec, asIso_inv, IsIso.hom_inv_id] simp rfl · intro i erw [CommRingCat.comp_apply, coe_eval₂Hom] simp only [eval₂_X] - exact homOfVector_app_top_coord _ _ _ + exact homOfVector_appTop_coord _ _ _ @[simp] -lemma isoOfIsAffine_hom_app_top [IsAffine S] : - (isoOfIsAffine n S).hom.app ⊤ = - (Scheme.ΓSpecIso _).hom ≫ eval₂Hom ((𝔸(n; S) ↘ S).app ⊤) (coord S) := by +lemma isoOfIsAffine_hom_appTop [IsAffine S] : + (isoOfIsAffine n S).hom.appTop = + (Scheme.ΓSpecIso _).hom ≫ eval₂Hom ((𝔸(n; S) ↘ S).appTop) (coord S) := by simp [isoOfIsAffine_hom] -@[local simp] -lemma isoOfIsAffine_inv_app_top_coord [IsAffine S] (i) : - (isoOfIsAffine n S).inv.app ⊤ (coord _ i) = (Scheme.ΓSpecIso (.of _)).inv (.X i) := - homOfVector_app_top_coord _ _ _ +@[simp] +lemma isoOfIsAffine_inv_appTop_coord [IsAffine S] (i) : + (isoOfIsAffine n S).inv.appTop (coord _ i) = (Scheme.ΓSpecIso (.of _)).inv (.X i) := + homOfVector_appTop_coord _ _ _ @[reassoc (attr := simp)] lemma isoOfIsAffine_inv_over [IsAffine S] : @@ -238,27 +233,27 @@ def SpecIso (R : CommRingCat.{max u v}) : (Scheme.ΓSpecIso R).symm.commRingCatIsoToRingEquiv).toCommRingCatIso.op @[simp] -lemma SpecIso_hom_app_top (R : CommRingCat.{max u v}) : - (SpecIso n R).hom.app ⊤ = (Scheme.ΓSpecIso _).hom ≫ - eval₂Hom ((Scheme.ΓSpecIso _).inv ≫ (𝔸(n; Spec R) ↘ Spec R).app ⊤) (coord (Spec R)) := by +lemma SpecIso_hom_appTop (R : CommRingCat.{max u v}) : + (SpecIso n R).hom.appTop = (Scheme.ΓSpecIso _).hom ≫ + eval₂Hom ((Scheme.ΓSpecIso _).inv ≫ (𝔸(n; Spec R) ↘ Spec R).appTop) (coord (Spec R)) := by simp only [SpecIso, Iso.trans_hom, Functor.mapIso_hom, Iso.op_hom, RingEquiv.toCommRingCatIso_hom, RingEquiv.toRingHom_eq_coe, Scheme.Spec_map, Quiver.Hom.unop_op, Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, TopologicalSpace.Opens.map_top, Scheme.comp_app, - isoOfIsAffine_hom_app_top] + isoOfIsAffine_hom_appTop] erw [Scheme.ΓSpecIso_naturality_assoc] congr 1 apply ringHom_ext' - · ext; simp; rfl + · ext; simp · simp -@[local simp] -lemma SpecIso_inv_app_top_coord (R : CommRingCat.{max u v}) (i) : - (SpecIso n R).inv.app ⊤ (coord _ i) = (Scheme.ΓSpecIso (.of _)).inv (.X i) := by +@[simp] +lemma SpecIso_inv_appTop_coord (R : CommRingCat.{max u v}) (i) : + (SpecIso n R).inv.appTop (coord _ i) = (Scheme.ΓSpecIso (.of _)).inv (.X i) := by simp only [SpecIso, Iso.trans_inv, Functor.mapIso_inv, Iso.op_inv, RingEquiv.toCommRingCatIso_inv, mapEquiv_symm, RingEquiv.toRingHom_eq_coe, Scheme.Spec_map, Quiver.Hom.unop_op, Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, TopologicalSpace.Opens.map_top, Scheme.comp_app, CommRingCat.comp_apply] - erw [isoOfIsAffine_inv_app_top_coord, ← CommRingCat.comp_apply] + erw [isoOfIsAffine_inv_appTop_coord, ← CommRingCat.comp_apply] rw [← Scheme.ΓSpecIso_inv_naturality] erw [CommRingCat.comp_apply] congr 1 @@ -286,14 +281,14 @@ def map {S T : Scheme.{max u v}} (f : S ⟶ T) : 𝔸(n; S) ⟶ 𝔸(n; T) := lemma map_over {S T : Scheme.{max u v}} (f : S ⟶ T) : map n f ≫ 𝔸(n; T) ↘ T = 𝔸(n; S) ↘ S ≫ f := pullback.lift_fst _ _ _ -@[local simp] -lemma map_app_top_coord {S T : Scheme.{max u v}} (f : S ⟶ T) (i) : - (map n f).app ⊤ (coord T i) = coord S i := - homOfVector_app_top_coord _ _ _ +@[simp] +lemma map_appTop_coord {S T : Scheme.{max u v}} (f : S ⟶ T) (i) : + (map n f).appTop (coord T i) = coord S i := + homOfVector_appTop_coord _ _ _ @[simp] lemma map_id : map n (𝟙 S) = 𝟙 𝔸(n; S) := by - ext1 <;> simp [-TopologicalSpace.Opens.map_top]; rfl + ext1 <;> simp @[reassoc, simp] lemma map_comp {S S' S'' : Scheme} (f : S ⟶ S') (g : S' ⟶ S'') : @@ -302,7 +297,7 @@ lemma map_comp {S S' S'' : Scheme} (f : S ⟶ S') (g : S' ⟶ S'') : · simp · simp only [TopologicalSpace.Opens.map_top, Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, Scheme.comp_app, CommRingCat.comp_apply] - erw [map_app_top_coord, map_app_top_coord, map_app_top_coord] + erw [map_appTop_coord, map_appTop_coord, map_appTop_coord] lemma map_Spec_map {R S : CommRingCat.{max u v}} (φ : R ⟶ S) : map n (Spec.map φ) = @@ -314,9 +309,9 @@ lemma map_Spec_map {R S : CommRingCat.{max u v}} (φ : R ⟶ S) : rw [map_comp_C] · simp only [Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, TopologicalSpace.Opens.map_top, Scheme.comp_app, CommRingCat.comp_apply] - conv_lhs => enter[2]; tactic => exact map_app_top_coord _ _ - conv_rhs => enter[2]; tactic => exact SpecIso_inv_app_top_coord _ _ - erw [SpecIso_inv_app_top_coord, ← CommRingCat.comp_apply] + conv_lhs => enter[2]; tactic => exact map_appTop_coord _ _ + conv_rhs => enter[2]; tactic => exact SpecIso_inv_appTop_coord _ _ + erw [SpecIso_inv_appTop_coord, ← CommRingCat.comp_apply] rw [← Scheme.ΓSpecIso_inv_naturality] erw [CommRingCat.comp_apply, map_X] rfl @@ -332,44 +327,34 @@ def mapSpecMap {R S : CommRingCat.{max u v}} (φ : R ⟶ S) : def reindex {n m : Type v} (i : m → n) (S : Scheme.{max u v}) : 𝔸(n; S) ⟶ 𝔸(m; S) := homOfVector (𝔸(n; S) ↘ S) (coord S ∘ i) -@[reassoc (attr := simp)] +@[simp, reassoc] lemma reindex_over {n m : Type v} (i : m → n) (S : Scheme.{max u v}) : reindex i S ≫ 𝔸(m; S) ↘ S = 𝔸(n; S) ↘ S := pullback.lift_fst _ _ _ -@[local simp] -lemma reindex_app_top_coord {n m : Type v} (i : m → n) (S : Scheme.{max u v}) (j : m) : - (reindex i S).app ⊤ (coord S j) = coord S (i j) := - homOfVector_app_top_coord _ _ _ +@[simp] +lemma reindex_appTop_coord {n m : Type v} (i : m → n) (S : Scheme.{max u v}) (j : m) : + (reindex i S).appTop (coord S j) = coord S (i j) := + homOfVector_appTop_coord _ _ _ @[simp] lemma reindex_id : reindex id S = 𝟙 𝔸(n; S) := by - ext1 <;> simp [-TopologicalSpace.Opens.map_top]; rfl + ext1 <;> simp +@[simp, reassoc] lemma reindex_comp {n₁ n₂ n₃ : Type v} (i : n₁ → n₂) (j : n₂ → n₃) (S : Scheme.{max u v}) : reindex (j ∘ i) S = reindex j S ≫ reindex i S := by have H₁ : reindex (j ∘ i) S ≫ 𝔸(n₁; S) ↘ S = (reindex j S ≫ reindex i S) ≫ 𝔸(n₁; S) ↘ S := by simp - have H₂ (k) : (reindex (j ∘ i) S).app ⊤ (coord S k) = - (reindex j S).app ⊤ ((reindex i S).app ⊤ (coord S k)) := by - rw [reindex_app_top_coord, reindex_app_top_coord, reindex_app_top_coord] + have H₂ (k) : (reindex (j ∘ i) S).appTop (coord S k) = + (reindex j S).appTop ((reindex i S).appTop (coord S k)) := by + rw [reindex_appTop_coord, reindex_appTop_coord, reindex_appTop_coord] rfl exact hom_ext H₁ H₂ --- These time out if added to `reindex_comp` directly. -attribute [reassoc] reindex_comp -attribute [simp] reindex_comp - +@[reassoc (attr := simp)] lemma map_reindex {n₁ n₂ : Type v} (i : n₁ → n₂) {S T : Scheme.{max u v}} (f : S ⟶ T) : map n₂ f ≫ reindex i T = reindex i S ≫ map n₁ f := by - apply hom_ext - · simp - · intro j - simp only [Scheme.comp_coeBase, TopologicalSpace.Opens.map_comp_obj, Scheme.comp_app, - CommRingCat.comp_apply, map_app_top_coord, reindex_app_top_coord] - simp only [TopologicalSpace.Opens.map_top] - erw [map_app_top_coord f (i j), reindex_app_top_coord i S] - -attribute [reassoc (attr := simp)] map_reindex + apply hom_ext <;> simp /-- The affine space as a functor. -/ @[simps] diff --git a/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean b/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean index e2226dd86717f9..53a9c4dfd20921 100644 --- a/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean +++ b/Mathlib/AlgebraicGeometry/Cover/MorphismProperty.lean @@ -73,6 +73,9 @@ theorem Cover.iUnion_range {X : Scheme.{u}} (𝒰 : X.Cover P) : rw [Set.mem_iUnion] exact ⟨𝒰.f x, 𝒰.covers x⟩ +lemma Cover.exists_eq (𝒰 : X.Cover P) (x : X) : ∃ i y, (𝒰.map i).base y = x := + ⟨_, 𝒰.covers x⟩ + /-- Given a family of schemes with morphisms to `X` satisfying `P` that jointly cover `X`, this an associated `P`-cover of `X`. -/ @[simps] diff --git a/Mathlib/AlgebraicGeometry/Cover/Over.lean b/Mathlib/AlgebraicGeometry/Cover/Over.lean new file mode 100644 index 00000000000000..e6b2a8b4e0e23c --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Cover/Over.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.AlgebraicGeometry.Morphisms.UnderlyingMap +import Mathlib.CategoryTheory.Limits.MorphismProperty + +/-! + +# Covers of schemes over a base + +In this file we define the typeclass `Cover.Over`. For a cover `𝒰` of an `S`-scheme `X`, +the datum `𝒰.Over S` contains `S`-scheme structures on the components of `𝒰` and asserts +that the component maps are morphisms of `S`-schemes. + +We provide instances of `𝒰.Over S` for standard constructions on covers. + +-/ + +universe v u + +noncomputable section + +open CategoryTheory Limits + +namespace AlgebraicGeometry.Scheme + +variable {P : MorphismProperty Scheme.{u}} (S : Scheme.{u}) + +/-- Bundle an `S`-scheme with `P` into an object of `P.Over ⊤ S`. -/ +abbrev asOverProp (X : Scheme.{u}) (S : Scheme.{u}) [X.Over S] (h : P (X ↘ S)) : P.Over ⊤ S := + ⟨X.asOver S, h⟩ + +/-- Bundle an `S`-morphism of `S`-scheme with `P` into a morphism in `P.Over ⊤ S`. -/ +abbrev Hom.asOverProp {X Y : Scheme.{u}} (f : X.Hom Y) (S : Scheme.{u}) [X.Over S] [Y.Over S] + [f.IsOver S] {hX : P (X ↘ S)} {hY : P (Y ↘ S)} : X.asOverProp S hX ⟶ Y.asOverProp S hY := + ⟨f.asOver S, trivial, trivial⟩ + +/-- A `P`-cover of a scheme `X` over `S` is a cover, where the components are over `S` and the +component maps commute with the structure morphisms. -/ +protected class Cover.Over {P : MorphismProperty Scheme.{u}} {X : Scheme.{u}} [X.Over S] + (𝒰 : X.Cover P) where + over (j : 𝒰.J) : (𝒰.obj j).Over S := by infer_instance + isOver_map (j : 𝒰.J) : (𝒰.map j).IsOver S := by infer_instance + +attribute [instance] Cover.Over.over Cover.Over.isOver_map + +instance [P.ContainsIdentities] [P.RespectsIso] {X Y : Scheme.{u}} (f : X ⟶ Y) [X.Over S] [Y.Over S] + [f.IsOver S] [IsIso f] : (coverOfIsIso (P := P) f).Over S where + over _ := inferInstanceAs <| X.Over S + isOver_map _ := inferInstanceAs <| f.IsOver S + +section + +variable [P.IsStableUnderBaseChange] [IsJointlySurjectivePreserving P] +variable {X W : Scheme.{u}} (𝒰 : X.Cover P) (f : W ⟶ X) [W.Over S] [X.Over S] + [𝒰.Over S] [f.IsOver S] + +/-- The pullback of a cover of `S`-schemes along a morphism of `S`-schemes. This is not +definitionally equal to `AlgebraicGeometry.Scheme.Cover.pullbackCover`, as here we take +the pullback in `Over S`, whose underlying scheme is only isomorphic but not equal to the +pullback in `Scheme`. -/ +@[simps] +def Cover.pullbackCoverOver : W.Cover P where + J := 𝒰.J + obj x := (pullback (f.asOver S) ((𝒰.map x).asOver S)).left + map x := (pullback.fst (f.asOver S) ((𝒰.map x).asOver S)).left + f x := 𝒰.f (f.base x) + covers x := (mem_range_iff_of_surjective ((𝒰.pullbackCover f).map (𝒰.f (f.base x))) _ + ((PreservesPullback.iso (Over.forget S) (f.asOver S) ((𝒰.map _).asOver S)).inv) + (PreservesPullback.iso_inv_fst _ _ _) x).mp ((𝒰.pullbackCover f).covers x) + map_prop j := by + dsimp only + rw [← Over.forget_map, ← PreservesPullback.iso_hom_fst, P.cancel_left_of_respectsIso] + exact P.pullback_fst _ _ (𝒰.map_prop j) + +instance (j : 𝒰.J) : ((𝒰.pullbackCoverOver S f).obj j).Over S where + hom := (pullback (f.asOver S) ((𝒰.map j).asOver S)).hom + +instance : (𝒰.pullbackCoverOver S f).Over S where + isOver_map j := { comp_over := by exact Over.w (pullback.fst (f.asOver S) ((𝒰.map j).asOver S)) } + +/-- A variant of `AlgebraicGeometry.Scheme.Cover.pullbackCoverOver` with the arguments in the +fiber products flipped. -/ +@[simps] +def Cover.pullbackCoverOver' : W.Cover P where + J := 𝒰.J + obj x := (pullback ((𝒰.map x).asOver S) (f.asOver S)).left + map x := (pullback.snd ((𝒰.map x).asOver S) (f.asOver S)).left + f x := 𝒰.f (f.base x) + covers x := (mem_range_iff_of_surjective ((𝒰.pullbackCover' f).map (𝒰.f (f.base x))) _ + ((PreservesPullback.iso (Over.forget S) ((𝒰.map _).asOver S) (f.asOver S)).inv) + (PreservesPullback.iso_inv_snd _ _ _) x).mp ((𝒰.pullbackCover' f).covers x) + map_prop j := by + dsimp only + rw [← Over.forget_map, ← PreservesPullback.iso_hom_snd, P.cancel_left_of_respectsIso] + exact P.pullback_snd _ _ (𝒰.map_prop j) + +instance (j : 𝒰.J) : ((𝒰.pullbackCoverOver' S f).obj j).Over S where + hom := (pullback ((𝒰.map j).asOver S) (f.asOver S)).hom + +instance : (𝒰.pullbackCoverOver' S f).Over S where + isOver_map j := { comp_over := by exact Over.w (pullback.snd ((𝒰.map j).asOver S) (f.asOver S)) } + +variable {Q : MorphismProperty Scheme.{u}} [Q.HasOfPostcompProperty Q] + [Q.IsStableUnderBaseChange] [Q.IsStableUnderComposition] + +variable (hX : Q (X ↘ S)) (hW : Q (W ↘ S)) (hQ : ∀ j, Q (𝒰.obj j ↘ S)) + +/-- The pullback of a cover of `S`-schemes with `Q` along a morphism of `S`-schemes. This is not +definitionally equal to `AlgebraicGeometry.Scheme.Cover.pullbackCover`, as here we take +the pullback in `Q.Over ⊤ S`, whose underlying scheme is only isomorphic but not equal to the +pullback in `Scheme`. -/ +@[simps (config := .lemmasOnly)] +def Cover.pullbackCoverOverProp : W.Cover P where + J := 𝒰.J + obj x := (pullback (f.asOverProp (hX := hW) (hY := hX) S) + ((𝒰.map x).asOverProp (hX := hQ x) (hY := hX) S)).left + map x := (pullback.fst (f.asOverProp S) ((𝒰.map x).asOverProp S)).left + f x := 𝒰.f (f.base x) + covers x := (mem_range_iff_of_surjective ((𝒰.pullbackCover f).map (𝒰.f (f.base x))) _ + ((PreservesPullback.iso (MorphismProperty.Over.forget Q _ _ ⋙ Over.forget S) + (f.asOverProp S) ((𝒰.map _).asOverProp S)).inv) + (PreservesPullback.iso_inv_fst _ _ _) x).mp ((𝒰.pullbackCover f).covers x) + map_prop j := by + dsimp only + rw [← Over.forget_map, MorphismProperty.Comma.toCommaMorphism_eq_hom, + ← MorphismProperty.Comma.forget_map, ← Functor.comp_map] + rw [← PreservesPullback.iso_hom_fst, P.cancel_left_of_respectsIso] + exact P.pullback_fst _ _ (𝒰.map_prop j) + +instance (j : 𝒰.J) : ((𝒰.pullbackCoverOverProp S f hX hW hQ).obj j).Over S where + hom := (pullback (f.asOverProp (hX := hW) (hY := hX) S) + ((𝒰.map j).asOverProp (hX := hQ j) (hY := hX) S)).hom + +instance : (𝒰.pullbackCoverOverProp S f hX hW hQ).Over S where + isOver_map j := + { comp_over := by exact (pullback.fst (f.asOverProp S) ((𝒰.map j).asOverProp S)).w } + +/-- A variant of `AlgebraicGeometry.Scheme.Cover.pullbackCoverOverProp` with the arguments in the +fiber products flipped. -/ +@[simps (config := .lemmasOnly)] +def Cover.pullbackCoverOverProp' : W.Cover P where + J := 𝒰.J + obj x := (pullback ((𝒰.map x).asOverProp (hX := hQ x) (hY := hX) S) + (f.asOverProp (hX := hW) (hY := hX) S)).left + map x := (pullback.snd ((𝒰.map x).asOverProp S) (f.asOverProp S)).left + f x := 𝒰.f (f.base x) + covers x := (mem_range_iff_of_surjective ((𝒰.pullbackCover' f).map (𝒰.f (f.base x))) _ + ((PreservesPullback.iso (MorphismProperty.Over.forget Q _ _ ⋙ Over.forget S) + ((𝒰.map _).asOverProp S) (f.asOverProp S)).inv) + (PreservesPullback.iso_inv_snd _ _ _) x).mp ((𝒰.pullbackCover' f).covers x) + map_prop j := by + dsimp only + rw [← Over.forget_map, MorphismProperty.Comma.toCommaMorphism_eq_hom, + ← MorphismProperty.Comma.forget_map, ← Functor.comp_map] + rw [← PreservesPullback.iso_hom_snd, P.cancel_left_of_respectsIso] + exact P.pullback_snd _ _ (𝒰.map_prop j) + +instance (j : 𝒰.J) : ((𝒰.pullbackCoverOverProp' S f hX hW hQ).obj j).Over S where + hom := (pullback ((𝒰.map j).asOverProp (hX := hQ j) (hY := hX) S) + (f.asOverProp (hX := hW) (hY := hX) S)).hom + +instance : (𝒰.pullbackCoverOverProp' S f hX hW hQ).Over S where + isOver_map j := + { comp_over := by exact (pullback.snd ((𝒰.map j).asOverProp S) (f.asOverProp S)).w } + +end + +variable [P.IsStableUnderComposition] +variable {X : Scheme.{u}} (𝒰 : X.Cover P) (𝒱 : ∀ x, (𝒰.obj x).Cover P) + [X.Over S] [𝒰.Over S] [∀ x, (𝒱 x).Over S] + +instance (j : (𝒰.bind 𝒱).J) : ((𝒰.bind 𝒱).obj j).Over S := + inferInstanceAs <| ((𝒱 j.1).obj j.2).Over S + +instance {X : Scheme.{u}} (𝒰 : X.Cover P) (𝒱 : ∀ x, (𝒰.obj x).Cover P) + [X.Over S] [𝒰.Over S] [∀ x, (𝒱 x).Over S] : (𝒰.bind 𝒱).Over S where + over := fun ⟨i, j⟩ ↦ inferInstanceAs <| ((𝒱 i).obj j).Over S + isOver_map := fun ⟨i, j⟩ ↦ { comp_over := by simp } + +end AlgebraicGeometry.Scheme diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean index 5a23dde317010d..231b6e92006e98 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean @@ -81,6 +81,7 @@ elliptic curve, rational point, affine coordinates -/ open Polynomial +open scoped Polynomial.Bivariate local macro "C_simp" : tactic => `(tactic| simp only [map_ofNat, C_0, C_1, C_neg, C_add, C_sub, C_mul, C_pow]) diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean index 5fb7a921a4ae80..15a2fccfcd2b3e 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean @@ -95,6 +95,7 @@ elliptic curve, division polynomial, torsion point -/ open Polynomial +open scoped Polynomial.Bivariate local macro "C_simp" : tactic => `(tactic| simp only [map_ofNat, C_0, C_1, C_neg, C_add, C_sub, C_mul, C_pow]) diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean index 7020898f0efde3..c01a58c13679a1 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean @@ -62,6 +62,7 @@ elliptic curve, group law, class group -/ open Ideal nonZeroDivisors Polynomial +open scoped Polynomial.Bivariate local macro "C_simp" : tactic => `(tactic| simp only [map_ofNat, C_0, C_1, C_neg, C_add, C_sub, C_mul, C_pow]) diff --git a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean index 6c8faa057ea860..87195c4877f610 100644 --- a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean +++ b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean @@ -415,12 +415,12 @@ theorem Scheme.toSpecΓ_base (X : Scheme.{u}) (x) : @[reassoc (attr := simp)] theorem Scheme.toSpecΓ_naturality {X Y : Scheme.{u}} (f : X ⟶ Y) : - f ≫ Y.toSpecΓ = X.toSpecΓ ≫ Spec.map (f.app ⊤) := + f ≫ Y.toSpecΓ = X.toSpecΓ ≫ Spec.map (f.appTop) := ΓSpec.adjunction.unit.naturality f @[simp] -theorem Scheme.toSpecΓ_app_top (X : Scheme.{u}) : - X.toSpecΓ.app ⊤ = (Scheme.ΓSpecIso Γ(X, ⊤)).hom := by +theorem Scheme.toSpecΓ_appTop (X : Scheme.{u}) : + X.toSpecΓ.appTop = (Scheme.ΓSpecIso Γ(X, ⊤)).hom := by have := ΓSpec.adjunction.left_triangle_components X dsimp at this rw [← IsIso.eq_comp_inv] at this @@ -428,6 +428,8 @@ theorem Scheme.toSpecΓ_app_top (X : Scheme.{u}) : Scheme.Γ_obj, Category.id_comp] at this rw [← Quiver.Hom.op_inj.eq_iff, this, ← op_inv, IsIso.Iso.inv_inv] +@[deprecated (since := "2024-11-23")] alias Scheme.toSpecΓ_app_top := Scheme.toSpecΓ_appTop + @[simp] theorem SpecMap_ΓSpecIso_hom (R : CommRingCat.{u}) : Spec.map ((Scheme.ΓSpecIso R).hom) = (Spec R).toSpecΓ := by @@ -437,9 +439,9 @@ theorem SpecMap_ΓSpecIso_hom (R : CommRingCat.{u}) : 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] + rw [← basicOpen_eq_of_affine, Scheme.preimage_basicOpen, ← Scheme.Hom.appTop] congr - rw [Scheme.toSpecΓ_app_top] + rw [Scheme.toSpecΓ_appTop] exact Iso.inv_hom_id_apply _ _ -- Warning: this LHS of this lemma breaks the structure-sheaf abstraction. @@ -456,25 +458,24 @@ theorem toOpen_toSpecΓ_app {X : Scheme.{u}} (U) : exact Category.id_comp _ lemma ΓSpecIso_inv_ΓSpec_adjunction_homEquiv {X : Scheme.{u}} {B : CommRingCat} (φ : B ⟶ Γ(X, ⊤)) : - (Scheme.ΓSpecIso B).inv ≫ ((ΓSpec.adjunction.homEquiv X (op B)) φ.op).app ⊤ = φ := by + (Scheme.ΓSpecIso B).inv ≫ ((ΓSpec.adjunction.homEquiv X (op B)) φ.op).appTop = φ := by simp only [Adjunction.homEquiv_apply, Scheme.Spec_map, Opens.map_top, Scheme.comp_app] simp lemma ΓSpec_adjunction_homEquiv_eq {X : Scheme.{u}} {B : CommRingCat} (φ : B ⟶ Γ(X, ⊤)) : - (((ΓSpec.adjunction.homEquiv X (op B)) φ.op).app ⊤) = (Scheme.ΓSpecIso B).hom ≫ φ := by - simp_rw [← ΓSpecIso_inv_ΓSpec_adjunction_homEquiv φ] - simp + ((ΓSpec.adjunction.homEquiv X (op B)) φ.op).appTop = (Scheme.ΓSpecIso B).hom ≫ φ := by + rw [← Iso.inv_comp_eq, ΓSpecIso_inv_ΓSpec_adjunction_homEquiv] theorem ΓSpecIso_obj_hom {X : Scheme.{u}} (U : X.Opens) : - (Scheme.ΓSpecIso Γ(X, U)).hom = (Spec.map U.topIso.inv).app ⊤ ≫ - U.toScheme.toSpecΓ.app ⊤ ≫ U.topIso.hom := by simp + (Scheme.ΓSpecIso Γ(X, U)).hom = (Spec.map U.topIso.inv).appTop ≫ + U.toScheme.toSpecΓ.appTop ≫ 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 +alias ΓSpec.adjunction_unit_app_app_top := Scheme.toSpecΓ_appTop @[deprecated (since := "2024-07-24")] alias ΓSpec.adjunction_unit_map_basicOpen := Scheme.toSpecΓ_preimage_basicOpen diff --git a/Mathlib/AlgebraicGeometry/Limits.lean b/Mathlib/AlgebraicGeometry/Limits.lean index 6c634b3aadaac4..b4f7a0106ddcad 100644 --- a/Mathlib/AlgebraicGeometry/Limits.lean +++ b/Mathlib/AlgebraicGeometry/Limits.lean @@ -48,7 +48,11 @@ instance : HasFiniteLimits Scheme := hasFiniteLimits_of_hasTerminal_and_pullbacks instance (X : Scheme.{u}) : X.Over (⊤_ _) := ⟨terminal.from _⟩ -instance {X Y : Scheme.{u}} (f : X ⟶ Y) : f.IsOver (⊤_ _) := ⟨terminal.hom_ext _ _⟩ +instance {X Y : Scheme.{u}} [X.Over (⊤_ Scheme)] [Y.Over (⊤_ Scheme)] (f : X ⟶ Y) : + @Scheme.Hom.IsOver _ _ f (⊤_ Scheme) ‹_› ‹_› := ⟨Subsingleton.elim _ _⟩ + +instance {X : Scheme} : Subsingleton (X.Over (⊤_ Scheme)) := + ⟨fun ⟨a⟩ ⟨b⟩ ↦ by simp [Subsingleton.elim a b]⟩ section Initial diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean index 66b28ced66e1b0..10aa7de982be93 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean @@ -158,7 +158,7 @@ instance : HasAffineProperty @IsAffineHom fun X _ _ _ ↦ IsAffine X where rw [Scheme.preimage_basicOpen] exact (isAffineOpen_top X).basicOpen _ · intro X Y _ f S hS hS' - apply_fun Ideal.map (f.app ⊤) at hS + apply_fun Ideal.map (f.appTop) at hS rw [Ideal.map_span, Ideal.map_top] at hS apply isAffine_of_isAffineOpen_basicOpen _ hS have : ∀ i : S, IsAffineOpen (f⁻¹ᵁ Y.basicOpen i.1) := hS' diff --git a/Mathlib/AlgebraicGeometry/Morphisms/AffineAnd.lean b/Mathlib/AlgebraicGeometry/Morphisms/AffineAnd.lean index 6eea058bd4042b..632a366ca72366 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/AffineAnd.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/AffineAnd.lean @@ -35,11 +35,11 @@ variable (Q : ∀ {R S : Type u} [CommRing R] [CommRing S], (R →+* S) → Prop /-- This is the affine target morphism property where the source is affine and the induced map of rings on global sections satisfies `P`. -/ def affineAnd : AffineTargetMorphismProperty := - fun X _ f ↦ IsAffine X ∧ Q (f.app ⊤) + fun X _ f ↦ IsAffine X ∧ Q (f.appTop) @[simp] lemma affineAnd_apply {X Y : Scheme.{u}} (f : X ⟶ Y) [IsAffine Y] : - affineAnd Q f ↔ IsAffine X ∧ Q (f.app ⊤) := + affineAnd Q f ↔ IsAffine X ∧ Q (f.appTop) := Iff.rfl attribute [local simp] AffineTargetMorphismProperty.toProperty_apply @@ -64,28 +64,29 @@ lemma affineAnd_isLocal (hPi : RingHom.RespectsIso Q) (hQl : RingHom.Localizatio constructor · simp only [Scheme.preimage_basicOpen, Opens.map_top] exact (isAffineOpen_top X).basicOpen _ - · dsimp only [Opens.map_top] - rw [morphismRestrict_app, hPi.cancel_right_isIso, Scheme.Opens.ι_image_top] + · dsimp only + rw [morphismRestrict_appTop, hPi.cancel_right_isIso, Scheme.Opens.ι_image_top] rw [(isAffineOpen_top Y).app_basicOpen_eq_away_map f (isAffineOpen_top X), - hPi.cancel_right_isIso] - haveI := (isAffineOpen_top X).isLocalization_basicOpen (f.app ⊤ r) + hPi.cancel_right_isIso, ← Scheme.Hom.appTop] + dsimp only [Opens.map_top] + haveI := (isAffineOpen_top X).isLocalization_basicOpen (f.appTop r) apply hQl exact hf of_basicOpenCover {X Y _} f s hs hf := by dsimp [affineAnd] at hf haveI : IsAffine X := by - apply isAffine_of_isAffineOpen_basicOpen (f.app ⊤ '' s) - · apply_fun Ideal.map (f.app ⊤) at hs + apply isAffine_of_isAffineOpen_basicOpen (f.appTop '' s) + · apply_fun Ideal.map (f.appTop) at hs rwa [Ideal.map_span, Ideal.map_top] at hs · rintro - ⟨r, hr, rfl⟩ simp_rw [Scheme.preimage_basicOpen] at hf exact (hf ⟨r, hr⟩).left - refine ⟨inferInstance, hQs.ofIsLocalization' hPi (f.app ⊤) s hs fun a ↦ ?_⟩ - refine ⟨Γ(Y, Y.basicOpen a.val), Γ(X, X.basicOpen (f.app ⊤ a.val)), inferInstance, + refine ⟨inferInstance, hQs.ofIsLocalization' hPi (f.appTop) s hs fun a ↦ ?_⟩ + refine ⟨Γ(Y, Y.basicOpen a.val), Γ(X, X.basicOpen (f.appTop a.val)), inferInstance, inferInstance, inferInstance, inferInstance, inferInstance, ?_, ?_⟩ - · exact (isAffineOpen_top X).isLocalization_basicOpen (f.app ⊤ a.val) + · exact (isAffineOpen_top X).isLocalization_basicOpen (f.appTop a.val) · obtain ⟨_, hf⟩ := hf a - rw [morphismRestrict_app, hPi.cancel_right_isIso, Scheme.Opens.ι_image_top] at hf + rw [morphismRestrict_appTop, hPi.cancel_right_isIso, Scheme.Opens.ι_image_top] at hf rw [(isAffineOpen_top Y).app_basicOpen_eq_away_map _ (isAffineOpen_top X)] at hf rwa [hPi.cancel_right_isIso] at hf @@ -96,7 +97,7 @@ lemma affineAnd_isStableUnderBaseChange (hQi : RingHom.RespectsIso Q) haveI : (affineAnd Q).toProperty.RespectsIso := affineAnd_respectsIso hQi apply AffineTargetMorphismProperty.IsStableUnderBaseChange.mk intro X Y S _ _ f g ⟨hY, hg⟩ - exact ⟨inferInstance, hQb.pullback_fst_app_top _ hQi f _ hg⟩ + exact ⟨inferInstance, hQb.pullback_fst_appTop _ hQi f _ hg⟩ lemma targetAffineLocally_affineAnd_iff (hQi : RingHom.RespectsIso Q) {X Y : Scheme.{u}} (f : X ⟶ Y) : @@ -133,7 +134,7 @@ lemma targetAffineLocally_affineAnd_iff_affineLocally (hQ : RingHom.PropertyIsLo intro U have : IsAffine (f ⁻¹ᵁ U) := hf.isAffine_preimage U U.2 rw [HasRingHomProperty.iff_of_isAffine (P := affineLocally Q), - morphismRestrict_app, hQ.respectsIso.cancel_right_isIso] + morphismRestrict_appTop, hQ.respectsIso.cancel_right_isIso] apply h rw [Scheme.Opens.ι_image_top] exact U.2 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean index 51f9c3ccf41d95..070c60d31cc77c 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean @@ -142,8 +142,7 @@ instance inf (P Q : MorphismProperty Scheme) [IsLocalAtTarget P] [IsLocalAtTarge fun h ↦ ⟨(iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).left), (iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).right)⟩⟩ -variable {P} [hP : IsLocalAtTarget P] -variable {X Y U V : Scheme.{u}} {f : X ⟶ Y} {g : U ⟶ Y} [IsOpenImmersion g] (𝒰 : Y.OpenCover) +variable {P} [hP : IsLocalAtTarget P] {X Y : Scheme.{u}} {f : X ⟶ Y} (𝒰 : Y.OpenCover) lemma of_isPullback {UX UY : Scheme.{u}} {iY : UY ⟶ Y} [IsOpenImmersion iY] {iX : UX ⟶ X} {f' : UX ⟶ UY} (h : IsPullback iX f' f iY) (H : P f) : P f' := by @@ -228,7 +227,7 @@ instance inf (P Q : MorphismProperty Scheme) [IsLocalAtSource P] [IsLocalAtSourc (iff_of_openCover' f 𝒰).mpr (fun i ↦ (h i).right)⟩⟩ variable {P} [IsLocalAtSource P] -variable {X Y U V : Scheme.{u}} {f : X ⟶ Y} {g : U ⟶ Y} [IsOpenImmersion g] (𝒰 : X.OpenCover) +variable {X Y : Scheme.{u}} {f : X ⟶ Y} (𝒰 : X.OpenCover) lemma comp {UX : Scheme.{u}} (H : P f) (i : UX ⟶ X) [IsOpenImmersion i] : P (i ≫ f) := diff --git a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean index 1cb1635d9fcb06..0145a3045d5dbf 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean @@ -62,8 +62,8 @@ lemma eq_inf : @IsClosedImmersion = (topologically IsClosedEmbedding) ⊓ lemma iff_isPreimmersion {X Y : Scheme} {f : X ⟶ Y} : IsClosedImmersion f ↔ IsPreimmersion f ∧ IsClosed (Set.range f.base) := by - rw [and_comm, isClosedImmersion_iff, isPreimmersion_iff, ← and_assoc, isClosedEmbedding_iff, - @and_comm (IsEmbedding _)] + rw [isClosedImmersion_iff, isPreimmersion_iff, ← surjectiveOnStalks_iff, and_comm, and_assoc, + isClosedEmbedding_iff] lemma of_isPreimmersion {X Y : Scheme} (f : X ⟶ Y) [IsPreimmersion f] (hf : IsClosed (Set.range f.base)) : IsClosedImmersion f := @@ -117,7 +117,7 @@ instance spec_of_quotient_mk {R : CommRingCat.{u}} (I : Ideal R) : /-- Any morphism between affine schemes that is surjective on global sections is a closed immersion. -/ lemma of_surjective_of_isAffine {X Y : Scheme} [IsAffine X] [IsAffine Y] (f : X ⟶ Y) - (h : Function.Surjective (f.app ⊤)) : IsClosedImmersion f := by + (h : Function.Surjective (f.appTop)) : IsClosedImmersion f := by rw [MorphismProperty.arrow_mk_iso_iff @IsClosedImmersion (arrowIsoSpecΓOfIsAffine f)] apply spec_of_surjective exact h @@ -161,7 +161,7 @@ open IsClosedImmersion LocallyRingedSpace has a closed image and `f` induces an injection on global sections, then `f` is surjective. -/ lemma surjective_of_isClosed_range_of_injective [CompactSpace X] - (hfcl : IsClosed (Set.range f.base)) (hfinj : Function.Injective (f.app ⊤)) : + (hfcl : IsClosed (Set.range f.base)) (hfinj : Function.Injective (f.appTop)) : Function.Surjective f.base := by obtain ⟨I, hI⟩ := (Scheme.eq_zeroLocus_of_isClosed_of_isAffine Y (Set.range f.base)).mp hfcl let 𝒰 : X.OpenCover := X.affineCover.finiteSubcover @@ -186,12 +186,12 @@ lemma surjective_of_isClosed_range_of_injective [CompactSpace X] injective if it is injective on global sections. -/ lemma stalkMap_injective_of_isOpenMap_of_injective [CompactSpace X] (hfopen : IsOpenMap f.base) (hfinj₁ : Function.Injective f.base) - (hfinj₂ : Function.Injective (f.app ⊤)) (x : X) : + (hfinj₂ : Function.Injective (f.appTop)) (x : X) : Function.Injective (f.stalkMap x) := by - let φ : Γ(Y, ⊤) ⟶ Γ(X, ⊤) := f.app ⊤ + let φ : Γ(Y, ⊤) ⟶ Γ(X, ⊤) := f.appTop let 𝒰 : X.OpenCover := X.affineCover.finiteSubcover have (i : 𝒰.J) : IsAffine (𝒰.obj i) := Scheme.isAffine_affineCover X _ - let res (i : 𝒰.J) : Γ(X, ⊤) ⟶ Γ(𝒰.obj i, ⊤) := (𝒰.map i).app ⊤ + let res (i : 𝒰.J) : Γ(X, ⊤) ⟶ Γ(𝒰.obj i, ⊤) := (𝒰.map i).appTop refine stalkMap_injective_of_isAffine _ _ (fun (g : Γ(Y, ⊤)) h ↦ ?_) rw [TopCat.Presheaf.Γgerm, Scheme.stalkMap_germ_apply] at h obtain ⟨U, w, (hx : x ∈ U), hg⟩ := @@ -200,8 +200,8 @@ lemma stalkMap_injective_of_isOpenMap_of_injective [CompactSpace X] (show f.base x ∈ ⟨f.base '' U.carrier, hfopen U.carrier U.is_open'⟩ from ⟨x, by simpa⟩) let W (i : 𝒰.J) : TopologicalSpace.Opens (𝒰.obj i) := (𝒰.obj i).basicOpen ((res i) (φ s)) have hwle (i : 𝒰.J) : W i ≤ (𝒰.map i)⁻¹ᵁ U := by - show ((𝒰.obj i).basicOpen ((𝒰.map i ≫ f).app ⊤ s)) ≤ _ - rw [← Scheme.preimage_basicOpen, Scheme.comp_coeBase, Opens.map_comp_obj] + show (𝒰.obj i).basicOpen ((𝒰.map i ≫ f).appTop s) ≤ _ + rw [← Scheme.preimage_basicOpen_top, Scheme.comp_coeBase, Opens.map_comp_obj] refine Scheme.Hom.preimage_le_preimage_of_le _ (le_trans (f.preimage_le_preimage_of_le bsle) (le_of_eq ?_)) simp [Set.preimage_image_eq _ hfinj₁] @@ -229,7 +229,7 @@ namespace IsClosedImmersion /-- If `f` is a closed immersion with affine target such that the induced map on global sections is injective, `f` is an isomorphism. -/ theorem isIso_of_injective_of_isAffine [IsClosedImmersion f] - (hf : Function.Injective (f.app ⊤)) : IsIso f := (isIso_iff_stalk_iso f).mpr <| + (hf : Function.Injective (f.appTop)) : IsIso f := (isIso_iff_stalk_iso f).mpr <| have : CompactSpace X := f.isClosedEmbedding.compactSpace have hiso : IsIso f.base := TopCat.isIso_of_bijective_of_isClosedMap _ ⟨f.isClosedEmbedding.injective, @@ -244,7 +244,7 @@ variable (f) /-- If `f` is a closed immersion with affine target, the source is affine and the induced map on global sections is surjective. -/ theorem isAffine_surjective_of_isAffine [IsClosedImmersion f] : - IsAffine X ∧ Function.Surjective (f.app ⊤) := by + IsAffine X ∧ Function.Surjective (f.appTop) := by haveI i : IsClosedImmersion f := inferInstance rw [← affineTargetImageFactorization_comp f] at i ⊢ haveI := of_surjective_of_isAffine (affineTargetImageInclusion f) @@ -254,7 +254,7 @@ theorem isAffine_surjective_of_isAffine [IsClosedImmersion f] : haveI := isIso_of_injective_of_isAffine (affineTargetImageFactorization_app_injective f) exact ⟨isAffine_of_isIso (affineTargetImageFactorization f), (ConcreteCategory.bijective_of_isIso - ((affineTargetImageFactorization f).app ⊤)).surjective.comp <| + ((affineTargetImageFactorization f).appTop)).surjective.comp <| affineTargetImageInclusion_app_surjective f⟩ end IsClosedImmersion @@ -268,7 +268,7 @@ instance IsClosedImmersion.isLocalAtTarget : IsLocalAtTarget @IsClosedImmersion /-- On morphisms with affine target, being a closed immersion is precisely having affine source and being surjective on global sections. -/ instance IsClosedImmersion.hasAffineProperty : HasAffineProperty @IsClosedImmersion - (fun X _ f ↦ IsAffine X ∧ Function.Surjective (f.app ⊤)) := by + (fun X _ f ↦ IsAffine X ∧ Function.Surjective (f.appTop)) := by convert HasAffineProperty.of_isLocalAtTarget @IsClosedImmersion refine ⟨fun ⟨h₁, h₂⟩ ↦ of_surjective_of_isAffine _ h₂, by apply isAffine_surjective_of_isAffine⟩ @@ -290,7 +290,7 @@ instance IsClosedImmersion.isStableUnderBaseChange : haveI := HasAffineProperty.isLocal_affineProperty @IsClosedImmersion apply AffineTargetMorphismProperty.IsStableUnderBaseChange.mk intro X Y S _ _ f g ⟨ha, hsurj⟩ - exact ⟨inferInstance, RingHom.surjective_isStableUnderBaseChange.pullback_fst_app_top _ + exact ⟨inferInstance, RingHom.surjective_isStableUnderBaseChange.pullback_fst_appTop _ RingHom.surjective_respectsIso f _ hsurj⟩ /-- Closed immersions are locally of finite type. -/ @@ -320,13 +320,13 @@ lemma isIso_of_isClosedImmersion_of_surjective {X Y : Scheme.{u}} (f : X ⟶ Y) · infer_instance apply IsClosedImmersion.isIso_of_injective_of_isAffine obtain ⟨hX, hf⟩ := HasAffineProperty.iff_of_isAffine.mp ‹IsClosedImmersion f› - let φ := f.app ⊤ + let φ := f.appTop suffices RingHom.ker φ ≤ nilradical _ by rwa [nilradical_eq_zero, Submodule.zero_eq_bot, le_bot_iff, ← RingHom.injective_iff_ker_eq_bot] at this refine (PrimeSpectrum.zeroLocus_eq_top_iff _).mp ?_ rw [← range_specComap_of_surjective _ _ hf, Set.top_eq_univ, Set.range_eq_univ] - have : Surjective (Spec.map (f.app ⊤)) := + have : Surjective (Spec.map (f.appTop)) := (MorphismProperty.arrow_mk_iso_iff @Surjective (arrowIsoSpecΓOfIsAffine f)).mp (inferInstanceAs (Surjective f)) exact this.1 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Etale.lean b/Mathlib/AlgebraicGeometry/Morphisms/Etale.lean index 665513b4b09cb2..35ee3280f7055d 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Etale.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Etale.lean @@ -28,7 +28,7 @@ abbrev IsEtale {X Y : Scheme.{u}} (f : X ⟶ Y) := IsSmoothOfRelativeDimension 0 namespace IsEtale -variable {X Y : Scheme.{u}} (f : X ⟶ Y) +variable {X : Scheme.{u}} instance : IsStableUnderBaseChange @IsEtale := isSmoothOfRelativeDimension_isStableUnderBaseChange 0 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean b/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean index 3a1aca10b2cbdd..60115fff857f2b 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Finite.lean @@ -3,9 +3,8 @@ 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.AffineAnd -import Mathlib.AlgebraicGeometry.Morphisms.FiniteType -import Mathlib.RingTheory.RingHom.Finite +import Mathlib.AlgebraicGeometry.Morphisms.Integral +import Mathlib.Algebra.Category.Ring.Epi /-! @@ -38,7 +37,7 @@ class IsFinite {X Y : Scheme} (f : X ⟶ Y) extends IsAffineHom f : Prop where namespace IsFinite -instance : HasAffineProperty @IsFinite (fun X _ f _ ↦ IsAffine X ∧ RingHom.Finite (f.app ⊤)) := by +instance : HasAffineProperty @IsFinite (fun X _ f _ ↦ IsAffine X ∧ RingHom.Finite (f.appTop)) := by show HasAffineProperty @IsFinite (affineAnd RingHom.Finite) rw [HasAffineProperty.affineAnd_iff _ RingHom.finite_respectsIso RingHom.finite_localizationPreserves RingHom.finite_ofLocalizationSpan] @@ -65,15 +64,52 @@ instance (priority := 900) [IsIso f] : IsFinite f := of_isIso @IsFinite f instance {Z : Scheme.{u}} (g : Y ⟶ Z) [IsFinite f] [IsFinite g] : IsFinite (f ≫ g) := IsStableUnderComposition.comp_mem f g ‹IsFinite f› ‹IsFinite g› -instance (priority := 900) [hf : IsFinite f] : LocallyOfFiniteType f := by - have : targetAffineLocally (affineAnd @RingHom.FiniteType) f := by - rw [HasAffineProperty.eq_targetAffineLocally (P := @IsFinite)] at hf - apply targetAffineLocally_affineAnd_le RingHom.Finite.finiteType - exact hf - rw [targetAffineLocally_affineAnd_eq_affineLocally - (HasRingHomProperty.isLocal_ringHomProperty @LocallyOfFiniteType)] at this - rw [HasRingHomProperty.eq_affineLocally (P := @LocallyOfFiniteType)] - exact this.2 +lemma iff_isIntegralHom_and_locallyOfFiniteType : + IsFinite f ↔ IsIntegralHom f ∧ LocallyOfFiniteType f := by + wlog hY : IsAffine Y + · rw [IsLocalAtTarget.iff_of_openCover (P := @IsFinite) Y.affineCover, + IsLocalAtTarget.iff_of_openCover (P := @IsIntegralHom) Y.affineCover, + IsLocalAtTarget.iff_of_openCover (P := @LocallyOfFiniteType) Y.affineCover] + simp_rw [this, forall_and] + rw [HasAffineProperty.iff_of_isAffine (P := @IsFinite), + HasAffineProperty.iff_of_isAffine (P := @IsIntegralHom), + RingHom.finite_iff_isIntegral_and_finiteType, ← and_assoc] + refine and_congr_right fun ⟨_, _⟩ ↦ + (HasRingHomProperty.iff_of_isAffine (P := @LocallyOfFiniteType)).symm + +lemma eq_inf : + @IsFinite = (@IsIntegralHom ⊓ @LocallyOfFiniteType : MorphismProperty Scheme) := by + ext; exact IsFinite.iff_isIntegralHom_and_locallyOfFiniteType _ + +instance (priority := 900) [IsFinite f] : IsIntegralHom f := + ((IsFinite.iff_isIntegralHom_and_locallyOfFiniteType f).mp ‹_›).1 + +instance (priority := 900) [hf : IsFinite f] : LocallyOfFiniteType f := + ((IsFinite.iff_isIntegralHom_and_locallyOfFiniteType f).mp ‹_›).2 + +lemma _root_.AlgebraicGeometry.IsClosedImmersion.iff_isFinite_and_mono : + IsClosedImmersion f ↔ IsFinite f ∧ Mono f := by + wlog hY : IsAffine Y + · show _ ↔ _ ∧ monomorphisms _ f + rw [IsLocalAtTarget.iff_of_openCover (P := @IsFinite) Y.affineCover, + IsLocalAtTarget.iff_of_openCover (P := @IsClosedImmersion) Y.affineCover, + IsLocalAtTarget.iff_of_openCover (P := monomorphisms _) Y.affineCover] + simp_rw [this, forall_and, monomorphisms] + rw [HasAffineProperty.iff_of_isAffine (P := @IsClosedImmersion), + HasAffineProperty.iff_of_isAffine (P := @IsFinite), + RingHom.surjective_iff_epi_and_finite, @and_comm (Epi _), ← and_assoc] + refine and_congr_right fun ⟨_, _⟩ ↦ + Iff.trans ?_ (arrow_mk_iso_iff (monomorphisms _) (arrowIsoSpecΓOfIsAffine f).symm) + trans Mono (f.app ⊤).op + · exact ⟨fun h ↦ inferInstance, fun h ↦ show Epi (f.app ⊤).op.unop by infer_instance⟩ + exact (Functor.mono_map_iff_mono Scheme.Spec _).symm + +lemma _root_.AlgebraicGeometry.IsClosedImmersion.eq_isFinite_inf_mono : + @IsClosedImmersion = (@IsFinite ⊓ monomorphisms Scheme : MorphismProperty _) := by + ext; exact IsClosedImmersion.iff_isFinite_and_mono _ + +instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsClosedImmersion f] : IsFinite f := + ((IsClosedImmersion.iff_isFinite_and_mono f).mp ‹_›).1 end IsFinite diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean b/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean new file mode 100644 index 00000000000000..09ee678d31470a --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/Integral.lean @@ -0,0 +1,64 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.AffineAnd +import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion +import Mathlib.RingTheory.RingHom.Integral + +/-! + +# Integral morphisms of schemes + +A morphism of schemes `f : X ⟶ Y` is integral if the preimage +of an arbitrary affine open subset of `Y` is affine and the induced ring map is integral. + +It is equivalent to ask only that `Y` is covered by affine opens whose preimage is affine +and the induced ring map is integral. + +## TODO + +- Show integral = universally closed + affine + +-/ + +universe v u + +open CategoryTheory TopologicalSpace Opposite MorphismProperty + +namespace AlgebraicGeometry + +/-- A morphism of schemes `X ⟶ Y` is finite if +the preimage of any affine open subset of `Y` is affine and the induced ring +hom is finite. -/ +@[mk_iff] +class IsIntegralHom {X Y : Scheme} (f : X ⟶ Y) extends IsAffineHom f : Prop where + integral_app (U : Y.Opens) (hU : IsAffineOpen U) : (f.app U).IsIntegral + +namespace IsIntegralHom + +instance hasAffineProperty : HasAffineProperty @IsIntegralHom + fun X _ f _ ↦ IsAffine X ∧ RingHom.IsIntegral (f.app ⊤) := by + show HasAffineProperty @IsIntegralHom (affineAnd RingHom.IsIntegral) + rw [HasAffineProperty.affineAnd_iff _ RingHom.isIntegral_respectsIso + RingHom.isIntegral_isStableUnderBaseChange.localizationPreserves + RingHom.isIntegral_ofLocalizationSpan] + simp [isIntegralHom_iff] + +instance : IsStableUnderComposition @IsIntegralHom := + HasAffineProperty.affineAnd_isStableUnderComposition (Q := RingHom.IsIntegral) hasAffineProperty + RingHom.isIntegral_stableUnderComposition + +instance : IsStableUnderBaseChange @IsIntegralHom := + HasAffineProperty.affineAnd_isStableUnderBaseChange (Q := RingHom.IsIntegral) hasAffineProperty + RingHom.isIntegral_respectsIso RingHom.isIntegral_isStableUnderBaseChange + +instance : ContainsIdentities @IsIntegralHom := + ⟨fun X ↦ ⟨fun _ _ ↦ by simpa using RingHom.isIntegral_of_surjective _ (Equiv.refl _).surjective⟩⟩ + +instance : IsMultiplicative @IsIntegralHom where + +end IsIntegralHom + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean b/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean index 06cb129fa9785b..ed9fb2ee4ca4d3 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/IsIso.lean @@ -36,10 +36,10 @@ lemma isomorphisms_eq_stalkwise : instance : IsLocalAtTarget (isomorphisms Scheme) := isomorphisms_eq_isOpenImmersion_inf_surjective ▸ inferInstance -instance : HasAffineProperty (isomorphisms Scheme) fun X _ f _ ↦ IsAffine X ∧ IsIso (f.app ⊤) := by +instance : HasAffineProperty (isomorphisms Scheme) fun X _ f _ ↦ IsAffine X ∧ IsIso (f.appTop) := by convert HasAffineProperty.of_isLocalAtTarget (isomorphisms Scheme) with X Y f hY exact ⟨fun ⟨_, _⟩ ↦ (arrow_mk_iso_iff (isomorphisms _) (arrowIsoSpecΓOfIsAffine f)).mpr - (inferInstanceAs (IsIso (Spec.map (f.app ⊤)))), + (inferInstanceAs (IsIso (Spec.map (f.appTop)))), fun (_ : IsIso f) ↦ ⟨isAffine_of_isIso f, inferInstance⟩⟩ instance : IsLocalAtTarget (monomorphisms Scheme) := diff --git a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean index 880a1a62832f1c..6cd62e8973f1bc 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean @@ -26,7 +26,7 @@ universe u namespace AlgebraicGeometry -variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) +variable {X Y : Scheme.{u}} theorem isOpenImmersion_iff_stalk {f : X ⟶ Y} : IsOpenImmersion f ↔ IsOpenEmbedding f.base ∧ ∀ x, IsIso (f.stalkMap x) := by diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean index 4d5503fe1dc7f5..a2505954c2c6e9 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean @@ -4,8 +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.RingHom.Surjective -import Mathlib.RingTheory.SurjectiveOnStalks +import Mathlib.AlgebraicGeometry.Morphisms.SurjectiveOnStalks /-! @@ -33,9 +32,8 @@ namespace AlgebraicGeometry /-- A morphism of schemes `f : X ⟶ Y` is a preimmersion if the underlying map of topological spaces is an embedding and the induced morphisms of stalks are all surjective. -/ @[mk_iff] -class IsPreimmersion {X Y : Scheme} (f : X ⟶ Y) : Prop where +class IsPreimmersion {X Y : Scheme} (f : X ⟶ Y) extends SurjectiveOnStalks f : Prop where base_embedding : IsEmbedding f.base - surj_on_stalks : ∀ x, Function.Surjective (f.stalkMap x) lemma Scheme.Hom.isEmbedding {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] : IsEmbedding f.base := IsPreimmersion.base_embedding @@ -43,12 +41,8 @@ lemma Scheme.Hom.isEmbedding {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] : I @[deprecated (since := "2024-10-26")] alias Scheme.Hom.embedding := Scheme.Hom.isEmbedding -lemma Scheme.Hom.stalkMap_surjective {X Y : Scheme} (f : Hom X Y) [IsPreimmersion f] (x) : - Function.Surjective (f.stalkMap x) := - IsPreimmersion.surj_on_stalks x - lemma isPreimmersion_eq_inf : - @IsPreimmersion = topologically IsEmbedding ⊓ stalkwise (Function.Surjective ·) := by + @IsPreimmersion = (@SurjectiveOnStalks ⊓ topologically IsEmbedding : MorphismProperty _) := by ext rw [isPreimmersion_iff] rfl @@ -69,10 +63,7 @@ instance (priority := 900) {X Y : Scheme} (f : X ⟶ Y) [IsOpenImmersion f] : Is instance : MorphismProperty.IsMultiplicative @IsPreimmersion where id_mem _ := inferInstance - comp_mem {X Y Z} f g hf hg := by - refine ⟨hg.base_embedding.comp hf.base_embedding, fun x ↦ ?_⟩ - rw [Scheme.stalkMap_comp] - exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.base x)) + comp_mem f g _ _ := ⟨g.isEmbedding.comp f.isEmbedding⟩ instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [IsPreimmersion f] [IsPreimmersion g] : IsPreimmersion (f ≫ g) := @@ -104,14 +95,8 @@ lemma Spec_map_iff {R S : CommRingCat.{u}} (f : R ⟶ S) : haveI : (RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).RespectsIso := by rw [← RingHom.toMorphismProperty_respectsIso_iff] exact RingHom.surjective_respectsIso - refine ⟨fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ?_⟩, fun ⟨h₁, h₂⟩ ↦ ⟨h₁, fun (x : PrimeSpectrum S) ↦ ?_⟩⟩ - · intro p hp - let e := Scheme.arrowStalkMapSpecIso f ⟨p, hp⟩ - apply ((RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).arrow_mk_iso_iff e).mp - exact h₂ ⟨p, hp⟩ - · let e := Scheme.arrowStalkMapSpecIso f x - apply ((RingHom.toMorphismProperty <| fun f ↦ Function.Surjective f).arrow_mk_iso_iff e).mpr - exact h₂ x.asIdeal x.isPrime + rw [← HasRingHomProperty.Spec_iff (P := @SurjectiveOnStalks), isPreimmersion_iff, and_comm] + rfl lemma mk_Spec_map {R S : CommRingCat.{u}} {f : R ⟶ S} (h₁ : IsEmbedding (PrimeSpectrum.comap f)) (h₂ : f.SurjectiveOnStalks) : @@ -125,6 +110,19 @@ lemma of_isLocalization {R S : Type u} [CommRing R] (M : Submonoid R) [CommRing (PrimeSpectrum.localization_comap_isEmbedding (R := R) S M) (RingHom.surjectiveOnStalks_of_isLocalization (M := M) S) +open Limits MorphismProperty in +instance : IsStableUnderBaseChange @IsPreimmersion := by + refine .mk' fun X Y Z f g _ _ ↦ ?_ + have := pullback_fst (P := @SurjectiveOnStalks) f g inferInstance + constructor + let L (x : (pullback f g : _)) : { x : X × Y | f.base x.1 = g.base x.2 } := + ⟨⟨(pullback.fst f g).base x, (pullback.snd f g).base x⟩, + by simp only [Set.mem_setOf, ← Scheme.comp_base_apply, pullback.condition]⟩ + have : IsEmbedding L := IsEmbedding.of_comp (by fun_prop) continuous_subtype_val + (SurjectiveOnStalks.isEmbedding_pullback f g) + exact IsEmbedding.subtypeVal.comp ((TopCat.pullbackHomeoPreimage _ f.continuous _ + g.isEmbedding).isEmbedding.comp this) + end IsPreimmersion end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean index 6a02465a5cb1a8..4306631e05eb23 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean @@ -39,9 +39,9 @@ For `HasRingHomProperty P Q` and `f : X ⟶ Y`, we provide these API lemmas: - `AlgebraicGeometry.HasRingHomProperty.iff_appLE`: `P f` if and only if `Q (f.appLE U V _)` for all affine `U : Opens Y` and `V : Opens X`. - `AlgebraicGeometry.HasRingHomProperty.iff_of_source_openCover`: - If `Y` is affine, `P f ↔ ∀ i, Q ((𝒰.map i ≫ f).app ⊤)` for an affine open cover `𝒰` of `X`. + If `Y` is affine, `P f ↔ ∀ i, Q ((𝒰.map i ≫ f).appTop)` for an affine open cover `𝒰` of `X`. - `AlgebraicGeometry.HasRingHomProperty.iff_of_isAffine`: - If `X` and `Y` are affine, then `P f ↔ Q (f.app ⊤)`. + If `X` and `Y` are affine, then `P f ↔ Q (f.appTop)`. - `AlgebraicGeometry.HasRingHomProperty.Spec_iff`: `P (Spec.map φ) ↔ Q φ` - `AlgebraicGeometry.HasRingHomProperty.iff_of_iSup_eq_top`: @@ -66,14 +66,14 @@ namespace RingHom variable (P : ∀ {R S : Type u} [CommRing R] [CommRing S], (R →+* S) → Prop) -theorem IsStableUnderBaseChange.pullback_fst_app_top +theorem IsStableUnderBaseChange.pullback_fst_appTop (hP : IsStableUnderBaseChange P) (hP' : RespectsIso P) {X Y S : Scheme} [IsAffine X] [IsAffine Y] [IsAffine S] (f : X ⟶ S) (g : Y ⟶ S) - (H : P (g.app ⊤)) : P ((pullback.fst f g).app ⊤) := by + (H : P g.appTop) : P (pullback.fst f g).appTop := by -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11224): change `rw` to `erw` erw [← PreservesPullback.iso_inv_fst AffineScheme.forgetToScheme (AffineScheme.ofHom f) (AffineScheme.ofHom g)] - rw [Scheme.comp_app, hP'.cancel_right_isIso, AffineScheme.forgetToScheme_map] + rw [Scheme.comp_appTop, hP'.cancel_right_isIso, AffineScheme.forgetToScheme_map] have := congr_arg Quiver.Hom.unop (PreservesPullback.iso_hom_fst AffineScheme.Γ.rightOp (AffineScheme.ofHom f) (AffineScheme.ofHom g)) @@ -83,6 +83,10 @@ theorem IsStableUnderBaseChange.pullback_fst_app_top rw [← this, hP'.cancel_right_isIso, ← pushoutIsoUnopPullback_inl_hom, hP'.cancel_right_isIso] exact hP.pushout_inl _ hP' _ _ H +@[deprecated (since := "2024-11-23")] +alias IsStableUnderBaseChange.pullback_fst_app_top := +IsStableUnderBaseChange.pullback_fst_appTop + end RingHom namespace AlgebraicGeometry @@ -268,10 +272,12 @@ theorem appLE (H : P f) (U : Y.affineOpens) (V : X.affineOpens) (e) : Q (f.appLE rw [eq_affineLocally P, affineLocally_iff_affineOpens_le] at H exact H _ _ _ -theorem app_top (H : P f) [IsAffine X] [IsAffine Y] : Q (f.app ⊤) := by - rw [Scheme.Hom.app_eq_appLE] +theorem appTop (H : P f) [IsAffine X] [IsAffine Y] : Q f.appTop := by + rw [Scheme.Hom.appTop, Scheme.Hom.app_eq_appLE] exact appLE P f H ⟨_, isAffineOpen_top _⟩ ⟨_, isAffineOpen_top _⟩ _ +@[deprecated (since := "2024-11-23")] alias app_top := appTop + include Q in theorem comp_of_isOpenImmersion [IsOpenImmersion f] (H : P g) : P (f ≫ g) := by @@ -291,7 +297,7 @@ lemma iff_appLE : P f ↔ ∀ (U : Y.affineOpens) (V : X.affineOpens) (e), Q (f. rw [eq_affineLocally P, affineLocally_iff_affineOpens_le] theorem of_source_openCover [IsAffine Y] - (𝒰 : X.OpenCover) [∀ i, IsAffine (𝒰.obj i)] (H : ∀ i, Q ((𝒰.map i ≫ f).app ⊤)) : + (𝒰 : X.OpenCover) [∀ i, IsAffine (𝒰.obj i)] (H : ∀ i, Q ((𝒰.map i ≫ f).appTop)) : P f := by rw [HasAffineProperty.iff_of_isAffine (P := P)] intro U @@ -313,17 +319,17 @@ theorem of_source_openCover [IsAffine Y] specialize H i rw [← (isLocal_ringHomProperty P).respectsIso.cancel_right_isIso _ ((IsOpenImmersion.isoOfRangeEq (𝒰.map i) (S i).1.ι - Subtype.range_coe.symm).inv.app _), ← Scheme.comp_app, - IsOpenImmersion.isoOfRangeEq_inv_fac_assoc, Scheme.comp_app, - Scheme.Opens.ι_app, Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map] at H + Subtype.range_coe.symm).inv.app _), ← Scheme.comp_appTop, + IsOpenImmersion.isoOfRangeEq_inv_fac_assoc, Scheme.comp_appTop, + Scheme.Opens.ι_appTop, Scheme.Hom.appTop, Scheme.Hom.app_eq_appLE, Scheme.Hom.appLE_map] at H exact (f.appLE_congr _ rfl (by simp) Q).mp H theorem iff_of_source_openCover [IsAffine Y] (𝒰 : X.OpenCover) [∀ i, IsAffine (𝒰.obj i)] : - P f ↔ ∀ i, Q ((𝒰.map i ≫ f).app ⊤) := - ⟨fun H i ↦ app_top P _ (comp_of_isOpenImmersion P (𝒰.map i) f H), of_source_openCover 𝒰⟩ + P f ↔ ∀ i, Q ((𝒰.map i ≫ f).appTop) := + ⟨fun H i ↦ appTop P _ (comp_of_isOpenImmersion P (𝒰.map i) f H), of_source_openCover 𝒰⟩ theorem iff_of_isAffine [IsAffine X] [IsAffine Y] : - P f ↔ Q (f.app ⊤) := by + P f ↔ Q (f.appTop) := by rw [iff_of_source_openCover (P := P) (Scheme.coverOfIsIso.{u} (𝟙 _))] simp @@ -359,7 +365,7 @@ lemma containsIdentities (hP : RingHom.ContainsIdentities Q) : P.ContainsIdentit 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] + rw [morphismRestrict_id, iff_of_isAffine (P := P), Scheme.id_appTop] apply hP variable (P) in @@ -504,7 +510,7 @@ lemma isStableUnderBaseChange (hP : RingHom.IsStableUnderBaseChange Q) : limit.lift_π, PullbackCone.mk_pt, PullbackCone.mk_π_app, Category.comp_id] apply this _ (comp_of_isOpenImmersion _ _ _ H) inferInstance rw [iff_of_isAffine (P := P)] at H ⊢ - exact hP.pullback_fst_app_top _ (isLocal_ringHomProperty P).respectsIso _ _ H + exact hP.pullback_fst_appTop _ (isLocal_ringHomProperty P).respectsIso _ _ H include Q in private lemma respects_isOpenImmersion_aux diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean index a97b12f9fcc9c3..c03365e68f13ff 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Separated.lean @@ -240,6 +240,16 @@ lemma ext_of_isDominant_of_isSeparated [IsReduced X] {f g : X ⟶ Y} rw [← cancel_epi (equalizer.ι f' g').left] exact congr($(equalizer.condition f' g').left) +variable (S) in +/-- +Suppose `X` is a reduced `S`-scheme and `Y` is a separated `S`-scheme. +For any `S`-morphisms `f g : X ⟶ Y`, `f = g` if `ι ≫ f = ι ≫ g` for some dominant `ι`. +-/ +lemma ext_of_isDominant_of_isSeparated' [X.Over S] [Y.Over S] [IsReduced X] [IsSeparated (Y ↘ S)] + {f g : X ⟶ Y} [f.IsOver S] [g.IsOver S] {W} (ι : W ⟶ X) [IsDominant ι] + (hU : ι ≫ f = ι ≫ g) : f = g := + ext_of_isDominant_of_isSeparated (Y ↘ S) (by simp) ι hU + namespace Scheme /-- A scheme `X` is separated if it is separated over `⊤_ Scheme`. -/ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean new file mode 100644 index 00000000000000..66aff1bb5a74d0 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean @@ -0,0 +1,185 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.RingHomProperties +import Mathlib.AlgebraicGeometry.PrimeSpectrum.TensorProduct +import Mathlib.Topology.LocalAtTarget + +/-! +# Morphisms surjective on stalks + +We define the classe of morphisms between schemes that are surjective on stalks. +We show that this class is stable under composition and base change. + +We also show that (`AlgebraicGeometry.SurjectiveOnStalks.isEmbedding_pullback`) +if `Y ⟶ S` is surjective on stalks, then for every `X ⟶ S`, `X ×ₛ Y` is a subset of +`X × Y` (cartesian product as topological spaces) with the induced topology. +-/ + +open CategoryTheory CategoryTheory.Limits Topology + +namespace AlgebraicGeometry + +universe u + +variable {X Y Z : Scheme.{u}} (f : X ⟶ Y) (g : Y ⟶ Z) + +/-- The class of morphisms `f : X ⟶ Y` between schemes such that +`𝒪_{Y, f x} ⟶ 𝒪_{X, x}` is surjective for all `x : X`. -/ +@[mk_iff] +class SurjectiveOnStalks : Prop where + surj_on_stalks : ∀ x, Function.Surjective (f.stalkMap x) + +theorem Scheme.Hom.stalkMap_surjective (f : X.Hom Y) [SurjectiveOnStalks f] (x) : + Function.Surjective (f.stalkMap x) := + SurjectiveOnStalks.surj_on_stalks x + +namespace SurjectiveOnStalks + +instance (priority := 900) [IsOpenImmersion f] : SurjectiveOnStalks f := + ⟨fun _ ↦ (ConcreteCategory.bijective_of_isIso _).2⟩ + +instance : MorphismProperty.IsMultiplicative @SurjectiveOnStalks where + id_mem _ := inferInstance + comp_mem {X Y Z} f g hf hg := by + refine ⟨fun x ↦ ?_⟩ + rw [Scheme.stalkMap_comp] + exact (hf.surj_on_stalks x).comp (hg.surj_on_stalks (f.base x)) + +instance comp {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) [SurjectiveOnStalks f] + [SurjectiveOnStalks g] : SurjectiveOnStalks (f ≫ g) := + MorphismProperty.IsStableUnderComposition.comp_mem f g inferInstance inferInstance + +lemma eq_stalkwise : + @SurjectiveOnStalks = stalkwise (Function.Surjective ·) := by + ext; exact surjectiveOnStalks_iff _ + +instance : IsLocalAtTarget @SurjectiveOnStalks := + eq_stalkwise ▸ stalkwiseIsLocalAtTarget_of_respectsIso RingHom.surjective_respectsIso + +instance : IsLocalAtSource @SurjectiveOnStalks := + eq_stalkwise ▸ stalkwise_isLocalAtSource_of_respectsIso RingHom.surjective_respectsIso + +lemma Spec_iff {R S : CommRingCat.{u}} {φ : R ⟶ S} : + SurjectiveOnStalks (Spec.map φ) ↔ RingHom.SurjectiveOnStalks φ := by + rw [eq_stalkwise, stalkwise_Spec_map_iff RingHom.surjective_respectsIso, + RingHom.SurjectiveOnStalks] + +instance : HasRingHomProperty @SurjectiveOnStalks RingHom.SurjectiveOnStalks := + eq_stalkwise ▸ .stalkwise RingHom.surjective_respectsIso + +variable {f} in +lemma iff_of_isAffine [IsAffine X] [IsAffine Y] : + SurjectiveOnStalks f ↔ RingHom.SurjectiveOnStalks (f.app ⊤) := by + rw [← Spec_iff, MorphismProperty.arrow_mk_iso_iff @SurjectiveOnStalks (arrowIsoSpecΓOfIsAffine f)] + +theorem of_comp [SurjectiveOnStalks (f ≫ g)] : SurjectiveOnStalks f := by + refine ⟨fun x ↦ ?_⟩ + have := (f ≫ g).stalkMap_surjective x + rw [Scheme.stalkMap_comp] at this + exact Function.Surjective.of_comp this + +instance stableUnderBaseChange : + MorphismProperty.IsStableUnderBaseChange @SurjectiveOnStalks := by + apply HasRingHomProperty.isStableUnderBaseChange + apply RingHom.IsStableUnderBaseChange.mk + · exact (HasRingHomProperty.isLocal_ringHomProperty @SurjectiveOnStalks).respectsIso + intros R S T _ _ _ _ _ H + exact H.baseChange + +/-- If `Y ⟶ S` is surjective on stalks, then for every `X ⟶ S`, `X ×ₛ Y` is a subset of +`X × Y` (cartesian product as topological spaces) with the induced topology. -/ +lemma isEmbedding_pullback {X Y S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) [SurjectiveOnStalks g] : + IsEmbedding (fun x ↦ ((pullback.fst f g).base x, (pullback.snd f g).base x)) := by + let L := (fun x ↦ ((pullback.fst f g).base x, (pullback.snd f g).base x)) + have H : ∀ R A B (f' : Spec A ⟶ Spec R) (g' : Spec B ⟶ Spec R) (iX : Spec A ⟶ X) + (iY : Spec B ⟶ Y) (iS : Spec R ⟶ S) (e₁ e₂), IsOpenImmersion iX → IsOpenImmersion iY → + IsOpenImmersion iS → IsEmbedding (L ∘ (pullback.map f' g' f g iX iY iS e₁ e₂).base) := by + intro R A B f' g' iX iY iS e₁ e₂ _ _ _ + have H : SurjectiveOnStalks g' := + have : SurjectiveOnStalks (g' ≫ iS) := e₂ ▸ inferInstance + .of_comp _ iS + obtain ⟨φ, rfl⟩ : ∃ φ, Spec.map φ = f' := ⟨_, Spec.map_preimage _⟩ + obtain ⟨ψ, rfl⟩ : ∃ ψ, Spec.map ψ = g' := ⟨_, Spec.map_preimage _⟩ + letI := φ.toAlgebra + letI := ψ.toAlgebra + rw [HasRingHomProperty.Spec_iff (P := @SurjectiveOnStalks)] at H + convert ((iX.isOpenEmbedding.prodMap iY.isOpenEmbedding).isEmbedding.comp + (PrimeSpectrum.isEmbedding_tensorProductTo_of_surjectiveOnStalks R A B H)).comp + (Scheme.homeoOfIso (pullbackSpecIso R A B)).isEmbedding + ext1 x + obtain ⟨x, rfl⟩ := (Scheme.homeoOfIso (pullbackSpecIso R A B).symm).surjective x + simp only [Scheme.homeoOfIso_apply, Function.comp_apply] + ext + · simp only [← Scheme.comp_base_apply, pullback.lift_fst, Iso.symm_hom, Iso.inv_hom_id] + erw [← Scheme.comp_base_apply, pullbackSpecIso_inv_fst_assoc] + rfl + · simp only [← Scheme.comp_base_apply, pullback.lift_snd, Iso.symm_hom, Iso.inv_hom_id] + erw [← Scheme.comp_base_apply, pullbackSpecIso_inv_snd_assoc] + rfl + let 𝒰 := S.affineOpenCover.openCover + let 𝒱 (i) := ((𝒰.pullbackCover f).obj i).affineOpenCover.openCover + let 𝒲 (i) := ((𝒰.pullbackCover g).obj i).affineOpenCover.openCover + let U (ijk : Σ i, (𝒱 i).J × (𝒲 i).J) : TopologicalSpace.Opens (X.carrier × Y) := + ⟨{ P | P.1 ∈ ((𝒱 ijk.1).map ijk.2.1 ≫ (𝒰.pullbackCover f).map ijk.1).opensRange ∧ + P.2 ∈ ((𝒲 ijk.1).map ijk.2.2 ≫ (𝒰.pullbackCover g).map ijk.1).opensRange }, + (continuous_fst.1 _ ((𝒱 ijk.1).map ijk.2.1 ≫ + (𝒰.pullbackCover f).map ijk.1).opensRange.2).inter (continuous_snd.1 _ + ((𝒲 ijk.1).map ijk.2.2 ≫ (𝒰.pullbackCover g).map ijk.1).opensRange.2)⟩ + have : Set.range L ⊆ (iSup U : _) := by + simp only [Scheme.Cover.pullbackCover_J, Scheme.Cover.pullbackCover_obj, Set.range_subset_iff] + intro z + simp only [SetLike.mem_coe, TopologicalSpace.Opens.mem_iSup, Sigma.exists, Prod.exists] + obtain ⟨is, s, hsx⟩ := 𝒰.exists_eq (f.base ((pullback.fst f g).base z)) + have hsy : (𝒰.map is).base s = g.base ((pullback.snd f g).base z) := by + rwa [← Scheme.comp_base_apply, ← pullback.condition, Scheme.comp_base_apply] + obtain ⟨x : (𝒰.pullbackCover f).obj is, hx⟩ := + Scheme.IsJointlySurjectivePreserving.exists_preimage_fst_triplet_of_prop + (P := @IsOpenImmersion) inferInstance _ _ hsx.symm + obtain ⟨y : (𝒰.pullbackCover g).obj is, hy⟩ := + Scheme.IsJointlySurjectivePreserving.exists_preimage_fst_triplet_of_prop + (P := @IsOpenImmersion) inferInstance _ _ hsy.symm + obtain ⟨ix, x, rfl⟩ := (𝒱 is).exists_eq x + obtain ⟨iy, y, rfl⟩ := (𝒲 is).exists_eq y + refine ⟨is, ix, iy, ⟨x, hx⟩, ⟨y, hy⟩⟩ + let 𝓤 := (Scheme.Pullback.openCoverOfBase 𝒰 f g).bind + (fun i ↦ Scheme.Pullback.openCoverOfLeftRight (𝒱 i) (𝒲 i) _ _) + refine isEmbedding_of_iSup_eq_top_of_preimage_subset_range _ ?_ U this _ (fun i ↦ (𝓤.map i).base) + (fun i ↦ (𝓤.map i).continuous) ?_ ?_ + · fun_prop + · rintro i x ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩⟩ + obtain ⟨x₁', hx₁'⟩ := + Scheme.IsJointlySurjectivePreserving.exists_preimage_fst_triplet_of_prop + (P := @IsOpenImmersion) inferInstance _ _ hx₁.symm + obtain ⟨x₂', hx₂'⟩ := + Scheme.IsJointlySurjectivePreserving.exists_preimage_fst_triplet_of_prop + (P := @IsOpenImmersion) inferInstance _ _ hx₂.symm + obtain ⟨z, hz⟩ := + Scheme.IsJointlySurjectivePreserving.exists_preimage_fst_triplet_of_prop + (P := @IsOpenImmersion) inferInstance _ _ (hx₁'.trans hx₂'.symm) + refine ⟨(pullbackFstFstIso _ _ _ _ _ _ (𝒰.map i.1) ?_ ?_).hom.base z, ?_⟩ + · simp [pullback.condition] + · simp [pullback.condition] + · dsimp only + rw [← hx₁', ← hz, ← Scheme.comp_base_apply] + erw [← Scheme.comp_base_apply] + congr 4 + apply pullback.hom_ext <;> simp [𝓤, ← pullback.condition, ← pullback.condition_assoc] + · intro i + have := H (S.affineOpenCover.obj i.1) (((𝒰.pullbackCover f).obj i.1).affineOpenCover.obj i.2.1) + (((𝒰.pullbackCover g).obj i.1).affineOpenCover.obj i.2.2) + ((𝒱 i.1).map i.2.1 ≫ 𝒰.pullbackHom f i.1) + ((𝒲 i.1).map i.2.2 ≫ 𝒰.pullbackHom g i.1) + ((𝒱 i.1).map i.2.1 ≫ (𝒰.pullbackCover f).map i.1) + ((𝒲 i.1).map i.2.2 ≫ (𝒰.pullbackCover g).map i.1) + (𝒰.map i.1) (by simp [pullback.condition]) (by simp [pullback.condition]) + inferInstance inferInstance inferInstance + convert this using 6 + apply pullback.hom_ext <;> + simp [𝓤, ← pullback.condition, ← pullback.condition_assoc, Scheme.Cover.pullbackHom] + +end SurjectiveOnStalks + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean index dbcc339026d059..065d25bd88b117 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UnderlyingMap.lean @@ -83,6 +83,18 @@ instance surjective_isLocalAtTarget : IsLocalAtTarget @Surjective := by obtain ⟨⟨y, _⟩, hy⟩ := hf i ⟨x, hxi⟩ exact ⟨y, congr(($hy).1)⟩ +@[simp] +lemma range_eq_univ [Surjective f] : Set.range f.base = Set.univ := by + simpa [Set.range_eq_univ] using f.surjective + +lemma range_eq_range_of_surjective {S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) (e : X ⟶ Y) + [Surjective e] (hge : e ≫ g = f) : Set.range f.base = Set.range g.base := by + rw [← hge] + simp [Set.range_comp] + +lemma mem_range_iff_of_surjective {S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) (e : X ⟶ Y) + [Surjective e] (hge : e ≫ g = f) (s : S) : s ∈ Set.range f.base ↔ s ∈ Set.range g.base := by + rw [range_eq_range_of_surjective f g e hge] end Surjective section Injective diff --git a/Mathlib/AlgebraicGeometry/Over.lean b/Mathlib/AlgebraicGeometry/Over.lean index c52efcbb93841f..15349f1b13a3e3 100644 --- a/Mathlib/AlgebraicGeometry/Over.lean +++ b/Mathlib/AlgebraicGeometry/Over.lean @@ -41,6 +41,17 @@ abbrev CanonicallyOver := CanonicallyOverClass X S `f.IsOver S` is the typeclass asserting `f` commutes with the structure morphisms. -/ abbrev Hom.IsOver (f : X.Hom Y) (S : Scheme.{u}) [X.Over S] [Y.Over S] := HomIsOver f S +@[simp] +lemma Hom.isOver_iff [X.Over S] [Y.Over S] {f : X ⟶ Y} : f.IsOver S ↔ f ≫ Y ↘ S = X ↘ S := + ⟨fun H ↦ H.1, fun h ↦ ⟨h⟩⟩ + /-! Also note the existence of `CategoryTheory.IsOverTower X Y S`. -/ +/-- Given `X.Over S`, this is the bundled object of `Over S`. -/ +abbrev asOver (X S : Scheme.{u}) [X.Over S] := OverClass.asOver X S + +/-- Given a morphism `X ⟶ Y` with `f.IsOver S`, this is the bundled morphism in `Over S`. -/ +abbrev Hom.asOver (f : X.Hom Y) (S : Scheme.{u}) [X.Over S] [Y.Over S] [f.IsOver S] := + OverClass.asOverHom S f + end AlgebraicGeometry.Scheme diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean index df037ab6863644..6a4899d2598b79 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean @@ -9,7 +9,7 @@ import Mathlib.RingTheory.Ideal.Over import Mathlib.RingTheory.KrullDimension.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs import Mathlib.RingTheory.LocalRing.RingHom.Basic -import Mathlib.RingTheory.Localization.Away.Basic +import Mathlib.RingTheory.Localization.Away.Lemmas import Mathlib.Tactic.StacksAttribute import Mathlib.Topology.KrullDimension import Mathlib.Topology.Sober @@ -156,7 +156,7 @@ theorem isIrreducible_zeroLocus_iff_of_radical (I : Ideal R) (hI : I.IsRadical) apply and_congr · rw [Set.nonempty_iff_ne_empty, Ne, zeroLocus_empty_iff_eq_top] · trans ∀ x y : Ideal R, Z(I) ⊆ Z(x) ∪ Z(y) → Z(I) ⊆ Z(x) ∨ Z(I) ⊆ Z(y) - · simp_rw [isPreirreducible_iff_closed_union_closed, isClosed_iff_zeroLocus_ideal] + · simp_rw [isPreirreducible_iff_isClosed_union_isClosed, isClosed_iff_zeroLocus_ideal] constructor · rintro h x y exact h _ _ ⟨x, rfl⟩ ⟨y, rfl⟩ @@ -212,6 +212,31 @@ instance compactSpace : CompactSpace (PrimeSpectrum R) := by simp_rw [hI, ← zeroLocus_iSup, zeroLocus_empty_iff_eq_top, ← top_le_iff] at S_empty ⊢ exact Ideal.isCompactElement_top.exists_finset_of_le_iSup _ _ S_empty +/-- The prime spectrum of a semiring has discrete Zariski topology iff it is finite and +all primes are maximal. -/ +theorem discreteTopology_iff_finite_and_isPrime_imp_isMaximal : DiscreteTopology (PrimeSpectrum R) ↔ + Finite (PrimeSpectrum R) ∧ ∀ I : Ideal R, I.IsPrime → I.IsMaximal := + ⟨fun _ ↦ ⟨finite_of_compact_of_discrete, fun I hI ↦ (isClosed_singleton_iff_isMaximal ⟨I, hI⟩).mp + <| discreteTopology_iff_forall_isClosed.mp ‹_› _⟩, fun ⟨_, h⟩ ↦ .of_finite_of_isClosed_singleton + fun p ↦ (isClosed_singleton_iff_isMaximal p).mpr <| h _ p.2⟩ + +/-- The prime spectrum of a semiring has discrete Zariski topology iff there are only +finitely many maximal ideals and their intersection is contained in the nilradical. -/ +theorem discreteTopology_iff_finite_isMaximal_and_sInf_le_nilradical : + letI s := {I : Ideal R | I.IsMaximal} + DiscreteTopology (PrimeSpectrum R) ↔ Finite s ∧ sInf s ≤ nilradical R := + discreteTopology_iff_finite_and_isPrime_imp_isMaximal.trans <| by + rw [(equivSubtype R).finite_iff, ← Set.coe_setOf, Set.finite_coe_iff, Set.finite_coe_iff] + refine ⟨fun h ↦ ⟨h.1.subset fun _ h ↦ h.isPrime, nilradical_eq_sInf R ▸ sInf_le_sInf h.2⟩, + fun ⟨fin, le⟩ ↦ ?_⟩ + have hpm (I : Ideal R) (hI : I.IsPrime): I.IsMaximal := by + replace le := le.trans (nilradical_le_prime I) + rw [← fin.coe_toFinset, ← Finset.inf_id_eq_sInf, hI.inf_le'] at le + have ⟨M, hM, hMI⟩ := le + rw [fin.mem_toFinset] at hM + rwa [← hM.eq_of_le hI.1 hMI] + exact ⟨fin.subset hpm, hpm⟩ + section Comap variable {S' : Type*} [CommSemiring S'] @@ -321,13 +346,6 @@ theorem comap_singleton_isClosed_of_surjective (f : R →+* S) (hf : Function.Su haveI : x.asIdeal.IsMaximal := (isClosed_singleton_iff_isMaximal x).1 hx (isClosed_singleton_iff_isMaximal _).2 (Ideal.comap_isMaximal_of_surjective f hf) -theorem comap_singleton_isClosed_of_isIntegral (f : R →+* S) (hf : f.IsIntegral) - (x : PrimeSpectrum S) (hx : IsClosed ({x} : Set (PrimeSpectrum S))) : - IsClosed ({comap f x} : Set (PrimeSpectrum R)) := - have := (isClosed_singleton_iff_isMaximal x).1 hx - (isClosed_singleton_iff_isMaximal _).2 - (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) := image_specComap_zeroLocus_eq_zeroLocus_comap _ f hf I @@ -508,6 +526,22 @@ lemma iSup_basicOpen_eq_top_iff' {s : Set R} : conv_rhs => rw [← Subtype.range_val (s := s), ← iSup_basicOpen_eq_top_iff] simp +theorem isLocalization_away_iff_atPrime_of_basicOpen_eq_singleton [Algebra R S] + {f : R} {p : PrimeSpectrum R} (h : (basicOpen f).1 = {p}) : + IsLocalization.Away f S ↔ IsLocalization.AtPrime S p.1 := + have : IsLocalization.AtPrime (Localization.Away f) p.1 := by + refine .of_le_of_exists_dvd (Submonoid.powers f) _ + (Submonoid.powers_le.mpr <| by apply h ▸ Set.mem_singleton p) fun r hr ↦ ?_ + contrapose! hr + simp_rw [← Ideal.mem_span_singleton] at hr + have ⟨q, prime, le, disj⟩ := Ideal.exists_le_prime_disjoint (Ideal.span {r}) + (Submonoid.powers f) (Set.disjoint_right.mpr hr) + have : ⟨q, prime⟩ ∈ (basicOpen f).1 := Set.disjoint_right.mp disj (Submonoid.mem_powers f) + rw [h, Set.mem_singleton_iff] at this + rw [← this] + exact not_not.mpr (q.span_singleton_le_iff_mem.mp le) + IsLocalization.isLocalization_iff_of_isLocalization _ _ (Localization.Away f) + end BasicOpen section Order @@ -676,14 +710,30 @@ lemma isCompact_isOpen_iff {s : Set (PrimeSpectrum R)} : fun ⟨s, e⟩ ↦ ⟨s, s.finite_toSet, by simpa using e.symm⟩⟩ lemma isCompact_isOpen_iff_ideal {s : Set (PrimeSpectrum R)} : - IsCompact s ∧ IsOpen s ↔ - ∃ I : Ideal R, I.FG ∧ (PrimeSpectrum.zeroLocus (I : Set R))ᶜ = s := by + IsCompact s ∧ IsOpen s ↔ ∃ I : Ideal R, I.FG ∧ (zeroLocus I)ᶜ = s := by rw [isCompact_isOpen_iff] exact ⟨fun ⟨s, e⟩ ↦ ⟨.span s, ⟨s, rfl⟩, by simpa using e⟩, fun ⟨I, ⟨s, hs⟩, e⟩ ↦ ⟨s, by simpa [hs.symm] using e⟩⟩ -lemma exists_idempotent_basicOpen_eq_of_is_clopen {s : Set (PrimeSpectrum R)} - (hs : IsClopen s) : ∃ e : R, IsIdempotentElem e ∧ s = basicOpen e := by +lemma basicOpen_injOn_isIdempotentElem : + {e : R | IsIdempotentElem e}.InjOn basicOpen := fun x hx y hy eq ↦ by + by_contra! ne + wlog ne' : x * y ≠ x generalizing x y + · apply this y hy x hx eq.symm ne.symm + rwa [mul_comm, of_not_not ne'] + have : x ∉ Ideal.span {y} := fun mem ↦ ne' <| by + obtain ⟨r, rfl⟩ := Ideal.mem_span_singleton'.mp mem + rw [mul_assoc, hy] + have ⟨p, prime, le, nmem⟩ := Ideal.exists_le_prime_nmem_of_isIdempotentElem _ x hx this + exact ne_of_mem_of_not_mem' (a := ⟨p, prime⟩) nmem + (not_not.mpr <| p.span_singleton_le_iff_mem.mp le) eq + +@[stacks 00EE] +lemma existsUnique_idempotent_basicOpen_eq_of_isClopen {s : Set (PrimeSpectrum R)} + (hs : IsClopen s) : ∃! e : R, IsIdempotentElem e ∧ s = basicOpen e := by + refine exists_unique_of_exists_of_unique ?_ ?_; swap + · rintro x y ⟨hx, rfl⟩ ⟨hy, eq⟩ + exact basicOpen_injOn_isIdempotentElem hx hy (SetLike.ext' eq) cases subsingleton_or_nontrivial R · exact ⟨0, Subsingleton.elim _ _, Subsingleton.elim _ _⟩ obtain ⟨I, hI, hI'⟩ := isCompact_isOpen_iff_ideal.mp ⟨hs.1.isCompact, hs.2⟩ @@ -719,6 +769,81 @@ lemma exists_idempotent_basicOpen_eq_of_is_clopen {s : Set (PrimeSpectrum R)} exact PrimeSpectrum.zeroLocus_anti_mono (Set.singleton_subset_iff.mpr <| Ideal.pow_le_self hnz hx) +lemma exists_idempotent_basicOpen_eq_of_isClopen {s : Set (PrimeSpectrum R)} + (hs : IsClopen s) : ∃ e : R, IsIdempotentElem e ∧ s = basicOpen e := + (existsUnique_idempotent_basicOpen_eq_of_isClopen hs).exists + +@[deprecated (since := "2024-11-11")] +alias exists_idempotent_basicOpen_eq_of_is_clopen := exists_idempotent_basicOpen_eq_of_isClopen + +section IsIntegral + +open Polynomial + +variable {R S : Type*} [CommRing R] [CommRing S] (f : R →+* S) + +theorem isClosedMap_comap_of_isIntegral (hf : f.IsIntegral) : + IsClosedMap (comap f) := by + refine fun s hs ↦ isClosed_image_of_stableUnderSpecialization _ _ hs ?_ + rintro _ y e ⟨x, hx, rfl⟩ + algebraize [f] + obtain ⟨q, hq₁, hq₂, hq₃⟩ := Ideal.exists_ideal_over_prime_of_isIntegral y.asIdeal x.asIdeal + ((le_iff_specializes _ _).mpr e) + refine ⟨⟨q, hq₂⟩, ((le_iff_specializes _ ⟨q, hq₂⟩).mp hq₁).mem_closed hs hx, + PrimeSpectrum.ext hq₃⟩ + +theorem isClosed_comap_singleton_of_isIntegral (hf : f.IsIntegral) + (x : PrimeSpectrum S) (hx : IsClosed ({x} : Set (PrimeSpectrum S))) : + IsClosed ({comap f x} : Set (PrimeSpectrum R)) := by + simpa using isClosedMap_comap_of_isIntegral f hf _ hx + +lemma closure_image_comap_zeroLocus (I : Ideal S) : + closure (comap f '' zeroLocus I) = zeroLocus (I.comap f) := by + apply subset_antisymm + · rw [(isClosed_zeroLocus _).closure_subset_iff, Set.image_subset_iff, preimage_comap_zeroLocus] + exact zeroLocus_anti_mono (Set.image_preimage_subset _ _) + · rintro x (hx : I.comap f ≤ x.asIdeal) + obtain ⟨q, hq₁, hq₂⟩ := Ideal.exists_minimalPrimes_le hx + obtain ⟨p', hp', hp'', rfl⟩ := Ideal.exists_comap_eq_of_mem_minimalPrimes f _ hq₁ + let p'' : PrimeSpectrum S := ⟨p', hp'⟩ + apply isClosed_closure.stableUnderSpecialization ((le_iff_specializes + (comap f ⟨p', hp'⟩) x).mp hq₂) (subset_closure (by exact ⟨_, hp'', rfl⟩)) + +lemma isIntegral_of_isClosedMap_comap_mapRingHom (h : IsClosedMap (comap (mapRingHom f))) : + f.IsIntegral := by + algebraize [f] + suffices Algebra.IsIntegral R S by rwa [Algebra.isIntegral_def] at this + nontriviality R + nontriviality S + constructor + intro r + let p : S[X] := C r * X - 1 + have : (1 : R[X]) ∈ Ideal.span {X} ⊔ (Ideal.span {p}).comap (mapRingHom f) := by + have H := h _ (isClosed_zeroLocus {p}) + rw [← zeroLocus_span, ← closure_eq_iff_isClosed, closure_image_comap_zeroLocus] at H + rw [← Ideal.eq_top_iff_one, sup_comm, ← zeroLocus_empty_iff_eq_top, zeroLocus_sup, H] + suffices ∀ (a : PrimeSpectrum S[X]), p ∈ a.asIdeal → X ∉ a.asIdeal by + simpa [Set.eq_empty_iff_forall_not_mem] + intro q hpq hXq + have : 1 ∈ q.asIdeal := by simpa [p] using (sub_mem (q.asIdeal.mul_mem_left (C r) hXq) hpq) + exact q.2.ne_top (q.asIdeal.eq_top_iff_one.mpr this) + obtain ⟨a, b, hb, e⟩ := Ideal.mem_span_singleton_sup.mp this + obtain ⟨c, hc : b.map (algebraMap R S) = _⟩ := Ideal.mem_span_singleton.mp hb + refine ⟨b.reverse * X ^ (1 + c.natDegree), ?_, ?_⟩ + · refine Monic.mul ?_ (by simp) + have h : b.coeff 0 = 1 := by simpa using congr(($e).coeff 0) + have : b.natTrailingDegree = 0 := by simp [h] + rw [Monic.def, reverse_leadingCoeff, trailingCoeff, this, h] + · have : p.natDegree ≤ 1 := by simpa using natDegree_linear_le (a := r) (b := -1) + rw [eval₂_eq_eval_map, reverse, Polynomial.map_mul, ← reflect_map, Polynomial.map_pow, + map_X, ← revAt_zero (1 + _), ← reflect_monomial, + ← reflect_mul _ _ (natDegree_map_le _ _) (by simp), pow_zero, mul_one, hc, + ← add_assoc, reflect_mul _ _ (this.trans (by simp)) le_rfl, + eval_mul, reflect_sub, reflect_mul _ _ (by simp) (by simp)] + simp [← pow_succ'] + +end IsIntegral + section LocalizationAtMinimal variable {I : Ideal R} [hI : I.IsPrime] @@ -878,7 +1003,10 @@ section Idempotent variable {R} [CommRing R] -lemma PrimeSpectrum.basicOpen_eq_zeroLocus_of_isIdempotentElem +namespace PrimeSpectrum + +@[stacks 00EC] +lemma basicOpen_eq_zeroLocus_of_isIdempotentElem (e : R) (he : IsIdempotentElem e) : basicOpen e = zeroLocus {1 - e} := by ext p @@ -890,24 +1018,123 @@ lemma PrimeSpectrum.basicOpen_eq_zeroLocus_of_isIdempotentElem rw [Ideal.eq_top_iff_one, ← sub_add_cancel 1 e] exact add_mem h₁ h₂ -lemma PrimeSpectrum.zeroLocus_eq_basicOpen_of_isIdempotentElem +@[stacks 00EC] +lemma zeroLocus_eq_basicOpen_of_isIdempotentElem (e : R) (he : IsIdempotentElem e) : zeroLocus {e} = basicOpen (1 - e) := by rw [basicOpen_eq_zeroLocus_of_isIdempotentElem _ he.one_sub, sub_sub_cancel] -lemma PrimeSpectrum.isClopen_iff {s : Set (PrimeSpectrum R)} : +lemma isClopen_iff {s : Set (PrimeSpectrum R)} : IsClopen s ↔ ∃ e : R, IsIdempotentElem e ∧ s = basicOpen e := by - refine ⟨PrimeSpectrum.exists_idempotent_basicOpen_eq_of_is_clopen, ?_⟩ + refine ⟨exists_idempotent_basicOpen_eq_of_isClopen, ?_⟩ rintro ⟨e, he, rfl⟩ refine ⟨?_, (basicOpen e).2⟩ rw [PrimeSpectrum.basicOpen_eq_zeroLocus_of_isIdempotentElem e he] exact isClosed_zeroLocus _ -lemma PrimeSpectrum.isClopen_iff_zeroLocus {s : Set (PrimeSpectrum R)} : - IsClopen s ↔ ∃ e : R, IsIdempotentElem e ∧ s = zeroLocus {e} := by - rw [isClopen_iff] - refine ⟨fun ⟨e, he, h⟩ ↦ ⟨1 - e, he.one_sub, - h.trans (basicOpen_eq_zeroLocus_of_isIdempotentElem e he)⟩, fun ⟨e, he, h⟩ ↦ - ⟨1 - e, he.one_sub, h.trans (zeroLocus_eq_basicOpen_of_isIdempotentElem e he)⟩⟩ +lemma isClopen_iff_zeroLocus {s : Set (PrimeSpectrum R)} : + IsClopen s ↔ ∃ e : R, IsIdempotentElem e ∧ s = zeroLocus {e} := + isClopen_iff.trans <| ⟨fun ⟨e, he, h⟩ ↦ ⟨1 - e, he.one_sub, + h.trans (basicOpen_eq_zeroLocus_of_isIdempotentElem e he)⟩, + fun ⟨e, he, h⟩ ↦ ⟨1 - e, he.one_sub, h.trans (zeroLocus_eq_basicOpen_of_isIdempotentElem e he)⟩⟩ + +open TopologicalSpace (Clopens Opens) + +/-- Clopen subsets in the prime spectrum of a commutative ring are in 1-1 correspondence +with idempotent elements in the ring. -/ +@[stacks 00EE] +def isIdempotentElemEquivClopens : + {e : R | IsIdempotentElem e} ≃ Clopens (PrimeSpectrum R) := + .ofBijective (fun e ↦ ⟨basicOpen e.1, isClopen_iff.mpr ⟨_, e.2, rfl⟩⟩) + ⟨fun x y eq ↦ Subtype.ext (basicOpen_injOn_isIdempotentElem x.2 y.2 <| + SetLike.ext' (congr_arg (·.1) eq)), fun s ↦ + have ⟨e, he, h⟩ := exists_idempotent_basicOpen_eq_of_isClopen s.2 + ⟨⟨e, he⟩, Clopens.ext h.symm⟩⟩ + +lemma basicOpen_isIdempotentElemEquivClopens_symm (s) : + basicOpen (isIdempotentElemEquivClopens (R := R).symm s).1 = s.toOpens := + Opens.ext <| congr_arg (·.1) (isIdempotentElemEquivClopens.apply_symm_apply s) + +lemma coe_isIdempotentElemEquivClopens_apply (e) : + (isIdempotentElemEquivClopens e : Set (PrimeSpectrum R)) = basicOpen (e.1 : R) := rfl + +lemma isIdempotentElemEquivClopens_apply_toOpens (e) : + (isIdempotentElemEquivClopens e).toOpens = basicOpen (e.1 : R) := rfl + +lemma isIdempotentElemEquivClopens_mul (e₁ e₂ : {e : R | IsIdempotentElem e}) : + isIdempotentElemEquivClopens ⟨_, e₁.2.mul e₂.2⟩ = + isIdempotentElemEquivClopens e₁ ⊓ isIdempotentElemEquivClopens e₂ := + Clopens.ext <| by simp_rw [coe_isIdempotentElemEquivClopens_apply, basicOpen_mul]; rfl + +lemma isIdempotentElemEquivClopens_one_sub (e : {e : R | IsIdempotentElem e}) : + isIdempotentElemEquivClopens ⟨_, e.2.one_sub⟩ = (isIdempotentElemEquivClopens e)ᶜ := + SetLike.ext' <| by + simp_rw [Clopens.coe_compl, coe_isIdempotentElemEquivClopens_apply] + rw [basicOpen_eq_zeroLocus_compl, basicOpen_eq_zeroLocus_of_isIdempotentElem _ e.2] + +lemma isIdempotentElemEquivClopens_symm_inf (s₁ s₂) : + letI e := isIdempotentElemEquivClopens (R := R).symm + e (s₁ ⊓ s₂) = ⟨_, (e s₁).2.mul (e s₂).2⟩ := + isIdempotentElemEquivClopens.symm_apply_eq.mpr <| by + simp_rw [isIdempotentElemEquivClopens_mul, Equiv.apply_symm_apply] + +lemma isIdempotentElemEquivClopens_symm_compl (s : Clopens (PrimeSpectrum R)) : + isIdempotentElemEquivClopens.symm sᶜ = ⟨_, (isIdempotentElemEquivClopens.symm s).2.one_sub⟩ := + isIdempotentElemEquivClopens.symm_apply_eq.mpr <| by + rw [isIdempotentElemEquivClopens_one_sub, Equiv.apply_symm_apply] + +lemma isIdempotentElemEquivClopens_symm_top : + isIdempotentElemEquivClopens.symm ⊤ = ⟨(1 : R), .one⟩ := + isIdempotentElemEquivClopens.symm_apply_eq.mpr <| Clopens.ext <| by + rw [coe_isIdempotentElemEquivClopens_apply, basicOpen_one]; rfl + +lemma isIdempotentElemEquivClopens_symm_bot : + isIdempotentElemEquivClopens.symm ⊥ = ⟨(0 : R), .zero⟩ := + isIdempotentElemEquivClopens.symm_apply_eq.mpr <| Clopens.ext <| by + rw [coe_isIdempotentElemEquivClopens_apply, basicOpen_zero]; rfl + +lemma isIdempotentElemEquivClopens_symm_sup (s₁ s₂ : Clopens (PrimeSpectrum R)) : + letI e := isIdempotentElemEquivClopens (R := R).symm + e (s₁ ⊔ s₂) = ⟨_, (e s₁).2.add_sub_mul (e s₂).2⟩ := Subtype.ext <| by + rw [← compl_compl (_ ⊔ _), compl_sup, isIdempotentElemEquivClopens_symm_compl] + simp_rw [isIdempotentElemEquivClopens_symm_inf, isIdempotentElemEquivClopens_symm_compl] + ring + +end PrimeSpectrum + +variable [DiscreteTopology (PrimeSpectrum R)] +open PrimeSpectrum + +variable (R) in +lemma RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology : + Function.Surjective (RingHom.toLocalizationIsMaximal R) := fun x ↦ by + let idem I := isIdempotentElemEquivClopens (R := R).symm ⟨{I}, isClopen_discrete _⟩ + let ideal I := Ideal.span {1 - (idem I).1} + let toSpec (I : {I : Ideal R | I.IsMaximal}) : PrimeSpectrum R := ⟨I.1, I.2.isPrime⟩ + have loc I : IsLocalization.AtPrime (R ⧸ ideal I) I.1 := by + rw [← isLocalization_away_iff_atPrime_of_basicOpen_eq_singleton] + exacts [IsLocalization.Away.quotient_of_isIdempotentElem (idem I).2, + congr_arg (·.1) (basicOpen_isIdempotentElemEquivClopens_symm ⟨{I}, isClopen_discrete _⟩)] + let equiv I := IsLocalization.algEquiv I.1.primeCompl (Localization.AtPrime I.1) (R ⧸ ideal I) + have := (discreteTopology_iff_finite_isMaximal_and_sInf_le_nilradical.mp ‹_›).1 + have ⟨r, hr⟩ := Ideal.pi_quotient_surjective ?_ fun I ↦ equiv (toSpec I) (x I) + · refine ⟨r, funext fun I ↦ (equiv <| toSpec I).injective ?_⟩ + rw [← hr]; exact (equiv _).commutes r + refine fun I J ne ↦ Ideal.isCoprime_iff_exists.mpr ?_ + have := ((idem <| toSpec I).2.mul (idem <| toSpec J).2).eq_zero_of_isNilpotent <| by + simp_rw [← basicOpen_eq_bot_iff, basicOpen_mul, SetLike.ext'_iff, idem, + TopologicalSpace.Opens.coe_inf, basicOpen_isIdempotentElemEquivClopens_symm] + exact Set.singleton_inter_eq_empty.mpr fun h ↦ ne (Subtype.ext <| congr_arg (·.1) h) + simp_rw [ideal, Ideal.mem_span_singleton', exists_exists_eq_and] + exact ⟨1, idem (toSpec I), by simpa [mul_sub]⟩ + +/-- If the prime spectrum of a commutative ring R has discrete Zariski topology, then R is +canonically isomorphic to the product of its localizations at the (finitely many) maximal ideals. -/ +@[stacks 00JA +"See also `PrimeSpectrum.discreteTopology_iff_finite_isMaximal_and_sInf_le_nilradical`."] +def RingHom.toLocalizationIsMaximalEquiv : R ≃+* + Π I : {I : Ideal R // I.IsMaximal}, haveI : I.1.IsMaximal := I.2; Localization.AtPrime I.1 := + .ofBijective _ ⟨RingHom.toLocalizationIsMaximal_injective R, + RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology R⟩ end Idempotent diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Basic.lean index b29a137f71eb26..1ebe7c785f7bba 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Basic.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Basic.lean @@ -166,6 +166,90 @@ lemma awayι_toSpecZero : awayι 𝒜 f f_deg hm ≫ toSpecZero 𝒜 = ← Spec.map_comp, ← Spec.map_comp, ← Spec.map_comp] rfl +variable {f} +variable {m' : ℕ} {g : A} (g_deg : g ∈ 𝒜 m') (hm' : 0 < m') {x : A} (hx : x = f * g) + +@[reassoc] +lemma awayMap_awayToSection : + CommRingCat.ofHom (awayMap 𝒜 g_deg hx) ≫ awayToSection 𝒜 x = + awayToSection 𝒜 f ≫ (Proj 𝒜).presheaf.map (homOfLE (basicOpen_mono _ _ _ ⟨_, hx⟩)).op := by + ext a + apply Subtype.ext + ext ⟨i, hi⟩ + obtain ⟨⟨n, a, ⟨b, hb'⟩, i, rfl : _ = b⟩, rfl⟩ := mk_surjective a + simp only [CommRingCat.forget_obj, CommRingCat.coe_of, CommRingCat.ofHom, CommRingCat.coe_comp_of, + RingHom.coe_comp, Function.comp_apply, homOfLE_leOfHom] + erw [ProjectiveSpectrum.Proj.awayToSection_apply] + rw [val_awayMap_mk, Localization.mk_eq_mk', IsLocalization.map_mk', + ← Localization.mk_eq_mk'] + refine Localization.mk_eq_mk_iff.mpr ?_ + rw [Localization.r_iff_exists] + use 1 + simp only [OneMemClass.coe_one, RingHom.id_apply, one_mul, hx] + ring + +@[reassoc] +lemma basicOpenToSpec_SpecMap_awayMap : + basicOpenToSpec 𝒜 x ≫ Spec.map (CommRingCat.ofHom (awayMap 𝒜 g_deg hx)) = + (Proj 𝒜).homOfLE (basicOpen_mono _ _ _ ⟨_, hx⟩) ≫ basicOpenToSpec 𝒜 f := by + rw [basicOpenToSpec, Category.assoc, ← Spec.map_comp, awayMap_awayToSection, + Spec.map_comp, Scheme.Opens.toSpecΓ_SpecMap_map_assoc] + rfl + +@[reassoc] +lemma SpecMap_awayMap_awayι : + Spec.map (CommRingCat.ofHom (awayMap 𝒜 g_deg hx)) ≫ awayι 𝒜 f f_deg hm = + awayι 𝒜 x (hx ▸ SetLike.mul_mem_graded f_deg g_deg) (hm.trans_le (m.le_add_right m')) := by + rw [awayι, awayι, Iso.eq_inv_comp, basicOpenIsoSpec_hom, basicOpenToSpec_SpecMap_awayMap_assoc, + ← basicOpenIsoSpec_hom _ _ f_deg hm, Iso.hom_inv_id_assoc, Scheme.homOfLE_ι] + +/-- The isomorphism `D₊(f) ×[Proj 𝒜] D₊(g) ≅ D₊(fg)`. -/ +noncomputable +def pullbackAwayιIso : + Limits.pullback (awayι 𝒜 f f_deg hm) (awayι 𝒜 g g_deg hm') ≅ + Spec (CommRingCat.of (Away 𝒜 x)) := + IsOpenImmersion.isoOfRangeEq (Limits.pullback.fst _ _ ≫ awayι 𝒜 f f_deg hm) + (awayι 𝒜 x (hx ▸ SetLike.mul_mem_graded f_deg g_deg) (hm.trans_le (m.le_add_right m'))) <| by + rw [IsOpenImmersion.range_pullback_to_base_of_left] + show ((awayι 𝒜 f _ _).opensRange ⊓ (awayι 𝒜 g _ _).opensRange).1 = (awayι 𝒜 _ _ _).opensRange.1 + rw [opensRange_awayι, opensRange_awayι, opensRange_awayι, ← basicOpen_mul, hx] + +@[reassoc (attr := simp)] +lemma pullbackAwayιIso_hom_awayι : + (pullbackAwayιIso 𝒜 f_deg hm g_deg hm' hx).hom ≫ + awayι 𝒜 x (hx ▸ SetLike.mul_mem_graded f_deg g_deg) (hm.trans_le (m.le_add_right m')) = + Limits.pullback.fst _ _ ≫ awayι 𝒜 f f_deg hm := + IsOpenImmersion.isoOfRangeEq_hom_fac .. + +@[reassoc (attr := simp)] +lemma pullbackAwayιIso_hom_SpecMap_awayMap_left : + (pullbackAwayιIso 𝒜 f_deg hm g_deg hm' hx).hom ≫ + Spec.map (CommRingCat.ofHom (awayMap 𝒜 g_deg hx)) = Limits.pullback.fst _ _ := by + rw [← cancel_mono (awayι 𝒜 f f_deg hm), ← pullbackAwayιIso_hom_awayι, + Category.assoc, SpecMap_awayMap_awayι] + +@[reassoc (attr := simp)] +lemma pullbackAwayιIso_hom_SpecMap_awayMap_right : + (pullbackAwayιIso 𝒜 f_deg hm g_deg hm' hx).hom ≫ + Spec.map (CommRingCat.ofHom (awayMap 𝒜 f_deg (hx.trans (mul_comm _ _)))) = + Limits.pullback.snd _ _ := by + rw [← cancel_mono (awayι 𝒜 g g_deg hm'), ← Limits.pullback.condition, + ← pullbackAwayιIso_hom_awayι 𝒜 f_deg hm g_deg hm' hx, + Category.assoc, SpecMap_awayMap_awayι] + rfl + +@[reassoc (attr := simp)] +lemma pullbackAwayιIso_inv_fst : + (pullbackAwayιIso 𝒜 f_deg hm g_deg hm' hx).inv ≫ Limits.pullback.fst _ _ = + Spec.map (CommRingCat.ofHom (awayMap 𝒜 g_deg hx)) := by + rw [← pullbackAwayιIso_hom_SpecMap_awayMap_left, Iso.inv_hom_id_assoc] + +@[reassoc (attr := simp)] +lemma pullbackAwayιIso_inv_snd : + (pullbackAwayιIso 𝒜 f_deg hm g_deg hm' hx).inv ≫ Limits.pullback.snd _ _ = + Spec.map (CommRingCat.ofHom (awayMap 𝒜 f_deg (hx.trans (mul_comm _ _)))) := by + rw [← pullbackAwayιIso_hom_SpecMap_awayMap_right, Iso.inv_hom_id_assoc] + open TopologicalSpace.Opens in /-- Given a family of homogeneous elements `f` of positive degree that spans the irrelavent ideal, `Spec (A_f)₀ ⟶ Proj A` forms an affine open cover of `Proj A`. -/ diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Proper.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Proper.lean new file mode 100644 index 00000000000000..6235852b32c97a --- /dev/null +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Proper.lean @@ -0,0 +1,126 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patience Ablett, Kevin Buzzard, Harald Carlens, Wayne Ng Kwing King, Michael Schlößer, + Justus Springer, Andrew Yang, Jujian Zhang +-/ +import Mathlib.AlgebraicGeometry.Morphisms.Separated +import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Basic + +/-! +# Properness of `Proj A` + +We show that `Proj 𝒜` is a separated scheme. + +## TODO +- Show that `Proj 𝒜` satisfies the valuative criterion. + +## Notes +This contribution was created as part of the Durham Computational Algebraic Geometry Workshop + +-/ + +namespace AlgebraicGeometry.Proj + +variable {R A : Type*} +variable [CommRing R] [CommRing A] [Algebra R A] +variable (𝒜 : ℕ → Submodule R A) +variable [GradedAlgebra 𝒜] + +open Scheme CategoryTheory Limits pullback HomogeneousLocalization + +lemma lift_awayMapₐ_awayMapₐ_surjective {d e : ℕ} {f : A} (hf : f ∈ 𝒜 d) + {g : A} (hg : g ∈ 𝒜 e) {x : A} (hx : x = f * g) (hd : 0 < d) : + Function.Surjective + (Algebra.TensorProduct.lift (awayMapₐ 𝒜 hg hx) (awayMapₐ 𝒜 hf (hx.trans (mul_comm _ _))) + (fun _ _ ↦ .all _ _)) := by + intro z + obtain ⟨⟨n, ⟨a, ha⟩, ⟨b, hb'⟩, ⟨j, (rfl : _ = b)⟩⟩, rfl⟩ := mk_surjective z + by_cases hfg : (f * g) ^ j = 0 + · use 0 + have := HomogeneousLocalization.subsingleton 𝒜 (x := Submonoid.powers x) ⟨j, hx ▸ hfg⟩ + exact this.elim _ _ + have : n = j * (d + e) := by + apply DirectSum.degree_eq_of_mem_mem 𝒜 hb' + convert SetLike.pow_mem_graded _ _ using 2 + · infer_instance + · exact hx ▸ SetLike.mul_mem_graded hf hg + · exact hx ▸ hfg + let x0 : NumDenSameDeg 𝒜 (.powers f) := + { deg := j * (d * (e + 1)) + num := ⟨a * g ^ (j * (d - 1)), by + convert SetLike.mul_mem_graded ha (SetLike.pow_mem_graded _ hg) using 2 + rw [this] + cases d + · contradiction + · simp; ring⟩ + den := ⟨f ^ (j * (e + 1)), by convert SetLike.pow_mem_graded _ hf using 2; ring⟩ + den_mem := ⟨_,rfl⟩ } + let y0 : NumDenSameDeg 𝒜 (.powers g) := + { deg := j * (d * e) + num := ⟨f ^ (j * e), by convert SetLike.pow_mem_graded _ hf using 2; ring⟩ + den := ⟨g ^ (j * d), by convert SetLike.pow_mem_graded _ hg using 2; ring⟩ + den_mem := ⟨_,rfl⟩ } + use mk x0 ⊗ₜ mk y0 + ext + simp only [Algebra.TensorProduct.lift_tmul, awayMapₐ_apply, val_mul, + val_awayMap_mk, Localization.mk_mul, val_mk, x0, y0] + rw [Localization.mk_eq_mk_iff, Localization.r_iff_exists] + use 1 + simp only [OneMemClass.coe_one, one_mul, Submonoid.mk_mul_mk] + cases d + · contradiction + · simp only [hx, add_tsub_cancel_right] + ring + +open TensorProduct in +instance isSeparated : IsSeparated (toSpecZero 𝒜) := by + refine ⟨IsLocalAtTarget.of_openCover (Pullback.openCoverOfLeftRight + (affineOpenCover 𝒜).openCover (affineOpenCover 𝒜).openCover _ _) ?_⟩ + intro ⟨i, j⟩ + dsimp [Scheme, Cover.pullbackHom] + refine (MorphismProperty.cancel_left_of_respectsIso (P := @IsClosedImmersion) + (f := (pullbackDiagonalMapIdIso ..).inv) _).mp ?_ + let e₁ : pullback ((affineOpenCover 𝒜).map i ≫ toSpecZero 𝒜) + ((affineOpenCover 𝒜).map j ≫ toSpecZero 𝒜) ≅ + Spec (.of <| TensorProduct (𝒜 0) (Away 𝒜 i.2) (Away 𝒜 j.2)) := by + refine pullback.congrHom ?_ ?_ ≪≫ pullbackSpecIso (𝒜 0) (Away 𝒜 i.2) (Away 𝒜 j.2) + · simp [affineOpenCover, openCoverOfISupEqTop, awayι_toSpecZero]; rfl + · simp [affineOpenCover, openCoverOfISupEqTop, awayι_toSpecZero]; rfl + let e₂ : pullback ((affineOpenCover 𝒜).map i) ((affineOpenCover 𝒜).map j) ≅ + Spec (.of <| (Away 𝒜 (i.2 * j.2))) := + pullbackAwayιIso 𝒜 _ _ _ _ rfl + rw [← MorphismProperty.cancel_right_of_respectsIso (P := @IsClosedImmersion) _ e₁.hom, + ← MorphismProperty.cancel_left_of_respectsIso (P := @IsClosedImmersion) e₂.inv] + let F : Away 𝒜 i.2.1 ⊗[𝒜 0] Away 𝒜 j.2.1 →+* Away 𝒜 (i.2.1 * j.2.1) := + (Algebra.TensorProduct.lift (awayMapₐ 𝒜 j.2.2 rfl) (awayMapₐ 𝒜 i.2.2 (mul_comm _ _)) + (fun _ _ ↦ .all _ _)).toRingHom + have : Function.Surjective F := lift_awayMapₐ_awayMapₐ_surjective 𝒜 i.2.2 j.2.2 rfl i.1.2 + convert IsClosedImmersion.spec_of_surjective + (CommRingCat.ofHom (R := Away 𝒜 i.2.1 ⊗[𝒜 0] Away 𝒜 j.2.1) F) this using 1 + rw [← cancel_mono (pullbackSpecIso ..).inv] + apply pullback.hom_ext + · simp only [Iso.trans_hom, congrHom_hom, Category.assoc, Iso.hom_inv_id, Category.comp_id, + limit.lift_π, id_eq, eq_mpr_eq_cast, PullbackCone.mk_pt, PullbackCone.mk_π_app, e₂, e₁, + pullbackDiagonalMapIdIso_inv_snd_fst, AlgHom.toRingHom_eq_coe, pullbackSpecIso_inv_fst, + ← Spec.map_comp] + erw [pullbackAwayιIso_inv_fst] + congr 1 + ext x + exact DFunLike.congr_fun (Algebra.TensorProduct.lift_comp_includeLeft + (awayMapₐ 𝒜 j.2.2 rfl) (awayMapₐ 𝒜 i.2.2 (mul_comm _ _)) (fun _ _ ↦ .all _ _)).symm x + · simp only [Iso.trans_hom, congrHom_hom, Category.assoc, Iso.hom_inv_id, Category.comp_id, + limit.lift_π, id_eq, eq_mpr_eq_cast, PullbackCone.mk_pt, PullbackCone.mk_π_app, + pullbackDiagonalMapIdIso_inv_snd_snd, AlgHom.toRingHom_eq_coe, pullbackSpecIso_inv_snd, ← + Spec.map_comp, e₂, e₁] + erw [pullbackAwayιIso_inv_snd] + congr 1 + ext x + exact DFunLike.congr_fun (Algebra.TensorProduct.lift_comp_includeRight + (awayMapₐ 𝒜 j.2.2 rfl) (awayMapₐ 𝒜 i.2.2 (mul_comm _ _)) (fun _ _ ↦ .all _ _)).symm x + +@[stacks 01MC] +instance : Scheme.IsSeparated (Proj 𝒜) := + (HasAffineProperty.iff_of_isAffine (P := @IsSeparated)).mp (isSeparated 𝒜) + +end AlgebraicGeometry.Proj diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean index 462689531697b7..781f0783739f0b 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean @@ -603,6 +603,16 @@ lemma awayToSection_germ (f x hx) : apply (Proj.stalkIso' 𝒜 x).eq_symm_apply.mpr apply Proj.stalkIso'_germ +lemma awayToSection_apply (f : A) (x p) : + (((ProjectiveSpectrum.Proj.awayToSection 𝒜 f).1 x).val p).val = + IsLocalization.map (M := Submonoid.powers f) (T := p.1.1.toIdeal.primeCompl) _ + (RingHom.id _) (Submonoid.powers_le.mpr p.2) x.val := by + obtain ⟨x, rfl⟩ := HomogeneousLocalization.mk_surjective x + show (HomogeneousLocalization.mapId 𝒜 _ _).val = _ + dsimp [HomogeneousLocalization.mapId, HomogeneousLocalization.map] + rw [Localization.mk_eq_mk', Localization.mk_eq_mk', IsLocalization.map_mk'] + rfl + /-- The ring map from `A⁰_ f` to the global sections of the structure sheaf of the projective spectrum of `A` restricted to the basic open set `D(f)`. diff --git a/Mathlib/AlgebraicGeometry/Properties.lean b/Mathlib/AlgebraicGeometry/Properties.lean index 800d80f9537659..79091bf28dd7a7 100644 --- a/Mathlib/AlgebraicGeometry/Properties.lean +++ b/Mathlib/AlgebraicGeometry/Properties.lean @@ -203,7 +203,7 @@ instance irreducibleSpace_of_isIntegral [IsIntegral X] : IrreducibleSpace X := b replace H : ¬IsPreirreducible (⊤ : Set X) := fun h => H { toPreirreducibleSpace := ⟨h⟩ toNonempty := inferInstance } - simp_rw [isPreirreducible_iff_closed_union_closed, not_forall, not_or] at H + simp_rw [isPreirreducible_iff_isClosed_union_isClosed, not_forall, not_or] at H rcases H with ⟨S, T, hS, hT, h₁, h₂, h₃⟩ erw [not_forall] at h₂ h₃ simp_rw [not_forall] at h₂ h₃ diff --git a/Mathlib/AlgebraicGeometry/RationalMap.lean b/Mathlib/AlgebraicGeometry/RationalMap.lean index aca42607f4a77d..e9894ddfbcd617 100644 --- a/Mathlib/AlgebraicGeometry/RationalMap.lean +++ b/Mathlib/AlgebraicGeometry/RationalMap.lean @@ -5,6 +5,7 @@ Authors: Andrew Yang -/ import Mathlib.AlgebraicGeometry.SpreadingOut import Mathlib.AlgebraicGeometry.FunctionField +import Mathlib.AlgebraicGeometry.Morphisms.Separated /-! # Rational maps between schemes @@ -17,10 +18,12 @@ import Mathlib.AlgebraicGeometry.FunctionField Two partial maps are equivalent if they are equal on a dense open subscheme. * `AlgebraicGeometry.Scheme.RationalMap`: A rational map from `X` to `Y` (`X ⤏ Y`) is an equivalence class of partial maps. -* `AlgebraicGeometry.Scheme.RationalMap.equivFunctionField`: +* `AlgebraicGeometry.Scheme.RationalMap.equivFunctionFieldOver`: Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and `X` is integral, `S`-morphisms `Spec K(X) ⟶ Y` correspond bijectively to `S`-rational maps from `X` to `Y`. - +* `AlgebraicGeometry.Scheme.RationalMap.toPartialMap`: + If `X` is integral and `Y` is separated, then any `f : X ⤏ Y` can be realized as a partial + map on `f.domain`, the domain of definition of `f`. -/ universe u @@ -44,6 +47,11 @@ structure PartialMap (X Y : Scheme.{u}) where /-- The underlying morphism of a partial map. -/ hom : ↑domain ⟶ Y +variable (S) in +/-- A partial map is a `S`-map if the underlying morphism is. -/ +abbrev PartialMap.IsOver [X.Over S] [Y.Over S] (f : X.PartialMap Y) := + f.hom.IsOver S + namespace PartialMap lemma ext_iff (f g : X.PartialMap Y) : @@ -64,7 +72,7 @@ lemma ext (f g : X.PartialMap Y) (e : f.domain = g.domain) exact ⟨e, H⟩ /-- The restriction of a partial map to a smaller domain. -/ -@[simps hom, simps (config := .lemmasOnly) domain] +@[simps hom domain] noncomputable def restrict (f : X.PartialMap Y) (U : X.Opens) (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : X.PartialMap Y where @@ -93,6 +101,10 @@ lemma restrict_restrict_hom (f : X.PartialMap Y) ((f.restrict U hU hU').restrict V hV hV').hom = (f.restrict V hV (hV'.trans hU')).hom := by simp +instance [X.Over S] [Y.Over S] (f : X.PartialMap Y) [f.IsOver S] + (U : X.Opens) (hU : Dense (U : Set X)) (hU' : U ≤ f.domain) : + (f.restrict U hU hU').IsOver S where + /-- The composition of a partial map and a morphism on the right. -/ @[simps] def compHom (f : X.PartialMap Y) (g : Y ⟶ Z) : X.PartialMap Z where @@ -100,11 +112,24 @@ def compHom (f : X.PartialMap Y) (g : Y ⟶ Z) : X.PartialMap Z where dense_domain := f.dense_domain hom := f.hom ≫ g +instance [X.Over S] [Y.Over S] [Z.Over S] (f : X.PartialMap Y) (g : Y ⟶ Z) + [f.IsOver S] [g.IsOver S] : (f.compHom g).IsOver S where + /-- A scheme morphism as a partial map. -/ @[simps] def _root_.AlgebraicGeometry.Scheme.Hom.toPartialMap (f : X.Hom Y) : X.PartialMap Y := ⟨⊤, dense_univ, X.topIso.hom ≫ f⟩ +instance [X.Over S] [Y.Over S] (f : X ⟶ Y) [f.IsOver S] : f.toPartialMap.IsOver S where + +lemma isOver_iff [X.Over S] [Y.Over S] {f : X.PartialMap Y} : + f.IsOver S ↔ (f.compHom (Y ↘ S)).hom = f.domain.ι ≫ X ↘ S := by + simp + +lemma isOver_iff_eq_restrict [X.Over S] [Y.Over S] {f : X.PartialMap Y} : + f.IsOver S ↔ f.compHom (Y ↘ S) = (X ↘ S).toPartialMap.restrict _ f.dense_domain (by simp) := by + simp [isOver_iff, PartialMap.ext_iff] + /-- If `x` is in the domain of a partial map `f`, then `f` restricts to a map from `Spec 𝒪_x`. -/ noncomputable def fromSpecStalkOfMem (f : X.PartialMap Y) {x} (hx : x ∈ f.domain) : @@ -230,6 +255,58 @@ lemma equiv_of_fromSpecStalkOfMem_eq [IrreducibleSpace X] simpa only [fromSpecStalkOfMem, restrict_domain, Opens.fromSpecStalkOfMem, Spec.map_inv, restrict_hom, Category.assoc, IsIso.eq_inv_comp, IsIso.hom_inv_id_assoc] using H +instance (U : X.Opens) [IsReduced X] : IsReduced U := isReduced_of_isOpenImmersion U.ι + +lemma Opens.isDominant_ι {U : X.Opens} (hU : Dense (X := X) U) : IsDominant U.ι := + ⟨by simpa [DenseRange] using hU⟩ + +lemma Opens.isDominant_homOfLE {U V : X.Opens} (hU : Dense (X := X) U) (hU' : U ≤ V) : + IsDominant (X.homOfLE hU') := + have : IsDominant (X.homOfLE hU' ≫ Opens.ι _) := by simpa using Opens.isDominant_ι hU + IsDominant.of_comp_of_isOpenImmersion (g := Opens.ι _) _ + +/-- Two partial maps from reduced schemes to separated schemes are equivalent if and only if +they are equal on **any** open dense subset. -/ +lemma equiv_iff_of_isSeparated_of_le [X.Over S] [Y.Over S] [IsReduced X] + [IsSeparated (Y ↘ S)] {f g : X.PartialMap Y} [f.IsOver S] [g.IsOver S] + {W : X.Opens} (hW : Dense (X := X) W) (hWl : W ≤ f.domain) (hWr : W ≤ g.domain) : f.equiv g ↔ + (f.restrict W hW hWl).hom = (g.restrict W hW hWr).hom := by + refine ⟨fun ⟨V, hV, hVl, hVr, e⟩ ↦ ?_, fun e ↦ ⟨_, _, _, _, e⟩⟩ + have : IsDominant (X.homOfLE (inf_le_left : W ⊓ V ≤ W)) := + Opens.isDominant_homOfLE (hW.inter_of_isOpen_left hV W.2) _ + apply ext_of_isDominant_of_isSeparated' S (X.homOfLE (inf_le_left : W ⊓ V ≤ W)) + simpa using congr(X.homOfLE (inf_le_right : W ⊓ V ≤ V) ≫ $e) + +/-- Two partial maps from reduced schemes to separated schemes are equivalent if and only if +they are equal on the intersection of the domains. -/ +lemma equiv_iff_of_isSeparated [X.Over S] [Y.Over S] [IsReduced X] + [IsSeparated (Y ↘ S)] {f g : X.PartialMap Y} + [f.IsOver S] [g.IsOver S] : f.equiv g ↔ + (f.restrict _ (f.2.inter_of_isOpen_left g.2 f.domain.2) inf_le_left).hom = + (g.restrict _ (f.2.inter_of_isOpen_left g.2 f.domain.2) inf_le_right).hom := + equiv_iff_of_isSeparated_of_le (S := S) _ _ _ + +/-- Two partial maps from reduced schemes to separated schemes with the same domain are equivalent +if and only if they are equal. -/ +lemma equiv_iff_of_domain_eq_of_isSeparated [X.Over S] [Y.Over S] [IsReduced X] + [IsSeparated (Y ↘ S)] {f g : X.PartialMap Y} (hfg : f.domain = g.domain) + [f.IsOver S] [g.IsOver S] : f.equiv g ↔ f = g := by + rw [equiv_iff_of_isSeparated_of_le (S := S) f.dense_domain le_rfl hfg.le] + obtain ⟨Uf, _, f⟩ := f + obtain ⟨Ug, _, g⟩ := g + obtain rfl : Uf = Ug := hfg + simp + +/-- A partial map from a reduced scheme to a separated scheme is equivalent to a morphism +if and only if it is equal to the restriction of the morphism. -/ +lemma equiv_toPartialMap_iff_of_isSeparated [X.Over S] [Y.Over S] [IsReduced X] + [IsSeparated (Y ↘ S)] {f : X.PartialMap Y} {g : X ⟶ Y} + [f.IsOver S] [g.IsOver S] : f.equiv g.toPartialMap ↔ + f.hom = f.domain.ι ≫ g := by + rw [equiv_iff_of_isSeparated (S := S), ← cancel_epi (X.isoOfEq (inf_top_eq f.domain)).hom] + simp + rfl + end PartialMap /-- A rational map from `X` to `Y` (`X ⤏ Y`) is an equivalence class of partial maps, @@ -246,6 +323,11 @@ def PartialMap.toRationalMap (f : X.PartialMap Y) : X ⤏ Y := Quotient.mk _ f /-- A scheme morphism as a rational map. -/ abbrev Hom.toRationalMap (f : X.Hom Y) : X ⤏ Y := f.toPartialMap.toRationalMap +variable (S) in +/-- A rational map is a `S`-map if some partial map in the equivalence class is a `S`-map. -/ +class RationalMap.IsOver [X.Over S] [Y.Over S] (f : X ⤏ Y) : Prop where + exists_partialMap_over : ∃ g : X.PartialMap Y, g.IsOver S ∧ g.toRationalMap = f + lemma PartialMap.toRationalMap_surjective : Function.Surjective (@toRationalMap X Y) := Quotient.exists_rep @@ -262,6 +344,14 @@ lemma PartialMap.restrict_toRationalMap (f : X.PartialMap Y) (U : X.Opens) (f.restrict U hU hU').toRationalMap = f.toRationalMap := toRationalMap_eq_iff.mpr (f.restrict_equiv U hU hU') +instance [X.Over S] [Y.Over S] (f : X.PartialMap Y) [f.IsOver S] : f.toRationalMap.IsOver S := + ⟨f, ‹_›, rfl⟩ + +variable (S) in +lemma RationalMap.exists_partialMap_over [X.Over S] [Y.Over S] (f : X ⤏ Y) [f.IsOver S] : + ∃ g : X.PartialMap Y, g.IsOver S ∧ g.toRationalMap = f := + IsOver.exists_partialMap_over + /-- The composition of a rational map and a morphism on the right. -/ def RationalMap.compHom (f : X ⤏ Y) (g : Y ⟶ Z) : X ⤏ Z := by refine Quotient.map (PartialMap.compHom · g) ?_ f @@ -275,6 +365,42 @@ def RationalMap.compHom (f : X ⤏ Y) (g : Y ⟶ Z) : X ⤏ Z := by lemma RationalMap.compHom_toRationalMap (f : X.PartialMap Y) (g : Y ⟶ Z) : (f.compHom g).toRationalMap = f.toRationalMap.compHom g := rfl +instance [X.Over S] [Y.Over S] [Z.Over S] (f : X ⤏ Y) (g : Y ⟶ Z) + [f.IsOver S] [g.IsOver S] : (f.compHom g).IsOver S where + exists_partialMap_over := by + obtain ⟨f, hf, rfl⟩ := f.exists_partialMap_over S + exact ⟨f.compHom g, inferInstance, rfl⟩ + +variable (S) in +lemma PartialMap.exists_restrict_isOver [X.Over S] [Y.Over S] (f : X.PartialMap Y) + [f.toRationalMap.IsOver S] : ∃ U hU hU', (f.restrict U hU hU').IsOver S := by + obtain ⟨f', hf₁, hf₂⟩ := RationalMap.IsOver.exists_partialMap_over (S := S) (f := f.toRationalMap) + obtain ⟨U, hU, hUl, hUr, e⟩ := PartialMap.toRationalMap_eq_iff.mp hf₂ + exact ⟨U, hU, hUr, by rw [IsOver, ← e]; infer_instance⟩ + +lemma RationalMap.isOver_iff [X.Over S] [Y.Over S] {f : X ⤏ Y} : + f.IsOver S ↔ f.compHom (Y ↘ S) = (X ↘ S).toRationalMap := by + constructor + · intro h + obtain ⟨g, hg, e⟩ := f.exists_partialMap_over S + rw [← e, Hom.toRationalMap, ← compHom_toRationalMap, PartialMap.isOver_iff_eq_restrict.mp hg, + PartialMap.restrict_toRationalMap] + · intro e + obtain ⟨f, rfl⟩ := PartialMap.toRationalMap_surjective f + obtain ⟨U, hU, hUl, hUr, e⟩ := PartialMap.toRationalMap_eq_iff.mp e + exact ⟨⟨f.restrict U hU hUl, by simpa using e, by simp⟩⟩ + +lemma PartialMap.isOver_toRationalMap_iff_of_isSeparated [X.Over S] [Y.Over S] [IsReduced X] + [S.IsSeparated] {f : X.PartialMap Y} : + f.toRationalMap.IsOver S ↔ f.IsOver S := by + refine ⟨fun _ ↦ ?_, fun _ ↦ inferInstance⟩ + obtain ⟨U, hU, hU', H⟩ := f.exists_restrict_isOver (S := S) + rw [isOver_iff] + have : IsDominant (X.homOfLE hU') := Opens.isDominant_homOfLE hU _ + exact ext_of_isDominant (ι := X.homOfLE hU') (by simpa using H.1) + +section functionField + /-- A rational map restricts to a map from `Spec K(X)`. -/ noncomputable def RationalMap.fromFunctionField [IrreducibleSpace X] (f : X ⤏ Y) : @@ -328,6 +454,94 @@ def RationalMap.equivFunctionField [IsIntegral X] [LocallyOfFiniteType sY] : (ofFunctionField sX sY f.1.fromFunctionField _) f (RationalMap.fromFunctionField_ofFunctionField _ _ _ _)) +/-- +Given `S`-schemes `X` and `Y` such that `Y` is locally of finite type and `X` is integral, +`S`-morphisms `Spec K(X) ⟶ Y` correspond bijectively to `S`-rational maps from `X` to `Y`. +-/ +noncomputable +def RationalMap.equivFunctionFieldOver [X.Over S] [Y.Over S] [IsIntegral X] + [LocallyOfFiniteType (Y ↘ S)] : + { f : Spec X.functionField ⟶ Y // f.IsOver S } ≃ { f : X ⤏ Y // f.IsOver S } := + ((Equiv.subtypeEquivProp (by simp only [Hom.isOver_iff]; rfl)).trans + (RationalMap.equivFunctionField (X ↘ S) (Y ↘ S))).trans + (Equiv.subtypeEquivProp (by ext f; rw [RationalMap.isOver_iff])) + +end functionField + +section domain + +/-- The domain of definition of a rational map. -/ +def RationalMap.domain (f : X ⤏ Y) : X.Opens := + sSup { PartialMap.domain g | (g) (_ : g.toRationalMap = f) } + +lemma PartialMap.le_domain_toRationalMap (f : X.PartialMap Y) : + f.domain ≤ f.toRationalMap.domain := + le_sSup ⟨f, rfl, rfl⟩ + +lemma RationalMap.mem_domain {f : X ⤏ Y} {x} : + x ∈ f.domain ↔ ∃ g : X.PartialMap Y, x ∈ g.domain ∧ g.toRationalMap = f := + TopologicalSpace.Opens.mem_sSup.trans (by simp [@and_comm (x ∈ _)]) + +lemma RationalMap.dense_domain (f : X ⤏ Y) : Dense (X := X) f.domain := + f.inductionOn (fun g ↦ g.dense_domain.mono g.le_domain_toRationalMap) + +/-- The open cover of the domain of `f : X ⤏ Y`, +consisting of all the domains of the partial maps in the equivalence class. -/ +noncomputable +def RationalMap.openCoverDomain (f : X ⤏ Y) : f.domain.toScheme.OpenCover where + J := { PartialMap.domain g | (g) (_ : g.toRationalMap = f) } + obj U := U.1.toScheme + map U := X.homOfLE (le_sSup U.2) + f x := ⟨_, (TopologicalSpace.Opens.mem_sSup.mp x.2).choose_spec.1⟩ + covers x := ⟨⟨x.1, (TopologicalSpace.Opens.mem_sSup.mp x.2).choose_spec.2⟩, Subtype.ext (by simp)⟩ + +/-- If `f : X ⤏ Y` is a rational map from a reduced scheme to a separated scheme, +then `f` can be represented as a partial map on its domain of definition. -/ +noncomputable +def RationalMap.toPartialMap [IsReduced X] [Y.IsSeparated] (f : X ⤏ Y) : X.PartialMap Y := by + refine ⟨f.domain, f.dense_domain, f.openCoverDomain.glueMorphisms + (fun x ↦ (X.isoOfEq x.2.choose_spec.2).inv ≫ x.2.choose.hom) ?_⟩ + intros x y + let g (x : f.openCoverDomain.J) := x.2.choose + have hg₁ (x) : (g x).toRationalMap = f := x.2.choose_spec.1 + have hg₂ (x) : (g x).domain = x.1 := x.2.choose_spec.2 + refine (cancel_epi (isPullback_opens_inf_le (le_sSup x.2) (le_sSup y.2)).isoPullback.hom).mp ?_ + simp only [openCoverDomain, IsPullback.isoPullback_hom_fst_assoc, + IsPullback.isoPullback_hom_snd_assoc] + show _ ≫ _ ≫ (g x).hom = _ ≫ _ ≫ (g y).hom + simp_rw [← cancel_epi (X.isoOfEq congr($(hg₂ x) ⊓ $(hg₂ y))).hom, ← Category.assoc] + convert (PartialMap.equiv_iff_of_isSeparated (S := ⊤_ _) (f := g x) (g := g y)).mp ?_ using 1 + · dsimp; congr 1; simp [← cancel_mono (Opens.ι _)] + · dsimp; congr 1; simp [← cancel_mono (Opens.ι _)] + · rw [← PartialMap.toRationalMap_eq_iff, hg₁, hg₁] + +lemma PartialMap.toPartialMap_toRationalMap_restrict [IsReduced X] [Y.IsSeparated] + (f : X.PartialMap Y) : (f.toRationalMap.toPartialMap.restrict _ f.dense_domain + f.le_domain_toRationalMap).hom = f.hom := by + dsimp [RationalMap.toPartialMap] + refine (f.toRationalMap.openCoverDomain.ι_glueMorphisms _ _ ⟨_, f, rfl, rfl⟩).trans ?_ + generalize_proofs _ _ H _ + have : H.choose = f := (equiv_iff_of_domain_eq_of_isSeparated (S := ⊤_ _) H.choose_spec.2).mp + (toRationalMap_eq_iff.mp H.choose_spec.1) + exact ((ext_iff _ _).mp this.symm).choose_spec.symm + +@[simp] +lemma RationalMap.toRationalMap_toPartialMap [IsReduced X] [Y.IsSeparated] + (f : X ⤏ Y) : f.toPartialMap.toRationalMap = f := by + obtain ⟨f, rfl⟩ := PartialMap.toRationalMap_surjective f + trans (f.toRationalMap.toPartialMap.restrict _ + f.dense_domain f.le_domain_toRationalMap).toRationalMap + · simp + · congr 1 + exact PartialMap.ext _ f rfl (by simpa using f.toPartialMap_toRationalMap_restrict) + +instance [IsReduced X] [Y.IsSeparated] [S.IsSeparated] [X.Over S] [Y.Over S] + (f : X ⤏ Y) [f.IsOver S] : f.toPartialMap.IsOver S := by + rw [← PartialMap.isOver_toRationalMap_iff_of_isSeparated, f.toRationalMap_toPartialMap] + infer_instance + +end domain + end Scheme end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Restrict.lean b/Mathlib/AlgebraicGeometry/Restrict.lean index e1e6db017d998b..1d336822caba37 100644 --- a/Mathlib/AlgebraicGeometry/Restrict.lean +++ b/Mathlib/AlgebraicGeometry/Restrict.lean @@ -52,8 +52,10 @@ def ι : ↑U ⟶ X := X.ofRestrict _ instance : IsOpenImmersion U.ι := inferInstanceAs (IsOpenImmersion (X.ofRestrict _)) -@[simps] instance : U.toScheme.Over X := ⟨U.ι⟩ @[simps! over] instance : U.toScheme.CanonicallyOver X where + hom := U.ι + +instance (U : X.Opens) : U.ι.IsOver X where lemma toScheme_carrier : (U : Type u) = (U : Set X) := rfl @@ -68,6 +70,11 @@ lemma ι_app (V) : U.ι.app V = X.presheaf.map (homOfLE (x := U.ι ''ᵁ U.ι ⁻¹ᵁ V) (Set.image_preimage_subset _ _)).op := rfl +@[simp] +lemma ι_appTop : + U.ι.appTop = X.presheaf.map (homOfLE (x := U.ι ''ᵁ ⊤) le_top).op := + rfl + @[simp] lemma ι_appLE (V W e) : U.ι.appLE V W e = @@ -168,7 +175,7 @@ def opensRestrict : instance ΓRestrictAlgebra {X : Scheme.{u}} (U : X.Opens) : Algebra (Γ(X, ⊤)) Γ(U, ⊤) := - (U.ι.app ⊤).toAlgebra + U.ι.appTop.toAlgebra lemma Scheme.map_basicOpen (r : Γ(U, ⊤)) : U.ι ''ᵁ U.toScheme.basicOpen r = X.basicOpen @@ -202,6 +209,8 @@ lemma Scheme.homOfLE_ι (X : Scheme.{u}) {U V : X.Opens} (e : U ≤ V) : X.homOfLE e ≫ V.ι = U.ι := IsOpenImmersion.lift_fac _ _ _ +instance {U V : X.Opens} (h : U ≤ V) : (X.homOfLE h).IsOver X where + @[simp] lemma Scheme.homOfLE_rfl (X : Scheme.{u}) (U : X.Opens) : X.homOfLE (refl U) = 𝟙 _ := by rw [← cancel_mono U.ι, Scheme.homOfLE_ι, Category.id_comp] @@ -242,6 +251,11 @@ theorem Scheme.homOfLE_app {U V : X.Opens} (e : U ≤ V) (W : Opens V) : rw [e₃, ← Functor.map_comp] congr 1 +theorem Scheme.homOfLE_appTop {U V : X.Opens} (e : U ≤ V) : + (X.homOfLE e).appTop = + X.presheaf.map (homOfLE <| X.ι_image_homOfLE_le_ι_image e ⊤).op := + homOfLE_app .. + instance (X : Scheme.{u}) {U V : X.Opens} (e : U ≤ V) : IsOpenImmersion (X.homOfLE e) := by delta Scheme.homOfLE infer_instance @@ -291,7 +305,7 @@ def Scheme.restrictFunctorΓ : X.restrictFunctor.op ⋙ (Over.forget X).op ⋙ S (by intro U V i dsimp - rw [X.homOfLE_app, ← Functor.map_comp, ← Functor.map_comp] + rw [X.homOfLE_appTop, ← Functor.map_comp, ← Functor.map_comp] congr 1) /-- `X ∣_ U ∣_ V` is isomorphic to `X ∣_ V ∣_ U` -/ @@ -444,6 +458,21 @@ theorem isPullback_morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Open -- Porting note: changed `rw` to `erw` erw [pullbackRestrictIsoRestrict_inv_fst]; rw [Category.comp_id] +lemma isPullback_opens_inf_le {X : Scheme} {U V W : X.Opens} (hU : U ≤ W) (hV : V ≤ W) : + IsPullback (X.homOfLE inf_le_left) (X.homOfLE inf_le_right) (X.homOfLE hU) (X.homOfLE hV) := by + refine (isPullback_morphismRestrict (X.homOfLE hV) (W.ι ⁻¹ᵁ U)).of_iso (V.ι.isoImage _ ≪≫ + X.isoOfEq ?_) (W.ι.isoImage _ ≪≫ X.isoOfEq ?_) (Iso.refl _) (Iso.refl _) ?_ ?_ ?_ ?_ + · rw [← TopologicalSpace.Opens.map_comp_obj, ← Scheme.comp_base, Scheme.homOfLE_ι] + exact V.functor_map_eq_inf U + · exact (W.functor_map_eq_inf U).trans (by simpa) + all_goals { simp [← cancel_mono (Scheme.Opens.ι _)] } + +lemma isPullback_opens_inf {X : Scheme} (U V : X.Opens) : + IsPullback (X.homOfLE inf_le_left) (X.homOfLE inf_le_right) U.ι V.ι := + (isPullback_morphismRestrict V.ι U).of_iso (V.ι.isoImage _ ≪≫ X.isoOfEq + (V.functor_map_eq_inf U)) (Iso.refl _) (Iso.refl _) (Iso.refl _) (by simp [← cancel_mono U.ι]) + (by simp [← cancel_mono V.ι]) (by simp) (by simp) + @[simp] lemma morphismRestrict_id {X : Scheme.{u}} (U : X.Opens) : 𝟙 X ∣_ U = 𝟙 _ := by rw [← cancel_mono U.ι, morphismRestrict_ι, Category.comp_id, Category.id_comp] @@ -512,6 +541,11 @@ theorem morphismRestrict_app {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : Quiver.Hom.unop_op, Hom.opensFunctor_map_homOfLE] rw [this, Hom.appLE_map, Hom.appLE_map, Hom.appLE_map] +theorem morphismRestrict_appTop {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : + (f ∣_ U).appTop = f.app (U.ι ''ᵁ ⊤) ≫ + X.presheaf.map (eqToHom (image_morphismRestrict_preimage f U ⊤)).op := + morphismRestrict_app .. + @[simp] theorem morphismRestrict_app' {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : Opens U) : (f ∣_ U).app V = f.appLE _ _ (image_morphismRestrict_preimage f U V).le := @@ -528,7 +562,7 @@ theorem Γ_map_morphismRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) : Scheme.Γ.map (f ∣_ U).op = Y.presheaf.map (eqToHom U.isOpenEmbedding_obj_top.symm).op ≫ f.app U ≫ X.presheaf.map (eqToHom (f ⁻¹ᵁ U).isOpenEmbedding_obj_top).op := by - rw [Scheme.Γ_map_op, morphismRestrict_app f U ⊤, f.naturality_assoc, ← X.presheaf.map_comp] + rw [Scheme.Γ_map_op, morphismRestrict_appTop f U, f.naturality_assoc, ← X.presheaf.map_comp] rfl /-- Restricting a morphism onto the image of an open immersion is isomorphic to the base change @@ -675,11 +709,11 @@ 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.mk ((f.resLE U V e).appTop) ≅ 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] + rw [Scheme.Hom.appTop, ← Scheme.Hom.appLE_eq_app, Scheme.Hom.resLE_appLE, Scheme.Hom.appLE_map] end MorphismRestrict diff --git a/Mathlib/AlgebraicGeometry/Scheme.lean b/Mathlib/AlgebraicGeometry/Scheme.lean index f6caa6dd8c1f75..dc282d80303ad7 100644 --- a/Mathlib/AlgebraicGeometry/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/Scheme.lean @@ -108,6 +108,11 @@ this is the induced map `Γ(Y, U) ⟶ Γ(X, f ⁻¹ᵁ U)`. -/ abbrev app (U : Y.Opens) : Γ(Y, U) ⟶ Γ(X, f ⁻¹ᵁ U) := f.c.app (op U) +/-- Given a morphism of schemes `f : X ⟶ Y`, +this is the induced map `Γ(Y, ⊤) ⟶ Γ(X, ⊤)`. -/ +abbrev appTop : Γ(Y, ⊤) ⟶ Γ(X, ⊤) := + f.app ⊤ + @[reassoc] lemma naturality (i : op U' ⟶ op U) : Y.presheaf.map i ≫ f.app U = f.app U' ≫ X.presheaf.map ((Opens.map f.base).map i.unop).op := @@ -214,6 +219,14 @@ def forgetToTop : Scheme ⥤ TopCat := noncomputable def homeoOfIso {X Y : Scheme.{u}} (e : X ≅ Y) : X ≃ₜ Y := TopCat.homeoOfIso (forgetToTop.mapIso e) +@[simp] +lemma homeoOfIso_symm {X Y : Scheme} (e : X ≅ Y) : + (homeoOfIso e).symm = homeoOfIso e.symm := rfl + +@[simp] +lemma homeoOfIso_apply {X Y : Scheme} (e : X ≅ Y) (x : X) : + homeoOfIso e x = e.hom.base x := rfl + alias _root_.CategoryTheory.Iso.schemeIsoToHomeo := homeoOfIso /-- An isomorphism of schemes induces a homeomorphism of the underlying topological spaces. -/ @@ -221,6 +234,10 @@ noncomputable def Hom.homeomorph {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := S X ≃ₜ Y := (asIso f).schemeIsoToHomeo +@[simp] +lemma Hom.homeomorph_apply {X Y : Scheme.{u}} (f : X.Hom Y) [IsIso (C := Scheme) f] (x) : + f.homeomorph x = f.base x := rfl + -- Porting note: Lean seems not able to find this coercion any more instance hasCoeToTopCat : CoeOut Scheme TopCat where coe X := X.carrier @@ -238,6 +255,11 @@ theorem id.base (X : Scheme) : (𝟙 X : _).base = 𝟙 _ := theorem id_app {X : Scheme} (U : X.Opens) : (𝟙 X : _).app U = 𝟙 _ := rfl +@[simp] +theorem id_appTop {X : Scheme} : + (𝟙 X : _).appTop = 𝟙 _ := + rfl + @[reassoc] theorem comp_toLRSHom {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g).toLRSHom = f.toLRSHom ≫ g.toLRSHom := @@ -263,6 +285,11 @@ theorem comp_app {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) (U) : (f ≫ g).app U = g.app U ≫ f.app _ := rfl +@[simp, reassoc] -- reassoc lemma does not need `simp` +theorem comp_appTop {X Y Z : Scheme} (f : X ⟶ Y) (g : Y ⟶ Z) : + (f ≫ g).appTop = g.appTop ≫ f.appTop := + rfl + @[deprecated (since := "2024-06-23")] alias comp_val_c_app := comp_app @[deprecated (since := "2024-06-23")] alias comp_val_c_app_assoc := comp_app_assoc @@ -323,8 +350,10 @@ theorem inv_app {X Y : Scheme} (f : X ⟶ Y) [IsIso f] (U : X.Opens) : rw [IsIso.eq_comp_inv, ← Scheme.comp_app, Scheme.congr_app (IsIso.hom_inv_id f), Scheme.id_app, Category.id_comp] -theorem inv_app_top {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : - (inv f).app ⊤ = inv (f.app ⊤) := by simp +theorem inv_appTop {X Y : Scheme} (f : X ⟶ Y) [IsIso f] : + (inv f).appTop = inv (f.appTop) := by simp + +@[deprecated (since := "2024-11-23")] alias inv_app_top := inv_appTop end Scheme @@ -428,10 +457,10 @@ theorem Γ_obj_op (X : Scheme) : Γ.obj (op X) = Γ(X, ⊤) := rfl @[simp] -theorem Γ_map {X Y : Schemeᵒᵖ} (f : X ⟶ Y) : Γ.map f = f.unop.app ⊤ := +theorem Γ_map {X Y : Schemeᵒᵖ} (f : X ⟶ Y) : Γ.map f = f.unop.appTop := rfl -theorem Γ_map_op {X Y : Scheme} (f : X ⟶ Y) : Γ.map f.op = f.app ⊤ := +theorem Γ_map_op {X Y : Scheme} (f : X ⟶ Y) : Γ.map f.op = f.appTop := rfl /-- @@ -454,13 +483,13 @@ def ΓSpecIso : Γ(Spec R, ⊤) ≅ R := SpecΓIdentity.app R @[reassoc (attr := simp)] lemma ΓSpecIso_naturality {R S : CommRingCat.{u}} (f : R ⟶ S) : - (Spec.map f).app ⊤ ≫ (ΓSpecIso S).hom = (ΓSpecIso R).hom ≫ f := SpecΓIdentity.hom.naturality f + (Spec.map f).appTop ≫ (ΓSpecIso S).hom = (ΓSpecIso R).hom ≫ f := SpecΓIdentity.hom.naturality f -- The RHS is not necessarily simpler than the LHS, but this direction coincides with the simp -- direction of `NatTrans.naturality`. @[reassoc (attr := simp)] lemma ΓSpecIso_inv_naturality {R S : CommRingCat.{u}} (f : R ⟶ S) : - f ≫ (ΓSpecIso S).inv = (ΓSpecIso R).inv ≫ (Spec.map f).app ⊤ := SpecΓIdentity.inv.naturality f + f ≫ (ΓSpecIso S).inv = (ΓSpecIso R).inv ≫ (Spec.map f).appTop := SpecΓIdentity.inv.naturality f -- This is not marked simp to respect the abstraction lemma ΓSpecIso_inv : (ΓSpecIso R).inv = StructureSheaf.toOpen R ⊤ := rfl @@ -526,6 +555,10 @@ theorem preimage_basicOpen {X Y : Scheme.{u}} (f : X ⟶ Y) {U : Y.Opens} (r : f ⁻¹ᵁ (Y.basicOpen r) = X.basicOpen (f.app U r) := LocallyRingedSpace.preimage_basicOpen f.toLRSHom r +theorem preimage_basicOpen_top {X Y : Scheme.{u}} (f : X ⟶ Y) (r : Γ(Y, ⊤)) : + f ⁻¹ᵁ (Y.basicOpen r) = X.basicOpen (f.appTop r) := + preimage_basicOpen .. + lemma basicOpen_appLE {X Y : Scheme.{u}} (f : X ⟶ Y) (U : X.Opens) (V : Y.Opens) (e : U ≤ f ⁻¹ᵁ V) (s : Γ(Y, V)) : X.basicOpen (f.appLE V U e s) = U ⊓ f ⁻¹ᵁ (Y.basicOpen s) := by simp only [preimage_basicOpen, Hom.appLE, CommRingCat.coe_comp_of, RingHom.coe_comp, diff --git a/Mathlib/AlgebraicGeometry/SpreadingOut.lean b/Mathlib/AlgebraicGeometry/SpreadingOut.lean index b5d7ef83b97b85..a327e1ae7ee02b 100644 --- a/Mathlib/AlgebraicGeometry/SpreadingOut.lean +++ b/Mathlib/AlgebraicGeometry/SpreadingOut.lean @@ -49,8 +49,7 @@ open CategoryTheory namespace AlgebraicGeometry -variable {X Y S : Scheme.{u}} (f : X ⟶ Y) (sX : X ⟶ S) (sY : Y ⟶ S) (e : f ≫ sY = sX) -variable {R A : CommRingCat.{u}} +variable {X Y S : Scheme.{u}} (f : X ⟶ Y) (sX : X ⟶ S) (sY : Y ⟶ S) {R A : CommRingCat.{u}} /-- The germ map at `x` is injective if there exists some affine `U ∋ x` such that the map `Γ(X, U) ⟶ X_x` is injective -/ diff --git a/Mathlib/AlgebraicGeometry/Stalk.lean b/Mathlib/AlgebraicGeometry/Stalk.lean index 6f520c2514a8f5..e06eb1b7ef0ca8 100644 --- a/Mathlib/AlgebraicGeometry/Stalk.lean +++ b/Mathlib/AlgebraicGeometry/Stalk.lean @@ -112,6 +112,13 @@ lemma fromSpecStalk_app {x : X} (hxU : x ∈ U) : hV.fromSpec_app_of_le _ hVU, ← X.presheaf.germ_res (homOfLE hVU) x hxV] simp [Category.assoc, ← ΓSpecIso_inv_naturality_assoc] +lemma fromSpecStalk_appTop {x : X} : + (X.fromSpecStalk x).appTop = + X.presheaf.germ ⊤ x trivial ≫ + (ΓSpecIso (X.presheaf.stalk x)).inv ≫ + (Spec (X.presheaf.stalk x)).presheaf.map (homOfLE le_top).op := + fromSpecStalk_app .. + @[reassoc (attr := simp)] lemma Spec_map_stalkSpecializes_fromSpecStalk {x y : X} (h : x ⤳ y) : Spec.map (X.presheaf.stalkSpecializes h) ≫ X.fromSpecStalk y = X.fromSpecStalk x := by @@ -184,7 +191,7 @@ instance {X : Scheme.{u}} (U : X.Opens) (x : X) (hxU : x ∈ U) : lemma fromSpecStalk_toSpecΓ (X : Scheme.{u}) (x : X) : X.fromSpecStalk x ≫ X.toSpecΓ = Spec.map (X.presheaf.germ ⊤ x trivial) := by rw [Scheme.toSpecΓ_naturality, ← SpecMap_ΓSpecIso_hom, ← Spec.map_comp, - @Scheme.fromSpecStalk_app X ⊤ _ trivial] + Scheme.fromSpecStalk_appTop] simp @[reassoc (attr := simp)] diff --git a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean index cb9082af37462c..dbc4ac5a160076 100644 --- a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean +++ b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean @@ -275,7 +275,7 @@ lemma IsSeparated.valuativeCriterion [IsSeparated f] : ValuativeCriterion.Unique conv_lhs => rw [← pullback.lift_fst l₁ l₂ h, ← pullback.condition_assoc] conv_rhs => rw [← pullback.lift_snd l₁ l₂ h, ← pullback.condition_assoc] simp - suffices h : Function.Bijective (g.app ⊤) by + suffices h : Function.Bijective (g.appTop) by refine (HasAffineProperty.iff_of_isAffine (P := MorphismProperty.isomorphisms Scheme)).mpr ?_ exact ⟨hZ, (ConcreteCategory.isIso_iff_bijective _).mpr h⟩ constructor @@ -286,7 +286,7 @@ lemma IsSeparated.valuativeCriterion [IsSeparated f] : ValuativeCriterion.Unique simpa using hl₂.symm have hg : l ≫ g = Spec.map (CommRingCat.ofHom (algebraMap S.R S.K)) := pullback.lift_snd _ _ _ - have : Function.Injective ((l ≫ g).app ⊤) := by + have : Function.Injective ((l ≫ g).appTop) := by rw [hg] let e := arrowIsoΓSpecOfIsAffine (CommRingCat.ofHom <| algebraMap S.R S.K) let P : MorphismProperty CommRingCat := @@ -296,7 +296,7 @@ lemma IsSeparated.valuativeCriterion [IsSeparated f] : ValuativeCriterion.Unique show P _ rw [← MorphismProperty.arrow_mk_iso_iff (P := P) e] exact NoZeroSMulDivisors.algebraMap_injective S.R S.K - rw [Scheme.comp_app _ _] at this + rw [Scheme.comp_appTop] at this exact Function.Injective.of_comp this · rw [@HasAffineProperty.iff_of_isAffine @IsClosedImmersion] at this exact this.right diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean b/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean similarity index 91% rename from Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean rename to Mathlib/AlgebraicTopology/Quasicategory/Basic.lean index 381e65660f6321..55b27d884364c8 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Quasicategory.lean +++ b/Mathlib/AlgebraicTopology/Quasicategory/Basic.lean @@ -13,13 +13,14 @@ In this file we define quasicategories, a common model of infinity categories. We show that every Kan complex is a quasicategory. -In `Mathlib/AlgebraicTopology/Nerve.lean` -we show (TODO) that the nerve of a category is a quasicategory. +In `Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean` +we show that the nerve of a category is a quasicategory. ## TODO - Generalize the definition to higher universes. - See the corresponding TODO in `Mathlib/AlgebraicTopology/KanComplex.lean`. + See the corresponding TODO in + `Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean`. -/ diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index a2e26b4118880d..7c9ce0278a0c3a 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean @@ -564,6 +564,50 @@ lemma δ_one_mkOfSucc {n : ℕ} (i : Fin n) : fin_cases x aesop +/-- If `i + 1 < j`, `mkOfSucc i ≫ δ j` is the morphism `[1] ⟶ [n]` that +sends `0` and `1` to `i` and `i + 1`, respectively. -/ +lemma mkOfSucc_δ_lt {n : ℕ} {i : Fin n} {j : Fin (n + 2)} + (h : i.succ.castSucc < j) : + mkOfSucc i ≫ δ j = mkOfSucc i.castSucc := by + ext x + fin_cases x + · simp [δ, Fin.succAbove_of_castSucc_lt _ _ (Nat.lt_trans _ h)] + · simp [δ, Fin.succAbove_of_castSucc_lt _ _ h] + +/-- If `i + 1 > j`, `mkOfSucc i ≫ δ j` is the morphism `[1] ⟶ [n]` that +sends `0` and `1` to `i + 1` and `i + 2`, respectively. -/ +lemma mkOfSucc_δ_gt {n : ℕ} {i : Fin n} {j : Fin (n + 2)} + (h : j < i.succ.castSucc) : + mkOfSucc i ≫ δ j = mkOfSucc i.succ := by + ext x + simp only [δ, len_mk, mkHom, comp_toOrderHom, Hom.toOrderHom_mk, OrderHom.comp_coe, + OrderEmbedding.toOrderHom_coe, Function.comp_apply, Fin.succAboveOrderEmb_apply] + fin_cases x <;> rw [Fin.succAbove_of_le_castSucc] + · rfl + · exact Nat.le_of_lt_succ h + · rfl + · exact Nat.le_of_lt h + +/-- If `i + 1 = j`, `mkOfSucc i ≫ δ j` is the morphism `[1] ⟶ [n]` that +sends `0` and `1` to `i` and `i + 2`, respectively. -/ +lemma mkOfSucc_δ_eq {n : ℕ} {i : Fin n} {j : Fin (n + 2)} + (h : j = i.succ.castSucc) : + mkOfSucc i ≫ δ j = intervalEdge i 2 (by omega) := by + ext x + fin_cases x + · subst h + simp only [δ, len_mk, Nat.reduceAdd, mkHom, comp_toOrderHom, Hom.toOrderHom_mk, + Fin.zero_eta, OrderHom.comp_coe, OrderEmbedding.toOrderHom_coe, Function.comp_apply, + mkOfSucc_homToOrderHom_zero, Fin.succAboveOrderEmb_apply, + Fin.castSucc_succAbove_castSucc, Fin.succAbove_succ_self] + rfl + · simp only [δ, len_mk, Nat.reduceAdd, mkHom, comp_toOrderHom, Hom.toOrderHom_mk, Fin.mk_one, + OrderHom.comp_coe, OrderEmbedding.toOrderHom_coe, Function.comp_apply, + mkOfSucc_homToOrderHom_one, Fin.succAboveOrderEmb_apply] + subst h + rw [Fin.succAbove_castSucc_self] + rfl + 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 diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean index 309fc78b1916aa..8c329680dec88e 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean @@ -106,6 +106,13 @@ def _root_.SSet.yonedaEquiv (X : SSet.{u}) (n : SimplexCategory) : (standardSimplex.obj n ⟶ X) ≃ X.obj (op n) := yonedaCompUliftFunctorEquiv X n +/-- The unique non-degenerate `n`-simplex in `Δ[n]`. -/ +def id (n : ℕ) : Δ[n] _[n] := yonedaEquiv Δ[n] [n] (𝟙 Δ[n]) + +lemma id_eq_objEquiv_symm (n : ℕ) : id n = (objEquiv _ _).symm (𝟙 _) := rfl + +lemma objEquiv_id (n : ℕ) : objEquiv _ _ (id n) = 𝟙 _ := rfl + /-- The (degenerate) `m`-simplex in the standard simplex concentrated in vertex `k`. -/ def const (n : ℕ) (k : Fin (n+1)) (m : SimplexCategoryᵒᵖ) : Δ[n].obj m := objMk (OrderHom.const _ k ) diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean index 531bc99ebc39c9..87cf0ca7bf9e52 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/KanComplex.lean @@ -10,7 +10,7 @@ import Mathlib.AlgebraicTopology.SimplicialSet.Basic # Kan complexes In this file we give the definition of Kan complexes. -In `Mathlib/AlgebraicTopology/Quasicategory.lean` +In `Mathlib/AlgebraicTopology/Quasicategory/Basic.lean` we show that every Kan complex is a quasicategory. ## TODO diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean index 696d2c7aa9498a..33e4d07da1bce4 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean @@ -73,4 +73,66 @@ lemma spine_map_subinterval {n : ℕ} (j l : ℕ) (hjl : j + l ≤ n) (Δ : X _[ · simp only [spine_arrow, Path.interval, ← FunctorToTypes.map_comp_apply, ← op_comp, mkOfSucc_subinterval_eq] +/-- Two paths of the same nonzero length are equal if all of their arrows are equal. -/ +@[ext] +lemma Path.ext' {n : ℕ} {f g : Path X (n + 1)} + (h : ∀ i : Fin (n + 1), f.arrow i = g.arrow i) : + f = g := by + ext j + · rcases Fin.eq_castSucc_or_eq_last j with ⟨k, hk⟩ | hl + · rw [hk, ← f.arrow_src k, ← g.arrow_src k, h] + · simp only [hl, ← Fin.succ_last] + rw [← f.arrow_tgt (Fin.last n), ← g.arrow_tgt (Fin.last n), h] + · exact h j + +/-- Maps of simplicial sets induce maps of paths in a simplicial set.-/ +@[simps] +def Path.map {X Y : SSet.{u}} {n : ℕ} (f : X.Path n) (σ : X ⟶ Y) : Y.Path n where + vertex i := σ.app (Opposite.op [0]) (f.vertex i) + arrow i := σ.app (Opposite.op [1]) (f.arrow i) + arrow_src i := by + simp only [← f.arrow_src i] + exact congr (σ.naturality (δ 1).op) rfl |>.symm + arrow_tgt i := by + simp only [← f.arrow_tgt i] + exact congr (σ.naturality (δ 0).op) rfl |>.symm + +/-- `Path.map` respects subintervals of paths.-/ +lemma map_interval {X Y : SSet.{u}} {n : ℕ} (f : X.Path n) (σ : X ⟶ Y) + (j l : ℕ) (hjl : j + l ≤ n) : + (f.map σ).interval j l hjl = (f.interval j l hjl).map σ := rfl + +/-- The spine of the unique non-degenerate `n`-simplex in `Δ[n]`.-/ +def standardSimplex.spineId (n : ℕ) : Path Δ[n] n := + spine Δ[n] n (standardSimplex.id n) + +/-- Any inner horn contains the spine of the unique non-degenerate `n`-simplex +in `Δ[n]`.-/ +@[simps] +def horn.spineId {n : ℕ} (i : Fin (n + 3)) + (h₀ : 0 < i) (hₙ : i < Fin.last (n + 2)) : + Path Λ[n + 2, i] (n + 2) where + vertex j := ⟨standardSimplex.spineId _ |>.vertex j, (horn.const n i j _).property⟩ + arrow j := ⟨standardSimplex.spineId _ |>.arrow j, by + let edge := horn.primitiveEdge h₀ hₙ j + have ha : (standardSimplex.spineId _).arrow j = edge.val := by + dsimp only [edge, standardSimplex.spineId, standardSimplex.id, spine_arrow, + mkOfSucc, horn.primitiveEdge, horn.edge, standardSimplex.edge, + standardSimplex.map_apply] + aesop + rw [ha] + exact edge.property⟩ + arrow_src := by + simp only [horn, SimplicialObject.δ, Subtype.mk.injEq] + exact standardSimplex.spineId _ |>.arrow_src + arrow_tgt := by + simp only [horn, SimplicialObject.δ, Subtype.mk.injEq] + exact standardSimplex.spineId _ |>.arrow_tgt + +@[simp] +lemma horn.spineId_map_hornInclusion {n : ℕ} (i : Fin (n + 3)) + (h₀ : 0 < i) (hₙ : i < Fin.last (n + 2)) : + Path.map (horn.spineId i h₀ hₙ) (hornInclusion (n + 2) i) = + standardSimplex.spineId (n + 2) := rfl + end SSet diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean b/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean index 13a41139b88edd..cef9a156cab5a5 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2024 Emily Riehl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro, Emily Riehl, Joël Riou +Authors: Mario Carneiro, Emily Riehl, Joël Riou, Johan Commelin, Nick Ward -/ +import Mathlib.AlgebraicTopology.Quasicategory.Basic import Mathlib.AlgebraicTopology.SimplicialSet.Nerve import Mathlib.AlgebraicTopology.SimplicialSet.Path import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction @@ -86,6 +87,147 @@ theorem spineToSimplex_edge (f : Path X n) (j l : ℕ) (hjl : j + l ≤ n) : unfold diagonal simp only [← FunctorToTypes.map_comp_apply, ← op_comp, diag_subinterval_eq] +/-- For any `σ : X ⟶ Y` between `StrictSegal` simplicial sets, `spineToSimplex` +commutes with `Path.map`. -/ +lemma spineToSimplex_map {X Y : SSet.{u}} [StrictSegal X] [StrictSegal Y] + {n : ℕ} (f : Path X (n + 1)) (σ : X ⟶ Y) : + spineToSimplex (f.map σ) = σ.app _ (spineToSimplex f) := by + apply spineInjective + ext k + dsimp only [spineEquiv, Equiv.coe_fn_mk, Path.map, spine_arrow] + rw [← types_comp_apply (σ.app _) (Y.map _), ← σ.naturality] + simp only [types_comp_apply, spineToSimplex_arrow] + +/-- If we take the path along the spine of the `j`th face of a `spineToSimplex`, +the common vertices will agree with those of the original path `f`. In particular, +a vertex `i` with `i < j` can be identified with the same vertex in `f`. -/ +lemma spine_δ_vertex_lt (f : Path X (n + 1)) {i : Fin (n + 1)} {j : Fin (n + 2)} + (h : i.castSucc < j) : + (X.spine n (X.δ j (spineToSimplex f))).vertex i = f.vertex i.castSucc := by + simp only [SimplicialObject.δ, spine_vertex] + rw [← FunctorToTypes.map_comp_apply, ← op_comp, const_comp, spineToSimplex_vertex] + simp only [SimplexCategory.δ, Hom.toOrderHom, len_mk, mkHom, Hom.mk, + OrderEmbedding.toOrderHom_coe, Fin.succAboveOrderEmb_apply] + rw [Fin.succAbove_of_castSucc_lt j i h] + +/-- If we take the path along the spine of the `j`th face of a `spineToSimplex`, +a vertex `i` with `i ≥ j` can be identified with vertex `i + 1` in the original +path. -/ +lemma spine_δ_vertex_ge (f : Path X (n + 1)) {i : Fin (n + 1)} {j : Fin (n + 2)} + (h : j ≤ i.castSucc) : + (X.spine n (X.δ j (spineToSimplex f))).vertex i = f.vertex i.succ := by + simp only [SimplicialObject.δ, spine_vertex] + rw [← FunctorToTypes.map_comp_apply, ← op_comp, const_comp, spineToSimplex_vertex] + simp only [SimplexCategory.δ, Hom.toOrderHom, len_mk, mkHom, Hom.mk, + OrderEmbedding.toOrderHom_coe, Fin.succAboveOrderEmb_apply] + rw [Fin.succAbove_of_le_castSucc j i h] + +/-- If we take the path along the spine of the `j`th face of a `spineToSimplex`, +the common arrows will agree with those of the original path `f`. In particular, +an arrow `i` with `i + 1 < j` can be identified with the same arrow in `f`. -/ +lemma spine_δ_arrow_lt (f : Path X (n + 1)) {i : Fin n} {j : Fin (n + 2)} + (h : i.succ.castSucc < j) : + (X.spine n (X.δ j (spineToSimplex f))).arrow i = f.arrow i.castSucc := by + simp only [SimplicialObject.δ, spine_arrow] + rw [← FunctorToTypes.map_comp_apply, ← op_comp] + rw [mkOfSucc_δ_lt h, spineToSimplex_arrow] + +/-- If we take the path along the spine of the `j`th face of a `spineToSimplex`, +an arrow `i` with `i + 1 > j` can be identified with arrow `i + 1` in the +original path. -/ +lemma spine_δ_arrow_gt (f : Path X (n + 1)) {i : Fin n} {j : Fin (n + 2)} + (h : j < i.succ.castSucc) : + (X.spine n (X.δ j (spineToSimplex f))).arrow i = f.arrow i.succ := by + simp only [SimplicialObject.δ, spine_arrow] + rw [← FunctorToTypes.map_comp_apply, ← op_comp] + rw [mkOfSucc_δ_gt h, spineToSimplex_arrow] + +/-- If we take the path along the spine of a face of a `spineToSimplex`, the +arrows not contained in the original path can be recovered as the diagonal edge +of the `spineToSimplex` that "composes" arrows `i` and `i + 1`. -/ +lemma spine_δ_arrow_eq (f : Path X (n + 1)) {i : Fin n} {j : Fin (n + 2)} + (h : j = i.succ.castSucc) : + (X.spine n (X.δ j (spineToSimplex f))).arrow i = + spineToDiagonal (Path.interval f i 2 (by omega)) := by + simp only [SimplicialObject.δ, spine_arrow] + rw [← FunctorToTypes.map_comp_apply, ← op_comp] + rw [mkOfSucc_δ_eq h, spineToSimplex_edge] + +/-- Any `StrictSegal` simplicial set is a `Quasicategory`. -/ +instance : Quasicategory X := by + apply quasicategory_of_filler X + intro n i σ₀ h₀ hₙ + use spineToSimplex <| Path.map (horn.spineId i h₀ hₙ) σ₀ + intro j hj + apply spineInjective + ext k + · dsimp only [spineEquiv, spine_arrow, Function.comp_apply, Equiv.coe_fn_mk] + rw [← types_comp_apply (σ₀.app _) (X.map _), ← σ₀.naturality] + let ksucc := k.succ.castSucc + obtain hlt | hgt | heq : ksucc < j ∨ j < ksucc ∨ j = ksucc := by omega + · rw [← spine_arrow, spine_δ_arrow_lt _ hlt] + dsimp only [Path.map, spine_arrow, Fin.coe_eq_castSucc] + apply congr_arg + simp only [horn, horn.spineId, standardSimplex, uliftFunctor, Functor.comp_obj, + yoneda_obj_obj, whiskering_obj_obj_map, uliftFunctor_map, yoneda_obj_map, + standardSimplex.objEquiv, Equiv.ulift, Equiv.coe_fn_symm_mk, + Quiver.Hom.unop_op, horn.face_coe, Subtype.mk.injEq] + rw [mkOfSucc_δ_lt hlt] + rfl + · rw [← spine_arrow, spine_δ_arrow_gt _ hgt] + dsimp only [Path.map, spine_arrow, Fin.coe_eq_castSucc] + apply congr_arg + simp only [horn, horn.spineId, standardSimplex, uliftFunctor, Functor.comp_obj, + yoneda_obj_obj, whiskering_obj_obj_map, uliftFunctor_map, yoneda_obj_map, + standardSimplex.objEquiv, Equiv.ulift, Equiv.coe_fn_symm_mk, + Quiver.Hom.unop_op, horn.face_coe, Subtype.mk.injEq] + rw [mkOfSucc_δ_gt hgt] + rfl + · /- The only inner horn of `Δ[2]` does not contain the diagonal edge. -/ + have hn0 : n ≠ 0 := by + rintro rfl + obtain rfl : k = 0 := by omega + fin_cases i <;> contradiction + /- We construct the triangle in the standard simplex as a 2-simplex in + the horn. While the triangle is not contained in the inner horn `Λ[2, 1]`, + we can inhabit `Λ[n + 2, i] _[2]` by induction on `n`. -/ + let triangle : Λ[n + 2, i] _[2] := by + cases n with + | zero => contradiction + | succ _ => exact horn.primitiveTriangle i h₀ hₙ k (by omega) + /- The interval spanning from `k` to `k + 2` is equivalently the spine + of the triangle with vertices `k`, `k + 1`, and `k + 2`. -/ + have hi : ((horn.spineId i h₀ hₙ).map σ₀).interval k 2 (by omega) = + X.spine 2 (σ₀.app _ triangle) := by + ext m + dsimp [spine_arrow, Path.interval, Path.map] + rw [← types_comp_apply (σ₀.app _) (X.map _), ← σ₀.naturality] + apply congr_arg + simp only [horn, standardSimplex, uliftFunctor, Functor.comp_obj, + whiskering_obj_obj_obj, yoneda_obj_obj, uliftFunctor_obj, ne_eq, + whiskering_obj_obj_map, uliftFunctor_map, yoneda_obj_map, len_mk, + Nat.reduceAdd, Quiver.Hom.unop_op] + cases n with + | zero => contradiction + | succ _ => ext x; fin_cases x <;> fin_cases m <;> rfl + rw [← spine_arrow, spine_δ_arrow_eq _ heq, hi] + simp only [spineToDiagonal, diagonal, spineToSimplex_spine] + rw [← types_comp_apply (σ₀.app _) (X.map _), ← σ₀.naturality, types_comp_apply] + apply congr_arg + simp only [horn, standardSimplex, uliftFunctor, Functor.comp_obj, + whiskering_obj_obj_obj, yoneda_obj_obj, uliftFunctor_obj, + uliftFunctor_map, whiskering_obj_obj_map, yoneda_obj_map, horn.face_coe, + len_mk, Nat.reduceAdd, Quiver.Hom.unop_op, Subtype.mk.injEq, ULift.up_inj] + ext z + cases n with + | zero => contradiction + | succ _ => + fin_cases z <;> + · simp only [standardSimplex.objEquiv, uliftFunctor_map, yoneda_obj_map, + Quiver.Hom.unop_op, Equiv.ulift_symm_down] + rw [mkOfSucc_δ_eq heq] + rfl + end StrictSegal end SSet @@ -118,4 +260,8 @@ noncomputable instance strictSegal (C : Type u) [Category.{v} C] : StrictSegal ( · intro i hi apply ComposableArrows.mkOfObjOfMapSucc_map_succ +/-- By virtue of satisfying the `StrictSegal` condition, the nerve of a +category is a `Quasicategory`. -/ +instance : Quasicategory (nerve C) := inferInstance + end Nerve diff --git a/Mathlib/Analysis/Analytic/Basic.lean b/Mathlib/Analysis/Analytic/Basic.lean index f2a06440fe3ef9..3ebd74ae9c5f31 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.lean @@ -214,7 +214,7 @@ theorem lt_radius_of_isBigO (h₀ : r ≠ 0) {a : ℝ} (ha : a ∈ Ioo (-1 : ℝ rw [← pos_iff_ne_zero, ← NNReal.coe_pos] at h₀ lift a to ℝ≥0 using ha.1.le have : (r : ℝ) < r / a := by - simpa only [div_one] using (div_lt_div_left h₀ zero_lt_one ha.1).2 ha.2 + simpa only [div_one] using (div_lt_div_iff_of_pos_left h₀ zero_lt_one ha.1).2 ha.2 norm_cast at this rw [← ENNReal.coe_lt_coe] at this refine this.trans_le (p.le_radius_of_bound C fun n => ?_) diff --git a/Mathlib/Analysis/Analytic/Inverse.lean b/Mathlib/Analysis/Analytic/Inverse.lean index c9a57e5bb69856..6efcaa447e7275 100644 --- a/Mathlib/Analysis/Analytic/Inverse.lean +++ b/Mathlib/Analysis/Analytic/Inverse.lean @@ -5,7 +5,7 @@ Authors: Sébastien Gouëzel -/ import Mathlib.Analysis.Analytic.Composition import Mathlib.Analysis.Analytic.Linear -import Mathlib.Tactic.Positivity.Finset +import Mathlib.Tactic.Positivity /-! diff --git a/Mathlib/Analysis/Analytic/OfScalars.lean b/Mathlib/Analysis/Analytic/OfScalars.lean index 432b903849ad79..688d6468fb486b 100644 --- a/Mathlib/Analysis/Analytic/OfScalars.lean +++ b/Mathlib/Analysis/Analytic/OfScalars.lean @@ -250,7 +250,7 @@ theorem ofScalars_radius_eq_zero_of_tendsto [NormOneClass E] cases hc' <;> aesop · filter_upwards [hc.eventually_ge_atTop (2*r⁻¹), eventually_ne_atTop 0] with n hc hn simp only [ofScalars_norm, norm_mul, norm_norm, norm_pow, NNReal.norm_eq] - rw [mul_comm ‖c n‖, ← mul_assoc, ← div_le_div_iff, mul_div_assoc] + rw [mul_comm ‖c n‖, ← mul_assoc, ← div_le_div_iff₀, mul_div_assoc] · convert hc rw [pow_succ, div_mul_cancel_left₀, NNReal.coe_inv] aesop diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 87c9e471f1eac4..c9ef3caef6893b 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -1149,7 +1149,7 @@ theorem isLittleO_const_iff_isLittleO_one {c : F''} (hc : c ≠ 0) : fun h => h.trans_isBigO <| isBigO_const_const _ hc _⟩ @[simp] -theorem isLittleO_one_iff : f' =o[l] (fun _x => 1 : α → F) ↔ Tendsto f' l (𝓝 0) := by +theorem isLittleO_one_iff {f : α → E'''} : f =o[l] (fun _x => 1 : α → F) ↔ Tendsto f l (𝓝 0) := by simp only [isLittleO_iff, norm_one, mul_one, Metric.nhds_basis_closedBall.tendsto_right_iff, Metric.mem_closedBall, dist_zero_right] diff --git a/Mathlib/Analysis/Asymptotics/TVS.lean b/Mathlib/Analysis/Asymptotics/TVS.lean index f116d2b07113c3..e4d49370e6a0ad 100644 --- a/Mathlib/Analysis/Asymptotics/TVS.lean +++ b/Mathlib/Analysis/Asymptotics/TVS.lean @@ -125,7 +125,7 @@ lemma isLittleOTVS_one [ContinuousSMul 𝕜 E] {f : α → E} {l : Filter α} : rcases NormedField.exists_one_lt_norm 𝕜 with ⟨c, hc⟩ obtain ⟨ε, hε₀, hε⟩ : ∃ ε : ℝ≥0, 0 < ε ∧ (ε * ‖c‖₊ / r : ℝ≥0∞) < 1 := by apply Eventually.exists_gt - refine eventually_lt_of_tendsto_lt zero_lt_one <| Continuous.tendsto' ?_ _ _ (by simp) + refine Continuous.tendsto' ?_ _ _ (by simp) |>.eventually_lt_const zero_lt_one fun_prop (disch := intros; first | apply ENNReal.coe_ne_top | positivity) filter_upwards [hr ε hε₀.ne'] with x hx refine mem_of_egauge_lt_one hUb (hx.trans_lt ?_) diff --git a/Mathlib/Analysis/BoundedVariation.lean b/Mathlib/Analysis/BoundedVariation.lean index 4f281d9bfca6d5..4a2fafb5a80006 100644 --- a/Mathlib/Analysis/BoundedVariation.lean +++ b/Mathlib/Analysis/BoundedVariation.lean @@ -180,7 +180,7 @@ theorem lowerSemicontinuous_aux {ι : Type*} {F : ι → α → E} {p : Filter (𝓝 (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i)))) := by apply tendsto_finset_sum exact fun i _ => Tendsto.edist (Ffs (u i.succ) (us i.succ)) (Ffs (u i) (us i)) - exact (eventually_gt_of_tendsto_gt hlt this).mono fun i h => h.trans_le (sum_le (F i) n um us) + exact (this.eventually_const_lt hlt).mono fun i h => h.trans_le (sum_le (F i) n um us) /-- The map `(eVariationOn · s)` is lower semicontinuous for pointwise convergence *on `s`*. Pointwise convergence on `s` is encoded here as uniform convergence on the family consisting of the diff --git a/Mathlib/Analysis/Calculus/AddTorsor/AffineMap.lean b/Mathlib/Analysis/Calculus/AddTorsor/AffineMap.lean index 5eb7534bb2ff4a..104a452fe54232 100644 --- a/Mathlib/Analysis/Calculus/AddTorsor/AffineMap.lean +++ b/Mathlib/Analysis/Calculus/AddTorsor/AffineMap.lean @@ -25,7 +25,7 @@ variable [NormedAddCommGroup V] [NormedSpace 𝕜 V] variable [NormedAddCommGroup W] [NormedSpace 𝕜 W] /-- A continuous affine map between normed vector spaces is smooth. -/ -theorem contDiff {n : ℕ∞} (f : V →ᴬ[𝕜] W) : ContDiff 𝕜 n f := by +theorem contDiff {n : WithTop ℕ∞} (f : V →ᴬ[𝕜] W) : ContDiff 𝕜 n f := by rw [f.decomp] apply f.contLinear.contDiff.add exact contDiff_const diff --git a/Mathlib/Analysis/Calculus/BumpFunction/Basic.lean b/Mathlib/Analysis/Calculus/BumpFunction/Basic.lean index bba1643f58b063..922effc6f97d8d 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/Basic.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/Basic.lean @@ -49,7 +49,7 @@ smooth function, smooth bump function noncomputable section open Function Set Filter -open scoped Topology Filter +open scoped Topology Filter ContDiff variable {E X : Type*} @@ -80,7 +80,7 @@ structure ContDiffBumpBase (E : Type*) [NormedAddCommGroup E] [NormedSpace ℝ E toFun : ℝ → E → ℝ mem_Icc : ∀ (R : ℝ) (x : E), toFun R x ∈ Icc (0 : ℝ) 1 symmetric : ∀ (R : ℝ) (x : E), toFun R (-x) = toFun R x - smooth : ContDiffOn ℝ ⊤ (uncurry toFun) (Ioi (1 : ℝ) ×ˢ (univ : Set E)) + smooth : ContDiffOn ℝ ∞ (uncurry toFun) (Ioi (1 : ℝ) ×ˢ (univ : Set E)) eq_one : ∀ R : ℝ, 1 < R → ∀ x : E, ‖x‖ ≤ 1 → toFun R x = 1 support : ∀ R : ℝ, 1 < R → Function.support (toFun R) = Metric.ball (0 : E) R @@ -149,7 +149,7 @@ theorem support_eq : Function.support f = Metric.ball c f.rOut := by simp only [toFun, support_comp_eq_preimage, ContDiffBumpBase.support _ _ f.one_lt_rOut_div_rIn] ext x simp only [mem_ball_iff_norm, sub_zero, norm_smul, mem_preimage, Real.norm_eq_abs, abs_inv, - abs_of_pos f.rIn_pos, ← div_eq_inv_mul, div_lt_div_right f.rIn_pos] + abs_of_pos f.rIn_pos, ← div_eq_inv_mul, div_lt_div_iff_of_pos_right f.rIn_pos] theorem tsupport_eq : tsupport f = closedBall c f.rOut := by simp_rw [tsupport, f.support_eq, closure_ball _ f.rOut_pos.ne'] @@ -178,7 +178,8 @@ protected theorem _root_.ContDiffWithinAt.contDiffBump {c g : X → E} {s : Set ContDiffWithinAt ℝ n (fun x => f x (g x)) s x := by change ContDiffWithinAt ℝ n (uncurry (someContDiffBumpBase E).toFun ∘ fun x : X => ((f x).rOut / (f x).rIn, (f x).rIn⁻¹ • (g x - c x))) s x - refine (((someContDiffBumpBase E).smooth.contDiffAt ?_).of_le le_top).comp_contDiffWithinAt x ?_ + refine (((someContDiffBumpBase E).smooth.contDiffAt ?_).of_le + (mod_cast le_top)).comp_contDiffWithinAt x ?_ · exact prod_mem_nhds (Ioi_mem_nhds (f x).one_lt_rOut_div_rIn) univ_mem · exact (hR.div hr (f x).rIn_pos.ne').prod ((hr.inv (f x).rIn_pos.ne').smul (hg.sub hc)) diff --git a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean index d0f390973978ce..2f3e0be74bdfb8 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean @@ -28,7 +28,7 @@ noncomputable section open Set Metric TopologicalSpace Function Asymptotics MeasureTheory Module ContinuousLinearMap Filter MeasureTheory.Measure Bornology -open scoped Pointwise Topology NNReal Convolution +open scoped Pointwise Topology NNReal Convolution ContDiff variable {E : Type*} [NormedAddCommGroup E] @@ -40,7 +40,7 @@ variable [NormedSpace ℝ E] [FiniteDimensional ℝ E] values in `[0, 1]`, supported in `s` and with `f x = 1`. -/ theorem exists_smooth_tsupport_subset {s : Set E} {x : E} (hs : s ∈ 𝓝 x) : ∃ f : E → ℝ, - tsupport f ⊆ s ∧ HasCompactSupport f ∧ ContDiff ℝ ⊤ f ∧ range f ⊆ Icc 0 1 ∧ f x = 1 := by + tsupport f ⊆ s ∧ HasCompactSupport f ∧ ContDiff ℝ ∞ f ∧ range f ⊆ Icc 0 1 ∧ f x = 1 := by obtain ⟨d : ℝ, d_pos : 0 < d, hd : Euclidean.closedBall x d ⊆ s⟩ := Euclidean.nhds_basis_closedBall.mem_iff.1 hs let c : ContDiffBump (toEuclidean x) := @@ -73,7 +73,7 @@ theorem exists_smooth_tsupport_subset {s : Set E} {x : E} (hs : s ∈ 𝓝 x) : /-- Given an open set `s` in a finite-dimensional real normed vector space, there exists a smooth function with values in `[0, 1]` whose support is exactly `s`. -/ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : - ∃ f : E → ℝ, f.support = s ∧ ContDiff ℝ ⊤ f ∧ Set.range f ⊆ Set.Icc 0 1 := by + ∃ f : E → ℝ, f.support = s ∧ ContDiff ℝ ∞ f ∧ Set.range f ⊆ Set.Icc 0 1 := by /- For any given point `x` in `s`, one can construct a smooth function with support in `s` and nonzero at `x`. By second-countability, it follows that we may cover `s` with the supports of countably many such functions, say `g i`. @@ -85,7 +85,7 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : · exact ⟨fun _ => 0, Function.support_zero, contDiff_const, by simp only [range_const, singleton_subset_iff, left_mem_Icc, zero_le_one]⟩ - let ι := { f : E → ℝ // f.support ⊆ s ∧ HasCompactSupport f ∧ ContDiff ℝ ⊤ f ∧ range f ⊆ Icc 0 1 } + let ι := { f : E → ℝ // f.support ⊆ s ∧ HasCompactSupport f ∧ ContDiff ℝ ∞ f ∧ range f ⊆ Icc 0 1 } obtain ⟨T, T_count, hT⟩ : ∃ T : Set ι, T.Countable ∧ ⋃ f ∈ T, support (f : E → ℝ) = s := by have : ⋃ f : ι, (f : E → ℝ).support = s := by refine Subset.antisymm (iUnion_subset fun f => f.2.1) ?_ @@ -116,7 +116,7 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : rcases iT with ⟨n, hn⟩ rw [← hn] at hi exact ⟨n, hi⟩ - have g_smooth : ∀ n, ContDiff ℝ ⊤ (g n) := fun n => (g0 n).2.2.2.1 + have g_smooth : ∀ n, ContDiff ℝ ∞ (g n) := fun n => (g0 n).2.2.2.1 have g_comp_supp : ∀ n, HasCompactSupport (g n) := fun n => (g0 n).2.2.1 have g_nonneg : ∀ n x, 0 ≤ g n x := fun n x => ((g0 n).2.2.2.2 (mem_range_self x)).1 obtain ⟨δ, δpos, c, δc, c_lt⟩ : @@ -127,8 +127,8 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : have : ∀ i, ∃ R, ∀ x, ‖iteratedFDeriv ℝ i (fun x => g n x) x‖ ≤ R := by intro i have : BddAbove (range fun x => ‖iteratedFDeriv ℝ i (fun x : E => g n x) x‖) := by - apply - ((g_smooth n).continuous_iteratedFDeriv le_top).norm.bddAbove_range_of_hasCompactSupport + apply ((g_smooth n).continuous_iteratedFDeriv + (mod_cast le_top)).norm.bddAbove_range_of_hasCompactSupport apply HasCompactSupport.comp_left _ norm_zero apply (g_comp_supp n).iteratedFDeriv rcases this with ⟨R, hR⟩ @@ -148,7 +148,8 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : refine ⟨M⁻¹ * δ n, by positivity, fun i hi x => ?_⟩ calc ‖iteratedFDeriv ℝ i ((M⁻¹ * δ n) • g n) x‖ = ‖(M⁻¹ * δ n) • iteratedFDeriv ℝ i (g n) x‖ := by - rw [iteratedFDeriv_const_smul_apply]; exact (g_smooth n).of_le le_top + rw [iteratedFDeriv_const_smul_apply] + exact (g_smooth n).of_le (mod_cast le_top) _ = M⁻¹ * δ n * ‖iteratedFDeriv ℝ i (g n) x‖ := by rw [norm_smul _ (iteratedFDeriv ℝ i (g n) x), Real.norm_of_nonneg]; positivity _ ≤ M⁻¹ * δ n * M := (mul_le_mul_of_nonneg_left ((hR i x).trans (IR i hi)) (by positivity)) @@ -207,10 +208,10 @@ variable (E) theorem u_exists : ∃ u : E → ℝ, - ContDiff ℝ ⊤ u ∧ (∀ x, u x ∈ Icc (0 : ℝ) 1) ∧ support u = ball 0 1 ∧ ∀ x, u (-x) = u x := by + ContDiff ℝ ∞ u ∧ (∀ x, u x ∈ Icc (0 : ℝ) 1) ∧ support u = ball 0 1 ∧ ∀ x, u (-x) = u x := by have A : IsOpen (ball (0 : E) 1) := isOpen_ball obtain ⟨f, f_support, f_smooth, f_range⟩ : - ∃ f : E → ℝ, f.support = ball (0 : E) 1 ∧ ContDiff ℝ ⊤ f ∧ Set.range f ⊆ Set.Icc 0 1 := + ∃ f : E → ℝ, f.support = ball (0 : E) 1 ∧ ContDiff ℝ ∞ f ∧ Set.range f ⊆ Set.Icc 0 1 := A.exists_smooth_support_eq have B : ∀ x, f x ∈ Icc (0 : ℝ) 1 := fun x => f_range (mem_range_self x) refine ⟨fun x => (f x + f (-x)) / 2, ?_, ?_, ?_, ?_⟩ @@ -243,7 +244,7 @@ def u (x : E) : ℝ := variable (E) -theorem u_smooth : ContDiff ℝ ⊤ (u : E → ℝ) := +theorem u_smooth : ContDiff ℝ ∞ (u : E → ℝ) := (Classical.choose_spec (u_exists E)).1 theorem u_continuous : Continuous (u : E → ℝ) := @@ -433,7 +434,7 @@ theorem y_pos_of_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D) (D_lt_one : D < 1) variable (E) -theorem y_smooth : ContDiffOn ℝ ⊤ (uncurry y) (Ioo (0 : ℝ) 1 ×ˢ (univ : Set E)) := by +theorem y_smooth : ContDiffOn ℝ ∞ (uncurry y) (Ioo (0 : ℝ) 1 ×ˢ (univ : Set E)) := by have hs : IsOpen (Ioo (0 : ℝ) (1 : ℝ)) := isOpen_Ioo have hk : IsCompact (closedBall (0 : E) 1) := ProperSpace.isCompact_closedBall _ _ refine contDiffOn_convolution_left_with_param (lsmul ℝ ℝ) hs hk ?_ ?_ ?_ @@ -489,7 +490,7 @@ instance (priority := 100) {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E · rfl smooth := by suffices - ContDiffOn ℝ ⊤ + ContDiffOn ℝ ∞ (uncurry y ∘ fun p : ℝ × E => ((p.1 - 1) / (p.1 + 1), ((p.1 + 1) / 2)⁻¹ • p.2)) (Ioi 1 ×ˢ univ) by apply this.congr diff --git a/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean index fd3e53a98f2313..540db4e96bee8a 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean @@ -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/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index 05d77c24f110e6..ad3ed57edf02c1 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -26,7 +26,7 @@ Similar results are given for `C^n` functions on domains. We use the notation `E [×n]→L[𝕜] F` for the space of continuous multilinear maps on `E^n` with values in `F`. This is the space in which the `n`-th derivative of a function from `E` to `F` lives. -In this file, we denote `⊤ : ℕ∞` with `∞`. +In this file, we denote `(⊤ : ℕ∞) : WithTop ℕ∞` with `∞` and `⊤ : WithTop ℕ∞` with `ω`. ## Tags @@ -35,9 +35,7 @@ derivative, differentiability, higher derivative, `C^n`, multilinear, Taylor ser noncomputable section -open scoped NNReal Nat - -local notation "∞" => (⊤ : ℕ∞) +open scoped NNReal Nat ContDiff universe u uE uF uG @@ -52,7 +50,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type uG} [NormedAddCommGroup G] [NormedSpace 𝕜 G] {X : Type*} [NormedAddCommGroup X] [NormedSpace 𝕜 X] {s t : Set E} {f : E → F} - {g : F → G} {x x₀ : E} {b : E × F → G} {m n : ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} + {g : F → G} {x x₀ : E} {b : E × F → G} {m n : WithTop ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} /-! ### Constants -/ @@ -72,16 +70,18 @@ theorem iteratedFDeriv_zero_fun {n : ℕ} : (iteratedFDeriv 𝕜 n fun _ : E ↦ funext fun x ↦ by simpa [← iteratedFDerivWithin_univ] using iteratedFDerivWithin_zero_fun uniqueDiffOn_univ (mem_univ x) -theorem contDiff_zero_fun : ContDiff 𝕜 n fun _ : E => (0 : F) := - contDiff_of_differentiable_iteratedFDeriv fun m _ => by - rw [iteratedFDeriv_zero_fun] - exact differentiable_const (0 : E[×m]→L[𝕜] F) +theorem contDiff_zero_fun : ContDiff 𝕜 n fun _ : E => (0 : F) := by + suffices ContDiff 𝕜 ω (fun _ : E => (0 : F)) from this.of_le le_top + rw [← contDiff_infty_iff_contDiff_omega] + apply contDiff_of_differentiable_iteratedFDeriv fun m _ ↦ ?_ + rw [iteratedFDeriv_zero_fun] + exact differentiable_const (0 : E[×m]→L[𝕜] F) /-- Constants are `C^∞`. -/ theorem contDiff_const {c : F} : ContDiff 𝕜 n fun _ : E => c := by - suffices h : ContDiff 𝕜 ∞ fun _ : E => c from h.of_le le_top - rw [contDiff_top_iff_fderiv] + suffices h : ContDiff 𝕜 ω fun _ : E => c from h.of_le le_top + rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] refine ⟨differentiable_const c, ?_⟩ rw [fderiv_const] exact contDiff_zero_fun @@ -144,8 +144,8 @@ theorem contDiffWithinAt_singleton : ContDiffWithinAt 𝕜 n f {x} x := /-- Unbundled bounded linear functions are `C^∞`. -/ theorem IsBoundedLinearMap.contDiff (hf : IsBoundedLinearMap 𝕜 f) : ContDiff 𝕜 n f := by - suffices h : ContDiff 𝕜 ∞ f from h.of_le le_top - rw [contDiff_top_iff_fderiv] + suffices h : ContDiff 𝕜 ω f from h.of_le le_top + rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] refine ⟨hf.differentiable, ?_⟩ simp_rw [hf.fderiv] exact contDiff_const @@ -179,15 +179,15 @@ theorem contDiffOn_id {s} : ContDiffOn 𝕜 n (id : E → E) s := /-- Bilinear functions are `C^∞`. -/ theorem IsBoundedBilinearMap.contDiff (hb : IsBoundedBilinearMap 𝕜 b) : ContDiff 𝕜 n b := by - suffices h : ContDiff 𝕜 ∞ b from h.of_le le_top - rw [contDiff_top_iff_fderiv] + suffices h : ContDiff 𝕜 ω b from h.of_le le_top + rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] refine ⟨hb.differentiable, ?_⟩ simp only [hb.fderiv] exact hb.isBoundedLinearMap_deriv.contDiff /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `g ∘ f` admits a Taylor series whose `k`-th term is given by `g ∘ (p k)`. -/ -theorem HasFTaylorSeriesUpToOn.continuousLinearMap_comp (g : F →L[𝕜] G) +theorem HasFTaylorSeriesUpToOn.continuousLinearMap_comp {n : WithTop ℕ∞} (g : F →L[𝕜] G) (hf : HasFTaylorSeriesUpToOn n f p s) : HasFTaylorSeriesUpToOn n (g ∘ f) (fun x k => g.compContinuousMultilinearMap (p x k)) s where zero_eq x hx := congr_arg g (hf.zero_eq x hx) @@ -221,16 +221,16 @@ theorem ContDiff.continuousLinearMap_comp {f : E → F} (g : F →L[𝕜] G) (hf /-- The iterated derivative within a set of the composition with a linear map on the left is obtained by applying the linear map to the iterated derivative. -/ theorem ContinuousLinearMap.iteratedFDerivWithin_comp_left {f : E → F} (g : F →L[𝕜] G) - (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {i : ℕ} (hi : i ≤ n) : iteratedFDerivWithin 𝕜 i (g ∘ f) s x = g.compContinuousMultilinearMap (iteratedFDerivWithin 𝕜 i f s x) := (((hf.ftaylorSeriesWithin hs).continuousLinearMap_comp g).eq_iteratedFDerivWithin_of_uniqueDiffOn - hi hs hx).symm + (mod_cast hi) hs hx).symm /-- The iterated derivative of the composition with a linear map on the left is obtained by applying the linear map to the iterated derivative. -/ theorem ContinuousLinearMap.iteratedFDeriv_comp_left {f : E → F} (g : F →L[𝕜] G) - (hf : ContDiff 𝕜 n f) (x : E) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hf : ContDiff 𝕜 n f) (x : E) {i : ℕ} (hi : i ≤ n) : iteratedFDeriv 𝕜 i (g ∘ f) x = g.compContinuousMultilinearMap (iteratedFDeriv 𝕜 i f x) := by simp only [← iteratedFDerivWithin_univ] exact g.iteratedFDerivWithin_comp_left hf.contDiffOn uniqueDiffOn_univ (mem_univ x) hi @@ -262,7 +262,7 @@ theorem ContinuousLinearEquiv.iteratedFDerivWithin_comp_left (g : F ≃L[𝕜] G /-- Composition with a linear isometry on the left preserves the norm of the iterated derivative within a set. -/ theorem LinearIsometry.norm_iteratedFDerivWithin_comp_left {f : E → F} (g : F →ₗᵢ[𝕜] G) - (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {i : ℕ} (hi : i ≤ n) : ‖iteratedFDerivWithin 𝕜 i (g ∘ f) s x‖ = ‖iteratedFDerivWithin 𝕜 i f s x‖ := by have : iteratedFDerivWithin 𝕜 i (g ∘ f) s x = @@ -274,7 +274,7 @@ theorem LinearIsometry.norm_iteratedFDerivWithin_comp_left {f : E → F} (g : F /-- Composition with a linear isometry on the left preserves the norm of the iterated derivative. -/ theorem LinearIsometry.norm_iteratedFDeriv_comp_left {f : E → F} (g : F →ₗᵢ[𝕜] G) - (hf : ContDiff 𝕜 n f) (x : E) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hf : ContDiff 𝕜 n f) (x : E) {i : ℕ} (hi : i ≤ n) : ‖iteratedFDeriv 𝕜 i (g ∘ f) x‖ = ‖iteratedFDeriv 𝕜 i f x‖ := by simp only [← iteratedFDerivWithin_univ] exact g.norm_iteratedFDerivWithin_comp_left hf.contDiffOn uniqueDiffOn_univ (mem_univ x) hi @@ -326,8 +326,8 @@ theorem ContinuousLinearEquiv.comp_contDiff_iff (e : F ≃L[𝕜] G) : /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `f ∘ g` admits a Taylor series in `g ⁻¹' s`, whose `k`-th term is given by `p k (g v₁, ..., g vₖ)` . -/ -theorem HasFTaylorSeriesUpToOn.compContinuousLinearMap (hf : HasFTaylorSeriesUpToOn n f p s) - (g : G →L[𝕜] E) : +theorem HasFTaylorSeriesUpToOn.compContinuousLinearMap {n : WithTop ℕ∞} + (hf : HasFTaylorSeriesUpToOn n f p s) (g : G →L[𝕜] E) : HasFTaylorSeriesUpToOn n (f ∘ g) (fun x k => (p (g x) k).compContinuousLinearMap fun _ => g) (g ⁻¹' s) := by let A : ∀ m : ℕ, (E[×m]→L[𝕜] F) → G[×m]→L[𝕜] F := fun m h => h.compContinuousLinearMap fun _ => g @@ -372,11 +372,11 @@ theorem ContDiff.comp_continuousLinearMap {f : E → F} {g : G →L[𝕜] E} (hf obtained by composing the iterated derivative with the linear map. -/ theorem ContinuousLinearMap.iteratedFDerivWithin_comp_right {f : E → F} (g : G →L[𝕜] E) (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (h's : UniqueDiffOn 𝕜 (g ⁻¹' s)) {x : G} - (hx : g x ∈ s) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hx : g x ∈ s) {i : ℕ} (hi : i ≤ n) : iteratedFDerivWithin 𝕜 i (f ∘ g) (g ⁻¹' s) x = (iteratedFDerivWithin 𝕜 i f s (g x)).compContinuousLinearMap fun _ => g := (((hf.ftaylorSeriesWithin hs).compContinuousLinearMap g).eq_iteratedFDerivWithin_of_uniqueDiffOn - hi h's hx).symm + (mod_cast hi) h's hx).symm /-- The iterated derivative within a set of the composition with a linear equiv on the right is obtained by composing the iterated derivative with the linear equiv. -/ @@ -406,7 +406,7 @@ theorem ContinuousLinearEquiv.iteratedFDerivWithin_comp_right (g : G ≃L[𝕜] /-- The iterated derivative of the composition with a linear map on the right is obtained by composing the iterated derivative with the linear map. -/ theorem ContinuousLinearMap.iteratedFDeriv_comp_right (g : G →L[𝕜] E) {f : E → F} - (hf : ContDiff 𝕜 n f) (x : G) {i : ℕ} (hi : (i : ℕ∞) ≤ n) : + (hf : ContDiff 𝕜 n f) (x : G) {i : ℕ} (hi : i ≤ n) : iteratedFDeriv 𝕜 i (f ∘ g) x = (iteratedFDeriv 𝕜 i f (g x)).compContinuousLinearMap fun _ => g := by simp only [← iteratedFDerivWithin_univ] @@ -463,7 +463,8 @@ theorem ContinuousLinearEquiv.contDiff_comp_iff (e : G ≃L[𝕜] E) : /-- If two functions `f` and `g` admit Taylor series `p` and `q` in a set `s`, then the cartesian product of `f` and `g` admits the cartesian product of `p` and `q` as a Taylor series. -/ -theorem HasFTaylorSeriesUpToOn.prod (hf : HasFTaylorSeriesUpToOn n f p s) {g : E → G} +theorem HasFTaylorSeriesUpToOn.prod {n : WithTop ℕ∞} + (hf : HasFTaylorSeriesUpToOn n f p s) {g : E → G} {q : E → FormalMultilinearSeries 𝕜 E G} (hg : HasFTaylorSeriesUpToOn n g q s) : HasFTaylorSeriesUpToOn n (fun y => (f y, g y)) (fun y k => (p y k).prod (q y k)) s := by set L := fun m => ContinuousMultilinearMap.prodL 𝕜 (fun _ : Fin m => E) F G @@ -882,8 +883,8 @@ section ClmApplyConst /-- Application of a `ContinuousLinearMap` to a constant commutes with `iteratedFDerivWithin`. -/ theorem iteratedFDerivWithin_clm_apply_const_apply - {s : Set E} (hs : UniqueDiffOn 𝕜 s) {n : ℕ∞} {c : E → F →L[𝕜] G} (hc : ContDiffOn 𝕜 n c s) - {i : ℕ} (hi : i ≤ n) {x : E} (hx : x ∈ s) {u : F} {m : Fin i → E} : + {s : Set E} (hs : UniqueDiffOn 𝕜 s) {c : E → F →L[𝕜] G} + (hc : ContDiffOn 𝕜 n c s) {i : ℕ} (hi : i ≤ n) {x : E} (hx : x ∈ s) {u : F} {m : Fin i → E} : (iteratedFDerivWithin 𝕜 i (fun y ↦ (c y) u) s x) m = (iteratedFDerivWithin 𝕜 i c s x) m u := by induction i generalizing x with | zero => simp @@ -904,7 +905,7 @@ theorem iteratedFDerivWithin_clm_apply_const_apply /-- Application of a `ContinuousLinearMap` to a constant commutes with `iteratedFDeriv`. -/ theorem iteratedFDeriv_clm_apply_const_apply - {n : ℕ∞} {c : E → F →L[𝕜] G} (hc : ContDiff 𝕜 n c) + {c : E → F →L[𝕜] G} (hc : ContDiff 𝕜 n c) {i : ℕ} (hi : i ≤ n) {x : E} {u : F} {m : Fin i → E} : (iteratedFDeriv 𝕜 i (fun y ↦ (c y) u) x) m = (iteratedFDeriv 𝕜 i c x) m u := by simp only [← iteratedFDerivWithin_univ] @@ -976,7 +977,7 @@ To show that `x ↦ D_yf(x,y)g(x)` (taken within `t`) is `C^m` at `x₀` within * `g` is `C^m` at `x₀` within `s`; * Derivatives are unique at `g(x)` within `t` for `x` sufficiently close to `x₀` within `s ∪ {x₀}`; * `t` is a neighborhood of `g(x₀)` within `g '' s`; -/ -theorem ContDiffWithinAt.fderivWithin'' {f : E → F → G} {g : E → F} {t : Set F} {n : ℕ∞} +theorem ContDiffWithinAt.fderivWithin'' {f : E → F → G} {g : E → F} {t : Set F} (hf : ContDiffWithinAt 𝕜 n (Function.uncurry f) (insert x₀ s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 m g s x₀) (ht : ∀ᶠ x in 𝓝[insert x₀ s] x₀, UniqueDiffWithinAt 𝕜 t (g x)) (hmn : m + 1 ≤ n) @@ -989,14 +990,18 @@ theorem ContDiffWithinAt.fderivWithin'' {f : E → F → G} {g : E → F} {t : S refine hf'.congr_of_eventuallyEq_insert ?_ filter_upwards [hv, ht] exact fun y hy h2y => (hvf' y hy).fderivWithin h2y - induction' m with m - · obtain rfl := eq_top_iff.mpr hmn + match m with + | ω => + intro k hk + apply this k hk + exact le_rfl + | ∞ => rw [contDiffWithinAt_top] - exact fun m => this m le_top - exact this _ le_rfl + exact fun m => this m (mod_cast le_top) + | (m : ℕ) => exact this _ le_rfl /-- A special case of `ContDiffWithinAt.fderivWithin''` where we require that `s ⊆ g⁻¹(t)`. -/ -theorem ContDiffWithinAt.fderivWithin' {f : E → F → G} {g : E → F} {t : Set F} {n : ℕ∞} +theorem ContDiffWithinAt.fderivWithin' {f : E → F → G} {g : E → F} {t : Set F} (hf : ContDiffWithinAt 𝕜 n (Function.uncurry f) (insert x₀ s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 m g s x₀) (ht : ∀ᶠ x in 𝓝[insert x₀ s] x₀, UniqueDiffWithinAt 𝕜 t (g x)) (hmn : m + 1 ≤ n) @@ -1005,7 +1010,7 @@ theorem ContDiffWithinAt.fderivWithin' {f : E → F → G} {g : E → F} {t : Se /-- A special case of `ContDiffWithinAt.fderivWithin'` where we require that `x₀ ∈ s` and there are unique derivatives everywhere within `t`. -/ -protected theorem ContDiffWithinAt.fderivWithin {f : E → F → G} {g : E → F} {t : Set F} {n : ℕ∞} +protected theorem ContDiffWithinAt.fderivWithin {f : E → F → G} {g : E → F} {t : Set F} (hf : ContDiffWithinAt 𝕜 n (Function.uncurry f) (s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 m g s x₀) (ht : UniqueDiffOn 𝕜 t) (hmn : m + 1 ≤ n) (hx₀ : x₀ ∈ s) (hst : s ⊆ g ⁻¹' t) : ContDiffWithinAt 𝕜 m (fun x => fderivWithin 𝕜 (f x) t (g x)) s x₀ := by @@ -1015,7 +1020,7 @@ protected theorem ContDiffWithinAt.fderivWithin {f : E → F → G} {g : E → F exact eventually_of_mem self_mem_nhdsWithin fun x hx => ht _ (hst hx) /-- `x ↦ fderivWithin 𝕜 (f x) t (g x) (k x)` is smooth at a point within a set. -/ -theorem ContDiffWithinAt.fderivWithin_apply {f : E → F → G} {g k : E → F} {t : Set F} {n : ℕ∞} +theorem ContDiffWithinAt.fderivWithin_apply {f : E → F → G} {g k : E → F} {t : Set F} (hf : ContDiffWithinAt 𝕜 n (Function.uncurry f) (s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 m g s x₀) (hk : ContDiffWithinAt 𝕜 m k s x₀) (ht : UniqueDiffOn 𝕜 t) (hmn : m + 1 ≤ n) (hx₀ : x₀ ∈ s) (hst : s ⊆ g ⁻¹' t) : @@ -1025,7 +1030,7 @@ theorem ContDiffWithinAt.fderivWithin_apply {f : E → F → G} {g k : E → F} /-- `fderivWithin 𝕜 f s` is smooth at `x₀` within `s`. -/ theorem ContDiffWithinAt.fderivWithin_right (hf : ContDiffWithinAt 𝕜 n f s x₀) - (hs : UniqueDiffOn 𝕜 s) (hmn : (m + 1 : ℕ∞) ≤ n) (hx₀s : x₀ ∈ s) : + (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) (hx₀s : x₀ ∈ s) : ContDiffWithinAt 𝕜 m (fderivWithin 𝕜 f s) s x₀ := ContDiffWithinAt.fderivWithin (ContDiffWithinAt.comp (x₀, x₀) hf contDiffWithinAt_snd <| prod_subset_preimage_snd s s) @@ -1035,7 +1040,7 @@ theorem ContDiffWithinAt.fderivWithin_right (hf : ContDiffWithinAt 𝕜 n f s x theorem ContDiffWithinAt.fderivWithin_right_apply {f : F → G} {k : F → F} {s : Set F} {n : ℕ∞} {x₀ : F} (hf : ContDiffWithinAt 𝕜 n f s x₀) (hk : ContDiffWithinAt 𝕜 m k s x₀) - (hs : UniqueDiffOn 𝕜 s) (hmn : (m + 1 : ℕ∞) ≤ n) (hx₀s : x₀ ∈ s) : + (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) (hx₀s : x₀ ∈ s) : ContDiffWithinAt 𝕜 m (fun x => fderivWithin 𝕜 f s x (k x)) s x₀ := ContDiffWithinAt.fderivWithin_apply (ContDiffWithinAt.comp (x₀, x₀) hf contDiffWithinAt_snd <| prod_subset_preimage_snd s s) @@ -1043,10 +1048,10 @@ theorem ContDiffWithinAt.fderivWithin_right_apply -- TODO: can we make a version of `ContDiffWithinAt.fderivWithin` for iterated derivatives? theorem ContDiffWithinAt.iteratedFderivWithin_right {i : ℕ} (hf : ContDiffWithinAt 𝕜 n f s x₀) - (hs : UniqueDiffOn 𝕜 s) (hmn : (m + i : ℕ∞) ≤ n) (hx₀s : x₀ ∈ s) : + (hs : UniqueDiffOn 𝕜 s) (hmn : m + i ≤ n) (hx₀s : x₀ ∈ s) : ContDiffWithinAt 𝕜 m (iteratedFDerivWithin 𝕜 i f s) s x₀ := by induction' i with i hi generalizing m - · rw [ENat.coe_zero, add_zero] at hmn + · simp only [CharP.cast_eq_zero, add_zero] at hmn exact (hf.of_le hmn).continuousLinearMap_comp ((continuousMultilinearCurryFin0 𝕜 E F).symm : _ →L[𝕜] E [×0]→L[𝕜] F) · rw [Nat.cast_succ, add_comm _ 1, ← add_assoc] at hmn @@ -1055,7 +1060,7 @@ theorem ContDiffWithinAt.iteratedFderivWithin_right {i : ℕ} (hf : ContDiffWith _ →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 : ℕ∞} +protected theorem ContDiffAt.fderiv {f : E → F → G} {g : E → F} (hf : ContDiffAt 𝕜 n (Function.uncurry f) (x₀, g x₀)) (hg : ContDiffAt 𝕜 m g x₀) (hmn : m + 1 ≤ n) : ContDiffAt 𝕜 m (fun x => fderiv 𝕜 (f x) (g x)) x₀ := by simp_rw [← fderivWithin_univ] @@ -1064,44 +1069,44 @@ protected theorem ContDiffAt.fderiv {f : E → F → G} {g : E → F} {n : ℕ rw [preimage_univ] /-- `fderiv 𝕜 f` is smooth at `x₀`. -/ -theorem ContDiffAt.fderiv_right (hf : ContDiffAt 𝕜 n f x₀) (hmn : (m + 1 : ℕ∞) ≤ n) : +theorem ContDiffAt.fderiv_right (hf : ContDiffAt 𝕜 n f x₀) (hmn : m + 1 ≤ n) : ContDiffAt 𝕜 m (fderiv 𝕜 f) x₀ := ContDiffAt.fderiv (ContDiffAt.comp (x₀, x₀) hf contDiffAt_snd) contDiffAt_id hmn theorem ContDiffAt.iteratedFDeriv_right {i : ℕ} (hf : ContDiffAt 𝕜 n f x₀) - (hmn : (m + i : ℕ∞) ≤ n) : ContDiffAt 𝕜 m (iteratedFDeriv 𝕜 i f) x₀ := by + (hmn : m + i ≤ n) : ContDiffAt 𝕜 m (iteratedFDeriv 𝕜 i f) x₀ := by rw [← iteratedFDerivWithin_univ, ← contDiffWithinAt_univ] at * exact hf.iteratedFderivWithin_right uniqueDiffOn_univ hmn trivial /-- `x ↦ fderiv 𝕜 (f x) (g x)` is smooth. -/ -protected theorem ContDiff.fderiv {f : E → F → G} {g : E → F} {n m : ℕ∞} +protected theorem ContDiff.fderiv {f : E → F → G} {g : E → F} (hf : ContDiff 𝕜 m <| Function.uncurry f) (hg : ContDiff 𝕜 n g) (hnm : n + 1 ≤ m) : ContDiff 𝕜 n fun x => fderiv 𝕜 (f x) (g x) := contDiff_iff_contDiffAt.mpr fun _ => hf.contDiffAt.fderiv hg.contDiffAt hnm /-- `fderiv 𝕜 f` is smooth. -/ -theorem ContDiff.fderiv_right (hf : ContDiff 𝕜 n f) (hmn : (m + 1 : ℕ∞) ≤ n) : +theorem ContDiff.fderiv_right (hf : ContDiff 𝕜 n f) (hmn : m + 1 ≤ n) : ContDiff 𝕜 m (fderiv 𝕜 f) := contDiff_iff_contDiffAt.mpr fun _x => hf.contDiffAt.fderiv_right hmn theorem ContDiff.iteratedFDeriv_right {i : ℕ} (hf : ContDiff 𝕜 n f) - (hmn : (m + i : ℕ∞) ≤ n) : ContDiff 𝕜 m (iteratedFDeriv 𝕜 i f) := + (hmn : m + i ≤ n) : ContDiff 𝕜 m (iteratedFDeriv 𝕜 i f) := contDiff_iff_contDiffAt.mpr fun _x => hf.contDiffAt.iteratedFDeriv_right hmn /-- `x ↦ fderiv 𝕜 (f x) (g x)` is continuous. -/ -theorem Continuous.fderiv {f : E → F → G} {g : E → F} {n : ℕ∞} +theorem Continuous.fderiv {f : E → F → G} {g : E → F} (hf : ContDiff 𝕜 n <| Function.uncurry f) (hg : Continuous g) (hn : 1 ≤ n) : Continuous fun x => fderiv 𝕜 (f x) (g x) := (hf.fderiv (contDiff_zero.mpr hg) hn).continuous /-- `x ↦ fderiv 𝕜 (f x) (g x) (k x)` is smooth. -/ -theorem ContDiff.fderiv_apply {f : E → F → G} {g k : E → F} {n m : ℕ∞} +theorem ContDiff.fderiv_apply {f : E → F → G} {g k : E → F} (hf : ContDiff 𝕜 m <| Function.uncurry f) (hg : ContDiff 𝕜 n g) (hk : ContDiff 𝕜 n k) (hnm : n + 1 ≤ m) : ContDiff 𝕜 n fun x => fderiv 𝕜 (f x) (g x) (k x) := (hf.fderiv hg hnm).clm_apply hk /-- The bundled derivative of a `C^{n+1}` function is `C^n`. -/ -theorem contDiffOn_fderivWithin_apply {m n : ℕ∞} {s : Set E} {f : E → F} (hf : ContDiffOn 𝕜 n f s) +theorem contDiffOn_fderivWithin_apply {s : Set E} {f : E → F} (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (fun p : E × E => (fderivWithin 𝕜 f s p.1 : E →L[𝕜] F) p.2) (s ×ˢ univ) := ((hf.fderivWithin hs hmn).comp contDiffOn_fst (prod_subset_preimage_fst _ _)).clm_apply @@ -1131,7 +1136,7 @@ variable {ι ι' : Type*} [Fintype ι] [Fintype ι'] {F' : ι → Type*} [∀ i, [∀ i, NormedSpace 𝕜 (F' i)] {φ : ∀ i, E → F' i} {p' : ∀ i, E → FormalMultilinearSeries 𝕜 E (F' i)} {Φ : E → ∀ i, F' i} {P' : E → FormalMultilinearSeries 𝕜 E (∀ i, F' i)} -theorem hasFTaylorSeriesUpToOn_pi : +theorem hasFTaylorSeriesUpToOn_pi {n : WithTop ℕ∞} : HasFTaylorSeriesUpToOn n (fun x i => φ i x) (fun x m => ContinuousMultilinearMap.pi fun i => p' i x m) s ↔ ∀ i, HasFTaylorSeriesUpToOn n (φ i) (p' i) s := by @@ -1150,7 +1155,7 @@ theorem hasFTaylorSeriesUpToOn_pi : exact (L m).continuous.comp_continuousOn <| continuousOn_pi.2 fun i => (h i).cont m hm @[simp] -theorem hasFTaylorSeriesUpToOn_pi' : +theorem hasFTaylorSeriesUpToOn_pi' {n : WithTop ℕ∞} : HasFTaylorSeriesUpToOn n Φ P' s ↔ ∀ i, HasFTaylorSeriesUpToOn n (fun x => Φ x i) (fun x m => (@ContinuousLinearMap.proj 𝕜 _ ι F' _ _ _ i).compContinuousMultilinearMap @@ -1175,7 +1180,7 @@ theorem contDiffAt_pi : ContDiffAt 𝕜 n Φ x ↔ ∀ i, ContDiffAt 𝕜 n (fun theorem contDiff_pi : ContDiff 𝕜 n Φ ↔ ∀ i, ContDiff 𝕜 n fun x => Φ x i := by simp only [← contDiffOn_univ, contDiffOn_pi] -theorem contDiff_update [DecidableEq ι] (k : ℕ∞) (x : ∀ i, F' i) (i : ι) : +theorem contDiff_update [DecidableEq ι] (k : WithTop ℕ∞) (x : ∀ i, F' i) (i : ι) : ContDiff 𝕜 k (update x i) := by rw [contDiff_pi] intro j @@ -1186,7 +1191,7 @@ theorem contDiff_update [DecidableEq ι] (k : ℕ∞) (x : ∀ i, F' i) (i : ι) · exact contDiff_const variable (F') in -theorem contDiff_single [DecidableEq ι] (k : ℕ∞) (i : ι) : +theorem contDiff_single [DecidableEq ι] (k : WithTop ℕ∞) (i : ι) : ContDiff 𝕜 k (Pi.single i : F' i → ∀ i, F' i) := contDiff_update k 0 i @@ -1204,9 +1209,9 @@ end Pi section Add -theorem HasFTaylorSeriesUpToOn.add {q g} (hf : HasFTaylorSeriesUpToOn n f p s) +theorem HasFTaylorSeriesUpToOn.add {n : WithTop ℕ∞} {q g} (hf : HasFTaylorSeriesUpToOn n f p s) (hg : HasFTaylorSeriesUpToOn n g q s) : HasFTaylorSeriesUpToOn n (f + g) (p + q) s := by - convert HasFTaylorSeriesUpToOn.continuousLinearMap_comp + exact HasFTaylorSeriesUpToOn.continuousLinearMap_comp (ContinuousLinearMap.fst 𝕜 F F + .snd 𝕜 F F) (hf.prod hg) -- The sum is smooth. @@ -1636,17 +1641,22 @@ invertible element. The proof is by induction, bootstrapping using an identity derivative of inversion as a bilinear map of inversion itself. -/ theorem contDiffAt_ring_inverse [CompleteSpace R] (x : Rˣ) : ContDiffAt 𝕜 n Ring.inverse (x : R) := by + suffices H : ∀ (n : ℕ∞), ContDiffAt 𝕜 n Ring.inverse (x : R) by + intro k hk + exact H ⊤ k (mod_cast le_top) + intro n induction' n using ENat.nat_induction with n IH Itop · intro m hm refine ⟨{ y : R | IsUnit y }, ?_, ?_⟩ · simpa [nhdsWithin_univ] using x.nhds · use ftaylorSeriesWithin 𝕜 inverse univ - rw [le_antisymm hm bot_le, hasFTaylorSeriesUpToOn_zero_iff] + have : (m : WithTop ℕ∞) = 0 := by exact_mod_cast le_antisymm hm bot_le + rw [this, hasFTaylorSeriesUpToOn_zero_iff] constructor · rintro _ ⟨x', rfl⟩ exact (inverse_continuousAt x').continuousWithinAt · simp [ftaylorSeriesWithin] - · rw [contDiffAt_succ_iff_hasFDerivAt] + · rw [show ((n.succ : ℕ∞) : WithTop ℕ∞) = n + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] refine ⟨fun x : R => -mulLeftRight 𝕜 R (inverse x) (inverse x), ?_, ?_⟩ · refine ⟨{ y : R | IsUnit y }, x.nhds, ?_⟩ rintro _ ⟨y, rfl⟩ @@ -1669,36 +1679,36 @@ variable {𝕜} -- TODO: the next few lemmas don't need `𝕜` or `𝕜'` to be complete -- A good way to show this is to generalize `contDiffAt_ring_inverse` to the setting -- of a function `f` such that `∀ᶠ x in 𝓝 a, x * f x = 1`. -theorem ContDiffWithinAt.inv {f : E → 𝕜'} {n} (hf : ContDiffWithinAt 𝕜 n f s x) (hx : f x ≠ 0) : +theorem ContDiffWithinAt.inv {f : E → 𝕜'} (hf : ContDiffWithinAt 𝕜 n f s x) (hx : f x ≠ 0) : ContDiffWithinAt 𝕜 n (fun x => (f x)⁻¹) s x := (contDiffAt_inv 𝕜 hx).comp_contDiffWithinAt x hf -theorem ContDiffOn.inv {f : E → 𝕜'} {n} (hf : ContDiffOn 𝕜 n f s) (h : ∀ x ∈ s, f x ≠ 0) : +theorem ContDiffOn.inv {f : E → 𝕜'} (hf : ContDiffOn 𝕜 n f s) (h : ∀ x ∈ s, f x ≠ 0) : ContDiffOn 𝕜 n (fun x => (f x)⁻¹) s := fun x hx => (hf.contDiffWithinAt hx).inv (h x hx) -nonrec theorem ContDiffAt.inv {f : E → 𝕜'} {n} (hf : ContDiffAt 𝕜 n f x) (hx : f x ≠ 0) : +nonrec theorem ContDiffAt.inv {f : E → 𝕜'} (hf : ContDiffAt 𝕜 n f x) (hx : f x ≠ 0) : ContDiffAt 𝕜 n (fun x => (f x)⁻¹) x := hf.inv hx -theorem ContDiff.inv {f : E → 𝕜'} {n} (hf : ContDiff 𝕜 n f) (h : ∀ x, f x ≠ 0) : +theorem ContDiff.inv {f : E → 𝕜'} (hf : ContDiff 𝕜 n f) (h : ∀ x, f x ≠ 0) : ContDiff 𝕜 n fun x => (f x)⁻¹ := by rw [contDiff_iff_contDiffAt]; exact fun x => hf.contDiffAt.inv (h x) -- TODO: generalize to `f g : E → 𝕜'` -theorem ContDiffWithinAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} {n} (hf : ContDiffWithinAt 𝕜 n f s x) +theorem ContDiffWithinAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffWithinAt 𝕜 n f s x) (hg : ContDiffWithinAt 𝕜 n g s x) (hx : g x ≠ 0) : ContDiffWithinAt 𝕜 n (fun x => f x / g x) s x := by simpa only [div_eq_mul_inv] using hf.mul (hg.inv hx) -theorem ContDiffOn.div [CompleteSpace 𝕜] {f g : E → 𝕜} {n} (hf : ContDiffOn 𝕜 n f s) +theorem ContDiffOn.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffOn 𝕜 n f s) (hg : ContDiffOn 𝕜 n g s) (h₀ : ∀ x ∈ s, g x ≠ 0) : ContDiffOn 𝕜 n (f / g) s := fun x hx => (hf x hx).div (hg x hx) (h₀ x hx) -nonrec theorem ContDiffAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} {n} (hf : ContDiffAt 𝕜 n f x) +nonrec theorem ContDiffAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffAt 𝕜 n f x) (hg : ContDiffAt 𝕜 n g x) (hx : g x ≠ 0) : ContDiffAt 𝕜 n (fun x => f x / g x) x := hf.div hg hx -theorem ContDiff.div [CompleteSpace 𝕜] {f g : E → 𝕜} {n} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) +theorem ContDiff.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) (h0 : ∀ x, g x ≠ 0) : ContDiff 𝕜 n fun x => f x / g x := by simp only [contDiff_iff_contDiffAt] at * exact fun x => (hf x).div (hg x) (h0 x) @@ -1736,23 +1746,17 @@ section FunctionInverse open ContinuousLinearMap -/-- If `f` is a local homeomorphism and the point `a` is in its target, -and if `f` is `n` times continuously differentiable at `f.symm a`, -and if the derivative at `f.symm a` is a continuous linear equivalence, -then `f.symm` is `n` times continuously differentiable at the point `a`. - -This is one of the easy parts of the inverse function theorem: it assumes that we already have -an inverse function. -/ -theorem PartialHomeomorph.contDiffAt_symm [CompleteSpace E] (f : PartialHomeomorph E F) +private theorem PartialHomeomorph.contDiffAt_symm_aux {n : ℕ∞} + [CompleteSpace E] (f : PartialHomeomorph E F) {f₀' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) (hf₀' : HasFDerivAt f (f₀' : E →L[𝕜] F) (f.symm a)) (hf : ContDiffAt 𝕜 n f (f.symm a)) : ContDiffAt 𝕜 n f.symm a := by - -- We prove this by induction on `n` + -- We prove this by induction on `n` induction' n using ENat.nat_induction with n IH Itop - · rw [contDiffAt_zero] + · apply contDiffAt_zero.2 exact ⟨f.target, IsOpen.mem_nhds f.open_target ha, f.continuousOn_invFun⟩ · obtain ⟨f', ⟨u, hu, hff'⟩, hf'⟩ := contDiffAt_succ_iff_hasFDerivAt.mp hf - rw [contDiffAt_succ_iff_hasFDerivAt] + rw [show ((n.succ : ℕ∞) : WithTop ℕ∞) = n + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] -- For showing `n.succ` times continuous differentiability (the main inductive step), it -- suffices to produce the derivative and show that it is `n` times continuously differentiable have eq_f₀' : f' (f.symm a) = f₀' := (hff' (f.symm a) (mem_of_mem_nhds hu)).unique hf₀' @@ -1789,6 +1793,24 @@ theorem PartialHomeomorph.contDiffAt_symm [CompleteSpace E] (f : PartialHomeomor intro n exact Itop n (contDiffAt_top.mp hf n) +/-- If `f` is a local homeomorphism and the point `a` is in its target, +and if `f` is `n` times continuously differentiable at `f.symm a`, +and if the derivative at `f.symm a` is a continuous linear equivalence, +then `f.symm` is `n` times continuously differentiable at the point `a`. + +This is one of the easy parts of the inverse function theorem: it assumes that we already have +an inverse function. -/ +theorem PartialHomeomorph.contDiffAt_symm [CompleteSpace E] (f : PartialHomeomorph E F) + {f₀' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) + (hf₀' : HasFDerivAt f (f₀' : E →L[𝕜] F) (f.symm a)) (hf : ContDiffAt 𝕜 n f (f.symm a)) : + ContDiffAt 𝕜 n f.symm a := by + match n with + | ω => + intro k hk + exact f.contDiffAt_symm_aux ha hf₀' (hf.of_le (m := k) le_top) k le_rfl + | (n : ℕ∞) => + exact f.contDiffAt_symm_aux ha hf₀' hf + /-- If `f` is an `n` times continuously differentiable homeomorphism, and if the derivative of `f` at each point is a continuous linear equivalence, then `f.symm` is `n` times continuously differentiable. @@ -1871,7 +1893,7 @@ open ContinuousLinearMap (smulRight) /-- A function is `C^(n + 1)` on a domain with unique derivatives if and only if it is differentiable there, and its derivative (formulated with `derivWithin`) is `C^n`. -/ theorem contDiffOn_succ_iff_derivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s₂) : - ContDiffOn 𝕜 (n + 1 : ℕ) f₂ s₂ ↔ + ContDiffOn 𝕜 (n + 1) f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 n (derivWithin f₂ s₂) s₂ := by rw [contDiffOn_succ_iff_fderivWithin hs, and_congr_right_iff] intro _ @@ -1893,7 +1915,7 @@ theorem contDiffOn_succ_iff_derivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s₂) /-- A function is `C^(n + 1)` on an open domain if and only if it is differentiable there, and its derivative (formulated with `deriv`) is `C^n`. -/ theorem contDiffOn_succ_iff_deriv_of_isOpen {n : ℕ} (hs : IsOpen s₂) : - ContDiffOn 𝕜 (n + 1 : ℕ) f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 n (deriv f₂) s₂ := by + ContDiffOn 𝕜 (n + 1) f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 n (deriv f₂) s₂ := by rw [contDiffOn_succ_iff_derivWithin hs.uniqueDiffOn] exact Iff.rfl.and (contDiffOn_congr fun _ => derivWithin_of_isOpen hs) @@ -1903,14 +1925,14 @@ theorem contDiffOn_top_iff_derivWithin (hs : UniqueDiffOn 𝕜 s₂) : ContDiffOn 𝕜 ∞ f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 ∞ (derivWithin f₂ s₂) s₂ := by constructor · intro h - refine ⟨h.differentiableOn le_top, ?_⟩ + refine ⟨h.differentiableOn (mod_cast le_top), ?_⟩ refine contDiffOn_top.2 fun n => ((contDiffOn_succ_iff_derivWithin hs).1 ?_).2 - exact h.of_le le_top + exact h.of_le (mod_cast le_top) · intro h refine contDiffOn_top.2 fun n => ?_ - have A : (n : ℕ∞) ≤ ∞ := le_top + have A : (n : ℕ∞) ≤ ∞ := mod_cast le_top apply ((contDiffOn_succ_iff_derivWithin hs).2 ⟨h.1, h.2.of_le A⟩).of_le - exact WithTop.coe_le_coe.2 (Nat.le_succ n) + exact_mod_cast (Nat.le_succ n) /-- A function is `C^∞` on an open domain if and only if it is differentiable there, and its derivative (formulated with `deriv`) is `C^∞`. -/ @@ -1921,13 +1943,17 @@ theorem contDiffOn_top_iff_deriv_of_isOpen (hs : IsOpen s₂) : protected theorem ContDiffOn.derivWithin (hf : ContDiffOn 𝕜 n f₂ s₂) (hs : UniqueDiffOn 𝕜 s₂) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (derivWithin f₂ s₂) s₂ := by - cases m - · change ∞ + 1 ≤ n at hmn - have : n = ∞ := by simpa using hmn - rw [this] at hf - exact ((contDiffOn_top_iff_derivWithin hs).1 hf).2 - · change (Nat.succ _ : ℕ∞) ≤ n at hmn - exact ((contDiffOn_succ_iff_derivWithin hs).1 (hf.of_le hmn)).2 + rcases le_or_lt ∞ n with hn | hn + · have : ContDiffOn 𝕜 ∞ (derivWithin f₂ s₂) s₂ := + ((contDiffOn_top_iff_derivWithin hs).1 (hf.of_le hn)).2 + intro x hx k hk + exact this x hx k (mod_cast le_top) + · match m with + | ω => simpa using hmn.trans_lt hn + | ∞ => simpa using hmn.trans_lt hn + | (m : ℕ) => + change (m.succ : ℕ∞) ≤ n at hmn + exact ((contDiffOn_succ_iff_derivWithin hs).1 (hf.of_le hmn)).2 theorem ContDiffOn.deriv_of_isOpen (hf : ContDiffOn 𝕜 n f₂ s₂) (hs : IsOpen s₂) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (deriv f₂) s₂ := @@ -1944,7 +1970,7 @@ theorem ContDiffOn.continuousOn_deriv_of_isOpen (h : ContDiffOn 𝕜 n f₂ s₂ /-- A function is `C^(n + 1)` if and only if it is differentiable, and its derivative (formulated in terms of `deriv`) is `C^n`. -/ theorem contDiff_succ_iff_deriv {n : ℕ} : - ContDiff 𝕜 (n + 1 : ℕ) f₂ ↔ Differentiable 𝕜 f₂ ∧ ContDiff 𝕜 n (deriv f₂) := by + ContDiff 𝕜 (n + 1) f₂ ↔ Differentiable 𝕜 f₂ ∧ ContDiff 𝕜 n (deriv f₂) := by simp only [← contDiffOn_univ, contDiffOn_succ_iff_deriv_of_isOpen, isOpen_univ, differentiableOn_univ] @@ -1992,7 +2018,8 @@ variable [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] variable [NormedSpace 𝕜' F] [IsScalarTower 𝕜 𝕜' F] variable {p' : E → FormalMultilinearSeries 𝕜' E F} -theorem HasFTaylorSeriesUpToOn.restrictScalars (h : HasFTaylorSeriesUpToOn n f p' s) : +theorem HasFTaylorSeriesUpToOn.restrictScalars {n : WithTop ℕ∞} + (h : HasFTaylorSeriesUpToOn n f p' s) : HasFTaylorSeriesUpToOn n f (fun x => (p' x).restrictScalars 𝕜) s where zero_eq x hx := h.zero_eq x hx fderivWithin m hm x hx := by @@ -2017,4 +2044,4 @@ theorem ContDiff.restrict_scalars (h : ContDiff 𝕜' n f) : ContDiff 𝕜 n f : end RestrictScalars -set_option linter.style.longFile 2100 +set_option linter.style.longFile 2200 diff --git a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean index 3d7d145291bee8..fe52bff69b40dc 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean @@ -53,7 +53,7 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_aux {Du Eu · 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] + · have In : (n : WithTop ℕ∞) + 1 ≤ n.succ := by simp only [Nat.cast_succ, le_refl] -- Porting note: the next line is a hack allowing Lean to find the operator norm instance. let norm := @ContinuousLinearMap.hasOpNorm _ _ Eu ((Du →L[𝕜] Fu) →L[𝕜] Du →L[𝕜] Gu) _ _ _ _ _ _ (RingHom.id 𝕜) @@ -101,7 +101,7 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_aux {Du Eu iteratedFDerivWithin 𝕜 n (fun y => B.precompR Du (f y) (fderivWithin 𝕜 g s y) + B.precompL Du (fderivWithin 𝕜 f s y) (g y)) s x := by apply iteratedFDerivWithin_congr (fun y hy => ?_) hx - have L : (1 : ℕ∞) ≤ n.succ := by + have L : (1 : WithTop ℕ∞) ≤ n.succ := by simpa only [ENat.coe_one, Nat.one_le_cast] using Nat.succ_pos n exact B.fderivWithin_of_bilinear (hf.differentiableOn L y hy) (hg.differentiableOn L y hy) (hs y hy) @@ -123,8 +123,8 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_aux {Du Eu iterated derivatives of `f` and `g` when `B` is bilinear: `‖D^n (x ↦ B (f x) (g x))‖ ≤ ‖B‖ ∑_{k ≤ n} n.choose k ‖D^k f‖ ‖D^{n-k} g‖` -/ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear (B : E →L[𝕜] F →L[𝕜] G) - {f : D → E} {g : D → F} {N : ℕ∞} {s : Set D} {x : D} (hf : ContDiffOn 𝕜 N f s) - (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (hn : (n : ℕ∞) ≤ N) : + {f : D → E} {g : D → F} {N : WithTop ℕ∞} {s : Set D} {x : D} (hf : ContDiffOn 𝕜 N f s) + (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (hn : n ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y => B (f y) (g y)) s x‖ ≤ ‖B‖ * ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDerivWithin 𝕜 i f s x‖ * ‖iteratedFDerivWithin 𝕜 (n - i) g s x‖ := by @@ -205,8 +205,8 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear (B : E →L iterated derivatives of `f` and `g` when `B` is bilinear: `‖D^n (x ↦ B (f x) (g x))‖ ≤ ‖B‖ ∑_{k ≤ n} n.choose k ‖D^k f‖ ‖D^{n-k} g‖` -/ theorem ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear (B : E →L[𝕜] F →L[𝕜] G) {f : D → E} - {g : D → F} {N : ℕ∞} (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) (x : D) {n : ℕ} - (hn : (n : ℕ∞) ≤ N) : + {g : D → F} {N : WithTop ℕ∞} (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) (x : D) {n : ℕ} + (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (fun y => B (f y) (g y)) x‖ ≤ ‖B‖ * ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDeriv 𝕜 i f x‖ * ‖iteratedFDeriv 𝕜 (n - i) g x‖ := by simp_rw [← iteratedFDerivWithin_univ] @@ -217,9 +217,9 @@ theorem ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear (B : E →L[𝕜] iterated derivatives of `f` and `g` when `B` is bilinear of norm at most `1`: `‖D^n (x ↦ B (f x) (g x))‖ ≤ ∑_{k ≤ n} n.choose k ‖D^k f‖ ‖D^{n-k} g‖` -/ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_of_le_one - (B : E →L[𝕜] F →L[𝕜] G) {f : D → E} {g : D → F} {N : ℕ∞} {s : Set D} {x : D} + (B : E →L[𝕜] F →L[𝕜] G) {f : D → E} {g : D → F} {N : WithTop ℕ∞} {s : Set D} {x : D} (hf : ContDiffOn 𝕜 N f s) (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} - (hn : (n : ℕ∞) ≤ N) (hB : ‖B‖ ≤ 1) : ‖iteratedFDerivWithin 𝕜 n (fun y => B (f y) (g y)) s x‖ ≤ + (hn : n ≤ N) (hB : ‖B‖ ≤ 1) : ‖iteratedFDerivWithin 𝕜 n (fun y => B (f y) (g y)) s x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDerivWithin 𝕜 i f s x‖ * ‖iteratedFDerivWithin 𝕜 (n - i) g s x‖ := by apply (B.norm_iteratedFDerivWithin_le_of_bilinear hf hg hs hx hn).trans @@ -229,8 +229,9 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_of_le_one iterated derivatives of `f` and `g` when `B` is bilinear of norm at most `1`: `‖D^n (x ↦ B (f x) (g x))‖ ≤ ∑_{k ≤ n} n.choose k ‖D^k f‖ ‖D^{n-k} g‖` -/ theorem ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear_of_le_one (B : E →L[𝕜] F →L[𝕜] G) - {f : D → E} {g : D → F} {N : ℕ∞} (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) (x : D) {n : ℕ} - (hn : (n : ℕ∞) ≤ N) (hB : ‖B‖ ≤ 1) : ‖iteratedFDeriv 𝕜 n (fun y => B (f y) (g y)) x‖ ≤ + {f : D → E} {g : D → F} {N : WithTop ℕ∞} (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) + (x : D) {n : ℕ} (hn : n ≤ N) (hB : ‖B‖ ≤ 1) : + ‖iteratedFDeriv 𝕜 n (fun y => B (f y) (g y)) x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDeriv 𝕜 i f x‖ * ‖iteratedFDeriv 𝕜 (n - i) g x‖ := by simp_rw [← iteratedFDerivWithin_univ] @@ -242,17 +243,17 @@ section variable {𝕜' : Type*} [NormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] [NormedSpace 𝕜' F] [IsScalarTower 𝕜 𝕜' F] -theorem norm_iteratedFDerivWithin_smul_le {f : E → 𝕜'} {g : E → F} {N : ℕ∞} +theorem norm_iteratedFDerivWithin_smul_le {f : E → 𝕜'} {g : E → F} {N : WithTop ℕ∞} (hf : ContDiffOn 𝕜 N f s) (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) {x : E} (hx : x ∈ s) - {n : ℕ} (hn : (n : ℕ∞) ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y => f y • g y) s x‖ ≤ + {n : ℕ} (hn : n ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y => f y • g y) s x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDerivWithin 𝕜 i f s x‖ * ‖iteratedFDerivWithin 𝕜 (n - i) g s x‖ := (ContinuousLinearMap.lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] F →L[𝕜] F).norm_iteratedFDerivWithin_le_of_bilinear_of_le_one hf hg hs hx hn ContinuousLinearMap.opNorm_lsmul_le -theorem norm_iteratedFDeriv_smul_le {f : E → 𝕜'} {g : E → F} {N : ℕ∞} (hf : ContDiff 𝕜 N f) - (hg : ContDiff 𝕜 N g) (x : E) {n : ℕ} (hn : (n : ℕ∞) ≤ N) : +theorem norm_iteratedFDeriv_smul_le {f : E → 𝕜'} {g : E → F} {N : WithTop ℕ∞} (hf : ContDiff 𝕜 N f) + (hg : ContDiff 𝕜 N g) (x : E) {n : ℕ} (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (fun y => f y • g y) x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDeriv 𝕜 i f x‖ * ‖iteratedFDeriv 𝕜 (n - i) g x‖ := (ContinuousLinearMap.lsmul 𝕜 𝕜' : 𝕜' →L[𝕜] F →L[𝕜] F).norm_iteratedFDeriv_le_of_bilinear_of_le_one @@ -265,17 +266,18 @@ section variable {ι : Type*} {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A] {A' : Type*} [NormedCommRing A'] [NormedAlgebra 𝕜 A'] -theorem norm_iteratedFDerivWithin_mul_le {f : E → A} {g : E → A} {N : ℕ∞} (hf : ContDiffOn 𝕜 N f s) - (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) {x : E} (hx : x ∈ s) {n : ℕ} - (hn : (n : ℕ∞) ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y => f y * g y) s x‖ ≤ +theorem norm_iteratedFDerivWithin_mul_le {f : E → A} {g : E → A} {N : WithTop ℕ∞} + (hf : ContDiffOn 𝕜 N f s) (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) + {x : E} (hx : x ∈ s) {n : ℕ} (hn : n ≤ N) : + ‖iteratedFDerivWithin 𝕜 n (fun y => f y * g y) s x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDerivWithin 𝕜 i f s x‖ * ‖iteratedFDerivWithin 𝕜 (n - i) g s x‖ := (ContinuousLinearMap.mul 𝕜 A : A →L[𝕜] A →L[𝕜] A).norm_iteratedFDerivWithin_le_of_bilinear_of_le_one hf hg hs hx hn (ContinuousLinearMap.opNorm_mul_le _ _) -theorem norm_iteratedFDeriv_mul_le {f : E → A} {g : E → A} {N : ℕ∞} (hf : ContDiff 𝕜 N f) - (hg : ContDiff 𝕜 N g) (x : E) {n : ℕ} (hn : (n : ℕ∞) ≤ N) : +theorem norm_iteratedFDeriv_mul_le {f : E → A} {g : E → A} {N : WithTop ℕ∞} (hf : ContDiff 𝕜 N f) + (hg : ContDiff 𝕜 N g) (x : E) {n : ℕ} (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (fun y => f y * g y) x‖ ≤ ∑ i ∈ Finset.range (n + 1), (n.choose i : ℝ) * ‖iteratedFDeriv 𝕜 i f x‖ * ‖iteratedFDeriv 𝕜 (n - i) g x‖ := by simp_rw [← iteratedFDerivWithin_univ] @@ -285,8 +287,8 @@ theorem norm_iteratedFDeriv_mul_le {f : E → A} {g : E → A} {N : ℕ∞} (hf -- TODO: Add `norm_iteratedFDeriv[Within]_list_prod_le` for non-commutative `NormedRing A`. theorem norm_iteratedFDerivWithin_prod_le [DecidableEq ι] [NormOneClass A'] {u : Finset ι} - {f : ι → E → A'} {N : ℕ∞} (hf : ∀ i ∈ u, ContDiffOn 𝕜 N (f i) s) (hs : UniqueDiffOn 𝕜 s) {x : E} - (hx : x ∈ s) {n : ℕ} (hn : (n : ℕ∞) ≤ N) : + {f : ι → E → A'} {N : WithTop ℕ∞} (hf : ∀ i ∈ u, ContDiffOn 𝕜 N (f i) s) + (hs : UniqueDiffOn 𝕜 s) {x : E} (hx : x ∈ s) {n : ℕ} (hn : n ≤ N) : ‖iteratedFDerivWithin 𝕜 n (∏ j ∈ u, f j ·) s x‖ ≤ ∑ p ∈ u.sym n, (p : Multiset ι).multinomial * ∏ j ∈ u, ‖iteratedFDerivWithin 𝕜 (Multiset.count j p) (f j) s x‖ := by @@ -309,7 +311,7 @@ theorem norm_iteratedFDerivWithin_prod_le [DecidableEq ι] [NormOneClass A'] {u simp only [comp_apply, Finset.symInsertEquiv_symm_apply_coe] refine Finset.sum_le_sum ?_ intro m _ - specialize IH hf.2 (n := n - m) (le_trans (WithTop.coe_le_coe.mpr (n.sub_le m)) hn) + specialize IH hf.2 (n := n - m) (le_trans (by exact_mod_cast n.sub_le m) hn) refine le_trans (mul_le_mul_of_nonneg_left IH (by simp [mul_nonneg])) ?_ rw [Finset.mul_sum, ← Finset.sum_coe_sort] refine Finset.sum_le_sum ?_ @@ -329,8 +331,8 @@ theorem norm_iteratedFDerivWithin_prod_le [DecidableEq ι] [NormOneClass A'] {u rw [Sym.count_coe_fill_of_ne hji] theorem norm_iteratedFDeriv_prod_le [DecidableEq ι] [NormOneClass A'] {u : Finset ι} - {f : ι → E → A'} {N : ℕ∞} (hf : ∀ i ∈ u, ContDiff 𝕜 N (f i)) {x : E} {n : ℕ} - (hn : (n : ℕ∞) ≤ N) : + {f : ι → E → A'} {N : WithTop ℕ∞} (hf : ∀ i ∈ u, ContDiff 𝕜 N (f i)) {x : E} {n : ℕ} + (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (∏ j ∈ u, f j ·) x‖ ≤ ∑ p ∈ u.sym n, (p : Multiset ι).multinomial * ∏ j ∈ u, ‖iteratedFDeriv 𝕜 ((p : Multiset ι).count j) (f j) x‖ := by @@ -362,7 +364,7 @@ theorem norm_iteratedFDerivWithin_comp_le_aux {Fu Gu : Type u} [NormedAddCommGro induction' n using Nat.case_strong_induction_on with n IH generalizing Gu · simpa [norm_iteratedFDerivWithin_zero, Nat.factorial_zero, algebraMap.coe_one, one_mul, pow_zero, mul_one, comp_apply] using hC 0 le_rfl - have M : (n : ℕ∞) < n.succ := Nat.cast_lt.2 n.lt_succ_self + have M : (n : WithTop ℕ∞) < n.succ := Nat.cast_lt.2 n.lt_succ_self have Cnonneg : 0 ≤ C := (norm_nonneg _).trans (hC 0 bot_le) have Dnonneg : 0 ≤ D := by have : 1 ≤ n + 1 := by simp only [le_add_iff_nonneg_left, zero_le'] @@ -404,7 +406,8 @@ theorem norm_iteratedFDerivWithin_comp_le_aux {Fu Gu : Type u} [NormedAddCommGro LinearIsometryEquiv.norm_map] _ = ‖iteratedFDerivWithin 𝕜 n (fun y : E => ContinuousLinearMap.compL 𝕜 E Fu Gu (fderivWithin 𝕜 g t (f y)) (fderivWithin 𝕜 f s y)) s x‖ := by - have L : (1 : ℕ∞) ≤ n.succ := by simpa only [ENat.coe_one, Nat.one_le_cast] using n.succ_pos + have L : (1 : WithTop ℕ∞) ≤ n.succ := by + simpa only [ENat.coe_one, Nat.one_le_cast] using n.succ_pos congr 1 refine iteratedFDerivWithin_congr (fun y hy => ?_) hx _ apply fderivWithin_comp _ _ _ hst (hs y hy) @@ -459,7 +462,7 @@ theorem norm_iteratedFDerivWithin_comp_le_aux {Fu Gu : Type u} [NormedAddCommGro within a set of `f` at `x` is bounded by `D^i` for all `1 ≤ i ≤ n`, then the `n`-th derivative of `g ∘ f` is bounded by `n! * C * D^n`. -/ theorem norm_iteratedFDerivWithin_comp_le {g : F → G} {f : E → F} {n : ℕ} {s : Set E} {t : Set F} - {x : E} {N : ℕ∞} (hg : ContDiffOn 𝕜 N g t) (hf : ContDiffOn 𝕜 N f s) (hn : (n : ℕ∞) ≤ N) + {x : E} {N : WithTop ℕ∞} (hg : ContDiffOn 𝕜 N g t) (hf : ContDiffOn 𝕜 N f s) (hn : n ≤ N) (ht : UniqueDiffOn 𝕜 t) (hs : UniqueDiffOn 𝕜 s) (hst : MapsTo f s t) (hx : x ∈ s) {C : ℝ} {D : ℝ} (hC : ∀ i, i ≤ n → ‖iteratedFDerivWithin 𝕜 i g t (f x)‖ ≤ C) (hD : ∀ i, 1 ≤ i → i ≤ n → ‖iteratedFDerivWithin 𝕜 i f s x‖ ≤ D ^ i) : @@ -509,8 +512,8 @@ theorem norm_iteratedFDerivWithin_comp_le {g : F → G} {f : E → F} {n : ℕ} /-- If the derivatives of `g` at `f x` are bounded by `C`, and the `i`-th derivative of `f` at `x` is bounded by `D^i` for all `1 ≤ i ≤ n`, then the `n`-th derivative of `g ∘ f` is bounded by `n! * C * D^n`. -/ -theorem norm_iteratedFDeriv_comp_le {g : F → G} {f : E → F} {n : ℕ} {N : ℕ∞} (hg : ContDiff 𝕜 N g) - (hf : ContDiff 𝕜 N f) (hn : (n : ℕ∞) ≤ N) (x : E) {C : ℝ} {D : ℝ} +theorem norm_iteratedFDeriv_comp_le {g : F → G} {f : E → F} {n : ℕ} {N : WithTop ℕ∞} + (hg : ContDiff 𝕜 N g) (hf : ContDiff 𝕜 N f) (hn : n ≤ N) (x : E) {C : ℝ} {D : ℝ} (hC : ∀ i, i ≤ n → ‖iteratedFDeriv 𝕜 i g (f x)‖ ≤ C) (hD : ∀ i, 1 ≤ i → i ≤ n → ‖iteratedFDeriv 𝕜 i f x‖ ≤ D ^ i) : ‖iteratedFDeriv 𝕜 n (g ∘ f) x‖ ≤ n ! * C * D ^ n := by @@ -521,8 +524,9 @@ theorem norm_iteratedFDeriv_comp_le {g : F → G} {f : E → F} {n : ℕ} {N : section Apply theorem norm_iteratedFDerivWithin_clm_apply {f : E → F →L[𝕜] G} {g : E → F} {s : Set E} {x : E} - {N : ℕ∞} {n : ℕ} (hf : ContDiffOn 𝕜 N f s) (hg : ContDiffOn 𝕜 N g s) (hs : UniqueDiffOn 𝕜 s) - (hx : x ∈ s) (hn : ↑n ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y => (f y) (g y)) s x‖ ≤ + {N : WithTop ℕ∞} {n : ℕ} (hf : ContDiffOn 𝕜 N f s) (hg : ContDiffOn 𝕜 N g s) + (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) (hn : n ≤ N) : + ‖iteratedFDerivWithin 𝕜 n (fun y => (f y) (g y)) s x‖ ≤ ∑ i ∈ Finset.range (n + 1), ↑(n.choose i) * ‖iteratedFDerivWithin 𝕜 i f s x‖ * ‖iteratedFDerivWithin 𝕜 (n - i) g s x‖ := by let B : (F →L[𝕜] G) →L[𝕜] F →L[𝕜] G := ContinuousLinearMap.flip (ContinuousLinearMap.apply 𝕜 G) @@ -533,8 +537,8 @@ theorem norm_iteratedFDerivWithin_clm_apply {f : E → F →L[𝕜] G} {g : E rfl exact B.norm_iteratedFDerivWithin_le_of_bilinear_of_le_one hf hg hs hx hn hB -theorem norm_iteratedFDeriv_clm_apply {f : E → F →L[𝕜] G} {g : E → F} {N : ℕ∞} {n : ℕ} - (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) (x : E) (hn : ↑n ≤ N) : +theorem norm_iteratedFDeriv_clm_apply {f : E → F →L[𝕜] G} {g : E → F} {N : WithTop ℕ∞} {n : ℕ} + (hf : ContDiff 𝕜 N f) (hg : ContDiff 𝕜 N g) (x : E) (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (fun y : E => (f y) (g y)) x‖ ≤ ∑ i ∈ Finset.range (n + 1), ↑(n.choose i) * ‖iteratedFDeriv 𝕜 i f x‖ * ‖iteratedFDeriv 𝕜 (n - i) g x‖ := by simp only [← iteratedFDerivWithin_univ] @@ -542,7 +546,8 @@ theorem norm_iteratedFDeriv_clm_apply {f : E → F →L[𝕜] G} {g : E → F} { (Set.mem_univ x) hn theorem norm_iteratedFDerivWithin_clm_apply_const {f : E → F →L[𝕜] G} {c : F} {s : Set E} {x : E} - {N : ℕ∞} {n : ℕ} (hf : ContDiffOn 𝕜 N f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) (hn : ↑n ≤ N) : + {N : WithTop ℕ∞} {n : ℕ} (hf : ContDiffOn 𝕜 N f s) (hs : UniqueDiffOn 𝕜 s) + (hx : x ∈ s) (hn : n ≤ N) : ‖iteratedFDerivWithin 𝕜 n (fun y : E => (f y) c) s x‖ ≤ ‖c‖ * ‖iteratedFDerivWithin 𝕜 n f s x‖ := by let g : (F →L[𝕜] G) →L[𝕜] G := ContinuousLinearMap.apply 𝕜 G c @@ -553,8 +558,8 @@ theorem norm_iteratedFDerivWithin_clm_apply_const {f : E → F →L[𝕜] G} {c rw [ContinuousLinearMap.apply_apply, mul_comm] exact f.le_opNorm c -theorem norm_iteratedFDeriv_clm_apply_const {f : E → F →L[𝕜] G} {c : F} {x : E} {N : ℕ∞} {n : ℕ} - (hf : ContDiff 𝕜 N f) (hn : ↑n ≤ N) : +theorem norm_iteratedFDeriv_clm_apply_const {f : E → F →L[𝕜] G} {c : F} {x : E} + {N : WithTop ℕ∞} {n : ℕ} (hf : ContDiff 𝕜 N f) (hn : n ≤ N) : ‖iteratedFDeriv 𝕜 n (fun y : E => (f y) c) x‖ ≤ ‖c‖ * ‖iteratedFDeriv 𝕜 n f x‖ := by simp only [← iteratedFDerivWithin_univ] exact norm_iteratedFDerivWithin_clm_apply_const hf.contDiffOn uniqueDiffOn_univ diff --git a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean index c7f8b24aa799b0..180ea22be1a5e0 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean @@ -93,7 +93,13 @@ noncomputable section open scoped Classical open NNReal Topology Filter -local notation "∞" => (⊤ : ℕ∞) +/-- Smoothness exponent for analytic functions. Not implemented yet, `ω` smoothness is equivalent +to `∞` smoothness in current mathlib. -/ +scoped [ContDiff] notation3 "ω" => (⊤ : WithTop ℕ∞) +/-- Smoothness exponent for infinitely differentiable functions. -/ +scoped [ContDiff] notation3 "∞" => ((⊤ : ℕ∞) : WithTop ℕ∞) + +open ContDiff /- Porting note: These lines are not required in Mathlib4. @@ -108,7 +114,7 @@ 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 : ℕ∞} + {s s₁ t u : Set E} {f f₁ : E → F} {g : F → G} {x x₀ : E} {c : F} {m n : WithTop ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} /-! ### Smooth functions within a set around a point -/ @@ -122,9 +128,12 @@ depend on the finite order we consider). For instance, a real function which is `C^m` on `(-1/m, 1/m)` for each natural `m`, but not better, is `C^∞` at `0` within `univ`. + +We take the exponent `n` in `WithTop ℕ∞` to allow for an extension to analytic functions in the +future, but currently the notion is the same for `n = ∞` and `n = ω`. -/ -def ContDiffWithinAt (n : ℕ∞) (f : E → F) (s : Set E) (x : E) : Prop := - ∀ m : ℕ, (m : ℕ∞) ≤ n → ∃ u ∈ 𝓝[insert x s] x, +def ContDiffWithinAt (n : WithTop ℕ∞) (f : E → F) (s : Set E) (x : E) : Prop := + ∀ m : ℕ, m ≤ n → ∃ u ∈ 𝓝[insert x s] x, ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn m f p u variable {𝕜} @@ -132,14 +141,14 @@ variable {𝕜} theorem contDiffWithinAt_nat {n : ℕ} : ContDiffWithinAt 𝕜 n f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn n f p u := - ⟨fun H => H n le_rfl, fun ⟨u, hu, p, hp⟩ _m hm => ⟨u, hu, p, hp.of_le hm⟩⟩ + ⟨fun H => H n le_rfl, fun ⟨u, hu, p, hp⟩ _m hm => ⟨u, hu, p, hp.of_le (mod_cast hm)⟩⟩ theorem ContDiffWithinAt.of_le (h : ContDiffWithinAt 𝕜 n f s x) (hmn : m ≤ n) : ContDiffWithinAt 𝕜 m f s x := fun k hk => h k (le_trans hk hmn) -theorem contDiffWithinAt_iff_forall_nat_le : +theorem contDiffWithinAt_iff_forall_nat_le {n : ℕ∞} : ContDiffWithinAt 𝕜 n f s x ↔ ∀ m : ℕ, ↑m ≤ n → ContDiffWithinAt 𝕜 m f s x := - ⟨fun H _m hm => H.of_le hm, fun H m hm => H m hm _ le_rfl⟩ + ⟨fun H _m hm => H.of_le (mod_cast hm), fun H m hm => H m (mod_cast hm) _ le_rfl⟩ theorem contDiffWithinAt_top : ContDiffWithinAt 𝕜 ∞ f s x ↔ ∀ n : ℕ, ContDiffWithinAt 𝕜 n f s x := contDiffWithinAt_iff_forall_nat_le.trans <| by simp only [forall_prop_of_true, le_top] @@ -290,30 +299,32 @@ theorem ContDiffWithinAt.differentiableWithinAt (h : ContDiffWithinAt 𝕜 n f s /-- A function is `C^(n + 1)` on a domain iff locally, it has a derivative which is `C^n`. -/ theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt {n : ℕ} : - ContDiffWithinAt 𝕜 (n + 1 : ℕ) f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ∃ f' : E → E →L[𝕜] F, + ContDiffWithinAt 𝕜 (n + 1) f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) u x) ∧ ContDiffWithinAt 𝕜 n f' u x := by constructor · intro h rcases h n.succ le_rfl with ⟨u, hu, p, Hp⟩ refine ⟨u, hu, fun y => (continuousMultilinearCurryFin1 𝕜 E F) (p y 1), fun y hy => - Hp.hasFDerivWithinAt (WithTop.coe_le_coe.2 (Nat.le_add_left 1 n)) hy, ?_⟩ + Hp.hasFDerivWithinAt (mod_cast (Nat.le_add_left 1 n)) hy, ?_⟩ intro m hm refine ⟨u, ?_, fun y : E => (p y).shift, ?_⟩ · -- Porting note: without the explicit argument Lean is not sure of the type. convert @self_mem_nhdsWithin _ _ x u have : x ∈ insert x s := by simp exact insert_eq_of_mem (mem_of_mem_nhdsWithin this hu) - · rw [hasFTaylorSeriesUpToOn_succ_iff_right] at Hp - exact Hp.2.2.of_le hm + · rw [show ((n.succ : ℕ) : WithTop ℕ∞) = n + 1 from rfl, + hasFTaylorSeriesUpToOn_succ_iff_right] at Hp + exact Hp.2.2.of_le (mod_cast hm) · rintro ⟨u, hu, f', f'_eq_deriv, Hf'⟩ - rw [contDiffWithinAt_nat] + rw [show (n : WithTop ℕ∞) + 1 = (n + 1 : ℕ) from rfl, contDiffWithinAt_nat] rcases Hf' n le_rfl with ⟨v, hv, p', Hp'⟩ refine ⟨v ∩ u, ?_, fun x => (p' x).unshift (f x), ?_⟩ · apply Filter.inter_mem _ hu apply nhdsWithin_le_of_mem hu exact nhdsWithin_mono _ (subset_insert x u) hv - · rw [hasFTaylorSeriesUpToOn_succ_iff_right] + · rw [show ((n.succ : ℕ) : WithTop ℕ∞) = n + 1 from rfl, + hasFTaylorSeriesUpToOn_succ_iff_right] refine ⟨fun y _ => rfl, fun y hy => ?_, ?_⟩ · change HasFDerivWithinAt (fun z => (continuousMultilinearCurryFin0 𝕜 E F).symm (f z)) @@ -340,7 +351,7 @@ theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt {n : ℕ} : /-- A version of `contDiffWithinAt_succ_iff_hasFDerivWithinAt` where all derivatives are taken within the same set. -/ theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt' {n : ℕ} : - ContDiffWithinAt 𝕜 (n + 1 : ℕ) f s x ↔ + ContDiffWithinAt 𝕜 (n + 1) f s x ↔ ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) s x) ∧ ContDiffWithinAt 𝕜 n f' s x := by refine ⟨fun hf => ?_, ?_⟩ @@ -368,7 +379,7 @@ admits continuous derivatives up to order `n` on a neighborhood of `x` in `s`. For `n = ∞`, we only require that this holds up to any finite order (where the neighborhood may depend on the finite order we consider). -/ -def ContDiffOn (n : ℕ∞) (f : E → F) (s : Set E) : Prop := +def ContDiffOn (n : WithTop ℕ∞) (f : E → F) (s : Set E) : Prop := ∀ x ∈ s, ContDiffWithinAt 𝕜 n f s x variable {𝕜} @@ -378,13 +389,13 @@ theorem HasFTaylorSeriesUpToOn.contDiffOn {f' : E → FormalMultilinearSeries intro x hx m hm use s simp only [Set.insert_eq_of_mem hx, self_mem_nhdsWithin, true_and] - exact ⟨f', hf.of_le hm⟩ + exact ⟨f', hf.of_le (mod_cast hm)⟩ theorem ContDiffOn.contDiffWithinAt (h : ContDiffOn 𝕜 n f s) (hx : x ∈ s) : ContDiffWithinAt 𝕜 n f s x := h x hx -theorem ContDiffWithinAt.contDiffOn' {m : ℕ} (hm : (m : ℕ∞) ≤ n) +theorem ContDiffWithinAt.contDiffOn' {m : ℕ} (hm : m ≤ n) (h : ContDiffWithinAt 𝕜 n f s x) : ∃ u, IsOpen u ∧ x ∈ u ∧ ContDiffOn 𝕜 m f (insert x s ∩ u) := by rcases h m hm with ⟨t, ht, p, hp⟩ @@ -392,7 +403,7 @@ theorem ContDiffWithinAt.contDiffOn' {m : ℕ} (hm : (m : ℕ∞) ≤ n) rw [inter_comm] at hut exact ⟨u, huo, hxu, (hp.mono hut).contDiffOn⟩ -theorem ContDiffWithinAt.contDiffOn {m : ℕ} (hm : (m : ℕ∞) ≤ n) (h : ContDiffWithinAt 𝕜 n f s x) : +theorem ContDiffWithinAt.contDiffOn {m : ℕ} (hm : m ≤ n) (h : ContDiffWithinAt 𝕜 n f s x) : ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ ContDiffOn 𝕜 m f u := let ⟨_u, uo, xu, h⟩ := h.contDiffOn' hm ⟨_, inter_mem_nhdsWithin _ (uo.mem_nhds xu), inter_subset_left, h⟩ @@ -425,13 +436,15 @@ theorem ContDiffOn.of_succ {n : ℕ} (h : ContDiffOn 𝕜 (n + 1) f s) : ContDif theorem ContDiffOn.one_of_succ {n : ℕ} (h : ContDiffOn 𝕜 (n + 1) f s) : ContDiffOn 𝕜 1 f s := h.of_le <| WithTop.coe_le_coe.mpr le_add_self -theorem contDiffOn_iff_forall_nat_le : ContDiffOn 𝕜 n f s ↔ ∀ m : ℕ, ↑m ≤ n → ContDiffOn 𝕜 m f s := - ⟨fun H _ hm => H.of_le hm, fun H x hx m hm => H m hm x hx m le_rfl⟩ +theorem contDiffOn_iff_forall_nat_le {n : ℕ∞} : + ContDiffOn 𝕜 n f s ↔ ∀ m : ℕ, ↑m ≤ n → ContDiffOn 𝕜 m f s := + ⟨fun H _ hm => H.of_le (mod_cast hm), fun H x hx m hm => H m (mod_cast hm) x hx m le_rfl⟩ theorem contDiffOn_top : ContDiffOn 𝕜 ∞ f s ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := contDiffOn_iff_forall_nat_le.trans <| by simp only [le_top, forall_prop_of_true] -theorem contDiffOn_all_iff_nat : (∀ n, ContDiffOn 𝕜 n f s) ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := by +theorem contDiffOn_all_iff_nat : + (∀ (n : ℕ∞), ContDiffOn 𝕜 n f s) ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := by refine ⟨fun H n => H n, ?_⟩ rintro H (_ | n) exacts [contDiffOn_top.2 H, H n] @@ -466,7 +479,7 @@ theorem contDiffOn_of_locally_contDiffOn /-- A function is `C^(n + 1)` on a domain iff locally, it has a derivative which is `C^n`. -/ theorem contDiffOn_succ_iff_hasFDerivWithinAt {n : ℕ} : - ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ + ContDiffOn 𝕜 (n + 1) f s ↔ ∀ x ∈ s, ∃ u ∈ 𝓝[insert x s] x, ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) u x) ∧ ContDiffOn 𝕜 n f' u := by constructor @@ -474,10 +487,11 @@ theorem contDiffOn_succ_iff_hasFDerivWithinAt {n : ℕ} : rcases (h x hx) n.succ le_rfl with ⟨u, hu, p, Hp⟩ refine ⟨u, hu, fun y => (continuousMultilinearCurryFin1 𝕜 E F) (p y 1), fun y hy => - Hp.hasFDerivWithinAt (WithTop.coe_le_coe.2 (Nat.le_add_left 1 n)) hy, ?_⟩ - rw [hasFTaylorSeriesUpToOn_succ_iff_right] at Hp + Hp.hasFDerivWithinAt (mod_cast (Nat.le_add_left 1 n)) hy, ?_⟩ + rw [show (n.succ : WithTop ℕ∞) = (n : ℕ) + 1 from rfl, + hasFTaylorSeriesUpToOn_succ_iff_right] at Hp intro z hz m hm - refine ⟨u, ?_, fun x : E => (p x).shift, Hp.2.2.of_le hm⟩ + refine ⟨u, ?_, fun x : E => (p x).shift, Hp.2.2.of_le (mod_cast hm)⟩ -- Porting note: without the explicit arguments `convert` can not determine the type. convert @self_mem_nhdsWithin _ _ z u exact insert_eq_of_mem hz @@ -490,7 +504,7 @@ theorem contDiffOn_succ_iff_hasFDerivWithinAt {n : ℕ} : @[simp] theorem contDiffOn_zero : ContDiffOn 𝕜 0 f s ↔ ContinuousOn f s := by refine ⟨fun H => H.continuousOn, fun H => fun x hx m hm ↦ ?_⟩ - have : (m : ℕ∞) = 0 := le_antisymm hm bot_le + have : (m : WithTop ℕ∞) = 0 := le_antisymm (mod_cast hm) bot_le rw [this] refine ⟨insert x s, self_mem_nhdsWithin, ftaylorSeriesWithin 𝕜 f s, ?_⟩ rw [hasFTaylorSeriesUpToOn_zero_iff] @@ -519,7 +533,8 @@ protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.curry0_apply, iteratedFDerivWithin_zero_apply] · intro m hm x hx - rcases (h x hx) m.succ (Order.add_one_le_of_lt hm) with ⟨u, hu, p, Hp⟩ + have : (m + 1 : ℕ) ≤ n := ENat.add_one_natCast_le_withTop_of_lt hm + rcases (h x hx).of_le this _ le_rfl 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 @@ -533,15 +548,15 @@ protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs change p y m = iteratedFDerivWithin 𝕜 m f s y rw [← iteratedFDerivWithin_inter_open o_open yo] exact - (Hp.mono ho).eq_iteratedFDerivWithin_of_uniqueDiffOn (WithTop.coe_le_coe.2 (Nat.le_succ m)) + (Hp.mono ho).eq_iteratedFDerivWithin_of_uniqueDiffOn (mod_cast Nat.le_succ m) (hs.inter o_open) ⟨hy, yo⟩ exact - ((Hp.mono ho).fderivWithin m (WithTop.coe_lt_coe.2 (lt_add_one m)) x ⟨hx, xo⟩).congr + ((Hp.mono ho).fderivWithin m (mod_cast lt_add_one m) x ⟨hx, xo⟩).congr (fun y hy => (A y hy).symm) (A x ⟨hx, xo⟩).symm · intro m hm apply continuousOn_of_locally_continuousOn intro x hx - rcases h x hx m hm with ⟨u, hu, p, Hp⟩ + rcases h x hx m (mod_cast hm) with ⟨u, hu, p, Hp⟩ rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ rw [insert_eq_of_mem hx] at ho rw [inter_comm] at ho @@ -553,9 +568,9 @@ protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs exact (Hp.mono ho).eq_iteratedFDerivWithin_of_uniqueDiffOn le_rfl (hs.inter o_open) ⟨hy, yo⟩ exact ((Hp.mono ho).cont m le_rfl).congr fun y hy => (A y hy).symm -theorem contDiffOn_of_continuousOn_differentiableOn - (Hcont : ∀ m : ℕ, (m : ℕ∞) ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) - (Hdiff : ∀ m : ℕ, (m : ℕ∞) < n → +theorem contDiffOn_of_continuousOn_differentiableOn {n : ℕ∞} + (Hcont : ∀ m : ℕ, m ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) + (Hdiff : ∀ m : ℕ, m < n → DifferentiableOn 𝕜 (fun x => iteratedFDerivWithin 𝕜 m f s x) s) : ContDiffOn 𝕜 n f s := by intro x hx m hm @@ -566,29 +581,29 @@ theorem contDiffOn_of_continuousOn_differentiableOn 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 + convert (Hdiff k (lt_of_lt_of_le (mod_cast hk) (mod_cast hm)) y hy).hasFDerivWithinAt · intro k hk - exact Hcont k (le_trans hk hm) + exact Hcont k (le_trans (mod_cast hk) (mod_cast hm)) -theorem contDiffOn_of_differentiableOn - (h : ∀ m : ℕ, (m : ℕ∞) ≤ n → DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s) : +theorem contDiffOn_of_differentiableOn {n : ℕ∞} + (h : ∀ m : ℕ, m ≤ n → DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s) : ContDiffOn 𝕜 n f s := contDiffOn_of_continuousOn_differentiableOn (fun m hm => (h m hm).continuousOn) fun m hm => h m (le_of_lt hm) theorem ContDiffOn.continuousOn_iteratedFDerivWithin {m : ℕ} (h : ContDiffOn 𝕜 n f s) - (hmn : (m : ℕ∞) ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedFDerivWithin 𝕜 m f s) s := - (h.ftaylorSeriesWithin hs).cont m hmn + (hmn : m ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedFDerivWithin 𝕜 m f s) s := + (h.ftaylorSeriesWithin hs).cont m (mod_cast hmn) theorem ContDiffOn.differentiableOn_iteratedFDerivWithin {m : ℕ} (h : ContDiffOn 𝕜 n f s) - (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 s) : + (hmn : m < n) (hs : UniqueDiffOn 𝕜 s) : DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s := fun x hx => - ((h.ftaylorSeriesWithin hs).fderivWithin m hmn x hx).differentiableWithinAt + ((h.ftaylorSeriesWithin hs).fderivWithin m (mod_cast hmn) x hx).differentiableWithinAt theorem ContDiffWithinAt.differentiableWithinAt_iteratedFDerivWithin {m : ℕ} - (h : ContDiffWithinAt 𝕜 n f s x) (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : + (h : ContDiffWithinAt 𝕜 n f s x) (hmn : m < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : DifferentiableWithinAt 𝕜 (iteratedFDerivWithin 𝕜 m f s) s x := by - rcases h.contDiffOn' (Order.add_one_le_of_lt hmn) with ⟨u, uo, xu, hu⟩ + rcases h.contDiffOn' (ENat.add_one_natCast_le_withTop_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'] @@ -603,16 +618,16 @@ theorem ContDiffWithinAt.differentiableWithinAt_iteratedFDerivWithin {m : ℕ} rw [differentiableWithinAt_congr_set' _ A] at C exact C.congr_of_eventuallyEq (B.filter_mono inf_le_left) B.self_of_nhds -theorem contDiffOn_iff_continuousOn_differentiableOn (hs : UniqueDiffOn 𝕜 s) : +theorem contDiffOn_iff_continuousOn_differentiableOn {n : ℕ∞} (hs : UniqueDiffOn 𝕜 s) : ContDiffOn 𝕜 n f s ↔ - (∀ m : ℕ, (m : ℕ∞) ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) ∧ - ∀ m : ℕ, (m : ℕ∞) < n → DifferentiableOn 𝕜 (fun x => iteratedFDerivWithin 𝕜 m f s x) s := - ⟨fun h => ⟨fun _m hm => h.continuousOn_iteratedFDerivWithin hm hs, fun _m hm => - h.differentiableOn_iteratedFDerivWithin hm hs⟩, + (∀ m : ℕ, m ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) ∧ + ∀ m : ℕ, m < n → DifferentiableOn 𝕜 (fun x => iteratedFDerivWithin 𝕜 m f s x) s := + ⟨fun h => ⟨fun _m hm => h.continuousOn_iteratedFDerivWithin (mod_cast hm) hs, fun _m hm => + h.differentiableOn_iteratedFDerivWithin (mod_cast hm) hs⟩, fun h => contDiffOn_of_continuousOn_differentiableOn h.1 h.2⟩ theorem contDiffOn_succ_of_fderivWithin {n : ℕ} (hf : DifferentiableOn 𝕜 f s) - (h : ContDiffOn 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) : ContDiffOn 𝕜 (n + 1 : ℕ) f s := by + (h : ContDiffOn 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) : ContDiffOn 𝕜 (n + 1) f s := by intro x hx rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt, insert_eq_of_mem hx] exact @@ -621,10 +636,10 @@ theorem contDiffOn_succ_of_fderivWithin {n : ℕ} (hf : DifferentiableOn 𝕜 f /-- A function is `C^(n + 1)` on a domain with unique derivatives if and only if it is differentiable there, and its derivative (expressed with `fderivWithin`) is `C^n`. -/ theorem contDiffOn_succ_iff_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : - ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ + ContDiffOn 𝕜 (n + 1) f s ↔ DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 n (fun y => fderivWithin 𝕜 f s y) s := by refine ⟨fun H => ?_, fun h => contDiffOn_succ_of_fderivWithin h.1 h.2⟩ - refine ⟨H.differentiableOn (WithTop.coe_le_coe.2 (Nat.le_add_left 1 n)), fun x hx => ?_⟩ + refine ⟨H.differentiableOn le_add_self, fun x hx => ?_⟩ rcases contDiffWithinAt_succ_iff_hasFDerivWithinAt.1 (H x hx) with ⟨u, hu, f', hff', hf'⟩ rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ rw [inter_comm, insert_eq_of_mem hx] at ho @@ -639,7 +654,7 @@ theorem contDiffOn_succ_iff_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : rwa [fderivWithin_inter (o_open.mem_nhds hy.2)] at A theorem contDiffOn_succ_iff_hasFDerivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : - ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ + ContDiffOn 𝕜 (n + 1) f s ↔ ∃ f' : E → E →L[𝕜] F, ContDiffOn 𝕜 n f' s ∧ ∀ x, x ∈ s → HasFDerivWithinAt f (f' x) s x := by rw [contDiffOn_succ_iff_fderivWithin hs] refine ⟨fun h => ⟨fderivWithin 𝕜 f s, h.2, fun x hx => (h.1 x hx).hasFDerivWithinAt⟩, fun h => ?_⟩ @@ -650,7 +665,7 @@ theorem contDiffOn_succ_iff_hasFDerivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) /-- A function is `C^(n + 1)` on an open domain if and only if it is differentiable there, and its derivative (expressed with `fderiv`) is `C^n`. -/ theorem contDiffOn_succ_iff_fderiv_of_isOpen {n : ℕ} (hs : IsOpen s) : - ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ + ContDiffOn 𝕜 (n + 1) f s ↔ DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 n (fun y => fderiv 𝕜 f y) s := by rw [contDiffOn_succ_iff_fderivWithin hs.uniqueDiffOn] exact Iff.rfl.and (contDiffOn_congr fun x hx ↦ fderivWithin_of_isOpen hs hx) @@ -662,14 +677,14 @@ theorem contDiffOn_top_iff_fderivWithin (hs : UniqueDiffOn 𝕜 s) : DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 ∞ (fun y => fderivWithin 𝕜 f s y) s := by constructor · intro h - refine ⟨h.differentiableOn le_top, ?_⟩ + refine ⟨h.differentiableOn (mod_cast le_top), ?_⟩ refine contDiffOn_top.2 fun n => ((contDiffOn_succ_iff_fderivWithin hs).1 ?_).2 - exact h.of_le le_top + exact h.of_le (mod_cast le_top) · intro h refine contDiffOn_top.2 fun n => ?_ - have A : (n : ℕ∞) ≤ ∞ := le_top + have A : (n : ℕ∞) ≤ ∞ := mod_cast le_top apply ((contDiffOn_succ_iff_fderivWithin hs).2 ⟨h.1, h.2.of_le A⟩).of_le - exact WithTop.coe_le_coe.2 (Nat.le_succ n) + exact_mod_cast (Nat.le_succ n) /-- A function is `C^∞` on an open domain if and only if it is differentiable there, and its derivative (expressed with `fderiv`) is `C^∞`. -/ @@ -680,13 +695,17 @@ theorem contDiffOn_top_iff_fderiv_of_isOpen (hs : IsOpen s) : protected theorem ContDiffOn.fderivWithin (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (fun y => fderivWithin 𝕜 f s y) s := by - cases' m with m - · change ∞ + 1 ≤ n at hmn - have : n = ∞ := by simpa using hmn - rw [this] at hf - exact ((contDiffOn_top_iff_fderivWithin hs).1 hf).2 - · change (m.succ : ℕ∞) ≤ n at hmn - exact ((contDiffOn_succ_iff_fderivWithin hs).1 (hf.of_le hmn)).2 + rcases le_or_lt ∞ n with hn | hn + · have : ContDiffOn 𝕜 ∞ (fun y ↦ fderivWithin 𝕜 f s y) s := + ((contDiffOn_top_iff_fderivWithin hs).1 (hf.of_le hn)).2 + intro x hx k hk + exact this x hx k (mod_cast le_top) + · match m with + | ω => simpa using hmn.trans_lt hn + | ∞ => simpa using hmn.trans_lt hn + | (m : ℕ) => + change (m.succ : ℕ∞) ≤ n at hmn + exact ((contDiffOn_succ_iff_fderivWithin hs).1 (hf.of_le hmn)).2 theorem ContDiffOn.fderiv_of_isOpen (hf : ContDiffOn 𝕜 n f s) (hs : IsOpen s) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (fun y => fderiv 𝕜 f y) s := @@ -700,6 +719,13 @@ 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 +/-- The following lemma will be removed when the definition of `C^ω` will be corrected. For now, +it is only there as a convenient shortcut. -/ +theorem contDiffOn_infty_iff_contDiffOn_omega : + ContDiffOn 𝕜 ∞ f s ↔ ContDiffOn 𝕜 ω f s := by + have A (m : ℕ) : m ≤ ∞ := mod_cast le_top + simp [ContDiffOn, ContDiffWithinAt, hasFTaylorSeriesUpTo_top_iff, A] + /-! ### Smooth functions at a point -/ variable (𝕜) @@ -707,7 +733,7 @@ variable (𝕜) /-- A function is continuously differentiable up to `n` at a point `x` if, for any integer `k ≤ n`, there is a neighborhood of `x` where `f` admits derivatives up to order `n`, which are continuous. -/ -def ContDiffAt (n : ℕ∞) (f : E → F) (x : E) : Prop := +def ContDiffAt (n : WithTop ℕ∞) (f : E → F) (x : E) : Prop := ContDiffWithinAt 𝕜 n f univ x variable {𝕜} @@ -762,7 +788,7 @@ nonrec lemma ContDiffAt.contDiffOn {m : ℕ} (h : ContDiffAt 𝕜 n f x) (hm : m /-- A function is `C^(n + 1)` at a point iff locally, it has a derivative which is `C^n`. -/ theorem contDiffAt_succ_iff_hasFDerivAt {n : ℕ} : - ContDiffAt 𝕜 (n + 1 : ℕ) f x ↔ + ContDiffAt 𝕜 (n + 1) f x ↔ ∃ f' : E → E →L[𝕜] F, (∃ u ∈ 𝓝 x, ∀ x ∈ u, HasFDerivAt f (f' x) x) ∧ ContDiffAt 𝕜 n f' x := by rw [← contDiffWithinAt_univ, contDiffWithinAt_succ_iff_hasFDerivWithinAt] simp only [nhdsWithin_univ, exists_prop, mem_univ, insert_eq_of_mem] @@ -791,7 +817,7 @@ variable (𝕜) order `n`, which are continuous. Contrary to the case of definitions in domains (where derivatives might not be unique) we do not need to localize the definition in space or time. -/ -def ContDiff (n : ℕ∞) (f : E → F) : Prop := +def ContDiff (n : WithTop ℕ∞) (f : E → F) : Prop := ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpTo n f p variable {𝕜} @@ -808,7 +834,8 @@ theorem contDiffOn_univ : ContDiffOn 𝕜 n f univ ↔ ContDiff 𝕜 n f := by rw [← hasFTaylorSeriesUpToOn_univ_iff] exact H.ftaylorSeriesWithin uniqueDiffOn_univ · rintro ⟨p, hp⟩ x _ m hm - exact ⟨univ, Filter.univ_sets _, p, (hp.hasFTaylorSeriesUpToOn univ).of_le hm⟩ + exact ⟨univ, Filter.univ_sets _, p, (hp.hasFTaylorSeriesUpToOn univ).of_le + (mod_cast hm)⟩ theorem contDiff_iff_contDiffAt : ContDiff 𝕜 n f ↔ ∀ x, ContDiffAt 𝕜 n f x := by simp [← contDiffOn_univ, ContDiffOn, ContDiffAt] @@ -819,10 +846,16 @@ theorem ContDiff.contDiffAt (h : ContDiff 𝕜 n f) : ContDiffAt 𝕜 n f x := theorem ContDiff.contDiffWithinAt (h : ContDiff 𝕜 n f) : ContDiffWithinAt 𝕜 n f s x := h.contDiffAt.contDiffWithinAt +/-- The following lemma will be removed when the definition of `C^ω` will be corrected. For now, +it is only there as a convenient shortcut. -/ +theorem contDiff_infty_iff_contDiff_omega : + ContDiff 𝕜 ∞ f ↔ ContDiff 𝕜 ω f := by + simp [ContDiff, hasFTaylorSeriesUpTo_top_iff] + theorem contDiff_top : ContDiff 𝕜 ∞ f ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by simp [contDiffOn_univ.symm, contDiffOn_top] -theorem contDiff_all_iff_nat : (∀ n, ContDiff 𝕜 n f) ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by +theorem contDiff_all_iff_nat : (∀ (n : ℕ∞), ContDiff 𝕜 n f) ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by simp only [← contDiffOn_univ, contDiffOn_all_iff_nat] theorem ContDiff.contDiffOn (h : ContDiff 𝕜 n f) : ContDiffOn 𝕜 n f s := @@ -839,8 +872,8 @@ theorem contDiffAt_zero : ContDiffAt 𝕜 0 f x ↔ ∃ u ∈ 𝓝 x, Continuous theorem contDiffAt_one_iff : ContDiffAt 𝕜 1 f x ↔ ∃ f' : E → E →L[𝕜] F, ∃ u ∈ 𝓝 x, ContinuousOn f' u ∧ ∀ x ∈ u, HasFDerivAt f (f' x) x := by - simp_rw [show (1 : ℕ∞) = (0 + 1 : ℕ) from (zero_add 1).symm, contDiffAt_succ_iff_hasFDerivAt, - show ((0 : ℕ) : ℕ∞) = 0 from rfl, contDiffAt_zero, + rw [show (1 : WithTop ℕ∞) = (0 : ℕ) + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] + simp_rw [show ((0 : ℕ) : WithTop ℕ∞) = 0 from rfl, contDiffAt_zero, exists_mem_and_iff antitone_bforall antitone_continuousOn, and_comm] theorem ContDiff.of_le (h : ContDiff 𝕜 n f) (hmn : m ≤ n) : ContDiff 𝕜 m f := @@ -859,12 +892,13 @@ theorem ContDiff.continuous (h : ContDiff 𝕜 n f) : Continuous f := theorem ContDiff.differentiable (h : ContDiff 𝕜 n f) (hn : 1 ≤ n) : Differentiable 𝕜 f := differentiableOn_univ.1 <| (contDiffOn_univ.2 h).differentiableOn hn -theorem contDiff_iff_forall_nat_le : ContDiff 𝕜 n f ↔ ∀ m : ℕ, ↑m ≤ n → ContDiff 𝕜 m f := by +theorem contDiff_iff_forall_nat_le {n : ℕ∞} : + ContDiff 𝕜 n f ↔ ∀ m : ℕ, ↑m ≤ n → ContDiff 𝕜 m f := by simp_rw [← contDiffOn_univ]; exact contDiffOn_iff_forall_nat_le /-- A function is `C^(n+1)` iff it has a `C^n` derivative. -/ theorem contDiff_succ_iff_hasFDerivAt {n : ℕ} : - ContDiff 𝕜 (n + 1 : ℕ) f ↔ + ContDiff 𝕜 (n + 1) f ↔ ∃ f' : E → E →L[𝕜] F, ContDiff 𝕜 n f' ∧ ∀ x, HasFDerivAt f (f' x) x := by simp only [← contDiffOn_univ, ← hasFDerivWithinAt_univ, contDiffOn_succ_iff_hasFDerivWithin uniqueDiffOn_univ, Set.mem_univ, forall_true_left] @@ -882,32 +916,33 @@ theorem contDiff_iff_ftaylorSeries : exact fun h => ContDiffOn.ftaylorSeriesWithin h uniqueDiffOn_univ · intro h; exact ⟨ftaylorSeries 𝕜 f, h⟩ -theorem contDiff_iff_continuous_differentiable : +theorem contDiff_iff_continuous_differentiable {n : ℕ∞} : ContDiff 𝕜 n f ↔ - (∀ m : ℕ, (m : ℕ∞) ≤ n → Continuous fun x => iteratedFDeriv 𝕜 m f x) ∧ - ∀ m : ℕ, (m : ℕ∞) < n → Differentiable 𝕜 fun x => iteratedFDeriv 𝕜 m f x := by + (∀ m : ℕ, m ≤ n → Continuous fun x => iteratedFDeriv 𝕜 m f x) ∧ + ∀ m : ℕ, m < n → Differentiable 𝕜 fun x => iteratedFDeriv 𝕜 m f x := by simp [contDiffOn_univ.symm, continuous_iff_continuousOn_univ, differentiableOn_univ.symm, iteratedFDerivWithin_univ, contDiffOn_iff_continuousOn_differentiableOn uniqueDiffOn_univ] /-- If `f` is `C^n` then its `m`-times iterated derivative is continuous for `m ≤ n`. -/ -theorem ContDiff.continuous_iteratedFDeriv {m : ℕ} (hm : (m : ℕ∞) ≤ n) (hf : ContDiff 𝕜 n f) : +theorem ContDiff.continuous_iteratedFDeriv {m : ℕ} (hm : m ≤ n) (hf : ContDiff 𝕜 n f) : Continuous fun x => iteratedFDeriv 𝕜 m f x := - (contDiff_iff_continuous_differentiable.mp hf).1 m hm + (contDiff_iff_continuous_differentiable.mp (hf.of_le hm)).1 m le_rfl /-- If `f` is `C^n` then its `m`-times iterated derivative is differentiable for `m < n`. -/ -theorem ContDiff.differentiable_iteratedFDeriv {m : ℕ} (hm : (m : ℕ∞) < n) (hf : ContDiff 𝕜 n f) : +theorem ContDiff.differentiable_iteratedFDeriv {m : ℕ} (hm : m < n) (hf : ContDiff 𝕜 n f) : Differentiable 𝕜 fun x => iteratedFDeriv 𝕜 m f x := - (contDiff_iff_continuous_differentiable.mp hf).2 m hm + (contDiff_iff_continuous_differentiable.mp + (hf.of_le (ENat.add_one_natCast_le_withTop_of_lt hm))).2 m (mod_cast lt_add_one m) -theorem contDiff_of_differentiable_iteratedFDeriv - (h : ∀ m : ℕ, (m : ℕ∞) ≤ n → Differentiable 𝕜 (iteratedFDeriv 𝕜 m f)) : ContDiff 𝕜 n f := +theorem contDiff_of_differentiable_iteratedFDeriv {n : ℕ∞} + (h : ∀ m : ℕ, m ≤ n → Differentiable 𝕜 (iteratedFDeriv 𝕜 m f)) : ContDiff 𝕜 n f := contDiff_iff_continuous_differentiable.2 ⟨fun m hm => (h m hm).continuous, fun m hm => h m (le_of_lt hm)⟩ /-- A function is `C^(n + 1)` if and only if it is differentiable, and its derivative (formulated in terms of `fderiv`) is `C^n`. -/ theorem contDiff_succ_iff_fderiv {n : ℕ} : - ContDiff 𝕜 (n + 1 : ℕ) f ↔ Differentiable 𝕜 f ∧ ContDiff 𝕜 n fun y => fderiv 𝕜 f y := by + ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ ContDiff 𝕜 n fun y => fderiv 𝕜 f y := by simp only [← contDiffOn_univ, ← differentiableOn_univ, ← fderivWithin_univ, contDiffOn_succ_iff_fderivWithin uniqueDiffOn_univ] diff --git a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean index 149c86f2c306e9..abdac0002a6e2e 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean @@ -99,7 +99,7 @@ In this file, we denote `⊤ : ℕ∞` with `∞`. noncomputable section open scoped Classical -open NNReal Topology Filter +open ENat NNReal Topology Filter local notation "∞" => (⊤ : ℕ∞) @@ -115,7 +115,8 @@ universe u uE uF variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] - {s t u : Set E} {f f₁ : E → F} {x : E} {m n : ℕ∞} {p : E → FormalMultilinearSeries 𝕜 E F} + {s t u : Set E} {f f₁ : E → F} {x : E} {m n N : WithTop ℕ∞} + {p : E → FormalMultilinearSeries 𝕜 E F} /-! ### Functions with a Taylor series on a domain -/ @@ -125,12 +126,12 @@ derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a pred 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 +structure HasFTaylorSeriesUpToOn + (n : WithTop ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) (s : Set E) : Prop where zero_eq : ∀ x ∈ s, (p x 0).curry0 = f x protected fderivWithin : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x ∈ s, HasFDerivWithinAt (p · m) (p x m.succ).curryLeft s x - cont : ∀ m : ℕ, (m : ℕ∞) ≤ n → ContinuousOn (p · m) s + 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 @@ -170,26 +171,31 @@ theorem hasFTaylorSeriesUpToOn_zero_iff : 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 +theorem hasFTaylorSeriesUpToOn_top_iff_add (hN : ∞ ≤ N) (k : ℕ) : + HasFTaylorSeriesUpToOn N f p s ↔ ∀ n : ℕ, HasFTaylorSeriesUpToOn (n + k : ℕ) f p s := by constructor - · intro H n; exact H.of_le le_top + · intro H n + apply H.of_le (natCast_le_of_coe_top_le_withTop hN _) · 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)) + apply (H m.succ).fderivWithin m (by norm_cast; omega) · intro m _ - apply (H m).cont m le_rfl + apply (H m).cont m (by simp) + +theorem hasFTaylorSeriesUpToOn_top_iff (hN : ∞ ≤ N) : + HasFTaylorSeriesUpToOn N f p s ↔ ∀ n : ℕ, HasFTaylorSeriesUpToOn n f p s := by + simpa using hasFTaylorSeriesUpToOn_top_iff_add hN 0 /-- In the case that `n = ∞` we don't need the continuity assumption in `HasFTaylorSeriesUpToOn`. -/ -theorem hasFTaylorSeriesUpToOn_top_iff' : - HasFTaylorSeriesUpToOn ∞ f p s ↔ +theorem hasFTaylorSeriesUpToOn_top_iff' (hN : ∞ ≤ N) : + HasFTaylorSeriesUpToOn N 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 := + ∀ m : ℕ, ∀ x ∈ s, HasFDerivWithinAt (fun y => p y m) (p x m.succ).curryLeft s x := by -- Everything except for the continuity is trivial: - ⟨fun h => ⟨h.1, fun m => h.2 m (WithTop.coe_lt_top m)⟩, fun h => + refine ⟨fun h => ⟨h.1, fun m => h.2 m (natCast_lt_of_coe_top_le_withTop hN _)⟩, 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⟩⟩ @@ -241,21 +247,21 @@ theorem hasFTaylorSeriesUpToOn_succ_iff_left {n : ℕ} : (∀ 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⟩ + · exact fun h ↦ ⟨h.of_le (mod_cast Nat.le_succ n), + h.fderivWithin _ (mod_cast 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' + · exact h.1.fderivWithin m (mod_cast h') + · have : m = n := Nat.eq_of_lt_succ_of_not_lt (mod_cast 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') + · apply h.1.cont m (mod_cast h') + · have : m = n + 1 := le_antisymm (mod_cast hm) (not_le.1 h') rw [this] exact h.2.2 @@ -273,8 +279,8 @@ theorem HasFTaylorSeriesUpToOn.shift_of_succ constructor · intro x _ rfl - · intro m (hm : (m : ℕ∞) < n) x (hx : x ∈ s) - have A : (m.succ : ℕ∞) < n.succ := by + · intro m (hm : (m : WithTop ℕ∞) < n) x (hx : x ∈ s) + have A : (m.succ : WithTop ℕ∞) < n.succ := by rw [Nat.cast_lt] at hm ⊢ exact Nat.succ_lt_succ hm change HasFDerivWithinAt (continuousMultilinearCurryRightEquiv' 𝕜 m E F ∘ (p · m.succ)) @@ -284,7 +290,7 @@ theorem HasFTaylorSeriesUpToOn.shift_of_succ 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) + · intro m (hm : (m : WithTop ℕ∞) ≤ n) suffices A : ContinuousOn (p · (m + 1)) s from (continuousMultilinearCurryRightEquiv' 𝕜 m E F).continuous.comp_continuousOn A refine H.cont _ ?_ @@ -292,8 +298,8 @@ theorem HasFTaylorSeriesUpToOn.shift_of_succ 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 : ℕ} : +for `p 1`, which is a derivative of `f`. Version for `n : ℕ`. -/ +theorem hasFTaylorSeriesUpToOn_succ_nat_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) ∧ @@ -306,10 +312,10 @@ theorem hasFTaylorSeriesUpToOn_succ_iff_right {n : ℕ} : · rintro ⟨Hzero_eq, Hfderiv_zero, Htaylor⟩ constructor · exact Hzero_eq - · intro m (hm : (m : ℕ∞) < n.succ) x (hx : x ∈ s) + · intro m (hm : (m : WithTop ℕ∞) < n.succ) x (hx : x ∈ s) cases' m with m · exact Hfderiv_zero x hx - · have A : (m : ℕ∞) < n := by + · have A : (m : WithTop ℕ∞) < n := by rw [Nat.cast_lt] at hm ⊢ exact Nat.lt_of_succ_lt_succ hm have : @@ -322,7 +328,7 @@ theorem hasFTaylorSeriesUpToOn_succ_iff_right {n : ℕ} : (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) + · intro m (hm : (m : WithTop ℕ∞) ≤ n.succ) cases' m with m · have : DifferentiableOn 𝕜 (fun x => p x 0) s := fun x hx => (Hfderiv_zero x hx).differentiableWithinAt @@ -332,6 +338,37 @@ theorem hasFTaylorSeriesUpToOn_succ_iff_right {n : ℕ} : rw [Nat.cast_le] at hm ⊢ exact Nat.lt_succ_iff.mp hm +/-- `p` is a Taylor series of `f` up to `⊤` if and only if `p.shift` is a Taylor series up to `⊤` +for `p 1`, which is a derivative of `f`. -/ +theorem hasFTaylorSeriesUpToOn_top_iff_right (hN : ∞ ≤ N) : + HasFTaylorSeriesUpToOn N 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 + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · rw [hasFTaylorSeriesUpToOn_top_iff_add hN 1] at h + rw [hasFTaylorSeriesUpToOn_top_iff hN] + exact ⟨(hasFTaylorSeriesUpToOn_succ_nat_iff_right.1 (h 1)).1, + (hasFTaylorSeriesUpToOn_succ_nat_iff_right.1 (h 1)).2.1, + fun n ↦ (hasFTaylorSeriesUpToOn_succ_nat_iff_right.1 (h n)).2.2⟩ + · apply (hasFTaylorSeriesUpToOn_top_iff_add hN 1).2 (fun n ↦ ?_) + rw [hasFTaylorSeriesUpToOn_succ_nat_iff_right] + exact ⟨h.1, h.2.1, (h.2.2).of_le (m := n) (natCast_le_of_coe_top_le_withTop hN n)⟩ + +/-- `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`. Version for `n : WithTop ℕ∞`. -/ +theorem hasFTaylorSeriesUpToOn_succ_iff_right : + 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 + match n with + | ⊤ => exact hasFTaylorSeriesUpToOn_top_iff_right (by simp) + | (⊤ : ℕ∞) => exact hasFTaylorSeriesUpToOn_top_iff_right (by simp) + | (n : ℕ) => exact hasFTaylorSeriesUpToOn_succ_nat_iff_right + /-! ### Iterated derivative within a set -/ @@ -537,11 +574,11 @@ theorem iteratedFDerivWithin_inter_open {n : ℕ} (hu : IsOpen u) (hx : x ∈ u) /-- 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) + (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 A : (m : ℕ∞) < n := lt_of_lt_of_le (mod_cast lt_add_one m) hmn have : HasFDerivWithinAt (fun y : E => iteratedFDerivWithin 𝕜 m f s y) (ContinuousMultilinearMap.curryLeft (p x (Nat.succ m))) s x := @@ -563,11 +600,11 @@ derivative of `p m` for `m < n`, and is continuous for `m ≤ n`. This is a pred 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 +structure HasFTaylorSeriesUpTo + (n : WithTop ℕ∞) (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 + 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 @@ -600,10 +637,13 @@ theorem HasFTaylorSeriesUpTo.hasFTaylorSeriesUpToOn (h : HasFTaylorSeriesUpTo n HasFTaylorSeriesUpToOn n f p s := (hasFTaylorSeriesUpToOn_univ_iff.2 h).mono (subset_univ _) -theorem HasFTaylorSeriesUpTo.ofLe (h : HasFTaylorSeriesUpTo n f p) (hmn : m ≤ n) : +theorem HasFTaylorSeriesUpTo.of_le (h : HasFTaylorSeriesUpTo n f p) (hmn : m ≤ n) : HasFTaylorSeriesUpTo m f p := by rw [← hasFTaylorSeriesUpToOn_univ_iff] at h ⊢; exact h.of_le hmn +@[deprecated (since := "2024-11-07")] +alias HasFTaylorSeriesUpTo.ofLe := HasFTaylorSeriesUpTo.of_le + theorem HasFTaylorSeriesUpTo.continuous (h : HasFTaylorSeriesUpTo n f p) : Continuous f := by rw [← hasFTaylorSeriesUpToOn_univ_iff] at h rw [continuous_iff_continuousOn_univ] @@ -614,17 +654,17 @@ theorem hasFTaylorSeriesUpTo_zero_iff : 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] +theorem hasFTaylorSeriesUpTo_top_iff (hN : ∞ ≤ N) : + HasFTaylorSeriesUpTo N f p ↔ ∀ n : ℕ, HasFTaylorSeriesUpTo n f p := by + simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff hN] /-- In the case that `n = ∞` we don't need the continuity assumption in `HasFTaylorSeriesUpTo`. -/ -theorem hasFTaylorSeriesUpTo_top_iff' : - HasFTaylorSeriesUpTo ∞ f p ↔ +theorem hasFTaylorSeriesUpTo_top_iff' (hN : ∞ ≤ N) : + HasFTaylorSeriesUpTo N 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, + simp only [← hasFTaylorSeriesUpToOn_univ_iff, hasFTaylorSeriesUpToOn_top_iff' hN, 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 @@ -639,15 +679,17 @@ theorem HasFTaylorSeriesUpTo.differentiable (h : HasFTaylorSeriesUpTo n f p) (hn /-- `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 : ℕ} : +theorem hasFTaylorSeriesUpTo_succ_nat_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, + simp only [hasFTaylorSeriesUpToOn_succ_nat_iff_right, ← hasFTaylorSeriesUpToOn_univ_iff, mem_univ, forall_true_left, hasFDerivWithinAt_univ] +@[deprecated (since := "2024-11-07")] +alias hasFTaylorSeriesUpTo_succ_iff_right := hasFTaylorSeriesUpTo_succ_nat_iff_right /-! ### Iterated derivative -/ diff --git a/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean b/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean index 1c2e5249d4f467..582c9ca4fec356 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean @@ -917,7 +917,7 @@ private lemma faaDiBruno_aux2 {m : ℕ} (q : FormalMultilinearSeries 𝕜 F G) /-- *Faa di Bruno* formula: If two functions `g` and `f` have Taylor series up to `n` given by `q` and `p`, then `g ∘ f` also has a Taylor series, given by `q.taylorComp p`. -/ -theorem HasFTaylorSeriesUpToOn.comp {n : ℕ∞} {g : F → G} {f : E → F} +theorem HasFTaylorSeriesUpToOn.comp {n : WithTop ℕ∞} {g : F → G} {f : E → F} (hg : HasFTaylorSeriesUpToOn n g q t) (hf : HasFTaylorSeriesUpToOn n f p s) (h : MapsTo f s t) : HasFTaylorSeriesUpToOn n (g ∘ f) (fun x ↦ (q (f x)).taylorComp (p x)) s := by /- One has to check that the `m+1`-th term is the derivative of the `m`-th term. The `m`-th term @@ -940,8 +940,8 @@ theorem HasFTaylorSeriesUpToOn.comp {n : ℕ∞} {g : F → G} {f : E → F} change HasFDerivWithinAt (fun y ↦ B (q (f y) c.length) (fun i ↦ p y (c.partSize i))) (∑ i : Option (Fin c.length), ((q (f x)).compAlongOrderedFinpartition (p x) (c.extend i)).curryLeft) s x - have cm : (c.length : ℕ∞) ≤ m := by exact_mod_cast OrderedFinpartition.length_le c - have cp i : (c.partSize i : ℕ∞) ≤ m := by + have cm : (c.length : WithTop ℕ∞) ≤ m := mod_cast OrderedFinpartition.length_le c + have cp i : (c.partSize i : WithTop ℕ∞) ≤ m := by exact_mod_cast OrderedFinpartition.partSize_le c i have I i : HasFDerivWithinAt (fun x ↦ p x (c.partSize i)) (p x (c.partSize i).succ).curryLeft s x := @@ -949,7 +949,8 @@ theorem HasFTaylorSeriesUpToOn.comp {n : ℕ∞} {g : F → G} {f : E → F} have J : HasFDerivWithinAt (fun x ↦ q x c.length) (q (f x) c.length.succ).curryLeft t (f x) := hg.fderivWithin c.length (cm.trans_lt hm) (f x) (h hx) have K : HasFDerivWithinAt f ((continuousMultilinearCurryFin1 𝕜 E F) (p x 1)) s x := - hf.hasFDerivWithinAt (le_trans le_add_self (Order.add_one_le_of_lt hm)) hx + hf.hasFDerivWithinAt (le_trans (mod_cast Nat.le_add_left 1 m) + (ENat.add_one_natCast_le_withTop_of_lt hm)) hx convert HasFDerivWithinAt.linear_multilinear_comp (J.comp x K h) I B simp only [Nat.succ_eq_add_one, Fintype.sum_option, comp_apply, faaDiBruno_aux1, faaDiBruno_aux2] @@ -975,8 +976,9 @@ theorem HasFTaylorSeriesUpToOn.comp {n : ℕ∞} {g : F → G} {f : E → F} change ContinuousOn ((fun p ↦ B p.1 p.2) ∘ (fun x ↦ (q (f x) c.length, fun i ↦ p x (c.partSize i)))) s apply B.continuous_uncurry_of_multilinear.comp_continuousOn (ContinuousOn.prod ?_ ?_) - · have : (c.length : ℕ∞) ≤ m := by exact_mod_cast OrderedFinpartition.length_le c + · have : (c.length : WithTop ℕ∞) ≤ m := mod_cast OrderedFinpartition.length_le c exact (hg.cont c.length (this.trans hm)).comp hf.continuousOn h · apply continuousOn_pi.2 (fun i ↦ ?_) - have : (c.partSize i : ℕ∞) ≤ m := by exact_mod_cast OrderedFinpartition.partSize_le c i + have : (c.partSize i : WithTop ℕ∞) ≤ m := by + exact_mod_cast OrderedFinpartition.partSize_le c i exact hf.cont _ (this.trans hm) diff --git a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean index e5d673c7ffac0a..c399175ddd00dd 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean @@ -20,6 +20,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {D : Type uD} [NormedAddCommGroup D] [NormedSpace 𝕜 D] {E : Type uE} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {F : Type uF} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {n : WithTop ℕ∞} {f : D → E} {s : Set D} /-! ### Finite dimensional results -/ @@ -30,7 +31,7 @@ open Function Module variable [CompleteSpace 𝕜] /-- A family of continuous linear maps is `C^n` on `s` if all its applications are. -/ -theorem contDiffOn_clm_apply {n : ℕ∞} {f : D → E →L[𝕜] F} {s : Set D} [FiniteDimensional 𝕜 E] : +theorem contDiffOn_clm_apply {f : D → E →L[𝕜] F} {s : Set D} [FiniteDimensional 𝕜 E] : ContDiffOn 𝕜 n f s ↔ ∀ y, ContDiffOn 𝕜 n (fun x => f x y) s := by refine ⟨fun h y => h.clm_apply contDiffOn_const, fun h => ?_⟩ let d := finrank 𝕜 E @@ -40,7 +41,7 @@ theorem contDiffOn_clm_apply {n : ℕ∞} {f : D → E →L[𝕜] F} {s : Set D} rw [← id_comp f, ← e₂.symm_comp_self] exact e₂.symm.contDiff.comp_contDiffOn (contDiffOn_pi.mpr fun i => h _) -theorem contDiff_clm_apply_iff {n : ℕ∞} {f : D → E →L[𝕜] F} [FiniteDimensional 𝕜 E] : +theorem contDiff_clm_apply_iff {f : D → E →L[𝕜] F} [FiniteDimensional 𝕜 E] : ContDiff 𝕜 n f ↔ ∀ y, ContDiff 𝕜 n fun x => f x y := by simp_rw [← contDiffOn_univ, contDiffOn_clm_apply] @@ -48,23 +49,23 @@ theorem contDiff_clm_apply_iff {n : ℕ∞} {f : D → E →L[𝕜] F} [FiniteDi When you do induction on `n`, this gives a useful characterization of a function being `C^(n+1)`, assuming you have already computed the derivative. The advantage of this version over `contDiff_succ_iff_fderiv` is that both occurrences of `ContDiff` are for functions with the same -domain and codomain (`E` and `F`). This is not the case for `contDiff_succ_iff_fderiv`, which +domain and codomain (`D` and `E`). This is not the case for `contDiff_succ_iff_fderiv`, which often requires an inconvenient need to generalize `F`, which results in universe issues (see the discussion in the section of `ContDiff.comp`). This lemma avoids these universe issues, but only applies for finite dimensional `E`. -/ theorem contDiff_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} : - ContDiff 𝕜 (n + 1 : ℕ) f ↔ Differentiable 𝕜 f ∧ ∀ y, ContDiff 𝕜 n fun x => fderiv 𝕜 f x y := by + ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ ∀ y, ContDiff 𝕜 n fun x => fderiv 𝕜 f x y := by rw [contDiff_succ_iff_fderiv, contDiff_clm_apply_iff] theorem contDiffOn_succ_of_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} {s : Set D} (hf : DifferentiableOn 𝕜 f s) (h : ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s) : - ContDiffOn 𝕜 (n + 1 : ℕ) f s := + ContDiffOn 𝕜 (n + 1) f s := contDiffOn_succ_of_fderivWithin hf <| contDiffOn_clm_apply.mpr h theorem contDiffOn_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} {s : Set D} (hs : UniqueDiffOn 𝕜 s) : - ContDiffOn 𝕜 (n + 1 : ℕ) f s ↔ + ContDiffOn 𝕜 (n + 1) f s ↔ DifferentiableOn 𝕜 f s ∧ ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s := by rw [contDiffOn_succ_iff_fderivWithin hs, contDiffOn_clm_apply] diff --git a/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean b/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean index d9f341edf671a7..e87af872c43a25 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean @@ -24,12 +24,13 @@ section Real its extension fields such as `ℂ`). -/ -variable {n : ℕ∞} {𝕂 : Type*} [RCLike 𝕂] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕂 E'] - {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕂 F'] +variable {n : WithTop ℕ∞} {𝕂 : Type*} [RCLike 𝕂] {E' : Type*} [NormedAddCommGroup E'] + [NormedSpace 𝕂 E'] {F' : Type*} [NormedAddCommGroup F'] [NormedSpace 𝕂 F'] /-- If a function has a Taylor series at order at least 1, then at points in the interior of the domain of definition, the term of order 1 of this series is a strict derivative of `f`. -/ -theorem HasFTaylorSeriesUpToOn.hasStrictFDerivAt {s : Set E'} {f : E' → F'} {x : E'} +theorem HasFTaylorSeriesUpToOn.hasStrictFDerivAt {n : WithTop ℕ∞} + {s : Set E'} {f : E' → F'} {x : E'} {p : E' → FormalMultilinearSeries 𝕂 E' F'} (hf : HasFTaylorSeriesUpToOn n f p s) (hn : 1 ≤ n) (hs : s ∈ 𝓝 x) : HasStrictFDerivAt f ((continuousMultilinearCurryFin1 𝕂 E' F') (p x 1)) x := hasStrictFDerivAt_of_hasFDerivAt_of_continuousAt (hf.eventually_hasFDerivAt hn hs) <| @@ -40,7 +41,7 @@ us as `f'`, then `f'` is also a strict derivative. -/ theorem ContDiffAt.hasStrictFDerivAt' {f : E' → F'} {f' : E' →L[𝕂] F'} {x : E'} (hf : ContDiffAt 𝕂 n f x) (hf' : HasFDerivAt f f' x) (hn : 1 ≤ n) : HasStrictFDerivAt f f' x := by - rcases hf 1 hn with ⟨u, H, p, hp⟩ + rcases hf.of_le hn 1 le_rfl with ⟨u, H, p, hp⟩ simp only [nhdsWithin_univ, mem_univ, insert_eq_of_mem] at H have := hp.hasStrictFDerivAt le_rfl H rwa [hf'.unique this.hasFDerivAt] @@ -134,7 +135,7 @@ lemma ContDiff.locallyLipschitz {f : E' → F'} (hf : ContDiff 𝕂 1 f) : Local use K, t /-- A `C^1` function with compact support is Lipschitz. -/ -theorem ContDiff.lipschitzWith_of_hasCompactSupport {f : E' → F'} {n : ℕ∞} +theorem ContDiff.lipschitzWith_of_hasCompactSupport {f : E' → F'} (hf : HasCompactSupport f) (h'f : ContDiff 𝕂 n f) (hn : 1 ≤ n) : ∃ C, LipschitzWith C f := by obtain ⟨C, hC⟩ := (hf.fderiv 𝕂).exists_bound_of_continuous (h'f.continuous_fderiv hn) diff --git a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean index 76c137c4bab788..9141ffab19f41a 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean @@ -63,7 +63,7 @@ differentiability at points in a neighborhood of `s`. Therefore, the theorem tha open Filter Asymptotics Set -open scoped ENNReal Topology +open scoped ENNReal Topology ContDiff universe u v @@ -261,7 +261,7 @@ by the sequence of its derivatives. Note that, if the function were just analyti 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) : + (n : WithTop ℕ∞) (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 @@ -270,25 +270,27 @@ lemma AnalyticOnNhd.hasFTaylorSeriesUpToOn [CompleteSpace F] exact (h.iteratedFDeriv m x hx).differentiableAt /-- An analytic function is infinitely differentiable. -/ -protected theorem AnalyticOnNhd.contDiffOn [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) {n : ℕ∞} : - ContDiffOn 𝕜 n f s := +protected theorem AnalyticOnNhd.contDiffOn [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) + {n : WithTop ℕ∞} : ContDiffOn 𝕜 n f s := by + suffices ContDiffOn 𝕜 ω f s from this.of_le le_top + rw [← contDiffOn_infty_iff_contDiffOn_omega] let t := { x | AnalyticAt 𝕜 f x } - suffices ContDiffOn 𝕜 n f t from this.mono h + suffices ContDiffOn 𝕜 ∞ f t from this.mono h have H : AnalyticOnNhd 𝕜 f t := fun _x hx ↦ hx have t_open : IsOpen t := isOpen_analyticAt 𝕜 f - contDiffOn_of_continuousOn_differentiableOn + exact contDiffOn_of_continuousOn_differentiableOn (fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) (fun m _ ↦ (H.iteratedFDeriv m).differentiableOn.congr fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) /-- An analytic function on the whole space is infinitely differentiable there. -/ -theorem AnalyticOnNhd.contDiff [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f univ) {n : ℕ∞} : +theorem AnalyticOnNhd.contDiff [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f univ) {n : WithTop ℕ∞} : ContDiff 𝕜 n f := by rw [← contDiffOn_univ] exact h.contDiffOn -theorem AnalyticAt.contDiffAt [CompleteSpace F] (h : AnalyticAt 𝕜 f x) {n : ℕ∞} : +theorem AnalyticAt.contDiffAt [CompleteSpace F] (h : AnalyticAt 𝕜 f x) {n : WithTop ℕ∞} : ContDiffAt 𝕜 n f x := by obtain ⟨s, hs, hf⟩ := h.exists_mem_nhds_analyticOnNhd exact hf.contDiffOn.contDiffAt hs @@ -306,7 +308,7 @@ protected lemma AnalyticOn.contDiffOn [CompleteSpace F] {f : E → F} {s : Set E alias AnalyticWithinOn.contDiffOn := AnalyticOn.contDiffOn lemma AnalyticWithinAt.exists_hasFTaylorSeriesUpToOn [CompleteSpace F] - (n : ℕ∞) (h : AnalyticWithinAt 𝕜 f s x) : + (n : WithTop ℕ∞) (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⟩ @@ -382,7 +384,7 @@ protected theorem AnalyticOn.iteratedFDerivWithin (h : AnalyticOn 𝕜 f s) apply AnalyticOnNhd.comp_analyticOn _ (IH.fderivWithin hu) (mapsTo_univ _ _) apply LinearIsometryEquiv.analyticOnNhd -lemma AnalyticOn.hasFTaylorSeriesUpToOn {n : ℕ∞} +lemma AnalyticOn.hasFTaylorSeriesUpToOn {n : WithTop ℕ∞} (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 ↦ ?_⟩ @@ -545,19 +547,21 @@ theorem CPolynomialOn.iteratedFDeriv (h : CPolynomialOn 𝕜 f s) (n : ℕ) : simp /-- A polynomial function is infinitely differentiable. -/ -theorem CPolynomialOn.contDiffOn (h : CPolynomialOn 𝕜 f s) {n : ℕ∞} : - ContDiffOn 𝕜 n f s := +theorem CPolynomialOn.contDiffOn (h : CPolynomialOn 𝕜 f s) {n : WithTop ℕ∞} : + ContDiffOn 𝕜 n f s := by + suffices ContDiffOn 𝕜 ω f s from this.of_le le_top let t := { x | CPolynomialAt 𝕜 f x } - suffices ContDiffOn 𝕜 n f t from this.mono h + suffices ContDiffOn 𝕜 ω f t from this.mono h + rw [← contDiffOn_infty_iff_contDiffOn_omega] have H : CPolynomialOn 𝕜 f t := fun _x hx ↦ hx have t_open : IsOpen t := isOpen_cPolynomialAt 𝕜 f - contDiffOn_of_continuousOn_differentiableOn + exact contDiffOn_of_continuousOn_differentiableOn (fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) (fun m _ ↦ (H.iteratedFDeriv m).analyticOnNhd.differentiableOn.congr fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) -theorem CPolynomialAt.contDiffAt (h : CPolynomialAt 𝕜 f x) {n : ℕ∞} : +theorem CPolynomialAt.contDiffAt (h : CPolynomialAt 𝕜 f x) {n : WithTop ℕ∞} : ContDiffAt 𝕜 n f x := let ⟨_, hs, hf⟩ := h.exists_mem_nhds_cPolynomialOn hf.contDiffOn.contDiffAt hs @@ -595,7 +599,7 @@ theorem changeOriginSeries_support {k l : ℕ} (h : k + l ≠ Fintype.card ι) : simp_rw [FormalMultilinearSeries.changeOriginSeriesTerm, toFormalMultilinearSeries, dif_neg h.symm, LinearIsometryEquiv.map_zero] -variable {n : ℕ∞} (x : ∀ i, E i) +variable {n : WithTop ℕ∞} (x : ∀ i, E i) open Finset in theorem changeOrigin_toFormalMultilinearSeries [DecidableEq ι] : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Norm.lean b/Mathlib/Analysis/Calculus/FDeriv/Norm.lean index 4587f2bbf6dfcb..fabdde33a4bfdf 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Norm.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Norm.lean @@ -38,7 +38,7 @@ differentiability, norm open ContinuousLinearMap Filter NNReal Real Set variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] -variable {n : ℕ∞} {f : E →L[ℝ] ℝ} {x : E} {t : ℝ} +variable {n : WithTop ℕ∞} {f : E →L[ℝ] ℝ} {x : E} {t : ℝ} variable (E) in theorem not_differentiableAt_norm_zero [Nontrivial E] : @@ -72,15 +72,15 @@ theorem contDiffAt_norm_smul_iff (ht : t ≠ 0) : 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] + rcases eq_bot_or_bot_lt n with rfl | hn + · apply contDiffAt_zero.2 exact ⟨univ, univ_mem, continuous_norm.continuousOn⟩ + replace hn : 1 ≤ n := ENat.add_one_natCast_le_withTop_of_lt hn 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 + exact (mt (ContDiffAt.differentiableAt · (mod_cast hn))) + (not_differentiableAt_norm_zero E) h |>.elim · rw [not_nontrivial_iff_subsingleton] at hE rw [eq_const_of_subsingleton (‖·‖) 0] exact contDiffAt_const diff --git a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean index a893dcc67f3d8a..b4f9b4db76e68a 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean @@ -444,7 +444,7 @@ theorem second_derivative_symmetric {f' : E → E →L[𝕜] F} {f'' : E →L[ second_derivative_symmetric_of_eventually (Filter.Eventually.of_forall hf) hx v w /-- If a function is `C^2` at a point, then its second derivative there is symmetric. -/ -theorem ContDiffAt.isSymmSndFDerivAt {n : ℕ∞} (hf : ContDiffAt 𝕜 n f x) (hn : 2 ≤ n) : +theorem ContDiffAt.isSymmSndFDerivAt {n : WithTop ℕ∞} (hf : ContDiffAt 𝕜 n f x) (hn : 2 ≤ n) : IsSymmSndFDerivAt 𝕜 f x := by intro v w apply second_derivative_symmetric_of_eventually (f := f) (f' := fderiv 𝕜 f) (x := x) @@ -462,7 +462,7 @@ theorem ContDiffAt.isSymmSndFDerivAt {n : ℕ∞} (hf : ContDiffAt 𝕜 n f x) ( /-- If a function is `C^2` within a set at a point, and accumulated by points in the interior of the set, then its second derivative there is symmetric. -/ -theorem ContDiffWithinAt.isSymmSndFDerivWithinAt {n : ℕ∞} (hf : ContDiffWithinAt 𝕜 n f s x) +theorem ContDiffWithinAt.isSymmSndFDerivWithinAt {n : WithTop ℕ∞} (hf : ContDiffWithinAt 𝕜 n f s x) (hn : 2 ≤ n) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ closure (interior s)) (h'x : x ∈ s) : IsSymmSndFDerivWithinAt 𝕜 f s x := by /- We argue that, at interior points, the second derivative is symmetric, and moreover by diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean index 55e18e301150af..49b5c3a3c929c6 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ContDiff.lean @@ -20,46 +20,46 @@ namespace ContDiffAt variable {𝕂 : Type*} [RCLike 𝕂] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕂 E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕂 F] -variable [CompleteSpace E] (f : E → F) {f' : E ≃L[𝕂] F} {a : E} +variable [CompleteSpace E] (f : E → F) {f' : E ≃L[𝕂] F} {a : E} {n : WithTop ℕ∞} /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible derivative at `a`, returns a `PartialHomeomorph` with `to_fun = f` and `a ∈ source`. -/ -def toPartialHomeomorph {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) +def toPartialHomeomorph (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : PartialHomeomorph E F := (hf.hasStrictFDerivAt' hf' hn).toPartialHomeomorph f variable {f} @[simp] -theorem toPartialHomeomorph_coe {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem toPartialHomeomorph_coe (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : (hf.toPartialHomeomorph f hf' hn : E → F) = f := rfl -theorem mem_toPartialHomeomorph_source {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem mem_toPartialHomeomorph_source (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : a ∈ (hf.toPartialHomeomorph f hf' hn).source := (hf.hasStrictFDerivAt' hf' hn).mem_toPartialHomeomorph_source -theorem image_mem_toPartialHomeomorph_target {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem image_mem_toPartialHomeomorph_target (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : f a ∈ (hf.toPartialHomeomorph f hf' hn).target := (hf.hasStrictFDerivAt' hf' hn).image_mem_toPartialHomeomorph_target /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible derivative at `a`, returns a function that is locally inverse to `f`. -/ -def localInverse {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) +def localInverse (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : F → E := (hf.hasStrictFDerivAt' hf' hn).localInverse f f' a -theorem localInverse_apply_image {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem localInverse_apply_image (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : hf.localInverse hf' hn (f a) = a := (hf.hasStrictFDerivAt' hf' hn).localInverse_apply_image /-- Given a `ContDiff` function over `𝕂` (which is `ℝ` or `ℂ`) with an invertible derivative at `a`, the inverse function (produced by `ContDiff.toPartialHomeomorph`) is also `ContDiff`. -/ -theorem to_localInverse {n : ℕ∞} (hf : ContDiffAt 𝕂 n f a) +theorem to_localInverse (hf : ContDiffAt 𝕂 n f a) (hf' : HasFDerivAt f (f' : E →L[𝕂] F) a) (hn : 1 ≤ n) : ContDiffAt 𝕂 n (hf.localInverse hf' hn) (f a) := by have := hf.localInverse_apply_image hf' hn diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean index 9fcaa3d13a0ccd..858642c83caa89 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean @@ -131,12 +131,13 @@ theorem contDiffOn_of_differentiableOn_deriv {n : ℕ∞} /-- On a set with unique derivatives, a `C^n` function has derivatives up to `n` which are continuous. -/ -theorem ContDiffOn.continuousOn_iteratedDerivWithin {n : ℕ∞} {m : ℕ} (h : ContDiffOn 𝕜 n f s) +theorem ContDiffOn.continuousOn_iteratedDerivWithin + {n : WithTop ℕ∞} {m : ℕ} (h : ContDiffOn 𝕜 n f s) (hmn : (m : ℕ∞) ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedDerivWithin m f s) s := by simpa only [iteratedDerivWithin_eq_equiv_comp, LinearIsometryEquiv.comp_continuousOn_iff] using h.continuousOn_iteratedFDerivWithin hmn hs -theorem ContDiffWithinAt.differentiableWithinAt_iteratedDerivWithin {n : ℕ∞} {m : ℕ} +theorem ContDiffWithinAt.differentiableWithinAt_iteratedDerivWithin {n : WithTop ℕ∞} {m : ℕ} (h : ContDiffWithinAt 𝕜 n f s x) (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : DifferentiableWithinAt 𝕜 (iteratedDerivWithin m f s) s x := by simpa only [iteratedDerivWithin_eq_equiv_comp, @@ -145,8 +146,8 @@ theorem ContDiffWithinAt.differentiableWithinAt_iteratedDerivWithin {n : ℕ∞} /-- On a set with unique derivatives, a `C^n` function has derivatives less than `n` which are differentiable. -/ -theorem ContDiffOn.differentiableOn_iteratedDerivWithin {n : ℕ∞} {m : ℕ} (h : ContDiffOn 𝕜 n f s) - (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 s) : +theorem ContDiffOn.differentiableOn_iteratedDerivWithin {n : WithTop ℕ∞} {m : ℕ} + (h : ContDiffOn 𝕜 n f s) (hmn : m < n) (hs : UniqueDiffOn 𝕜 s) : DifferentiableOn 𝕜 (iteratedDerivWithin m f s) s := fun x hx => (h x hx).differentiableWithinAt_iteratedDerivWithin hmn <| by rwa [insert_eq_of_mem hx] @@ -238,13 +239,14 @@ theorem contDiff_of_differentiable_iteratedDeriv {n : ℕ∞} (h : ∀ m : ℕ, (m : ℕ∞) ≤ n → Differentiable 𝕜 (iteratedDeriv m f)) : ContDiff 𝕜 n f := contDiff_iff_iteratedDeriv.2 ⟨fun m hm => (h m hm).continuous, fun m hm => h m (le_of_lt hm)⟩ -theorem ContDiff.continuous_iteratedDeriv {n : ℕ∞} (m : ℕ) (h : ContDiff 𝕜 n f) - (hmn : (m : ℕ∞) ≤ n) : Continuous (iteratedDeriv m f) := - (contDiff_iff_iteratedDeriv.1 h).1 m hmn +theorem ContDiff.continuous_iteratedDeriv {n : WithTop ℕ∞} (m : ℕ) (h : ContDiff 𝕜 n f) + (hmn : m ≤ n) : Continuous (iteratedDeriv m f) := + (contDiff_iff_iteratedDeriv.1 (h.of_le hmn)).1 m le_rfl -theorem ContDiff.differentiable_iteratedDeriv {n : ℕ∞} (m : ℕ) (h : ContDiff 𝕜 n f) - (hmn : (m : ℕ∞) < n) : Differentiable 𝕜 (iteratedDeriv m f) := - (contDiff_iff_iteratedDeriv.1 h).2 m hmn +theorem ContDiff.differentiable_iteratedDeriv {n : WithTop ℕ∞} (m : ℕ) (h : ContDiff 𝕜 n f) + (hmn : m < n) : Differentiable 𝕜 (iteratedDeriv m f) := + (contDiff_iff_iteratedDeriv.1 (h.of_le (ENat.add_one_natCast_le_withTop_of_lt hmn))).2 m + (mod_cast (lt_add_one m)) /-- The `n+1`-th iterated derivative can be obtained by differentiating the `n`-th iterated derivative. -/ diff --git a/Mathlib/Analysis/Calculus/LHopital.lean b/Mathlib/Analysis/Calculus/LHopital.lean index f1e691d8342cfe..66b0aac6e04ccd 100644 --- a/Mathlib/Analysis/Calculus/LHopital.lean +++ b/Mathlib/Analysis/Calculus/LHopital.lean @@ -110,11 +110,11 @@ theorem lhopital_zero_left_on_Ioo (hab : a < b) (hff' : ∀ x ∈ Ioo a b, HasDe comp x (hff' (-x) hx) (hasDerivAt_neg x) have hdng : ∀ x ∈ -Ioo a b, HasDerivAt (g ∘ Neg.neg) (g' (-x) * -1) x := fun x hx => comp x (hgg' (-x) hx) (hasDerivAt_neg x) - rw [preimage_neg_Ioo] at hdnf - rw [preimage_neg_Ioo] at hdng + rw [neg_Ioo] at hdnf + rw [neg_Ioo] at hdng have := lhopital_zero_right_on_Ioo (neg_lt_neg hab) hdnf hdng (by intro x hx h - apply hg' _ (by rw [← preimage_neg_Ioo] at hx; exact hx) + apply hg' _ (by rw [← neg_Ioo] at hx; exact hx) rwa [mul_comm, ← neg_eq_neg_one_mul, neg_eq_zero] at h) (hfb.comp tendsto_neg_nhdsWithin_Ioi_neg) (hgb.comp tendsto_neg_nhdsWithin_Ioi_neg) (by @@ -176,12 +176,12 @@ theorem lhopital_zero_atBot_on_Iio (hff' : ∀ x ∈ Iio a, HasDerivAt f (f' x) comp x (hff' (-x) hx) (hasDerivAt_neg x) have hdng : ∀ x ∈ -Iio a, HasDerivAt (g ∘ Neg.neg) (g' (-x) * -1) x := fun x hx => comp x (hgg' (-x) hx) (hasDerivAt_neg x) - rw [preimage_neg_Iio] at hdnf - rw [preimage_neg_Iio] at hdng + rw [neg_Iio] at hdnf + rw [neg_Iio] at hdng have := lhopital_zero_atTop_on_Ioi hdnf hdng (by intro x hx h - apply hg' _ (by rw [← preimage_neg_Iio] at hx; exact hx) + apply hg' _ (by rw [← neg_Iio] at hx; exact hx) rwa [mul_comm, ← neg_eq_neg_one_mul, neg_eq_zero] at h) (hfbot.comp tendsto_neg_atTop_atBot) (hgbot.comp tendsto_neg_atTop_atBot) (by diff --git a/Mathlib/Analysis/Calculus/MeanValue.lean b/Mathlib/Analysis/Calculus/MeanValue.lean index c91086f4d4c709..691da7a3e65627 100644 --- a/Mathlib/Analysis/Calculus/MeanValue.lean +++ b/Mathlib/Analysis/Calculus/MeanValue.lean @@ -117,7 +117,7 @@ theorem image_le_of_liminf_slope_right_lt_deriv_boundary' {f f' : ℝ → ℝ} { (hf'.and_eventually (HB.and (Ioc_mem_nhdsWithin_Ioi ⟨le_rfl, hy⟩))).exists refine ⟨z, ?_, hz⟩ have := (hfz.trans hzB).le - rwa [slope_def_field, slope_def_field, div_le_div_right (sub_pos.2 hz.1), hxB, + rwa [slope_def_field, slope_def_field, div_le_div_iff_of_pos_right (sub_pos.2 hz.1), hxB, sub_le_sub_iff_right] at this /-- General fencing theorem for continuous functions with an estimate on the derivative. diff --git a/Mathlib/Analysis/Calculus/Monotone.lean b/Mathlib/Analysis/Calculus/Monotone.lean index 599a701b6b2119..f54f48fe98117c 100644 --- a/Mathlib/Analysis/Calculus/Monotone.lean +++ b/Mathlib/Analysis/Calculus/Monotone.lean @@ -108,7 +108,7 @@ theorem StieltjesFunction.ae_hasDerivAt (f : StieltjesFunction) : filter_upwards [this] rintro y ⟨hy : x - 1 < y, h'y : y < x⟩ rw [mem_Iio] - norm_num; nlinarith + nlinarith -- Deduce the correct limit on the left, by sandwiching. have L4 : Tendsto (fun y => (f y - f x) / (y - x)) (𝓝[<] x) (𝓝 (rnDeriv f.measure volume x).toReal) := by @@ -118,7 +118,7 @@ theorem StieltjesFunction.ae_hasDerivAt (f : StieltjesFunction) : refine div_le_div_of_nonpos_of_le (by linarith) ((sub_le_sub_iff_right _).2 ?_) apply f.mono.le_leftLim have : ↑0 < (x - y) ^ 2 := sq_pos_of_pos (sub_pos.2 hy) - norm_num; linarith + linarith · filter_upwards [self_mem_nhdsWithin] rintro y (hy : y < x) refine div_le_div_of_nonpos_of_le (by linarith) ?_ @@ -161,7 +161,7 @@ theorem Monotone.ae_hasDerivAt {f : ℝ → ℝ} (hf : Monotone f) : filter_upwards [this] rintro y ⟨hy : x < y, h'y : y < x + 1⟩ rw [mem_Ioi] - norm_num; nlinarith + nlinarith -- apply the sandwiching argument, with the helper function and `g` apply tendsto_of_tendsto_of_tendsto_of_le_of_le' this hx.2 · filter_upwards [self_mem_nhdsWithin] with y hy @@ -190,7 +190,7 @@ theorem Monotone.ae_hasDerivAt {f : ℝ → ℝ} (hf : Monotone f) : rintro y hy rw [mem_Ioo] at hy rw [mem_Iio] - norm_num; nlinarith + nlinarith -- apply the sandwiching argument, with `g` and the helper function apply tendsto_of_tendsto_of_tendsto_of_le_of_le' hx.1 this · filter_upwards [self_mem_nhdsWithin] @@ -203,7 +203,7 @@ theorem Monotone.ae_hasDerivAt {f : ℝ → ℝ} (hf : Monotone f) : rw [mem_Iio, ← sub_neg] at hy have : 0 < (y - x) ^ 2 := sq_pos_of_neg hy apply div_le_div_of_nonpos_of_le hy.le - exact (sub_le_sub_iff_right _).2 (hf.rightLim_le (by norm_num; linarith)) + exact (sub_le_sub_iff_right _).2 (hf.rightLim_le (by linarith)) -- conclude global differentiability rw [hasDerivAt_iff_tendsto_slope, slope_fun_def_field, (nhds_left'_sup_nhds_right' x).symm, tendsto_sup] diff --git a/Mathlib/Analysis/Calculus/Rademacher.lean b/Mathlib/Analysis/Calculus/Rademacher.lean index 28ad0559741a1e..1c836a3a36f925 100644 --- a/Mathlib/Analysis/Calculus/Rademacher.lean +++ b/Mathlib/Analysis/Calculus/Rademacher.lean @@ -221,9 +221,9 @@ theorem ae_lineDeriv_sum_eq suffices S2 : ∫ x, (∑ i ∈ s, a i * fderiv ℝ g x (v i)) * f x ∂μ = ∑ i ∈ s, a i * ∫ x, fderiv ℝ g x (v i) * f x ∂μ by obtain ⟨D, g_lip⟩ : ∃ D, LipschitzWith D g := - ContDiff.lipschitzWith_of_hasCompactSupport g_comp g_smooth le_top + ContDiff.lipschitzWith_of_hasCompactSupport g_comp g_smooth (mod_cast le_top) simp_rw [integral_lineDeriv_mul_eq hf g_lip g_comp] - simp_rw [(g_smooth.differentiable le_top).differentiableAt.lineDeriv_eq_fderiv] + simp_rw [(g_smooth.differentiable (mod_cast le_top)).differentiableAt.lineDeriv_eq_fderiv] simp only [map_neg, _root_.map_sum, _root_.map_smul, smul_eq_mul, neg_mul] simp only [integral_neg, mul_neg, Finset.sum_neg_distrib, neg_inj] exact S2 @@ -233,7 +233,8 @@ theorem ae_lineDeriv_sum_eq let L : (E →L[ℝ] ℝ) → ℝ := fun f ↦ f (v i) change Integrable (fun x ↦ a i * ((L ∘ (fderiv ℝ g)) x * f x)) μ refine (Continuous.integrable_of_hasCompactSupport ?_ ?_).const_mul _ - · exact ((g_smooth.continuous_fderiv le_top).clm_apply continuous_const).mul hf.continuous + · exact ((g_smooth.continuous_fderiv (mod_cast le_top)).clm_apply continuous_const).mul + hf.continuous · exact ((g_comp.fderiv ℝ).comp_left rfl).mul_right /-! diff --git a/Mathlib/Analysis/Calculus/SmoothSeries.lean b/Mathlib/Analysis/Calculus/SmoothSeries.lean index 58d0f39d86c54d..073a4b2192939e 100644 --- a/Mathlib/Analysis/Calculus/SmoothSeries.lean +++ b/Mathlib/Analysis/Calculus/SmoothSeries.lean @@ -198,7 +198,8 @@ theorem iteratedFDeriv_tsum (hf : ∀ i, ContDiff 𝕜 N (f i)) have A : Summable fun n => iteratedFDeriv 𝕜 k (f n) 0 := .of_norm_bounded (v k) (hv k h'k.le) fun n => h'f k n 0 h'k.le simp_rw [iteratedFDeriv_succ_eq_comp_left, IH h'k.le] - rw [fderiv_tsum (hv _ hk) (fun n => (hf n).differentiable_iteratedFDeriv h'k) _ A] + rw [fderiv_tsum (hv _ hk) (fun n => (hf n).differentiable_iteratedFDeriv + (mod_cast h'k)) _ A] · ext1 x exact (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (k + 1) => E) F).symm.toContinuousLinearEquiv.map_tsum @@ -219,7 +220,7 @@ theorem iteratedFDeriv_tsum_apply (hf : ∀ i, ContDiff 𝕜 N (f i)) class `C^N`, and moreover there is a uniform summable upper bound on the `k`-th derivative for each `k ≤ N`. Then the series is also `C^N`. -/ theorem contDiff_tsum (hf : ∀ i, ContDiff 𝕜 N (f i)) (hv : ∀ k : ℕ, (k : ℕ∞) ≤ N → Summable (v k)) - (h'f : ∀ (k : ℕ) (i : α) (x : E), (k : ℕ∞) ≤ N → ‖iteratedFDeriv 𝕜 k (f i) x‖ ≤ v k i) : + (h'f : ∀ (k : ℕ) (i : α) (x : E), k ≤ N → ‖iteratedFDeriv 𝕜 k (f i) x‖ ≤ v k i) : ContDiff 𝕜 N fun x => ∑' i, f i x := by rw [contDiff_iff_continuous_differentiable] constructor @@ -227,16 +228,16 @@ theorem contDiff_tsum (hf : ∀ i, ContDiff 𝕜 N (f i)) (hv : ∀ k : ℕ, (k rw [iteratedFDeriv_tsum hf hv h'f hm] refine continuous_tsum ?_ (hv m hm) ?_ · intro i - exact ContDiff.continuous_iteratedFDeriv hm (hf i) + exact ContDiff.continuous_iteratedFDeriv (mod_cast hm) (hf i) · intro n x exact h'f _ _ _ hm · intro m hm have h'm : ((m + 1 : ℕ) : ℕ∞) ≤ N := by 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 := - fun n x => (ContDiff.differentiable_iteratedFDeriv hm (hf n)).differentiableAt.hasFDerivAt + have A n x : HasFDerivAt (iteratedFDeriv 𝕜 m (f n)) (fderiv 𝕜 (iteratedFDeriv 𝕜 m (f n)) x) x := + (ContDiff.differentiable_iteratedFDeriv (mod_cast hm) + (hf n)).differentiableAt.hasFDerivAt refine differentiable_tsum (hv _ h'm) A fun n x => ?_ rw [fderiv_iteratedFDeriv, comp_apply, LinearIsometryEquiv.norm_map] exact h'f _ _ _ h'm @@ -245,11 +246,9 @@ theorem contDiff_tsum (hf : ∀ i, ContDiff 𝕜 N (f i)) (hv : ∀ k : ℕ, (k class `C^N`, and moreover there is a uniform summable upper bound on the `k`-th derivative for each `k ≤ N` (except maybe for finitely many `i`s). Then the series is also `C^N`. -/ theorem contDiff_tsum_of_eventually (hf : ∀ i, ContDiff 𝕜 N (f i)) - (hv : ∀ k : ℕ, (k : ℕ∞) ≤ N → Summable (v k)) - (h'f : - ∀ k : ℕ, - (k : ℕ∞) ≤ N → - ∀ᶠ i in (Filter.cofinite : Filter α), ∀ x : E, ‖iteratedFDeriv 𝕜 k (f i) x‖ ≤ v k i) : + (hv : ∀ k : ℕ, k ≤ N → Summable (v k)) + (h'f : ∀ k : ℕ, k ≤ N → + ∀ᶠ i in (Filter.cofinite : Filter α), ∀ x : E, ‖iteratedFDeriv 𝕜 k (f i) x‖ ≤ v k i) : ContDiff 𝕜 N fun x => ∑' i, f i x := by classical refine contDiff_iff_forall_nat_le.2 fun m hm => ?_ @@ -274,10 +273,10 @@ theorem contDiff_tsum_of_eventually (hf : ∀ i, ContDiff 𝕜 N (f i)) filter_upwards [h'f 0 (zero_le _)] with i hi simpa only [norm_iteratedFDeriv_zero] using hi x rw [this] - apply (ContDiff.sum fun i _ => (hf i).of_le hm).add + apply (ContDiff.sum fun i _ => (hf i).of_le (mod_cast hm)).add have h'u : ∀ k : ℕ, (k : ℕ∞) ≤ m → Summable (v k ∘ ((↑) : { i // i ∉ T } → α)) := fun k hk => (hv k (hk.trans hm)).subtype _ - refine contDiff_tsum (fun i => (hf i).of_le hm) h'u ?_ + refine contDiff_tsum (fun i => (hf i).of_le (mod_cast hm)) h'u ?_ rintro k ⟨i, hi⟩ x hk simp only [t, T, Finite.mem_toFinset, mem_setOf_eq, Finset.mem_range, not_forall, not_le, exists_prop, not_exists, not_and, not_lt] at hi diff --git a/Mathlib/Analysis/Calculus/Taylor.lean b/Mathlib/Analysis/Calculus/Taylor.lean index 71293eb9d30587..8a56fcf0d80a43 100644 --- a/Mathlib/Analysis/Calculus/Taylor.lean +++ b/Mathlib/Analysis/Calculus/Taylor.lean @@ -119,7 +119,8 @@ theorem continuousOn_taylorWithinEval {f : ℝ → E} {x : ℝ} {n : ℕ} {s : S simp_rw [taylor_within_apply] refine continuousOn_finset_sum (Finset.range (n + 1)) fun i hi => ?_ refine (continuousOn_const.mul ((continuousOn_const.sub continuousOn_id).pow _)).smul ?_ - rw [contDiffOn_iff_continuousOn_differentiableOn_deriv hs] at hf + rw [show (n : WithTop ℕ∞) = (n : ℕ∞) by rfl, + contDiffOn_iff_continuousOn_differentiableOn_deriv hs] at hf cases' hf with hf_left specialize hf_left i simp only [Finset.mem_range] at hi @@ -179,7 +180,7 @@ theorem hasDerivWithinAt_taylorWithinEval {f : ℝ → E} {x y : ℝ} {n : ℕ} 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 + (hf.differentiableOn_iteratedDerivWithin (mod_cast coe_lt_succ) hs_unique).mono h specialize hk hf.of_succ ((hdiff y hy).mono_of_mem_nhdsWithin hs') convert hk.add (hasDerivWithinAt_taylor_coeff_within hs'_unique (nhdsWithin_mono _ h self_mem_nhdsWithin) hf') using 1 @@ -305,7 +306,7 @@ theorem taylor_mean_remainder_bound {f : ℝ → E} {a b C x : ℝ} {n : ℕ} (h simp [hx] -- The nth iterated derivative is differentiable have hf' : DifferentiableOn ℝ (iteratedDerivWithin n f (Icc a b)) (Icc a b) := - hf.differentiableOn_iteratedDerivWithin (WithTop.coe_lt_coe.mpr n.lt_succ_self) + hf.differentiableOn_iteratedDerivWithin (mod_cast n.lt_succ_self) (uniqueDiffOn_Icc h) -- We can uniformly bound the derivative of the Taylor polynomial have h' : ∀ y ∈ Ico a x, diff --git a/Mathlib/Analysis/Calculus/VectorField.lean b/Mathlib/Analysis/Calculus/VectorField.lean new file mode 100644 index 00000000000000..ac4eb32fdc707c --- /dev/null +++ b/Mathlib/Analysis/Calculus/VectorField.lean @@ -0,0 +1,343 @@ +/- +Copyright (c) 2024 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastien Gouëzel +-/ +import Mathlib.Analysis.Calculus.FDeriv.Symmetric + +/-! +# Vector fields in vector spaces + +We study functions of the form `V : E → E` on a vector space, thinking of these as vector fields. +We define several notions in this context, with the aim to generalize them to vector fields on +manifolds. + +Notably, we define the pullback of a vector field under a map, as +`VectorField.pullback 𝕜 f V x := (fderiv 𝕜 f x).inverse (V (f x))` (together with the same notion +within a set). + +In addition to comprehensive API on this notion, the main result is the following: +* `VectorField.leibniz_identity_lieBracket` is the Leibniz + identity `[U, [V, W]] = [[U, V], W] + [V, [U, W]]`. + +-/ + +open Set +open scoped Topology + +noncomputable section + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {G : Type*} [NormedAddCommGroup G] [NormedSpace 𝕜 G] + {V W V₁ W₁ : E → E} {s t : Set E} {x : E} + +/-! +### The Lie bracket of vector fields in a vector space + +We define the Lie bracket of two vector fields, and call it `lieBracket 𝕜 V W x`. We also define +a version localized to sets, `lieBracketWithin 𝕜 V W s x`. We copy the relevant API +of `fderivWithin` and `fderiv` for these notions to get a comprehensive API. +-/ + +namespace VectorField + +variable (𝕜) in +/-- The Lie bracket `[V, W] (x)` of two vector fields at a point, defined as +`DW(x) (V x) - DV(x) (W x)`. -/ +def lieBracket (V W : E → E) (x : E) : E := + fderiv 𝕜 W x (V x) - fderiv 𝕜 V x (W x) + +variable (𝕜) in +/-- The Lie bracket `[V, W] (x)` of two vector fields within a set at a point, defined as +`DW(x) (V x) - DV(x) (W x)` where the derivatives are taken inside `s`. -/ +def lieBracketWithin (V W : E → E) (s : Set E) (x : E) : E := + fderivWithin 𝕜 W s x (V x) - fderivWithin 𝕜 V s x (W x) + +lemma lieBracket_eq : + lieBracket 𝕜 V W = fun x ↦ fderiv 𝕜 W x (V x) - fderiv 𝕜 V x (W x) := rfl + +lemma lieBracketWithin_eq : + lieBracketWithin 𝕜 V W s = + fun x ↦ fderivWithin 𝕜 W s x (V x) - fderivWithin 𝕜 V s x (W x) := rfl + +@[simp] +theorem lieBracketWithin_univ : lieBracketWithin 𝕜 V W univ = lieBracket 𝕜 V W := by + ext1 x + simp [lieBracketWithin, lieBracket] + +lemma lieBracketWithin_eq_zero_of_eq_zero (hV : V x = 0) (hW : W x = 0) : + lieBracketWithin 𝕜 V W s x = 0 := by + simp [lieBracketWithin, hV, hW] + +lemma lieBracket_eq_zero_of_eq_zero (hV : V x = 0) (hW : W x = 0) : + lieBracket 𝕜 V W x = 0 := by + simp [lieBracket, hV, hW] + +lemma lieBracketWithin_smul_left {c : 𝕜} (hV : DifferentiableWithinAt 𝕜 V s x) + (hs : UniqueDiffWithinAt 𝕜 s x) : + lieBracketWithin 𝕜 (c • V) W s x = + c • lieBracketWithin 𝕜 V W s x := by + simp only [lieBracketWithin, Pi.add_apply, map_add, Pi.smul_apply, map_smul, smul_sub] + rw [fderivWithin_const_smul' hs hV] + rfl + +lemma lieBracket_smul_left {c : 𝕜} (hV : DifferentiableAt 𝕜 V x) : + lieBracket 𝕜 (c • V) W x = c • lieBracket 𝕜 V W x := by + simp only [← differentiableWithinAt_univ, ← lieBracketWithin_univ] at hV ⊢ + exact lieBracketWithin_smul_left hV uniqueDiffWithinAt_univ + +lemma lieBracketWithin_smul_right {c : 𝕜} (hW : DifferentiableWithinAt 𝕜 W s x) + (hs : UniqueDiffWithinAt 𝕜 s x) : + lieBracketWithin 𝕜 V (c • W) s x = + c • lieBracketWithin 𝕜 V W s x := by + simp only [lieBracketWithin, Pi.add_apply, map_add, Pi.smul_apply, map_smul, smul_sub] + rw [fderivWithin_const_smul' hs hW] + rfl + +lemma lieBracket_smul_right {c : 𝕜} (hW : DifferentiableAt 𝕜 W x) : + lieBracket 𝕜 V (c • W) x = c • lieBracket 𝕜 V W x := by + simp only [← differentiableWithinAt_univ, ← lieBracketWithin_univ] at hW ⊢ + exact lieBracketWithin_smul_right hW uniqueDiffWithinAt_univ + +lemma lieBracketWithin_add_left (hV : DifferentiableWithinAt 𝕜 V s x) + (hV₁ : DifferentiableWithinAt 𝕜 V₁ s x) (hs : UniqueDiffWithinAt 𝕜 s x) : + lieBracketWithin 𝕜 (V + V₁) W s x = + lieBracketWithin 𝕜 V W s x + lieBracketWithin 𝕜 V₁ W s x := by + simp only [lieBracketWithin, Pi.add_apply, map_add] + rw [fderivWithin_add' hs hV hV₁, ContinuousLinearMap.add_apply] + abel + +lemma lieBracket_add_left (hV : DifferentiableAt 𝕜 V x) (hV₁ : DifferentiableAt 𝕜 V₁ x) : + lieBracket 𝕜 (V + V₁) W x = + lieBracket 𝕜 V W x + lieBracket 𝕜 V₁ W x := by + simp only [lieBracket, Pi.add_apply, map_add] + rw [fderiv_add' hV hV₁, ContinuousLinearMap.add_apply] + abel + +lemma lieBracketWithin_add_right (hW : DifferentiableWithinAt 𝕜 W s x) + (hW₁ : DifferentiableWithinAt 𝕜 W₁ s x) (hs : UniqueDiffWithinAt 𝕜 s x) : + lieBracketWithin 𝕜 V (W + W₁) s x = + lieBracketWithin 𝕜 V W s x + lieBracketWithin 𝕜 V W₁ s x := by + simp only [lieBracketWithin, Pi.add_apply, map_add] + rw [fderivWithin_add' hs hW hW₁, ContinuousLinearMap.add_apply] + abel + +lemma lieBracket_add_right (hW : DifferentiableAt 𝕜 W x) (hW₁ : DifferentiableAt 𝕜 W₁ x) : + lieBracket 𝕜 V (W + W₁) x = + lieBracket 𝕜 V W x + lieBracket 𝕜 V W₁ x := by + simp only [lieBracket, Pi.add_apply, map_add] + rw [fderiv_add' hW hW₁, ContinuousLinearMap.add_apply] + abel + +lemma lieBracketWithin_swap : lieBracketWithin 𝕜 V W s = - lieBracketWithin 𝕜 W V s := by + ext x; simp [lieBracketWithin] + +lemma lieBracket_swap : lieBracket 𝕜 V W x = - lieBracket 𝕜 W V x := by + simp [lieBracket] + +@[simp] lemma lieBracketWithin_self : lieBracketWithin 𝕜 V V s = 0 := by + ext x; simp [lieBracketWithin] + +@[simp] lemma lieBracket_self : lieBracket 𝕜 V V = 0 := by + ext x; simp [lieBracket] + +lemma _root_.ContDiffWithinAt.lieBracketWithin_vectorField + {m n : WithTop ℕ∞} (hV : ContDiffWithinAt 𝕜 n V s x) + (hW : ContDiffWithinAt 𝕜 n W s x) (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) (hx : x ∈ s) : + ContDiffWithinAt 𝕜 m (lieBracketWithin 𝕜 V W s) s x := by + apply ContDiffWithinAt.sub + · exact ContDiffWithinAt.clm_apply (hW.fderivWithin_right hs hmn hx) + (hV.of_le (le_trans le_self_add hmn)) + · exact ContDiffWithinAt.clm_apply (hV.fderivWithin_right hs hmn hx) + (hW.of_le (le_trans le_self_add hmn)) + +lemma _root_.ContDiffAt.lieBracket_vectorField {m n : WithTop ℕ∞} (hV : ContDiffAt 𝕜 n V x) + (hW : ContDiffAt 𝕜 n W x) (hmn : m + 1 ≤ n) : + ContDiffAt 𝕜 m (lieBracket 𝕜 V W) x := by + rw [← contDiffWithinAt_univ] at hV hW ⊢ + simp_rw [← lieBracketWithin_univ] + exact hV.lieBracketWithin_vectorField hW uniqueDiffOn_univ hmn (mem_univ _) + +lemma _root_.ContDiffOn.lieBracketWithin_vectorField {m n : WithTop ℕ∞} (hV : ContDiffOn 𝕜 n V s) + (hW : ContDiffOn 𝕜 n W s) (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) : + ContDiffOn 𝕜 m (lieBracketWithin 𝕜 V W s) s := + fun x hx ↦ (hV x hx).lieBracketWithin_vectorField (hW x hx) hs hmn hx + +lemma _root_.ContDiff.lieBracket_vectorField {m n : WithTop ℕ∞} (hV : ContDiff 𝕜 n V) + (hW : ContDiff 𝕜 n W) (hmn : m + 1 ≤ n) : + ContDiff 𝕜 m (lieBracket 𝕜 V W) := + contDiff_iff_contDiffAt.2 (fun _ ↦ hV.contDiffAt.lieBracket_vectorField hW.contDiffAt hmn) + +theorem lieBracketWithin_of_mem_nhdsWithin (st : t ∈ 𝓝[s] x) (hs : UniqueDiffWithinAt 𝕜 s x) + (hV : DifferentiableWithinAt 𝕜 V t x) (hW : DifferentiableWithinAt 𝕜 W t x) : + lieBracketWithin 𝕜 V W s x = lieBracketWithin 𝕜 V W t x := by + simp [lieBracketWithin, fderivWithin_of_mem_nhdsWithin st hs hV, + fderivWithin_of_mem_nhdsWithin st hs hW] + +theorem lieBracketWithin_subset (st : s ⊆ t) (ht : UniqueDiffWithinAt 𝕜 s x) + (hV : DifferentiableWithinAt 𝕜 V t x) (hW : DifferentiableWithinAt 𝕜 W t x) : + lieBracketWithin 𝕜 V W s x = lieBracketWithin 𝕜 V W t x := + lieBracketWithin_of_mem_nhdsWithin (nhdsWithin_mono _ st self_mem_nhdsWithin) ht hV hW + +theorem lieBracketWithin_inter (ht : t ∈ 𝓝 x) : + lieBracketWithin 𝕜 V W (s ∩ t) x = lieBracketWithin 𝕜 V W s x := by + simp [lieBracketWithin, fderivWithin_inter, ht] + +theorem lieBracketWithin_of_mem_nhds (h : s ∈ 𝓝 x) : + lieBracketWithin 𝕜 V W s x = lieBracket 𝕜 V W x := by + rw [← lieBracketWithin_univ, ← univ_inter s, lieBracketWithin_inter h] + +theorem lieBracketWithin_of_isOpen (hs : IsOpen s) (hx : x ∈ s) : + lieBracketWithin 𝕜 V W s x = lieBracket 𝕜 V W x := + lieBracketWithin_of_mem_nhds (hs.mem_nhds hx) + +theorem lieBracketWithin_eq_lieBracket (hs : UniqueDiffWithinAt 𝕜 s x) + (hV : DifferentiableAt 𝕜 V x) (hW : DifferentiableAt 𝕜 W x) : + lieBracketWithin 𝕜 V W s x = lieBracket 𝕜 V W x := by + simp [lieBracketWithin, lieBracket, fderivWithin_eq_fderiv, hs, hV, hW] + +/-- Variant of `lieBracketWithin_congr_set` where one requires the sets to coincide only in +the complement of a point. -/ +theorem lieBracketWithin_congr_set' (y : E) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) : + lieBracketWithin 𝕜 V W s x = lieBracketWithin 𝕜 V W t x := by + simp [lieBracketWithin, fderivWithin_congr_set' _ h] + +theorem lieBracketWithin_congr_set (h : s =ᶠ[𝓝 x] t) : + lieBracketWithin 𝕜 V W s x = lieBracketWithin 𝕜 V W t x := + lieBracketWithin_congr_set' x <| h.filter_mono inf_le_left + +/-- Variant of `lieBracketWithin_eventually_congr_set` where one requires the sets to coincide only +in the complement of a point. -/ +theorem lieBracketWithin_eventually_congr_set' (y : E) (h : s =ᶠ[𝓝[{y}ᶜ] x] t) : + lieBracketWithin 𝕜 V W s =ᶠ[𝓝 x] lieBracketWithin 𝕜 V W t := + (eventually_nhds_nhdsWithin.2 h).mono fun _ => lieBracketWithin_congr_set' y + +theorem lieBracketWithin_eventually_congr_set (h : s =ᶠ[𝓝 x] t) : + lieBracketWithin 𝕜 V W s =ᶠ[𝓝 x] lieBracketWithin 𝕜 V W t := + lieBracketWithin_eventually_congr_set' x <| h.filter_mono inf_le_left + +theorem _root_.DifferentiableWithinAt.lieBracketWithin_congr_mono + (hV : DifferentiableWithinAt 𝕜 V s x) (hVs : EqOn V₁ V t) (hVx : V₁ x = V x) + (hW : DifferentiableWithinAt 𝕜 W s x) (hWs : EqOn W₁ W t) (hWx : W₁ x = W x) + (hxt : UniqueDiffWithinAt 𝕜 t x) (h₁ : t ⊆ s) : + lieBracketWithin 𝕜 V₁ W₁ t x = lieBracketWithin 𝕜 V W s x := by + simp [lieBracketWithin, hV.fderivWithin_congr_mono, hW.fderivWithin_congr_mono, hVs, hVx, + hWs, hWx, hxt, h₁] + +theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField_eq + (hV : V₁ =ᶠ[𝓝[s] x] V) (hxV : V₁ x = V x) (hW : W₁ =ᶠ[𝓝[s] x] W) (hxW : W₁ x = W x) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := by + simp only [lieBracketWithin, hV.fderivWithin_eq hxV, hW.fderivWithin_eq hxW, hxV, hxW] + +theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField_eq_of_mem + (hV : V₁ =ᶠ[𝓝[s] x] V) (hW : W₁ =ᶠ[𝓝[s] x] W) (hx : x ∈ s) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := + hV.lieBracketWithin_vectorField_eq (mem_of_mem_nhdsWithin hx hV :) + hW (mem_of_mem_nhdsWithin hx hW :) + +/-- If vector fields coincide on a neighborhood of a point within a set, then the Lie brackets +also coincide on a neighborhood of this point within this set. Version where one considers the Lie +bracket within a subset. -/ +theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField' + (hV : V₁ =ᶠ[𝓝[s] x] V) (hW : W₁ =ᶠ[𝓝[s] x] W) (ht : t ⊆ s) : + lieBracketWithin 𝕜 V₁ W₁ t =ᶠ[𝓝[s] x] lieBracketWithin 𝕜 V W t := by + filter_upwards [hV.fderivWithin' ht (𝕜 := 𝕜), hW.fderivWithin' ht (𝕜 := 𝕜), hV, hW] + with x hV' hW' hV hW + simp [lieBracketWithin, hV', hW', hV, hW] + +protected theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField + (hV : V₁ =ᶠ[𝓝[s] x] V) (hW : W₁ =ᶠ[𝓝[s] x] W) : + lieBracketWithin 𝕜 V₁ W₁ s =ᶠ[𝓝[s] x] lieBracketWithin 𝕜 V W s := + hV.lieBracketWithin_vectorField' hW Subset.rfl + +protected theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField_eq_of_insert + (hV : V₁ =ᶠ[𝓝[insert x s] x] V) (hW : W₁ =ᶠ[𝓝[insert x s] x] W) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := by + apply mem_of_mem_nhdsWithin (mem_insert x s) (hV.lieBracketWithin_vectorField' hW + (subset_insert x s)) + +theorem _root_.Filter.EventuallyEq.lieBracketWithin_vectorField_eq_nhds + (hV : V₁ =ᶠ[𝓝 x] V) (hW : W₁ =ᶠ[𝓝 x] W) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := + (hV.filter_mono nhdsWithin_le_nhds).lieBracketWithin_vectorField_eq hV.self_of_nhds + (hW.filter_mono nhdsWithin_le_nhds) hW.self_of_nhds + +theorem lieBracketWithin_congr + (hV : EqOn V₁ V s) (hVx : V₁ x = V x) (hW : EqOn W₁ W s) (hWx : W₁ x = W x) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := + (hV.eventuallyEq.filter_mono inf_le_right).lieBracketWithin_vectorField_eq hVx + (hW.eventuallyEq.filter_mono inf_le_right) hWx + +/-- Version of `lieBracketWithin_congr` in which one assumes that the point belongs to the +given set. -/ +theorem lieBracketWithin_congr' (hV : EqOn V₁ V s) (hW : EqOn W₁ W s) (hx : x ∈ s) : + lieBracketWithin 𝕜 V₁ W₁ s x = lieBracketWithin 𝕜 V W s x := + lieBracketWithin_congr hV (hV hx) hW (hW hx) + +theorem _root_.Filter.EventuallyEq.lieBracket_vectorField_eq + (hV : V₁ =ᶠ[𝓝 x] V) (hW : W₁ =ᶠ[𝓝 x] W) : + lieBracket 𝕜 V₁ W₁ x = lieBracket 𝕜 V W x := by + rw [← lieBracketWithin_univ, ← lieBracketWithin_univ, hV.lieBracketWithin_vectorField_eq_nhds hW] + +protected theorem _root_.Filter.EventuallyEq.lieBracket_vectorField + (hV : V₁ =ᶠ[𝓝 x] V) (hW : W₁ =ᶠ[𝓝 x] W) : lieBracket 𝕜 V₁ W₁ =ᶠ[𝓝 x] lieBracket 𝕜 V W := by + filter_upwards [hV.eventuallyEq_nhds, hW.eventuallyEq_nhds] with y hVy hWy + exact hVy.lieBracket_vectorField_eq hWy + +/-- The Lie bracket of vector fields in vector spaces satisfies the Leibniz identity +`[U, [V, W]] = [[U, V], W] + [V, [U, W]]`. -/ +lemma leibniz_identity_lieBracketWithin_of_isSymmSndFDerivWithinAt + {U V W : E → E} {s : Set E} {x : E} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) + (hU : ContDiffWithinAt 𝕜 2 U s x) (hV : ContDiffWithinAt 𝕜 2 V s x) + (hW : ContDiffWithinAt 𝕜 2 W s x) + (h'U : IsSymmSndFDerivWithinAt 𝕜 U s x) (h'V : IsSymmSndFDerivWithinAt 𝕜 V s x) + (h'W : IsSymmSndFDerivWithinAt 𝕜 W s x) : + lieBracketWithin 𝕜 U (lieBracketWithin 𝕜 V W s) s x = + lieBracketWithin 𝕜 (lieBracketWithin 𝕜 U V s) W s x + + lieBracketWithin 𝕜 V (lieBracketWithin 𝕜 U W s) s x := by + simp only [lieBracketWithin_eq, map_sub] + have aux₁ {U V : E → E} (hU : ContDiffWithinAt 𝕜 2 U s x) (hV : ContDiffWithinAt 𝕜 2 V s x) : + DifferentiableWithinAt 𝕜 (fun x ↦ (fderivWithin 𝕜 V s x) (U x)) s x := + have := hV.fderivWithin_right_apply (hU.of_le one_le_two) hs le_rfl hx + this.differentiableWithinAt le_rfl + have aux₂ {U V : E → E} (hU : ContDiffWithinAt 𝕜 2 U s x) (hV : ContDiffWithinAt 𝕜 2 V s x) : + fderivWithin 𝕜 (fun y ↦ (fderivWithin 𝕜 U s y) (V y)) s x = + (fderivWithin 𝕜 U s x).comp (fderivWithin 𝕜 V s x) + + (fderivWithin 𝕜 (fderivWithin 𝕜 U s) s x).flip (V x) := by + refine fderivWithin_clm_apply (hs x hx) ?_ (hV.differentiableWithinAt one_le_two) + exact (hU.fderivWithin_right hs le_rfl hx).differentiableWithinAt le_rfl + rw [fderivWithin_sub (hs x hx) (aux₁ hV hW) (aux₁ hW hV)] + rw [fderivWithin_sub (hs x hx) (aux₁ hU hV) (aux₁ hV hU)] + rw [fderivWithin_sub (hs x hx) (aux₁ hU hW) (aux₁ hW hU)] + rw [aux₂ hW hV, aux₂ hV hW, aux₂ hV hU, aux₂ hU hV, aux₂ hW hU, aux₂ hU hW] + simp only [ContinuousLinearMap.coe_sub', Pi.sub_apply, ContinuousLinearMap.add_apply, + ContinuousLinearMap.coe_comp', Function.comp_apply, ContinuousLinearMap.flip_apply, h'V.eq, + h'U.eq, h'W.eq] + abel + +/-- The Lie bracket of vector fields in vector spaces satisfies the Leibniz identity +`[U, [V, W]] = [[U, V], W] + [V, [U, W]]`. -/ +lemma leibniz_identity_lieBracketWithin [IsRCLikeNormedField 𝕜] {U V W : E → E} {s : Set E} {x : E} + (hs : UniqueDiffOn 𝕜 s) (h'x : x ∈ closure (interior s)) (hx : x ∈ s) + (hU : ContDiffWithinAt 𝕜 2 U s x) (hV : ContDiffWithinAt 𝕜 2 V s x) + (hW : ContDiffWithinAt 𝕜 2 W s x) : + lieBracketWithin 𝕜 U (lieBracketWithin 𝕜 V W s) s x = + lieBracketWithin 𝕜 (lieBracketWithin 𝕜 U V s) W s x + + lieBracketWithin 𝕜 V (lieBracketWithin 𝕜 U W s) s x := by + apply leibniz_identity_lieBracketWithin_of_isSymmSndFDerivWithinAt hs hx hU hV hW + · exact hU.isSymmSndFDerivWithinAt le_rfl hs h'x hx + · exact hV.isSymmSndFDerivWithinAt le_rfl hs h'x hx + · exact hW.isSymmSndFDerivWithinAt le_rfl hs h'x hx + +/-- The Lie bracket of vector fields in vector spaces satisfies the Leibniz identity +`[U, [V, W]] = [[U, V], W] + [V, [U, W]]`. -/ +lemma leibniz_identity_lieBracket [IsRCLikeNormedField 𝕜] {U V W : E → E} {x : E} + (hU : ContDiffAt 𝕜 2 U x) (hV : ContDiffAt 𝕜 2 V x) (hW : ContDiffAt 𝕜 2 W x) : + lieBracket 𝕜 U (lieBracket 𝕜 V W) x = + lieBracket 𝕜 (lieBracket 𝕜 U V) W x + lieBracket 𝕜 V (lieBracket 𝕜 U W) x := by + simp only [← lieBracketWithin_univ, ← contDiffWithinAt_univ] at hU hV hW ⊢ + exact leibniz_identity_lieBracketWithin uniqueDiffOn_univ (by simp) (mem_univ _) hU hV hW + +end VectorField diff --git a/Mathlib/Analysis/Complex/AbelLimit.lean b/Mathlib/Analysis/Complex/AbelLimit.lean index 25d7f649514c64..7e5aea15a89672 100644 --- a/Mathlib/Analysis/Complex/AbelLimit.lean +++ b/Mathlib/Analysis/Complex/AbelLimit.lean @@ -6,7 +6,7 @@ Authors: Jeremy Tan import Mathlib.Analysis.Complex.Basic import Mathlib.Analysis.SpecificLimits.Normed import Mathlib.Tactic.Peel -import Mathlib.Tactic.Positivity.Finset +import Mathlib.Tactic.Positivity /-! # Abel's limit theorem diff --git a/Mathlib/Analysis/Complex/AbsMax.lean b/Mathlib/Analysis/Complex/AbsMax.lean index 7d73410532dd9c..9f5038937c5e60 100644 --- a/Mathlib/Analysis/Complex/AbsMax.lean +++ b/Mathlib/Analysis/Complex/AbsMax.lean @@ -132,7 +132,7 @@ theorem norm_max_aux₁ [CompleteSpace F] {f : ℂ → F} {z w : ℂ} exact hz (hsub hζ) show ‖(w - z)⁻¹ • f w‖ < ‖f z‖ / r rw [norm_smul, norm_inv, norm_eq_abs, ← div_eq_inv_mul] - exact (div_lt_div_right hr).2 hw_lt + exact (div_lt_div_iff_of_pos_right hr).2 hw_lt /-! Now we drop the assumption `CompleteSpace F` by embedding `F` into its completion. diff --git a/Mathlib/Analysis/Complex/Circle.lean b/Mathlib/Analysis/Complex/Circle.lean index 72e66ae46c1b71..e4a9a2e283278f 100644 --- a/Mathlib/Analysis/Complex/Circle.lean +++ b/Mathlib/Analysis/Complex/Circle.lean @@ -41,17 +41,17 @@ open ComplexConjugate /-- The unit circle in `ℂ`, here given the structure of a submonoid of `ℂ`. Please use `Circle` when referring to the circle as a type. -/ -@[deprecated (since := "2024-07-24")] +@[deprecated "No deprecation message was provided." (since := "2024-07-24")] def circle : Submonoid ℂ := Submonoid.unitSphere ℂ set_option linter.deprecated false in -@[deprecated (since := "2024-07-24")] +@[deprecated "No deprecation message was provided." (since := "2024-07-24")] theorem mem_circle_iff_abs {z : ℂ} : z ∈ circle ↔ abs z = 1 := mem_sphere_zero_iff_norm set_option linter.deprecated false in -@[deprecated (since := "2024-07-24")] +@[deprecated "No deprecation message was provided." (since := "2024-07-24")] theorem mem_circle_iff_normSq {z : ℂ} : z ∈ circle ↔ normSq z = 1 := by simp [Complex.abs, mem_circle_iff_abs] diff --git a/Mathlib/Analysis/Complex/Liouville.lean b/Mathlib/Analysis/Complex/Liouville.lean index 1075a8ade0521c..2d327b794e4161 100644 --- a/Mathlib/Analysis/Complex/Liouville.lean +++ b/Mathlib/Analysis/Complex/Liouville.lean @@ -53,7 +53,7 @@ theorem norm_deriv_le_aux [CompleteSpace F] {c : ℂ} {R C : ℝ} {f : ℂ → F have : ∀ z ∈ sphere c R, ‖(z - c) ^ (-2 : ℤ) • f z‖ ≤ C / (R * R) := fun z (hz : abs (z - c) = R) => by simpa [-mul_inv_rev, norm_smul, hz, zpow_two, ← div_eq_inv_mul] using - (div_le_div_right (mul_pos hR hR)).2 (hC z hz) + (div_le_div_iff_of_pos_right (mul_pos hR hR)).2 (hC z hz) calc ‖deriv f c‖ = ‖(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), (z - c) ^ (-2 : ℤ) • f z‖ := congr_arg norm (deriv_eq_smul_circleIntegral hR hf) diff --git a/Mathlib/Analysis/Complex/LocallyUniformLimit.lean b/Mathlib/Analysis/Complex/LocallyUniformLimit.lean index 14b603b86f48e4..cb464f7dc6892d 100644 --- a/Mathlib/Analysis/Complex/LocallyUniformLimit.lean +++ b/Mathlib/Analysis/Complex/LocallyUniformLimit.lean @@ -52,7 +52,7 @@ theorem norm_cderiv_le (hr : 0 < r) (hf : ∀ w ∈ sphere z r, ‖f w‖ ≤ M) intro w hw simp only [mem_sphere_iff_norm, norm_eq_abs] at hw simp only [norm_smul, inv_mul_eq_div, hw, norm_eq_abs, map_inv₀, Complex.abs_pow] - exact div_le_div hM (hf w hw) (sq_pos_of_pos hr) le_rfl + exact div_le_div₀ hM (hf w hw) (sq_pos_of_pos hr) le_rfl have h2 := circleIntegral.norm_integral_le_of_norm_le_const hr.le h1 simp only [cderiv, norm_smul] refine (mul_le_mul le_rfl h2 (norm_nonneg _) (norm_nonneg _)).trans (le_of_eq ?_) @@ -77,7 +77,7 @@ theorem norm_cderiv_lt (hr : 0 < r) (hfM : ∀ w ∈ sphere z r, ‖f w‖ < M) have e2 : ContinuousOn (fun w => ‖f w‖) (sphere z r) := continuous_norm.comp_continuousOn hf obtain ⟨x, hx, hx'⟩ := (isCompact_sphere z r).exists_isMaxOn e1 e2 exact ⟨‖f x‖, hfM x hx, hx'⟩ - exact (norm_cderiv_le hr hL2).trans_lt ((div_lt_div_right hr).mpr hL1) + exact (norm_cderiv_le hr hL2).trans_lt ((div_lt_div_iff_of_pos_right hr).mpr hL1) theorem norm_cderiv_sub_lt (hr : 0 < r) (hfg : ∀ w ∈ sphere z r, ‖f w - g w‖ < M) (hf : ContinuousOn f (sphere z r)) (hg : ContinuousOn g (sphere z r)) : diff --git a/Mathlib/Analysis/Complex/Periodic.lean b/Mathlib/Analysis/Complex/Periodic.lean index 2237eb83d967e6..2186d2e121a796 100644 --- a/Mathlib/Analysis/Complex/Periodic.lean +++ b/Mathlib/Analysis/Complex/Periodic.lean @@ -67,7 +67,7 @@ theorem qParam_left_inv_mod_period (hh : h ≠ 0) (z : ℂ) : theorem abs_qParam_lt_iff (hh : 0 < h) (A : ℝ) (z : ℂ) : abs (qParam h z) < Real.exp (-2 * π * A / h) ↔ A < im z := by - rw [abs_qParam, Real.exp_lt_exp, div_lt_div_right hh, mul_lt_mul_left_of_neg] + rw [abs_qParam, Real.exp_lt_exp, div_lt_div_iff_of_pos_right hh, mul_lt_mul_left_of_neg] simpa using Real.pi_pos theorem qParam_tendsto (hh : 0 < h) : Tendsto (qParam h) I∞ (𝓝[≠] 0) := by diff --git a/Mathlib/Analysis/Complex/RealDeriv.lean b/Mathlib/Analysis/Complex/RealDeriv.lean index 3ce85a20eb6f54..1609fa5e357a43 100644 --- a/Mathlib/Analysis/Complex/RealDeriv.lean +++ b/Mathlib/Analysis/Complex/RealDeriv.lean @@ -77,14 +77,14 @@ theorem HasDerivAt.real_of_complex (h : HasDerivAt e e' z) : rw [ContinuousLinearMap.comp_apply, ContinuousLinearMap.comp_apply] simp -theorem ContDiffAt.real_of_complex {n : ℕ∞} (h : ContDiffAt ℂ n e z) : +theorem ContDiffAt.real_of_complex {n : WithTop ℕ∞} (h : ContDiffAt ℂ n e z) : ContDiffAt ℝ n (fun x : ℝ => (e x).re) z := by have A : ContDiffAt ℝ n ((↑) : ℝ → ℂ) z := ofRealCLM.contDiff.contDiffAt have B : ContDiffAt ℝ n e z := h.restrict_scalars ℝ have C : ContDiffAt ℝ n re (e z) := reCLM.contDiff.contDiffAt exact C.comp z (B.comp z A) -theorem ContDiff.real_of_complex {n : ℕ∞} (h : ContDiff ℂ n e) : +theorem ContDiff.real_of_complex {n : WithTop ℕ∞} (h : ContDiff ℂ n e) : ContDiff ℝ n fun x : ℝ => (e x).re := contDiff_iff_contDiffAt.2 fun _ => h.contDiffAt.real_of_complex diff --git a/Mathlib/Analysis/Complex/Schwarz.lean b/Mathlib/Analysis/Complex/Schwarz.lean index 9b43623115be13..91338bfc42214b 100644 --- a/Mathlib/Analysis/Complex/Schwarz.lean +++ b/Mathlib/Analysis/Complex/Schwarz.lean @@ -80,7 +80,7 @@ theorem schwarz_aux {f : ℂ → ℂ} (hd : DifferentiableOn ℂ f (ball c R₁) intro z hz have hz' : z ≠ c := ne_of_mem_sphere hz hr₀.ne' rw [dslope_of_ne _ hz', slope_def_module, norm_smul, norm_inv, mem_sphere_iff_norm.1 hz, ← - div_eq_inv_mul, div_le_div_right hr₀, ← dist_eq_norm] + div_eq_inv_mul, div_le_div_iff_of_pos_right hr₀, ← dist_eq_norm] exact le_of_lt (h_maps (mem_ball.2 (by rw [mem_sphere.1 hz]; exact hr.2))) · rw [closure_ball c hr₀.ne', mem_closedBall] exact hr.1.le diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean index 52bf76205cdd16..6a3125c87d0c95 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean @@ -243,9 +243,9 @@ theorem denom_cocycle (x y : GL(2, ℝ)⁺) (z : ℍ) : denom (x * y) z = denom x (smulAux y z) * denom y z := by change _ = (_ * (_ / _) + _) * _ field_simp [denom_ne_zero] - simp only [Matrix.mul_apply, dotProduct, Fin.sum_univ_succ, denom, num, Subgroup.coe_mul, - GeneralLinearGroup.coe_mul, Fintype.univ_ofSubsingleton, Fin.mk_zero, Finset.sum_singleton, - Fin.succ_zero_eq_one, Complex.ofReal_add, Complex.ofReal_mul] + simp only [denom, Subgroup.coe_mul, Fin.isValue, Units.val_mul, mul_apply, Fin.sum_univ_succ, + Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton, Fin.succ_zero_eq_one, + Complex.ofReal_add, Complex.ofReal_mul, num] ring theorem mul_smul' (x y : GL(2, ℝ)⁺) (z : ℍ) : smulAux (x * y) z = smulAux x (smulAux y z) := by @@ -254,9 +254,9 @@ theorem mul_smul' (x y : GL(2, ℝ)⁺) (z : ℍ) : smulAux (x * y) z = smulAux change _ / _ = (_ * (_ / _) + _) / _ rw [denom_cocycle] field_simp [denom_ne_zero] - simp only [Matrix.mul_apply, dotProduct, Fin.sum_univ_succ, num, denom, Subgroup.coe_mul, - GeneralLinearGroup.coe_mul, Fintype.univ_ofSubsingleton, Fin.mk_zero, Finset.sum_singleton, - Fin.succ_zero_eq_one, Complex.ofReal_add, Complex.ofReal_mul] + simp only [num, Subgroup.coe_mul, Fin.isValue, Units.val_mul, mul_apply, Fin.sum_univ_succ, + Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton, Fin.succ_zero_eq_one, + Complex.ofReal_add, Complex.ofReal_mul, denom] ring /-- The action of `GLPos 2 ℝ` on the upper half-plane by fractional linear transformations. -/ @@ -268,50 +268,9 @@ instance : MulAction GL(2, ℝ)⁺ ℍ where simp [num, denom] mul_smul := mul_smul' -section ModularScalarTowers - instance SLAction {R : Type*} [CommRing R] [Algebra R ℝ] : MulAction SL(2, R) ℍ := MulAction.compHom ℍ <| SpecialLinearGroup.toGLPos.comp <| map (algebraMap R ℝ) -namespace ModularGroup - -variable (Γ : Subgroup (SpecialLinearGroup (Fin 2) ℤ)) - -/-- Canonical embedding of `SL(2, ℤ)` into `GL(2, ℝ)⁺`. -/ -@[coe] -def coe' : SL(2, ℤ) → GL(2, ℝ)⁺ := fun g => ((g : SL(2, ℝ)) : GL(2, ℝ)⁺) - -instance : Coe SL(2, ℤ) GL(2, ℝ)⁺ := - ⟨coe'⟩ - -@[simp] -theorem coe'_apply_complex {g : SL(2, ℤ)} {i j : Fin 2} : - (Units.val <| Subtype.val <| coe' g) i j = (Subtype.val g i j : ℂ) := - rfl - -@[simp] -theorem det_coe' {g : SL(2, ℤ)} : det (Units.val <| Subtype.val <| coe' g) = 1 := by - simp only [SpecialLinearGroup.coe_GLPos_coe_GL_coe_matrix, SpecialLinearGroup.det_coe, coe'] - -lemma coe_one : UpperHalfPlane.ModularGroup.coe' 1 = 1 := by - simp only [coe', _root_.map_one] - -instance SLOnGLPos : SMul SL(2, ℤ) GL(2, ℝ)⁺ := - ⟨fun s g => s * g⟩ - -theorem SLOnGLPos_smul_apply (s : SL(2, ℤ)) (g : GL(2, ℝ)⁺) (z : ℍ) : - (s • g) • z = ((s : GL(2, ℝ)⁺) * g) • z := - rfl - -instance SL_to_GL_tower : IsScalarTower SL(2, ℤ) GL(2, ℝ)⁺ ℍ where - smul_assoc s g z := by - simp only [SLOnGLPos_smul_apply] - apply mul_smul' - -end ModularGroup - -end ModularScalarTowers - -- Porting note: in the statement, we used to have coercions `↑· : ℝ` -- rather than `algebraMap R ℝ ·`. theorem specialLinearGroup_apply {R : Type*} [CommRing R] [Algebra R ℝ] (g : SL(2, R)) (z : ℍ) : @@ -322,23 +281,23 @@ theorem specialLinearGroup_apply {R : Type*} [CommRing R] [Algebra R ℝ] (g : S (g • z).property := rfl +variable (g : GL(2, ℝ)⁺) (z : ℍ) + @[simp] -theorem coe_smul (g : GL(2, ℝ)⁺) (z : ℍ) : ↑(g • z) = num g z / denom g z := +theorem coe_smul : ↑(g • z) = num g z / denom g z := rfl @[simp] -theorem re_smul (g : GL(2, ℝ)⁺) (z : ℍ) : (g • z).re = (num g z / denom g z).re := +theorem re_smul : (g • z).re = (num g z / denom g z).re := rfl -theorem im_smul (g : GL(2, ℝ)⁺) (z : ℍ) : (g • z).im = (num g z / denom g z).im := +theorem im_smul : (g • z).im = (num g z / denom g z).im := rfl -theorem im_smul_eq_div_normSq (g : GL(2, ℝ)⁺) (z : ℍ) : - (g • z).im = det ↑ₘg * z.im / Complex.normSq (denom g z) := +theorem im_smul_eq_div_normSq : (g • z).im = det ↑ₘg * z.im / Complex.normSq (denom g z) := smulAux'_im g z -theorem c_mul_im_sq_le_normSq_denom (z : ℍ) (g : SL(2, ℝ)) : - (g 1 0 * z.im) ^ 2 ≤ Complex.normSq (denom g z) := by +theorem c_mul_im_sq_le_normSq_denom : (g 1 0 * z.im) ^ 2 ≤ Complex.normSq (denom g z) := by set c := g 1 0 set d := g 1 1 calc @@ -346,40 +305,15 @@ theorem c_mul_im_sq_le_normSq_denom (z : ℍ) (g : SL(2, ℝ)) : _ = Complex.normSq (denom g z) := by dsimp [c, d, denom, Complex.normSq]; ring @[simp] -theorem neg_smul (g : GL(2, ℝ)⁺) (z : ℍ) : -g • z = g • z := by +theorem neg_smul : -g • z = g • z := by ext1 change _ / _ = _ / _ field_simp [denom_ne_zero] simp only [num, denom, Complex.ofReal_neg, neg_mul, GLPos.coe_neg_GL, Units.val_neg, neg_apply] ring_nf -section SLModularAction - -namespace ModularGroup - -variable (g : SL(2, ℤ)) (z : ℍ) (Γ : Subgroup SL(2, ℤ)) - -@[simp] -theorem sl_moeb (A : SL(2, ℤ)) (z : ℍ) : A • z = (A : GL(2, ℝ)⁺) • z := - rfl - -@[simp high] -theorem SL_neg_smul (g : SL(2, ℤ)) (z : ℍ) : -g • z = g • z := by - simp only [coe_GLPos_neg, sl_moeb, coe_int_neg, neg_smul, coe'] - -nonrec theorem im_smul_eq_div_normSq : - (g • z).im = z.im / Complex.normSq (denom g z) := by - convert im_smul_eq_div_normSq g z - simp only [GeneralLinearGroup.val_det_apply, coe_GLPos_coe_GL_coe_matrix, - Int.coe_castRingHom, (g : SL(2, ℝ)).prop, one_mul, coe'] - -theorem denom_apply (g : SL(2, ℤ)) (z : ℍ) : - denom g z = (↑g : Matrix (Fin 2) (Fin 2) ℤ) 1 0 * z + (↑g : Matrix (Fin 2) (Fin 2) ℤ) 1 1 := by - simp [denom, coe'] - -end ModularGroup - -end SLModularAction +lemma denom_one : denom 1 z = 1 := by + simp [denom] section PosRealAction @@ -475,3 +409,75 @@ theorem exists_SL2_smul_eq_of_apply_zero_one_ne_zero (g : SL(2, ℝ)) (hc : g 1 linear_combination (-(z * (c : ℂ) ^ 2) - c * d) * h end UpperHalfPlane + +namespace ModularGroup -- results specific to `SL(2, ℤ)` + +section ModularScalarTowers + +/-- Canonical embedding of `SL(2, ℤ)` into `GL(2, ℝ)⁺`. -/ +@[coe] +def coe (g : SL(2, ℤ)) : GL(2, ℝ)⁺ := ((g : SL(2, ℝ)) : GL(2, ℝ)⁺) + +@[deprecated (since := "2024-11-19")] noncomputable alias coe' := coe + +instance : Coe SL(2, ℤ) GL(2, ℝ)⁺ := + ⟨coe⟩ + +@[simp] +theorem coe_apply_complex {g : SL(2, ℤ)} {i j : Fin 2} : + (Units.val <| Subtype.val <| coe g) i j = (Subtype.val g i j : ℂ) := + rfl + +@[deprecated (since := "2024-11-19")] alias coe'_apply_complex := coe_apply_complex + +@[simp] +theorem det_coe {g : SL(2, ℤ)} : det (Units.val <| Subtype.val <| coe g) = 1 := by + simp only [SpecialLinearGroup.coe_GLPos_coe_GL_coe_matrix, SpecialLinearGroup.det_coe, coe] + +@[deprecated (since := "2024-11-19")] alias det_coe' := det_coe + +lemma coe_one : coe 1 = 1 := by + simp only [coe, _root_.map_one] + +instance SLOnGLPos : SMul SL(2, ℤ) GL(2, ℝ)⁺ := + ⟨fun s g => s * g⟩ + +theorem SLOnGLPos_smul_apply (s : SL(2, ℤ)) (g : GL(2, ℝ)⁺) (z : ℍ) : + (s • g) • z = ((s : GL(2, ℝ)⁺) * g) • z := + rfl + +instance SL_to_GL_tower : IsScalarTower SL(2, ℤ) GL(2, ℝ)⁺ ℍ where + smul_assoc s g z := by + simp only [SLOnGLPos_smul_apply] + apply mul_smul' + +end ModularScalarTowers + +section SLModularAction + +variable (g : SL(2, ℤ)) (z : ℍ) + +@[simp] +theorem sl_moeb (A : SL(2, ℤ)) (z : ℍ) : A • z = (A : GL(2, ℝ)⁺) • z := + rfl + +@[simp high] +theorem SL_neg_smul (g : SL(2, ℤ)) (z : ℍ) : -g • z = g • z := by + simp only [coe_GLPos_neg, sl_moeb, coe_int_neg, neg_smul, coe] + +theorem im_smul_eq_div_normSq : (g • z).im = z.im / Complex.normSq (denom g z) := by + simpa only [coe, coe_GLPos_coe_GL_coe_matrix, (g : SL(2, ℝ)).prop, one_mul] using + z.im_smul_eq_div_normSq g + +theorem denom_apply (g : SL(2, ℤ)) (z : ℍ) : + denom g z = g 1 0 * z + g 1 1 := by + simp [denom, coe] + +@[simp] +lemma denom_S (z : ℍ) : denom S z = z := by + simp only [S, denom_apply, of_apply, cons_val', cons_val_zero, empty_val', cons_val_fin_one, + cons_val_one, head_fin_const, Int.cast_one, one_mul, head_cons, Int.cast_zero, add_zero] + +end SLModularAction + +end ModularGroup diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/FunctionsBoundedAtInfty.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/FunctionsBoundedAtInfty.lean index 7ecb4b7001f40d..b784bb49355384 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/FunctionsBoundedAtInfty.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/FunctionsBoundedAtInfty.lean @@ -53,19 +53,22 @@ def zeroAtImInftySubmodule (α : Type*) [NormedField α] : Submodule α (ℍ → def boundedAtImInftySubalgebra (α : Type*) [NormedField α] : Subalgebra α (ℍ → α) := boundedFilterSubalgebra _ atImInfty -nonrec theorem IsBoundedAtImInfty.mul {f g : ℍ → ℂ} (hf : IsBoundedAtImInfty f) - (hg : IsBoundedAtImInfty g) : IsBoundedAtImInfty (f * g) := by - simpa only [Pi.one_apply, mul_one, norm_eq_abs] using hf.mul hg - -theorem bounded_mem (f : ℍ → ℂ) : - IsBoundedAtImInfty f ↔ ∃ M A : ℝ, ∀ z : ℍ, A ≤ im z → abs (f z) ≤ M := by +theorem isBoundedAtImInfty_iff {α : Type*} [Norm α] {f : ℍ → α} : + IsBoundedAtImInfty f ↔ ∃ M A : ℝ, ∀ z : ℍ, A ≤ im z → ‖f z‖ ≤ M := by simp [IsBoundedAtImInfty, BoundedAtFilter, Asymptotics.isBigO_iff, Filter.Eventually, atImInfty_mem] -theorem zero_at_im_infty (f : ℍ → ℂ) : - IsZeroAtImInfty f ↔ ∀ ε : ℝ, 0 < ε → ∃ A : ℝ, ∀ z : ℍ, A ≤ im z → abs (f z) ≤ ε := - (atImInfty_basis.tendsto_iff Metric.nhds_basis_closedBall).trans <| by - simp only [true_and, mem_closedBall_zero_iff]; rfl +@[deprecated (since := "2024-08-27")] alias _root_.bounded_mem := isBoundedAtImInfty_iff + +theorem isZeroAtImInfty_iff {α : Type*} [SeminormedAddGroup α] {f : ℍ → α} : + IsZeroAtImInfty f ↔ ∀ ε : ℝ, 0 < ε → ∃ A : ℝ, ∀ z : ℍ, A ≤ im z → ‖f z‖ ≤ ε := + (atImInfty_basis.tendsto_iff Metric.nhds_basis_closedBall).trans <| by simp + +@[deprecated (since := "2024-08-27")] alias _root_.zero_at_im_infty := isZeroAtImInfty_iff + +theorem IsZeroAtImInfty.isBoundedAtImInfty {α : Type*} [SeminormedAddGroup α] {f : ℍ → α} + (hf : IsZeroAtImInfty f) : IsBoundedAtImInfty f := + hf.boundedAtFilter lemma tendsto_comap_im_ofComplex : Tendsto ofComplex (comap Complex.im atTop) atImInfty := by diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean index c821c8feafdcbe..9529dbcb764f23 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean @@ -26,15 +26,17 @@ instance : SmoothManifoldWithCorners 𝓘(ℂ) ℍ := UpperHalfPlane.isOpenEmbedding_coe.singleton_smoothManifoldWithCorners /-- The inclusion map `ℍ → ℂ` is a smooth map of manifolds. -/ -theorem smooth_coe : Smooth 𝓘(ℂ) 𝓘(ℂ) ((↑) : ℍ → ℂ) := fun _ => contMDiffAt_extChartAt +theorem contMDiff_coe : ContMDiff 𝓘(ℂ) 𝓘(ℂ) ⊤ ((↑) : ℍ → ℂ) := fun _ => contMDiffAt_extChartAt + +@[deprecated (since := "2024-11-20")] alias smooth_coe := contMDiff_coe /-- The inclusion map `ℍ → ℂ` is a differentiable map of manifolds. -/ theorem mdifferentiable_coe : MDifferentiable 𝓘(ℂ) 𝓘(ℂ) ((↑) : ℍ → ℂ) := - smooth_coe.mdifferentiable + contMDiff_coe.mdifferentiable (by simp) -lemma smoothAt_ofComplex {z : ℂ} (hz : 0 < z.im) : - SmoothAt 𝓘(ℂ) 𝓘(ℂ) ofComplex z := by - rw [SmoothAt, contMDiffAt_iff] +lemma contMDiffAt_ofComplex {z : ℂ} (hz : 0 < z.im) : + ContMDiffAt 𝓘(ℂ) 𝓘(ℂ) ⊤ ofComplex z := by + rw [contMDiffAt_iff] constructor · -- continuity at z rw [ContinuousAt, nhds_induced, tendsto_comap_iff] @@ -48,9 +50,11 @@ lemma smoothAt_ofComplex {z : ℂ} (hz : 0 < z.im) : Set.range_id, id_eq, contDiffWithinAt_univ] exact contDiffAt_id.congr_of_eventuallyEq (eventuallyEq_coe_comp_ofComplex hz) +@[deprecated (since := "2024-11-20")] alias smoothAt_ofComplex := contMDiffAt_ofComplex + lemma mdifferentiableAt_ofComplex {z : ℂ} (hz : 0 < z.im) : MDifferentiableAt 𝓘(ℂ) 𝓘(ℂ) ofComplex z := - (smoothAt_ofComplex hz).mdifferentiableAt + (contMDiffAt_ofComplex hz).mdifferentiableAt (by simp) lemma mdifferentiableAt_iff {f : ℍ → ℂ} {τ : ℍ} : MDifferentiableAt 𝓘(ℂ) 𝓘(ℂ) f τ ↔ DifferentiableAt ℂ (f ∘ ofComplex) ↑τ := by diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean index 79fd0dfe4e765d..88a6d6642a9b96 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean @@ -79,7 +79,7 @@ protected theorem dist_comm (z w : ℍ) : dist z w = dist w z := by theorem dist_le_iff_le_sinh : dist z w ≤ r ↔ dist (z : ℂ) w / (2 * √(z.im * w.im)) ≤ sinh (r / 2) := by - rw [← div_le_div_right (zero_lt_two' ℝ), ← sinh_le_sinh, sinh_half_dist] + rw [← div_le_div_iff_of_pos_right (zero_lt_two' ℝ), ← sinh_le_sinh, sinh_half_dist] theorem dist_eq_iff_eq_sinh : dist z w = r ↔ dist (z : ℂ) w / (2 * √(z.im * w.im)) = sinh (r / 2) := by diff --git a/Mathlib/Analysis/Convex/Gauge.lean b/Mathlib/Analysis/Convex/Gauge.lean index 5ecb5e8b2c4cdb..f9d037d23877ab 100644 --- a/Mathlib/Analysis/Convex/Gauge.lean +++ b/Mathlib/Analysis/Convex/Gauge.lean @@ -41,7 +41,7 @@ open scoped Pointwise Topology NNReal noncomputable section -variable {𝕜 E F : Type*} +variable {𝕜 E : Type*} section AddCommGroup diff --git a/Mathlib/Analysis/Convex/Mul.lean b/Mathlib/Analysis/Convex/Mul.lean index 634ffe1a33097d..f8a3db0f444b40 100644 --- a/Mathlib/Analysis/Convex/Mul.lean +++ b/Mathlib/Analysis/Convex/Mul.lean @@ -176,7 +176,7 @@ lemma convexOn_zpow : ∀ n : ℤ, ConvexOn 𝕜 (Ioi 0) fun x : 𝕜 ↦ x ^ n refine (convexOn_iff_forall_pos.2 ⟨convex_Ioi _, ?_⟩).pow (fun x (hx : 0 < x) ↦ by positivity) _ rintro x (hx : 0 < x) y (hy : 0 < y) a b ha hb hab field_simp - rw [div_le_div_iff, ← sub_nonneg] + rw [div_le_div_iff₀, ← sub_nonneg] · calc 0 ≤ a * b * (x - y) ^ 2 := by positivity _ = _ := by obtain rfl := eq_sub_of_add_eq hab; ring diff --git a/Mathlib/Analysis/Convex/Normed.lean b/Mathlib/Analysis/Convex/Normed.lean index fae3e58b55f18f..9a305c1457de06 100644 --- a/Mathlib/Analysis/Convex/Normed.lean +++ b/Mathlib/Analysis/Convex/Normed.lean @@ -25,14 +25,14 @@ We prove the following facts: is bounded. -/ -variable {ι : Type*} {E P : Type*} +variable {E P : Type*} 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} +variable {s : Set E} /-- The norm on a real normed space is convex on any convex set. See also `Seminorm.convexOn` and `convexOn_univ_norm`. -/ diff --git a/Mathlib/Analysis/Convex/Slope.lean b/Mathlib/Analysis/Convex/Slope.lean index 38072902d3e919..51a20a60734cd9 100644 --- a/Mathlib/Analysis/Convex/Slope.lean +++ b/Mathlib/Analysis/Convex/Slope.lean @@ -38,9 +38,9 @@ theorem ConvexOn.slope_mono_adjacent (hf : ConvexOn 𝕜 s f) {x y z : 𝕜} (hx rw [hy] at key replace key := mul_le_mul_of_nonneg_left key hxz.le field_simp [a, b, mul_comm (z - x) _] at key ⊢ - rw [div_le_div_right] + rw [div_le_div_iff_of_pos_right] · linarith - · nlinarith + · positivity /-- If `f : 𝕜 → 𝕜` is concave, then for any three points `x < y < z` the slope of the secant line of `f` on `[x, y]` is greater than the slope of the secant line of `f` on `[y, z]`. -/ @@ -71,9 +71,9 @@ theorem StrictConvexOn.slope_strict_mono_adjacent (hf : StrictConvexOn 𝕜 s f) rw [hy] at key replace key := mul_lt_mul_of_pos_left key hxz field_simp [mul_comm (z - x) _] at key ⊢ - rw [div_lt_div_right] + rw [div_lt_div_iff_of_pos_right] · linarith - · nlinarith + · positivity /-- If `f : 𝕜 → 𝕜` is strictly concave, then for any three points `x < y < z` the slope of the secant line of `f` on `[x, y]` is strictly greater than the slope of the secant line of `f` on @@ -100,7 +100,7 @@ theorem convexOn_of_slope_mono_adjacent (hs : Convex 𝕜 s) rw [← one_mul z, ← hab, add_mul] exact add_lt_add_right ((mul_lt_mul_left ha).2 hxz) _ have : (f y - f x) * (z - y) ≤ (f z - f y) * (y - x) := - (div_le_div_iff (sub_pos.2 hxy) (sub_pos.2 hyz)).1 (hf hx hz hxy hyz) + (div_le_div_iff₀ (sub_pos.2 hxy) (sub_pos.2 hyz)).1 (hf hx hz hxy hyz) have hxz : 0 < z - x := sub_pos.2 (hxy.trans hyz) have ha : (z - y) / (z - x) = a := by rw [eq_comm, ← sub_eq_iff_eq_add'] at hab @@ -145,7 +145,7 @@ theorem strictConvexOn_of_slope_strict_mono_adjacent (hs : Convex 𝕜 s) rw [← one_mul z, ← hab, add_mul] exact add_lt_add_right ((mul_lt_mul_left ha).2 hxz) _ have : (f y - f x) * (z - y) < (f z - f y) * (y - x) := - (div_lt_div_iff (sub_pos.2 hxy) (sub_pos.2 hyz)).1 (hf hx hz hxy hyz) + (div_lt_div_iff₀ (sub_pos.2 hxy) (sub_pos.2 hyz)).1 (hf hx hz hxy hyz) have hxz : 0 < z - x := sub_pos.2 (hxy.trans hyz) have ha : (z - y) / (z - x) = a := by rw [eq_comm, ← sub_eq_iff_eq_add'] at hab @@ -238,14 +238,14 @@ theorem ConvexOn.secant_mono_aux2 (hf : ConvexOn 𝕜 s f) {x y z : 𝕜} (hx : (hxy : x < y) (hyz : y < z) : (f y - f x) / (y - x) ≤ (f z - f x) / (z - x) := by have hxy' : 0 < y - x := by linarith have hxz' : 0 < z - x := by linarith - rw [div_le_div_iff hxy' hxz'] + rw [div_le_div_iff₀ hxy' hxz'] linarith only [hf.secant_mono_aux1 hx hz hxy hyz] theorem ConvexOn.secant_mono_aux3 (hf : ConvexOn 𝕜 s f) {x y z : 𝕜} (hx : x ∈ s) (hz : z ∈ s) (hxy : x < y) (hyz : y < z) : (f z - f x) / (z - x) ≤ (f z - f y) / (z - y) := by have hyz' : 0 < z - y := by linarith have hxz' : 0 < z - x := by linarith - rw [div_le_div_iff hxz' hyz'] + rw [div_le_div_iff₀ hxz' hyz'] linarith only [hf.secant_mono_aux1 hx hz hxy hyz] /-- If `f : 𝕜 → 𝕜` is convex, then for any point `a` the slope of the secant line of `f` through `a` @@ -284,14 +284,14 @@ theorem StrictConvexOn.secant_strict_mono_aux2 (hf : StrictConvexOn 𝕜 s f) {x (hz : z ∈ s) (hxy : x < y) (hyz : y < z) : (f y - f x) / (y - x) < (f z - f x) / (z - x) := by have hxy' : 0 < y - x := by linarith have hxz' : 0 < z - x := by linarith - rw [div_lt_div_iff hxy' hxz'] + rw [div_lt_div_iff₀ hxy' hxz'] linarith only [hf.secant_strict_mono_aux1 hx hz hxy hyz] theorem StrictConvexOn.secant_strict_mono_aux3 (hf : StrictConvexOn 𝕜 s f) {x y z : 𝕜} (hx : x ∈ s) (hz : z ∈ s) (hxy : x < y) (hyz : y < z) : (f z - f x) / (z - x) < (f z - f y) / (z - y) := by have hyz' : 0 < z - y := by linarith have hxz' : 0 < z - x := by linarith - rw [div_lt_div_iff hxz' hyz'] + rw [div_lt_div_iff₀ hxz' hyz'] linarith only [hf.secant_strict_mono_aux1 hx hz hxy hyz] /-- If `f : 𝕜 → 𝕜` is strictly convex, then for any point `a` the slope of the secant line of `f` diff --git a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean index b293f4c6a7eb3e..e58b1bbfd22133 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Basic.lean @@ -110,7 +110,7 @@ theorem one_add_mul_self_lt_rpow_one_add {s : ℝ} (hs : -1 ≤ s) (hs' : s ≠ · 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_iff_of_pos_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] @@ -149,7 +149,7 @@ theorem rpow_one_add_lt_one_add_mul_self {s : ℝ} (hs : -1 ≤ s) (hs' : s ≠ · 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_iff_of_pos_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,7 +175,7 @@ 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', + rw [div_lt_iff₀ q, ← div_lt_div_iff_of_pos_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, @@ -186,7 +186,7 @@ theorem strictConvexOn_rpow {p : ℝ} (hp : 1 < p) : StrictConvexOn ℝ (Ici 0) · 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', + rw [lt_div_iff₀ q, ← div_lt_div_iff_of_pos_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'] diff --git a/Mathlib/Analysis/Convex/StoneSeparation.lean b/Mathlib/Analysis/Convex/StoneSeparation.lean index 76a95705677f6e..5a52d98fda2ea3 100644 --- a/Mathlib/Analysis/Convex/StoneSeparation.lean +++ b/Mathlib/Analysis/Convex/StoneSeparation.lean @@ -67,8 +67,8 @@ theorem not_disjoint_segment_convexHull_triple {p q u v x y z : E} (hz : z ∈ s ((az * av * bu) • p + ((bz * au * bv) • q + (au * av) • (az • x + bz • y))) · module congr 3 - simp only [w, z, smul_add, List.foldr, Matrix.cons_val_succ', Fin.mk_one, - Matrix.cons_val_one, Matrix.head_cons, add_zero] + simp only [smul_add, List.foldr, Fin.reduceFinMk, id_eq, Fin.isValue, Matrix.cons_val_two, + Nat.succ_eq_add_one, Nat.reduceAdd, Matrix.tail_cons, Matrix.head_cons, add_zero, w, z] /-- **Stone's Separation Theorem** -/ theorem exists_convex_convex_compl_subset (hs : Convex 𝕜 s) (ht : Convex 𝕜 t) (hst : Disjoint s t) : diff --git a/Mathlib/Analysis/Convex/Topology.lean b/Mathlib/Analysis/Convex/Topology.lean index a38bd1386b8ea6..86c3bddbec48e1 100644 --- a/Mathlib/Analysis/Convex/Topology.lean +++ b/Mathlib/Analysis/Convex/Topology.lean @@ -360,8 +360,8 @@ theorem Convex.closure_subset_image_homothety_interior_of_one_lt {s : Set E} (hs refine ⟨homothety x t⁻¹ y, hs.openSegment_interior_closure_subset_interior hx hy ?_, (AffineEquiv.homothetyUnitsMulHom x (Units.mk0 t hne)).apply_symm_apply y⟩ - rw [openSegment_eq_image_lineMap, ← inv_one, ← inv_Ioi (zero_lt_one' ℝ), ← image_inv, image_image, - homothety_eq_lineMap] + rw [openSegment_eq_image_lineMap, ← inv_one, ← inv_Ioi₀ (zero_lt_one' ℝ), ← image_inv, + image_image, homothety_eq_lineMap] exact mem_image_of_mem _ ht /-- If we dilate a convex set about a point in its interior by a scale `t > 1`, the interior of diff --git a/Mathlib/Analysis/Convex/Uniform.lean b/Mathlib/Analysis/Convex/Uniform.lean index 152127c0a4736b..5c0511976660cc 100644 --- a/Mathlib/Analysis/Convex/Uniform.lean +++ b/Mathlib/Analysis/Convex/Uniform.lean @@ -96,16 +96,7 @@ theorem exists_forall_closed_ball_dist_add_le_two_sub (hε : 0 < ε) : _ ≤ 2 - δ + δ' + δ' := (add_le_add_three (h (h₁ _ hx') (h₁ _ hy') hxy') (h₂ _ hx hx'.le) (h₂ _ hy hy'.le)) _ ≤ 2 - δ' := by - dsimp only [δ'] - rw [← le_sub_iff_add_le, ← le_sub_iff_add_le, sub_sub, sub_sub] - refine sub_le_sub_left ?_ _ - ring_nf - rw [← mul_div_cancel₀ δ three_ne_zero] - norm_num - -- Porting note: these three extra lines needed to make `exact` work - have : 3 * (δ / 3) * (1 / 3) = δ / 3 := by linarith - rw [this, mul_comm] - gcongr + suffices δ' ≤ δ / 3 by linarith exact min_le_of_right_le <| min_le_right _ _ theorem exists_forall_closed_ball_dist_add_le_two_mul_sub (hε : 0 < ε) (r : ℝ) : @@ -118,7 +109,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_iff_of_pos_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 a50566576f0f1b..f2e6fd1a550aa9 100644 --- a/Mathlib/Analysis/Convolution.lean +++ b/Mathlib/Analysis/Convolution.lean @@ -1179,16 +1179,18 @@ theorem contDiffOn_convolution_right_with_param_aux {G : Type uP} {E' : Type uP} come from the same universe). -/ induction n using ENat.nat_induction generalizing g E' F with | h0 => - rw [contDiffOn_zero] at hg ⊢ + rw [WithTop.coe_zero, contDiffOn_zero] at hg ⊢ exact continuousOn_convolution_right_with_param L hk hgs hf hg | hsuc n ih => + simp only [Nat.succ_eq_add_one, Nat.cast_add, Nat.cast_one, WithTop.coe_add, + WithTop.coe_natCast, WithTop.coe_one] at hg ⊢ 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₀ := hasFDerivAt_convolution_right_with_param L hs hk hgs hf hg.one_of_succ rw [contDiffOn_succ_iff_fderiv_of_isOpen (hs.prod (@isOpen_univ G _))] at hg ⊢ - constructor + refine ⟨?_, ?_⟩ · rintro ⟨p, x⟩ ⟨hp, -⟩ exact (A (p, x) hp).differentiableAt.differentiableWithinAt · suffices H : ContDiffOn 𝕜 n (↿f') (s ×ˢ univ) by diff --git a/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean b/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean index fb4a816b271bca..8aa816c388f411 100644 --- a/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean +++ b/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean @@ -24,7 +24,7 @@ as `ae_eq_zero_of_integral_smooth_smul_eq_zero` and `ae_eq_of_integral_smooth_sm open MeasureTheory Filter Metric Function Set TopologicalSpace -open scoped Topology Manifold +open scoped Topology Manifold ContDiff variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] [CompleteSpace F] @@ -40,7 +40,7 @@ variable {H : Type*} [TopologicalSpace H] (I : ModelWithCorners ℝ E H) when multiplied by any smooth compactly supported function, then `f` vanishes almost everywhere. -/ theorem ae_eq_zero_of_integral_smooth_smul_eq_zero [SigmaCompactSpace M] (hf : LocallyIntegrable f μ) - (h : ∀ g : M → ℝ, Smooth I 𝓘(ℝ) g → HasCompactSupport g → ∫ x, g x • f x ∂μ = 0) : + (h : ∀ g : M → ℝ, ContMDiff I 𝓘(ℝ) ⊤ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = 0) : ∀ᵐ x ∂μ, f x = 0 := by -- record topological properties of `M` have := I.locallyCompactSpace @@ -60,7 +60,7 @@ theorem ae_eq_zero_of_integral_smooth_smul_eq_zero [SigmaCompactSpace M] let v : ℕ → Set M := fun n ↦ thickening (u n) s obtain ⟨K, K_compact, vK⟩ : ∃ K, IsCompact K ∧ ∀ n, v n ⊆ K := ⟨_, hδ, fun n ↦ thickening_subset_cthickening_of_le (u_pos n).2.le _⟩ - have : ∀ n, ∃ (g : M → ℝ), support g = v n ∧ Smooth I 𝓘(ℝ) g ∧ Set.range g ⊆ Set.Icc 0 1 + have : ∀ n, ∃ (g : M → ℝ), support g = v n ∧ ContMDiff I 𝓘(ℝ) ⊤ g ∧ Set.range g ⊆ Set.Icc 0 1 ∧ ∀ x ∈ s, g x = 1 := by intro n rcases exists_msmooth_support_eq_eq_one_iff I isOpen_thickening hs.isClosed @@ -121,7 +121,7 @@ instance (U : Opens M) : BorelSpace U := inferInstanceAs (BorelSpace (U : Set M) nonrec theorem IsOpen.ae_eq_zero_of_integral_smooth_smul_eq_zero' {U : Set M} (hU : IsOpen U) (hSig : IsSigmaCompact U) (hf : LocallyIntegrableOn f U μ) (h : ∀ g : M → ℝ, - Smooth I 𝓘(ℝ) g → HasCompactSupport g → tsupport g ⊆ U → ∫ x, g x • f x ∂μ = 0) : + ContMDiff I 𝓘(ℝ) ⊤ g → HasCompactSupport g → tsupport g ⊆ U → ∫ x, g x • f x ∂μ = 0) : ∀ᵐ x ∂μ, x ∈ U → f x = 0 := by have meas_U := hU.measurableSet rw [← ae_restrict_iff' meas_U, ae_restrict_iff_subtype meas_U] @@ -146,7 +146,7 @@ variable [SigmaCompactSpace M] theorem IsOpen.ae_eq_zero_of_integral_smooth_smul_eq_zero {U : Set M} (hU : IsOpen U) (hf : LocallyIntegrableOn f U μ) (h : ∀ g : M → ℝ, - Smooth I 𝓘(ℝ) g → HasCompactSupport g → tsupport g ⊆ U → ∫ x, g x • f x ∂μ = 0) : + ContMDiff I 𝓘(ℝ) ⊤ g → HasCompactSupport g → tsupport g ⊆ U → ∫ x, g x • f x ∂μ = 0) : ∀ᵐ x ∂μ, x ∈ U → f x = 0 := haveI := I.locallyCompactSpace haveI := ChartedSpace.locallyCompactSpace H M @@ -160,7 +160,7 @@ theorem IsOpen.ae_eq_zero_of_integral_smooth_smul_eq_zero {U : Set M} (hU : IsOp when multiplied by any smooth compactly supported function, then they coincide almost everywhere. -/ theorem ae_eq_of_integral_smooth_smul_eq (hf : LocallyIntegrable f μ) (hf' : LocallyIntegrable f' μ) (h : ∀ (g : M → ℝ), - Smooth I 𝓘(ℝ) g → HasCompactSupport g → ∫ x, g x • f x ∂μ = ∫ x, g x • f' x ∂μ) : + ContMDiff I 𝓘(ℝ) ⊤ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = ∫ x, g x • f' x ∂μ) : ∀ᵐ x ∂μ, f x = f' x := by have : ∀ᵐ x ∂μ, (f - f') x = 0 := by apply ae_eq_zero_of_integral_smooth_smul_eq_zero I (hf.sub hf') @@ -182,7 +182,7 @@ variable [MeasurableSpace E] [BorelSpace E] {f f' : E → F} {μ : Measure E} /-- If a locally integrable function `f` on a finite-dimensional real vector space has zero integral when multiplied by any smooth compactly supported function, then `f` vanishes almost everywhere. -/ theorem ae_eq_zero_of_integral_contDiff_smul_eq_zero (hf : LocallyIntegrable f μ) - (h : ∀ (g : E → ℝ), ContDiff ℝ ⊤ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = 0) : + (h : ∀ (g : E → ℝ), ContDiff ℝ ∞ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = 0) : ∀ᵐ x ∂μ, f x = 0 := ae_eq_zero_of_integral_smooth_smul_eq_zero 𝓘(ℝ, E) hf (fun g g_diff g_supp ↦ h g g_diff.contDiff g_supp) @@ -192,7 +192,7 @@ integral when multiplied by any smooth compactly supported function, then they c everywhere. -/ theorem ae_eq_of_integral_contDiff_smul_eq (hf : LocallyIntegrable f μ) (hf' : LocallyIntegrable f' μ) (h : ∀ (g : E → ℝ), - ContDiff ℝ ⊤ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = ∫ x, g x • f' x ∂μ) : + ContDiff ℝ ∞ g → HasCompactSupport g → ∫ x, g x • f x ∂μ = ∫ x, g x • f' x ∂μ) : ∀ᵐ x ∂μ, f x = f' x := ae_eq_of_integral_smooth_smul_eq 𝓘(ℝ, E) hf hf' (fun g g_diff g_supp ↦ h g g_diff.contDiff g_supp) @@ -202,7 +202,7 @@ theorem ae_eq_of_integral_contDiff_smul_eq in an open set `U`, then `f` vanishes almost everywhere in `U`. -/ theorem IsOpen.ae_eq_zero_of_integral_contDiff_smul_eq_zero {U : Set E} (hU : IsOpen U) (hf : LocallyIntegrableOn f U μ) - (h : ∀ (g : E → ℝ), ContDiff ℝ ⊤ g → HasCompactSupport g → tsupport g ⊆ U → + (h : ∀ (g : E → ℝ), ContDiff ℝ ∞ g → HasCompactSupport g → tsupport g ⊆ U → ∫ x, g x • f x ∂μ = 0) : ∀ᵐ x ∂μ, x ∈ U → f x = 0 := hU.ae_eq_zero_of_integral_smooth_smul_eq_zero 𝓘(ℝ, E) hf diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index 6debdf4d51000e..b1f19e08a826bc 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -61,7 +61,7 @@ Schwartz space, tempered distributions noncomputable section -open scoped Nat NNReal +open scoped Nat NNReal ContDiff variable {𝕜 𝕜' D E F G V : Type*} variable [NormedAddCommGroup E] [NormedSpace ℝ E] @@ -72,7 +72,7 @@ variable (E F) any power of `‖x‖`. -/ structure SchwartzMap where toFun : E → F - smooth' : ContDiff ℝ ⊤ toFun + smooth' : ContDiff ℝ ∞ toFun decay' : ∀ k n : ℕ, ∃ C : ℝ, ∀ x, ‖x‖ ^ k * ‖iteratedFDeriv ℝ n toFun x‖ ≤ C /-- A function is a Schwartz function if it is smooth and all derivatives decay faster than @@ -98,7 +98,7 @@ theorem decay (f : 𝓢(E, F)) (k n : ℕ) : /-- Every Schwartz function is smooth. -/ theorem smooth (f : 𝓢(E, F)) (n : ℕ∞) : ContDiff ℝ n f := - f.smooth'.of_le le_top + f.smooth'.of_le (mod_cast le_top) /-- Every Schwartz function is continuous. -/ @[continuity] @@ -521,7 +521,7 @@ section TemperateGrowth /-- A function is called of temperate growth if it is smooth and all iterated derivatives are polynomially bounded. -/ def _root_.Function.HasTemperateGrowth (f : E → F) : Prop := - ContDiff ℝ ⊤ f ∧ ∀ n : ℕ, ∃ (k : ℕ) (C : ℝ), ∀ x, ‖iteratedFDeriv ℝ n f x‖ ≤ C * (1 + ‖x‖) ^ k + ContDiff ℝ ∞ f ∧ ∀ n : ℕ, ∃ (k : ℕ) (C : ℝ), ∀ x, ‖iteratedFDeriv ℝ n f x‖ ≤ C * (1 + ‖x‖) ^ k theorem _root_.Function.HasTemperateGrowth.norm_iteratedFDeriv_le_uniform_aux {f : E → F} (hf_temperate : f.HasTemperateGrowth) (n : ℕ) : @@ -680,7 +680,7 @@ variable {σ : 𝕜 →+* 𝕜'} Note: This is a helper definition for `mkCLM`. -/ def mkLM (A : (D → E) → F → G) (hadd : ∀ (f g : 𝓢(D, E)) (x), A (f + g) x = A f x + A g x) (hsmul : ∀ (a : 𝕜) (f : 𝓢(D, E)) (x), A (a • f) x = σ a • A f x) - (hsmooth : ∀ f : 𝓢(D, E), ContDiff ℝ ⊤ (A f)) + (hsmooth : ∀ f : 𝓢(D, E), ContDiff ℝ ∞ (A f)) (hbound : ∀ n : ℕ × ℕ, ∃ (s : Finset (ℕ × ℕ)) (C : ℝ), 0 ≤ C ∧ ∀ (f : 𝓢(D, E)) (x : F), ‖x‖ ^ n.fst * ‖iteratedFDeriv ℝ n.snd (A f) x‖ ≤ C * s.sup (schwartzSeminormFamily 𝕜 D E) f) : 𝓢(D, E) →ₛₗ[σ] 𝓢(F, G) where @@ -700,7 +700,7 @@ For an example of using this definition, see `fderivCLM`. -/ def mkCLM [RingHomIsometric σ] (A : (D → E) → F → G) (hadd : ∀ (f g : 𝓢(D, E)) (x), A (f + g) x = A f x + A g x) (hsmul : ∀ (a : 𝕜) (f : 𝓢(D, E)) (x), A (a • f) x = σ a • A f x) - (hsmooth : ∀ f : 𝓢(D, E), ContDiff ℝ ⊤ (A f)) + (hsmooth : ∀ f : 𝓢(D, E), ContDiff ℝ ∞ (A f)) (hbound : ∀ n : ℕ × ℕ, ∃ (s : Finset (ℕ × ℕ)) (C : ℝ), 0 ≤ C ∧ ∀ (f : 𝓢(D, E)) (x : F), ‖x‖ ^ n.fst * ‖iteratedFDeriv ℝ n.snd (A f) x‖ ≤ C * s.sup (schwartzSeminormFamily 𝕜 D E) f) : 𝓢(D, E) →SL[σ] 𝓢(F, G) where @@ -740,19 +740,16 @@ variable [NormedField 𝕜] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] /-- The map applying a vector to Hom-valued Schwartz function as a continuous linear map. -/ protected def evalCLM (m : E) : 𝓢(E, E →L[ℝ] F) →L[𝕜] 𝓢(E, F) := mkCLM (fun f x => f x m) (fun _ _ _ => rfl) (fun _ _ _ => rfl) - (fun f => ContDiff.clm_apply f.2 contDiff_const) - (by - rintro ⟨k, n⟩ - use {(k, n)}, ‖m‖, norm_nonneg _ - intro f x - refine - le_trans - (mul_le_mul_of_nonneg_left (norm_iteratedFDeriv_clm_apply_const f.2 le_top) - (by positivity)) - ?_ - move_mul [‖m‖] - gcongr ?_ * ‖m‖ - simp only [Finset.sup_singleton, schwartzSeminormFamily_apply, le_seminorm]) + (fun f => ContDiff.clm_apply f.2 contDiff_const) <| by + rintro ⟨k, n⟩ + use {(k, n)}, ‖m‖, norm_nonneg _ + intro f x + refine le_trans + (mul_le_mul_of_nonneg_left (norm_iteratedFDeriv_clm_apply_const f.2 (mod_cast le_top)) + (by positivity)) ?_ + move_mul [‖m‖] + gcongr ?_ * ‖m‖ + simp only [Finset.sup_singleton, schwartzSeminormFamily_apply, le_seminorm] end EvalCLM @@ -764,53 +761,52 @@ variable [NormedAddCommGroup G] [NormedSpace ℝ G] /-- The map `f ↦ (x ↦ B (f x) (g x))` as a continuous `𝕜`-linear map on Schwartz space, where `B` is a continuous `𝕜`-linear map and `g` is a function of temperate growth. -/ def bilinLeftCLM (B : E →L[ℝ] F →L[ℝ] G) {g : D → F} (hg : g.HasTemperateGrowth) : - 𝓢(D, E) →L[ℝ] 𝓢(D, G) := + 𝓢(D, E) →L[ℝ] 𝓢(D, G) := by -- Todo (after port): generalize to `B : E →L[𝕜] F →L[𝕜] G` and `𝕜`-linear - mkCLM - (fun f x => B (f x) (g x)) + refine mkCLM (fun f x => B (f x) (g x)) (fun _ _ _ => by simp only [map_add, add_left_inj, Pi.add_apply, eq_self_iff_true, ContinuousLinearMap.add_apply]) (fun _ _ _ => by simp only [smul_apply, map_smul, ContinuousLinearMap.coe_smul', Pi.smul_apply, RingHom.id_apply]) - (fun f => (B.isBoundedBilinearMap.contDiff.restrict_scalars ℝ).comp (f.smooth'.prod hg.1)) - (by - rintro ⟨k, n⟩ - rcases hg.norm_iteratedFDeriv_le_uniform_aux n with ⟨l, C, hC, hgrowth⟩ - use - Finset.Iic (l + k, n), ‖B‖ * ((n : ℝ) + (1 : ℝ)) * n.choose (n / 2) * (C * 2 ^ (l + k)), - by positivity - intro f x - have hxk : 0 ≤ ‖x‖ ^ k := by positivity - have hnorm_mul := - ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear B f.smooth' hg.1 x (n := n) le_top - refine le_trans (mul_le_mul_of_nonneg_left hnorm_mul hxk) ?_ - move_mul [← ‖B‖] - simp_rw [mul_assoc ‖B‖] - gcongr _ * ?_ - rw [Finset.mul_sum] - have : (∑ _x ∈ Finset.range (n + 1), (1 : ℝ)) = n + 1 := by simp - simp_rw [mul_assoc ((n : ℝ) + 1)] - rw [← this, Finset.sum_mul] - refine Finset.sum_le_sum fun i hi => ?_ - simp only [one_mul] - move_mul [(Nat.choose n i : ℝ), (Nat.choose n (n / 2) : ℝ)] - gcongr ?_ * ?_ - swap - · norm_cast - exact i.choose_le_middle n - specialize hgrowth (n - i) (by simp only [tsub_le_self]) x - refine le_trans (mul_le_mul_of_nonneg_left hgrowth (by positivity)) ?_ - move_mul [C] - gcongr ?_ * C - rw [Finset.mem_range_succ_iff] at hi - change i ≤ (l + k, n).snd at hi - refine le_trans ?_ (one_add_le_sup_seminorm_apply le_rfl hi f x) - rw [pow_add] - move_mul [(1 + ‖x‖) ^ l] - gcongr - simp) + (fun f => (B.isBoundedBilinearMap.contDiff.restrict_scalars ℝ).comp (f.smooth'.prod hg.1)) ?_ + rintro ⟨k, n⟩ + rcases hg.norm_iteratedFDeriv_le_uniform_aux n with ⟨l, C, hC, hgrowth⟩ + use + Finset.Iic (l + k, n), ‖B‖ * ((n : ℝ) + (1 : ℝ)) * n.choose (n / 2) * (C * 2 ^ (l + k)), + by positivity + intro f x + have hxk : 0 ≤ ‖x‖ ^ k := by positivity + have hnorm_mul := + ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear B f.smooth' hg.1 x (n := n) + (mod_cast le_top) + refine le_trans (mul_le_mul_of_nonneg_left hnorm_mul hxk) ?_ + move_mul [← ‖B‖] + simp_rw [mul_assoc ‖B‖] + gcongr _ * ?_ + rw [Finset.mul_sum] + have : (∑ _x ∈ Finset.range (n + 1), (1 : ℝ)) = n + 1 := by simp + simp_rw [mul_assoc ((n : ℝ) + 1)] + rw [← this, Finset.sum_mul] + refine Finset.sum_le_sum fun i hi => ?_ + simp only [one_mul] + move_mul [(Nat.choose n i : ℝ), (Nat.choose n (n / 2) : ℝ)] + gcongr ?_ * ?_ + swap + · norm_cast + exact i.choose_le_middle n + specialize hgrowth (n - i) (by simp only [tsub_le_self]) x + refine le_trans (mul_le_mul_of_nonneg_left hgrowth (by positivity)) ?_ + move_mul [C] + gcongr ?_ * C + rw [Finset.mem_range_succ_iff] at hi + change i ≤ (l + k, n).snd at hi + refine le_trans ?_ (one_add_le_sup_seminorm_apply le_rfl hi f x) + rw [pow_add] + move_mul [(1 + ‖x‖) ^ l] + gcongr + simp end Multiplication @@ -824,68 +820,67 @@ variable [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] /-- Composition with a function on the right is a continuous linear map on Schwartz space provided that the function is temperate and growths polynomially near infinity. -/ def compCLM {g : D → E} (hg : g.HasTemperateGrowth) - (hg_upper : ∃ (k : ℕ) (C : ℝ), ∀ x, ‖x‖ ≤ C * (1 + ‖g x‖) ^ k) : 𝓢(E, F) →L[𝕜] 𝓢(D, F) := - mkCLM (fun f x => f (g x)) + (hg_upper : ∃ (k : ℕ) (C : ℝ), ∀ x, ‖x‖ ≤ C * (1 + ‖g x‖) ^ k) : 𝓢(E, F) →L[𝕜] 𝓢(D, F) := by + refine mkCLM (fun f x => f (g x)) (fun _ _ _ => by simp only [add_left_inj, Pi.add_apply, eq_self_iff_true]) (fun _ _ _ => rfl) - (fun f => f.smooth'.comp hg.1) - (by - rintro ⟨k, n⟩ - rcases hg.norm_iteratedFDeriv_le_uniform_aux n with ⟨l, C, hC, hgrowth⟩ - rcases hg_upper with ⟨kg, Cg, hg_upper'⟩ - have hCg : 1 ≤ 1 + Cg := by - refine le_add_of_nonneg_right ?_ - specialize hg_upper' 0 - rw [norm_zero] at hg_upper' - exact nonneg_of_mul_nonneg_left hg_upper' (by positivity) - let k' := kg * (k + l * n) - use Finset.Iic (k', n), (1 + Cg) ^ (k + l * n) * ((C + 1) ^ n * n ! * 2 ^ k'), by positivity - intro f x - let seminorm_f := ((Finset.Iic (k', n)).sup (schwartzSeminormFamily 𝕜 _ _)) f - have hg_upper'' : (1 + ‖x‖) ^ (k + l * n) ≤ (1 + Cg) ^ (k + l * n) * (1 + ‖g x‖) ^ k' := by - rw [pow_mul, ← mul_pow] - gcongr - rw [add_mul] - refine add_le_add ?_ (hg_upper' x) - nth_rw 1 [← one_mul (1 : ℝ)] - gcongr - 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] - change i ≤ (k', n).snd at hi - exact one_add_le_sup_seminorm_apply le_rfl hi _ _ - have hgrowth' : ∀ N : ℕ, 1 ≤ N → N ≤ n → - ‖iteratedFDeriv ℝ N g x‖ ≤ ((C + 1) * (1 + ‖x‖) ^ l) ^ N := by - intro N hN₁ hN₂ - refine (hgrowth N hN₂ x).trans ?_ - 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₀ ?_) 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 := - pow_le_pow_left₀ (norm_nonneg _) (by simp only [zero_le_one, le_add_iff_nonneg_left]) _ - refine le_trans (mul_le_mul hxk this (by positivity) (by positivity)) ?_ - have rearrange : - (1 + ‖x‖) ^ k * - (n ! * (2 ^ k' * seminorm_f / (1 + ‖g x‖) ^ k') * ((C + 1) * (1 + ‖x‖) ^ l) ^ n) = - (1 + ‖x‖) ^ (k + l * n) / (1 + ‖g x‖) ^ k' * - ((C + 1) ^ n * n ! * 2 ^ k' * seminorm_f) := by - rw [mul_pow, pow_add, ← pow_mul] - ring - rw [rearrange] - have hgxk' : 0 < (1 + ‖g x‖) ^ k' := by positivity - 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 - refine le_trans (mul_le_mul_of_nonneg_right hg_upper'' hpos) ?_ - rw [← mul_assoc]) + (fun f => f.smooth'.comp hg.1) ?_ + rintro ⟨k, n⟩ + rcases hg.norm_iteratedFDeriv_le_uniform_aux n with ⟨l, C, hC, hgrowth⟩ + rcases hg_upper with ⟨kg, Cg, hg_upper'⟩ + have hCg : 1 ≤ 1 + Cg := by + refine le_add_of_nonneg_right ?_ + specialize hg_upper' 0 + rw [norm_zero] at hg_upper' + exact nonneg_of_mul_nonneg_left hg_upper' (by positivity) + let k' := kg * (k + l * n) + use Finset.Iic (k', n), (1 + Cg) ^ (k + l * n) * ((C + 1) ^ n * n ! * 2 ^ k'), by positivity + intro f x + let seminorm_f := ((Finset.Iic (k', n)).sup (schwartzSeminormFamily 𝕜 _ _)) f + have hg_upper'' : (1 + ‖x‖) ^ (k + l * n) ≤ (1 + Cg) ^ (k + l * n) * (1 + ‖g x‖) ^ k' := by + rw [pow_mul, ← mul_pow] + gcongr + rw [add_mul] + refine add_le_add ?_ (hg_upper' x) + nth_rw 1 [← one_mul (1 : ℝ)] + gcongr + 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] + change i ≤ (k', n).snd at hi + exact one_add_le_sup_seminorm_apply le_rfl hi _ _ + have hgrowth' : ∀ N : ℕ, 1 ≤ N → N ≤ n → + ‖iteratedFDeriv ℝ N g x‖ ≤ ((C + 1) * (1 + ‖x‖) ^ l) ^ N := by + intro N hN₁ hN₂ + refine (hgrowth N hN₂ x).trans ?_ + 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₀ ?_) hN₁' + simp only [le_add_iff_nonneg_right, norm_nonneg] + have := norm_iteratedFDeriv_comp_le f.smooth' hg.1 (mod_cast le_top) x hbound hgrowth' + have hxk : ‖x‖ ^ k ≤ (1 + ‖x‖) ^ k := + pow_le_pow_left₀ (norm_nonneg _) (by simp only [zero_le_one, le_add_iff_nonneg_left]) _ + refine le_trans (mul_le_mul hxk this (by positivity) (by positivity)) ?_ + have rearrange : + (1 + ‖x‖) ^ k * + (n ! * (2 ^ k' * seminorm_f / (1 + ‖g x‖) ^ k') * ((C + 1) * (1 + ‖x‖) ^ l) ^ n) = + (1 + ‖x‖) ^ (k + l * n) / (1 + ‖g x‖) ^ k' * + ((C + 1) ^ n * n ! * 2 ^ k' * seminorm_f) := by + rw [mul_pow, pow_add, ← pow_mul] + ring + rw [rearrange] + have hgxk' : 0 < (1 + ‖g x‖) ^ k' := by positivity + 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 + refine le_trans (mul_le_mul_of_nonneg_right hg_upper'' hpos) ?_ + rw [← mul_assoc] @[simp] lemma compCLM_apply {g : D → E} (hg : g.HasTemperateGrowth) (hg_upper : ∃ (k : ℕ) (C : ℝ), ∀ x, ‖x‖ ≤ C * (1 + ‖g x‖) ^ k) (f : 𝓢(E, F)) : @@ -1021,7 +1016,8 @@ theorem iteratedPDeriv_eq_iteratedFDeriv {n : ℕ} {m : Fin n → E} {f : 𝓢(E simp only [iteratedPDeriv_succ_left, iteratedFDeriv_succ_apply_left] rw [← fderiv_continuousMultilinear_apply_const_apply] · simp [← ih] - · exact f.smooth'.differentiable_iteratedFDeriv (WithTop.coe_lt_top n) _ + · exact f.smooth'.differentiable_iteratedFDeriv (mod_cast ENat.coe_lt_top n) x + end Derivatives @@ -1056,7 +1052,7 @@ lemma integrable_pow_mul_iteratedFDeriv (f : 𝓢(D, V)) (k n : ℕ) : Integrable (fun x ↦ ‖x‖ ^ k * ‖iteratedFDeriv ℝ n f x‖) μ := integrable_of_le_of_pow_mul_le (norm_iteratedFDeriv_le_seminorm ℝ _ _) (le_seminorm ℝ _ _ _) - ((f.smooth ⊤).continuous_iteratedFDeriv le_top).aestronglyMeasurable + ((f.smooth ⊤).continuous_iteratedFDeriv (mod_cast le_top)).aestronglyMeasurable variable (μ) in lemma integrable_pow_mul (f : 𝓢(D, V)) @@ -1070,25 +1066,22 @@ lemma integrable (f : 𝓢(D, V)) : Integrable f μ := variable (𝕜 μ) in /-- The integral as a continuous linear map from Schwartz space to the codomain. -/ -def integralCLM : 𝓢(D, V) →L[𝕜] V := - mkCLMtoNormedSpace (∫ x, · x ∂μ) - (fun f g ↦ by - exact integral_add f.integrable g.integrable) - (integral_smul · ·) - (by - rcases hμ.exists_integrable with ⟨n, h⟩ - let m := (n, 0) - use Finset.Iic m, 2 ^ n * ∫ x : D, (1 + ‖x‖) ^ (- (n : ℝ)) ∂μ - refine ⟨by positivity, fun f ↦ (norm_integral_le_integral_norm f).trans ?_⟩ - 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] - 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)] - rfl - apply h.mul_const) +def integralCLM : 𝓢(D, V) →L[𝕜] V := by + refine mkCLMtoNormedSpace (∫ x, · x ∂μ) + (fun f g ↦ integral_add f.integrable g.integrable) (integral_smul · ·) ?_ + rcases hμ.exists_integrable with ⟨n, h⟩ + let m := (n, 0) + use Finset.Iic m, 2 ^ n * ∫ x : D, (1 + ‖x‖) ^ (- (n : ℝ)) ∂μ + refine ⟨by positivity, fun f ↦ (norm_integral_le_integral_norm f).trans ?_⟩ + 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] + 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)] + rfl + apply h.mul_const variable (𝕜) in @[simp] @@ -1178,7 +1171,7 @@ instance instZeroAtInftyContinuousMapClass : ZeroAtInftyContinuousMapClass 𝓢( intro x hx rw [div_lt_iff₀ hε] at hx have hxpos : 0 < ‖x‖ := by - rw [norm_pos_iff'] + 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) diff --git a/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean index 7a53f32811c4c1..0151b546881374 100644 --- a/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean +++ b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean @@ -81,7 +81,7 @@ noncomputable section open Real Complex MeasureTheory Filter TopologicalSpace -open scoped FourierTransform Topology +open scoped FourierTransform Topology ContDiff -- without this local instance, Lean tries first the instance -- `secondCountableTopologyEither_of_right` (whose priority is 100) and takes a very long time to @@ -310,7 +310,8 @@ lemma _root_.Continuous.fourierPowSMulRight {f : V → E} (hf : Continuous f) (n apply (smulRightL ℝ (fun (_ : Fin n) ↦ W) E).continuous₂.comp₂ _ hf exact Continuous.comp (map_continuous _) (continuous_pi (fun _ ↦ L.continuous)) -lemma _root_.ContDiff.fourierPowSMulRight {f : V → E} {k : ℕ∞} (hf : ContDiff ℝ k f) (n : ℕ) : +lemma _root_.ContDiff.fourierPowSMulRight + {f : V → E} {k : WithTop ℕ∞} (hf : ContDiff ℝ k f) (n : ℕ) : ContDiff ℝ k (fun v ↦ fourierPowSMulRight L f v n) := by simp_rw [fourierPowSMulRight_eq_comp] apply ContDiff.const_smul @@ -335,7 +336,7 @@ set_option maxSynthPendingDepth 2 in /-- The iterated derivative of a function multiplied by `(L v ⬝) ^ n` can be controlled in terms of the iterated derivatives of the initial function. -/ lemma norm_iteratedFDeriv_fourierPowSMulRight - {f : V → E} {K : ℕ∞} {C : ℝ} (hf : ContDiff ℝ K f) {n : ℕ} {k : ℕ} (hk : k ≤ K) + {f : V → E} {K : WithTop ℕ∞} {C : ℝ} (hf : ContDiff ℝ K f) {n : ℕ} {k : ℕ} (hk : k ≤ K) {v : V} (hv : ∀ i ≤ k, ∀ j ≤ n, ‖v‖ ^ j * ‖iteratedFDeriv ℝ i f v‖ ≤ C) : ‖iteratedFDeriv ℝ k (fun v ↦ fourierPowSMulRight L f v n) v‖ ≤ (2 * π) ^ n * (2 * n + 2) ^ k * ‖L‖ ^ n * C := by @@ -440,7 +441,7 @@ lemma integrable_fourierPowSMulRight {n : ℕ} (hf : Integrable (fun v ↦ ‖v filter_upwards with v exact (norm_fourierPowSMulRight_le L f v n).trans (le_of_eq (by ring)) -lemma hasFTaylorSeriesUpTo_fourierIntegral {N : ℕ∞} +lemma hasFTaylorSeriesUpTo_fourierIntegral {N : WithTop ℕ∞} (hf : ∀ (n : ℕ), n ≤ N → Integrable (fun v ↦ ‖v‖^n * ‖f v‖) μ) (h'f : AEStronglyMeasurable f μ) : HasFTaylorSeriesUpTo N (fourierIntegral 𝐞 μ L.toLinearMap₂ f) @@ -455,7 +456,8 @@ 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) (Order.add_one_le_of_lt hn)).const_mul ((2 * π * ‖L‖) ^ n)).mono' + apply ((hf (n+1) (ENat.add_one_natCast_le_withTop_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] @@ -465,7 +467,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) (Order.add_one_le_of_lt hn)) h'f + integrable_fourierPowSMulRight L (hf (n + 1) (ENat.add_one_natCast_le_withTop_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 @@ -488,12 +490,22 @@ lemma hasFTaylorSeriesUpTo_fourierIntegral {N : ℕ∞} apply fourierIntegral_continuous Real.continuous_fourierChar (by apply L.continuous₂) exact integrable_fourierPowSMulRight L (hf n hn) h'f +/-- Variant of `hasFTaylorSeriesUpTo_fourierIntegral` in which the smoothness index is restricted +to `ℕ∞` (and so are the inequalities in the assumption `hf`). Avoids normcasting in some +applications. -/ +lemma hasFTaylorSeriesUpTo_fourierIntegral' {N : ℕ∞} + (hf : ∀ (n : ℕ), n ≤ N → Integrable (fun v ↦ ‖v‖^n * ‖f v‖) μ) + (h'f : AEStronglyMeasurable f μ) : + HasFTaylorSeriesUpTo N (fourierIntegral 𝐞 μ L.toLinearMap₂ f) + (fun w n ↦ fourierIntegral 𝐞 μ L.toLinearMap₂ (fun v ↦ fourierPowSMulRight L f v n) w) := + hasFTaylorSeriesUpTo_fourierIntegral _ (fun n hn ↦ hf n (mod_cast hn)) h'f + /-- If `‖v‖^n * ‖f v‖` is integrable for all `n ≤ N`, then the Fourier transform of `f` is `C^N`. -/ theorem contDiff_fourierIntegral {N : ℕ∞} (hf : ∀ (n : ℕ), n ≤ N → Integrable (fun v ↦ ‖v‖^n * ‖f v‖) μ) : ContDiff ℝ N (fourierIntegral 𝐞 μ L.toLinearMap₂ f) := by by_cases h'f : Integrable f μ - · exact (hasFTaylorSeriesUpTo_fourierIntegral L hf h'f.1).contDiff + · exact (hasFTaylorSeriesUpTo_fourierIntegral' L hf h'f.1).contDiff · have : fourierIntegral 𝐞 μ L.toLinearMap₂ f = 0 := by ext w; simp [fourierIntegral, integral, h'f] simpa [this] using contDiff_const @@ -507,7 +519,8 @@ lemma iteratedFDeriv_fourierIntegral {N : ℕ∞} iteratedFDeriv ℝ n (fourierIntegral 𝐞 μ L.toLinearMap₂ f) = fourierIntegral 𝐞 μ L.toLinearMap₂ (fun v ↦ fourierPowSMulRight L f v n) := by ext w : 1 - exact ((hasFTaylorSeriesUpTo_fourierIntegral L hf h'f).eq_iteratedFDeriv hn w).symm + exact ((hasFTaylorSeriesUpTo_fourierIntegral' L hf h'f).eq_iteratedFDeriv + (mod_cast hn) w).symm end SecondCountableTopology @@ -540,7 +553,8 @@ theorem fourierIntegral_iteratedFDeriv [FiniteDimensional ℝ V] ← fourierIntegral_continuousLinearMap_apply' J] exact H have h'n : n < N := (Nat.cast_lt.mpr n.lt_succ_self).trans_le hn - rw [fourierIntegral_fderiv _ (h'f n h'n.le) (hf.differentiable_iteratedFDeriv h'n) J] + rw [fourierIntegral_fderiv _ (h'f n h'n.le) + (hf.differentiable_iteratedFDeriv (mod_cast h'n)) J] simp only [ih h'n.le, fourierSMulRight_apply, ContinuousLinearMap.neg_apply, ContinuousLinearMap.flip_apply, neg_smul, smul_neg, neg_neg, smul_apply, fourierPowSMulRight_apply, ← coe_smul (E := E), smul_smul] @@ -571,9 +585,9 @@ theorem fourierPowSMulRight_iteratedFDeriv_fourierIntegral [FiniteDimensional simp only [Finset.mem_product, Finset.mem_range_succ_iff] at hp exact h'f _ _ ((Nat.cast_le.2 hp.1).trans hk) ((Nat.cast_le.2 hp.2).trans hm) apply (I.const_mul ((2 * π) ^ k * (2 * k + 2) ^ m * ‖L‖ ^ k)).mono' - ((hf.fourierPowSMulRight L k).continuous_iteratedFDeriv hm).aestronglyMeasurable + ((hf.fourierPowSMulRight L k).continuous_iteratedFDeriv (mod_cast hm)).aestronglyMeasurable filter_upwards with v - refine norm_iteratedFDeriv_fourierPowSMulRight _ hf hm (fun i hi j hj ↦ ?_) + refine norm_iteratedFDeriv_fourierPowSMulRight _ hf (mod_cast hm) (fun i hi j hj ↦ ?_) apply Finset.single_le_sum (f := fun p ↦ ‖v‖ ^ p.1 * ‖iteratedFDeriv ℝ p.2 f v‖) (a := (j, i)) · intro i _hi positivity @@ -604,7 +618,7 @@ theorem norm_fourierPowSMulRight_iteratedFDeriv_fourierIntegral_le [FiniteDimens · filter_upwards with v using norm_nonneg _ · exact (integrable_finset_sum _ I).const_mul _ · filter_upwards with v - apply norm_iteratedFDeriv_fourierPowSMulRight _ hf hn _ + apply norm_iteratedFDeriv_fourierPowSMulRight _ hf (mod_cast hn) _ intro i hi j hj apply Finset.single_le_sum (f := fun p ↦ ‖v‖ ^ p.1 * ‖iteratedFDeriv ℝ p.2 f v‖) (a := (j, i)) · intro i _hi diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index 4acfe80398b104..6f06b27cb078c6 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -1600,9 +1600,7 @@ end ContinuousLinearMap section -variable {ι : Type*} {ι' : Type*} {ι'' : Type*} -variable {E' : Type*} [SeminormedAddCommGroup E'] [InnerProductSpace 𝕜 E'] -variable {E'' : Type*} [SeminormedAddCommGroup E''] [InnerProductSpace 𝕜 E''] +variable {ι : Type*} {ι' : Type*} {E' : Type*} [SeminormedAddCommGroup E'] [InnerProductSpace 𝕜 E'] @[simp] theorem Orthonormal.equiv_refl {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) : @@ -1683,7 +1681,7 @@ open scoped InnerProductSpace variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] variable [NormedAddCommGroup F] [InnerProductSpace ℝ F] -variable {ι : Type*} {ι' : Type*} {ι'' : Type*} +variable {ι : Type*} local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y @@ -2188,18 +2186,16 @@ local notation "IK" => @RCLike.I 𝕜 _ local postfix:90 "†" => starRingEnd _ -variable {ι : Type*} -variable {G : ι → Type*} [∀ i, NormedAddCommGroup (G i)] [∀ i, InnerProductSpace 𝕜 (G i)] - {V : ∀ i, G i →ₗᵢ[𝕜] E} (hV : OrthogonalFamily 𝕜 G V) [dec_V : ∀ (i) (x : G i), Decidable (x ≠ 0)] +variable {ι : Type*} {G : ι → Type*} /-- An orthogonal family forms an independent family of subspaces; that is, any collection of elements each from a different subspace in the family is linearly independent. In particular, the pairwise intersections of elements of the family are 0. -/ theorem OrthogonalFamily.independent {V : ι → Submodule 𝕜 E} (hV : OrthogonalFamily 𝕜 (fun i => V i) fun i => (V i).subtypeₗᵢ) : - CompleteLattice.Independent V := by + iSupIndep V := by classical - apply CompleteLattice.independent_of_dfinsupp_lsum_injective + apply iSupIndep_of_dfinsupp_lsum_injective refine LinearMap.ker_eq_bot.mp ?_ rw [Submodule.eq_bot_iff] intro v hv diff --git a/Mathlib/Analysis/InnerProductSpace/Positive.lean b/Mathlib/Analysis/InnerProductSpace/Positive.lean index f49a0c4973a85a..305ed79703826b 100644 --- a/Mathlib/Analysis/InnerProductSpace/Positive.lean +++ b/Mathlib/Analysis/InnerProductSpace/Positive.lean @@ -109,7 +109,7 @@ lemma antilipschitz_of_forall_le_inner_map {H : Type*} [NormedAddCommGroup H] 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 + · 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) diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index c2ea3c53471075..6be13bb9ce5f1d 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -1218,7 +1218,7 @@ theorem OrthogonalFamily.isInternal_iff_of_isComplete [DecidableEq ι] {V : ι (hV : OrthogonalFamily 𝕜 (fun i => V i) fun i => (V i).subtypeₗᵢ) (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, + simp only [DirectSum.isInternal_submodule_iff_iSupIndep_and_iSup_eq_top, hV.independent, true_and, Submodule.orthogonal_eq_bot_iff] /-- An orthogonal family of subspaces of `E` satisfies `DirectSum.IsInternal` (that is, diff --git a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean index 2fcd08ccaa66d9..fe6587c770dc53 100644 --- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean +++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean @@ -149,7 +149,7 @@ theorem isSymmetric_iff_inner_map_self_real (T : V →ₗ[ℂ] V) : · intro h x y rw [← inner_conj_symm x (T y)] rw [inner_map_polarization T x y] - simp only [starRingEnd_apply, star_div', star_sub, star_add, star_mul] + simp only [starRingEnd_apply, star_div₀, star_sub, star_add, star_mul] simp only [← starRingEnd_apply] rw [h (x + y), h (x - y), h (x + Complex.I • y), h (x - Complex.I • y)] simp only [Complex.conj_I] diff --git a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean index b07b1d09381f72..afdbc274d603b2 100644 --- a/Mathlib/Analysis/InnerProductSpace/TwoDim.lean +++ b/Mathlib/Analysis/InnerProductSpace/TwoDim.lean @@ -354,14 +354,16 @@ theorem inner_mul_inner_add_areaForm_mul_areaForm' (a x : E) : apply (o.basisRightAngleRotation a ha).ext intro i fin_cases i - · simp only [Fin.mk_zero, coe_basisRightAngleRotation, Matrix.cons_val_zero, LinearMap.add_apply, - LinearMap.smul_apply, innerₛₗ_apply, real_inner_self_eq_norm_sq, smul_eq_mul, - areaForm_apply_self, mul_zero, add_zero, Real.rpow_two, real_inner_comm] + · simp only [Fin.zero_eta, Fin.isValue, id_eq, coe_basisRightAngleRotation, Nat.succ_eq_add_one, + Nat.reduceAdd, Matrix.cons_val_zero, LinearMap.add_apply, LinearMap.smul_apply, innerₛₗ_apply, + real_inner_self_eq_norm_sq, smul_eq_mul, areaForm_apply_self, mul_zero, add_zero, + real_inner_comm] ring - · simp only [Fin.mk_one, coe_basisRightAngleRotation, Matrix.cons_val_one, Matrix.head_cons, - LinearMap.add_apply, LinearMap.smul_apply, innerₛₗ_apply, inner_rightAngleRotation_right, - areaForm_apply_self, neg_zero, smul_eq_mul, mul_zero, areaForm_rightAngleRotation_right, - real_inner_self_eq_norm_sq, zero_add, Real.rpow_two, mul_neg] + · simp only [Fin.mk_one, Fin.isValue, id_eq, coe_basisRightAngleRotation, Nat.succ_eq_add_one, + Nat.reduceAdd, Matrix.cons_val_one, Matrix.head_cons, LinearMap.add_apply, + LinearMap.smul_apply, innerₛₗ_apply, inner_rightAngleRotation_right, areaForm_apply_self, + neg_zero, smul_eq_mul, mul_zero, areaForm_rightAngleRotation_right, + real_inner_self_eq_norm_sq, zero_add, mul_neg] rw [o.areaForm_swap] ring @@ -381,15 +383,16 @@ theorem inner_mul_areaForm_sub' (a x : E) : ⟪a, x⟫ • ω a - ω a x • inn apply (o.basisRightAngleRotation a ha).ext intro i fin_cases i - · simp only [o.areaForm_swap a x, neg_smul, sub_neg_eq_add, Fin.mk_zero, - coe_basisRightAngleRotation, Matrix.cons_val_zero, LinearMap.add_apply, LinearMap.smul_apply, - areaForm_apply_self, smul_eq_mul, mul_zero, innerₛₗ_apply, real_inner_self_eq_norm_sq, - zero_add, Real.rpow_two] + · simp only [o.areaForm_swap a x, neg_smul, sub_neg_eq_add, Fin.zero_eta, Fin.isValue, id_eq, + coe_basisRightAngleRotation, Nat.succ_eq_add_one, Nat.reduceAdd, Matrix.cons_val_zero, + LinearMap.add_apply, LinearMap.smul_apply, areaForm_apply_self, smul_eq_mul, mul_zero, + innerₛₗ_apply, real_inner_self_eq_norm_sq, zero_add] ring - · simp only [Fin.mk_one, coe_basisRightAngleRotation, Matrix.cons_val_one, Matrix.head_cons, - LinearMap.sub_apply, LinearMap.smul_apply, areaForm_rightAngleRotation_right, - real_inner_self_eq_norm_sq, smul_eq_mul, innerₛₗ_apply, inner_rightAngleRotation_right, - areaForm_apply_self, neg_zero, mul_zero, sub_zero, Real.rpow_two, real_inner_comm] + · simp only [Fin.mk_one, Fin.isValue, id_eq, coe_basisRightAngleRotation, Nat.succ_eq_add_one, + Nat.reduceAdd, Matrix.cons_val_one, Matrix.head_cons, LinearMap.sub_apply, + LinearMap.smul_apply, areaForm_rightAngleRotation_right, real_inner_self_eq_norm_sq, + smul_eq_mul, innerₛₗ_apply, inner_rightAngleRotation_right, areaForm_apply_self, neg_zero, + mul_zero, sub_zero, real_inner_comm] ring /-- For vectors `a x y : E`, the identity `⟪a, x⟫ * ω a y - ω a x * ⟪a, y⟫ = ‖a‖ ^ 2 * ω x y`. -/ diff --git a/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean b/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean index 7491177284cf86..b948db9a803a4f 100644 --- a/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean +++ b/Mathlib/Analysis/Normed/Affine/ContinuousAffineMap.lean @@ -175,7 +175,7 @@ noncomputable instance : NormedAddCommGroup (V →ᴬ[𝕜] W) := simp only [norm_eq_zero, coe_const, Function.const_apply] at h₁ rw [h₁] rfl - · rw [norm_eq_zero', contLinear_eq_zero_iff_exists_const] at h₁ + · rw [norm_eq_zero, contLinear_eq_zero_iff_exists_const] at h₁ obtain ⟨q, rfl⟩ := h₁ simp only [norm_le_zero_iff, coe_const, Function.const_apply] at h₂ rw [h₂] diff --git a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean index 5dd3a9d8f7ddd9..4f081227992a49 100644 --- a/Mathlib/Analysis/Normed/Algebra/Spectrum.lean +++ b/Mathlib/Analysis/Normed/Algebra/Spectrum.lean @@ -483,7 +483,7 @@ theorem exp_mem_exp [RCLike 𝕜] [NormedRing A] [NormedAlgebra 𝕜 A] [Complet refine .of_norm_bounded_eventually _ (Real.summable_pow_div_factorial ‖a - ↑ₐ z‖) ?_ filter_upwards [Filter.eventually_cofinite_ne 0] with n hn rw [norm_smul, mul_comm, norm_inv, RCLike.norm_natCast, ← div_eq_mul_inv] - exact div_le_div (pow_nonneg (norm_nonneg _) n) (norm_pow_le' (a - ↑ₐ z) (zero_lt_iff.mpr hn)) + exact div_le_div₀ (pow_nonneg (norm_nonneg _) n) (norm_pow_le' (a - ↑ₐ z) (zero_lt_iff.mpr hn)) (mod_cast Nat.factorial_pos n) (mod_cast Nat.factorial_le (lt_add_one n).le) have h₀ : (∑' n : ℕ, ((n + 1).factorial⁻¹ : 𝕜) • (a - ↑ₐ z) ^ (n + 1)) = (a - ↑ₐ z) * b := by simpa only [mul_smul_comm, pow_succ'] using hb.tsum_mul_left (a - ↑ₐ z) diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean index a81ab41393a9d6..00424d49f89732 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -5,10 +5,10 @@ Authors: Patrick Massot, Johannes Hölzl -/ import Mathlib.Algebra.Algebra.NonUnitalSubalgebra import Mathlib.Algebra.Algebra.Subalgebra.Basic +import Mathlib.Algebra.Field.Subfield.Defs +import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.Analysis.Normed.Group.Constructions import Mathlib.Analysis.Normed.Group.Submodule -import Mathlib.Data.Set.Pointwise.Interval -import Mathlib.Algebra.Field.Subfield.Defs /-! # Normed fields @@ -955,7 +955,7 @@ theorem NormedAddCommGroup.tendsto_atTop' [Nonempty α] [Preorder α] [IsDirecte section RingHomIsometric -variable {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} +variable {R₁ R₂ : Type*} /-- This class states that a ring homomorphism is isometric. This is a sufficient assumption for a continuous semilinear map to be bounded and this is the main use for this typeclass. -/ @@ -965,7 +965,7 @@ class RingHomIsometric [Semiring R₁] [Semiring R₂] [Norm R₁] [Norm R₂] ( attribute [simp] RingHomIsometric.is_iso -variable [SeminormedRing R₁] [SeminormedRing R₂] [SeminormedRing R₃] +variable [SeminormedRing R₁] instance RingHomIsometric.ids : RingHomIsometric (RingHom.id R₁) := ⟨rfl⟩ diff --git a/Mathlib/Analysis/Normed/Field/Lemmas.lean b/Mathlib/Analysis/Normed/Field/Lemmas.lean index e22f72874193cd..2943b39e7e0977 100644 --- a/Mathlib/Analysis/Normed/Field/Lemmas.lean +++ b/Mathlib/Analysis/Normed/Field/Lemmas.lean @@ -5,7 +5,8 @@ Authors: Patrick Massot, Johannes Hölzl -/ import Mathlib.Algebra.Group.AddChar -import Mathlib.Algebra.Order.Ring.Finset +import Mathlib.Algebra.Group.TypeTags.Finite +import Mathlib.Algebra.Order.GroupWithZero.Finset import Mathlib.Analysis.Normed.Field.Basic import Mathlib.Analysis.Normed.Group.Bounded import Mathlib.Analysis.Normed.Group.Rat @@ -59,7 +60,7 @@ instance Pi.nonUnitalSeminormedRing {π : ι → Type*} [Fintype ι] 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 _ + Finset.sup_mul_le_mul_sup_of_nonneg (fun _ _ => zero_le _) fun _ _ => zero_le _ } end NonUnitalSeminormedRing diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 4242b77e0dfd6b..da9bbaf0e7c481 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Johannes Hölzl, Yaël Dillies -/ import Mathlib.Algebra.CharP.Defs -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.Analysis.Normed.Group.Seminorm import Mathlib.Topology.Metrizable.Uniformity import Mathlib.Topology.Sequences @@ -44,7 +44,7 @@ normed group -/ -variable {𝓕 𝕜 α ι κ E F G : Type*} +variable {𝓕 α ι κ E F G : Type*} open Filter Function Metric Bornology @@ -337,7 +337,7 @@ abbrev GroupNorm.toNormedCommGroup [CommGroup E] (f : GroupNorm E) : NormedCommG section SeminormedGroup variable [SeminormedGroup E] [SeminormedGroup F] [SeminormedGroup G] {s : Set E} - {a a₁ a₂ b b₁ b₂ c : E} {r r₁ r₂ : ℝ} + {a a₁ a₂ b c : E} {r r₁ r₂ : ℝ} @[to_additive] theorem dist_eq_norm_div (a b : E) : dist a b = ‖a / b‖ := @@ -922,20 +922,6 @@ theorem SeminormedCommGroup.mem_closure_iff : a ∈ closure s ↔ ∀ ε, 0 < ε → ∃ b ∈ s, ‖a / b‖ < ε := by simp [Metric.mem_closure_iff, dist_eq_norm_div] -@[to_additive norm_le_zero_iff'] -theorem norm_le_zero_iff''' [T0Space E] {a : E} : ‖a‖ ≤ 0 ↔ a = 1 := by - letI : NormedGroup E := - { ‹SeminormedGroup E› with toMetricSpace := MetricSpace.ofT0PseudoMetricSpace E } - rw [← dist_one_right, dist_le_zero] - -@[to_additive norm_eq_zero'] -theorem norm_eq_zero''' [T0Space E] {a : E} : ‖a‖ = 0 ↔ a = 1 := - (norm_nonneg' a).le_iff_eq.symm.trans norm_le_zero_iff''' - -@[to_additive norm_pos_iff'] -theorem norm_pos_iff''' [T0Space E] {a : E} : 0 < ‖a‖ ↔ a ≠ 1 := by - rw [← not_le, norm_le_zero_iff'''] - @[to_additive] theorem SeminormedGroup.tendstoUniformlyOn_one {f : ι → κ → G} {s : Set κ} {l : Filter ι} : TendstoUniformlyOn f 1 l s ↔ ∀ ε > 0, ∀ᶠ i in l, ∀ x ∈ s, ‖f i x‖ < ε := by @@ -1024,7 +1010,7 @@ end Induced section SeminormedCommGroup -variable [SeminormedCommGroup E] [SeminormedCommGroup F] {a a₁ a₂ b b₁ b₂ : E} {r r₁ r₂ : ℝ} +variable [SeminormedCommGroup E] [SeminormedCommGroup F] {a b : E} {r : ℝ} @[to_additive] theorem dist_inv (x y : E) : dist x⁻¹ y = dist x y⁻¹ := by @@ -1290,26 +1276,28 @@ end SeminormedCommGroup section NormedGroup -variable [NormedGroup E] [NormedGroup F] {a b : E} +variable [NormedGroup E] {a b : E} + +@[to_additive (attr := simp) norm_le_zero_iff] +lemma norm_le_zero_iff' : ‖a‖ ≤ 0 ↔ a = 1 := by rw [← dist_one_right, dist_le_zero] + +@[to_additive (attr := simp) norm_pos_iff] +lemma norm_pos_iff' : 0 < ‖a‖ ↔ a ≠ 1 := by rw [← not_le, norm_le_zero_iff'] @[to_additive (attr := simp) norm_eq_zero] -theorem norm_eq_zero'' : ‖a‖ = 0 ↔ a = 1 := - norm_eq_zero''' +lemma norm_eq_zero' : ‖a‖ = 0 ↔ a = 1 := (norm_nonneg' a).le_iff_eq.symm.trans norm_le_zero_iff' @[to_additive norm_ne_zero_iff] -theorem norm_ne_zero_iff' : ‖a‖ ≠ 0 ↔ a ≠ 1 := - norm_eq_zero''.not +lemma norm_ne_zero_iff' : ‖a‖ ≠ 0 ↔ a ≠ 1 := norm_eq_zero'.not -@[to_additive (attr := simp) norm_pos_iff] -theorem norm_pos_iff'' : 0 < ‖a‖ ↔ a ≠ 1 := - norm_pos_iff''' - -@[to_additive (attr := simp) norm_le_zero_iff] -theorem norm_le_zero_iff'' : ‖a‖ ≤ 0 ↔ a = 1 := - norm_le_zero_iff''' +@[deprecated (since := "2024-11-24")] alias norm_le_zero_iff'' := norm_le_zero_iff' +@[deprecated (since := "2024-11-24")] alias norm_le_zero_iff''' := norm_le_zero_iff' +@[deprecated (since := "2024-11-24")] alias norm_pos_iff'' := norm_pos_iff' +@[deprecated (since := "2024-11-24")] alias norm_eq_zero'' := norm_eq_zero' +@[deprecated (since := "2024-11-24")] alias norm_eq_zero''' := norm_eq_zero' @[to_additive] -theorem norm_div_eq_zero_iff : ‖a / b‖ = 0 ↔ a = b := by rw [norm_eq_zero'', div_eq_one] +theorem norm_div_eq_zero_iff : ‖a / b‖ = 0 ↔ a = b := by rw [norm_eq_zero', div_eq_one] @[to_additive] theorem norm_div_pos_iff : 0 < ‖a / b‖ ↔ a ≠ b := by @@ -1318,7 +1306,7 @@ theorem norm_div_pos_iff : 0 < ‖a / b‖ ↔ a ≠ b := by @[to_additive eq_of_norm_sub_le_zero] theorem eq_of_norm_div_le_zero (h : ‖a / b‖ ≤ 0) : a = b := by - rwa [← div_eq_one, ← norm_le_zero_iff''] + rwa [← div_eq_one, ← norm_le_zero_iff'] alias ⟨eq_of_norm_div_eq_zero, _⟩ := norm_div_eq_zero_iff @@ -1334,7 +1322,7 @@ theorem eq_one_or_nnnorm_pos (a : E) : a = 1 ∨ 0 < ‖a‖₊ := @[to_additive (attr := simp) nnnorm_eq_zero] theorem nnnorm_eq_zero' : ‖a‖₊ = 0 ↔ a = 1 := by - rw [← NNReal.coe_eq_zero, coe_nnnorm', norm_eq_zero''] + rw [← NNReal.coe_eq_zero, coe_nnnorm', norm_eq_zero'] @[to_additive nnnorm_ne_zero_iff] theorem nnnorm_ne_zero_iff' : ‖a‖₊ ≠ 0 ↔ a ≠ 1 := @@ -1346,24 +1334,24 @@ lemma nnnorm_pos' : 0 < ‖a‖₊ ↔ a ≠ 1 := pos_iff_ne_zero.trans nnnorm_n /-- See `tendsto_norm_one` for a version with full neighborhoods. -/ @[to_additive "See `tendsto_norm_zero` for a version with full neighborhoods."] lemma tendsto_norm_one' : Tendsto (norm : E → ℝ) (𝓝[≠] 1) (𝓝[>] 0) := - tendsto_norm_one.inf <| tendsto_principal_principal.2 fun _ hx ↦ norm_pos_iff''.2 hx + tendsto_norm_one.inf <| tendsto_principal_principal.2 fun _ hx ↦ norm_pos_iff'.2 hx @[to_additive] theorem tendsto_norm_div_self_punctured_nhds (a : E) : Tendsto (fun x => ‖x / a‖) (𝓝[≠] a) (𝓝[>] 0) := (tendsto_norm_div_self a).inf <| - tendsto_principal_principal.2 fun _x hx => norm_pos_iff''.2 <| div_ne_one.2 hx + tendsto_principal_principal.2 fun _x hx => norm_pos_iff'.2 <| div_ne_one.2 hx @[to_additive] theorem tendsto_norm_nhdsWithin_one : Tendsto (norm : E → ℝ) (𝓝[≠] 1) (𝓝[>] 0) := - tendsto_norm_one.inf <| tendsto_principal_principal.2 fun _x => norm_pos_iff''.2 + tendsto_norm_one.inf <| tendsto_principal_principal.2 fun _x => norm_pos_iff'.2 variable (E) /-- The norm of a normed group as a group norm. -/ @[to_additive "The norm of a normed group as an additive group norm."] def normGroupNorm : GroupNorm E := - { normGroupSeminorm _ with eq_one_of_map_eq_zero' := fun _ => norm_eq_zero''.1 } + { normGroupSeminorm _ with eq_one_of_map_eq_zero' := fun _ => norm_eq_zero'.1 } @[simp] theorem coe_normGroupNorm : ⇑(normGroupNorm E) = norm := diff --git a/Mathlib/Analysis/Normed/Group/Bounded.lean b/Mathlib/Analysis/Normed/Group/Bounded.lean index bd28a0b52f3409..0795999cb55410 100644 --- a/Mathlib/Analysis/Normed/Group/Bounded.lean +++ b/Mathlib/Analysis/Normed/Group/Bounded.lean @@ -6,7 +6,6 @@ Authors: Patrick Massot, Johannes Hölzl, Yaël Dillies import Mathlib.Analysis.Normed.Group.Basic import Mathlib.Topology.MetricSpace.Bounded import Mathlib.Order.Filter.Pointwise -import Mathlib.Order.LiminfLimsup /-! # Boundedness in normed groups @@ -21,11 +20,10 @@ normed group open Filter Metric Bornology open scoped Pointwise Topology -variable {α ι E F G : Type*} +variable {α E F G : Type*} section SeminormedGroup variable [SeminormedGroup E] [SeminormedGroup F] [SeminormedGroup G] {s : Set E} - {a a₁ a₂ b b₁ b₂ : E} {r r₁ r₂ : ℝ} @[to_additive (attr := simp) comap_norm_atTop] lemma comap_norm_atTop' : comap norm atTop = cobounded E := by diff --git a/Mathlib/Analysis/Normed/Group/Constructions.lean b/Mathlib/Analysis/Normed/Group/Constructions.lean index c9ee9cc5d178f0..95eb19382e9658 100644 --- a/Mathlib/Analysis/Normed/Group/Constructions.lean +++ b/Mathlib/Analysis/Normed/Group/Constructions.lean @@ -103,11 +103,11 @@ variable [Norm E] instance Additive.toNorm : Norm (Additive E) := ‹Norm E› instance Multiplicative.toNorm : Norm (Multiplicative E) := ‹Norm E› -@[simp] lemma norm_toMul (x) : ‖(toMul x : E)‖ = ‖x‖ := rfl +@[simp] lemma norm_toMul (x : Additive E) : ‖(x.toMul : E)‖ = ‖x‖ := rfl @[simp] lemma norm_ofMul (x : E) : ‖ofMul x‖ = ‖x‖ := rfl -@[simp] lemma norm_toAdd (x) : ‖(toAdd x : E)‖ = ‖x‖ := rfl +@[simp] lemma norm_toAdd (x : Multiplicative E) : ‖(x.toAdd : E)‖ = ‖x‖ := rfl @[simp] lemma norm_ofAdd (x : E) : ‖ofAdd x‖ = ‖x‖ := rfl @@ -120,23 +120,23 @@ instance Additive.toNNNorm : NNNorm (Additive E) := ‹NNNorm E› instance Multiplicative.toNNNorm : NNNorm (Multiplicative E) := ‹NNNorm E› -@[simp] lemma nnnorm_toMul (x) : ‖(toMul x : E)‖₊ = ‖x‖₊ := rfl +@[simp] lemma nnnorm_toMul (x : Additive E) : ‖(x.toMul : E)‖₊ = ‖x‖₊ := rfl @[simp] lemma nnnorm_ofMul (x : E) : ‖ofMul x‖₊ = ‖x‖₊ := rfl -@[simp] lemma nnnorm_toAdd (x) : ‖(toAdd x : E)‖₊ = ‖x‖₊ := rfl +@[simp] lemma nnnorm_toAdd (x : Multiplicative E) : ‖(x.toAdd : E)‖₊ = ‖x‖₊ := rfl @[simp] lemma nnnorm_ofAdd (x : E) : ‖ofAdd x‖₊ = ‖x‖₊ := rfl end NNNorm instance Additive.seminormedAddGroup [SeminormedGroup E] : SeminormedAddGroup (Additive E) where - dist_eq x y := dist_eq_norm_div (toMul x) (toMul y) + dist_eq x y := dist_eq_norm_div x.toMul y.toMul instance Multiplicative.seminormedGroup [SeminormedAddGroup E] : SeminormedGroup (Multiplicative E) where - dist_eq x y := dist_eq_norm_sub (toMul x) (toMul y) + dist_eq x y := dist_eq_norm_sub x.toAdd y.toAdd instance Additive.seminormedCommGroup [SeminormedCommGroup E] : SeminormedAddCommGroup (Additive E) := diff --git a/Mathlib/Analysis/Normed/Group/Seminorm.lean b/Mathlib/Analysis/Normed/Group/Seminorm.lean index 38c8d7fee64ca1..e895bf01b8d3c1 100644 --- a/Mathlib/Analysis/Normed/Group/Seminorm.lean +++ b/Mathlib/Analysis/Normed/Group/Seminorm.lean @@ -44,6 +44,7 @@ having a superfluous `add_le'` field in the resulting structure. The same applie norm, seminorm -/ +assert_not_exists Finset open Set diff --git a/Mathlib/Analysis/Normed/Group/Uniform.lean b/Mathlib/Analysis/Normed/Group/Uniform.lean index 8f4a7f9f06b4e0..ca6dd25e1c9bba 100644 --- a/Mathlib/Analysis/Normed/Group/Uniform.lean +++ b/Mathlib/Analysis/Normed/Group/Uniform.lean @@ -15,13 +15,13 @@ This file proves lipschitzness of normed group operations and shows that normed groups. -/ -variable {𝓕 α E F : Type*} +variable {𝓕 E F : Type*} open Filter Function Metric Bornology open scoped ENNReal NNReal Uniformity Pointwise Topology section SeminormedGroup -variable [SeminormedGroup E] [SeminormedGroup F] {s : Set E} {a a₁ a₂ b b₁ b₂ : E} {r r₁ r₂ : ℝ} +variable [SeminormedGroup E] [SeminormedGroup F] {s : Set E} {a b : E} {r : ℝ} @[to_additive] instance NormedGroup.to_isometricSMul_right : IsometricSMul Eᵐᵒᵖ E := @@ -177,7 +177,7 @@ end SeminormedGroup section SeminormedCommGroup -variable [SeminormedCommGroup E] [SeminormedCommGroup F] {a a₁ a₂ b b₁ b₂ : E} {r r₁ r₂ : ℝ} +variable [SeminormedCommGroup E] [SeminormedCommGroup F] {a₁ a₂ b₁ b₂ : E} {r₁ r₂ : ℝ} @[to_additive] instance NormedGroup.to_isometricSMul_left : IsometricSMul E E := @@ -239,7 +239,7 @@ theorem edist_mul_mul_le (a₁ a₂ b₁ b₂ : E) : section PseudoEMetricSpace variable {α E : Type*} [SeminormedCommGroup E] [PseudoEMetricSpace α] {K Kf Kg : ℝ≥0} - {f g : α → E} {s : Set α} {x : α} + {f g : α → E} {s : Set α} @[to_additive (attr := simp)] lemma lipschitzWith_inv_iff : LipschitzWith K f⁻¹ ↔ LipschitzWith K f := by simp [LipschitzWith] @@ -381,7 +381,7 @@ instance : NormedCommGroup (SeparationQuotient E) where @[to_additive] theorem mk_eq_one_iff {p : E} : mk p = 1 ↔ ‖p‖ = 0 := by - rw [← norm_mk', norm_eq_zero''] + rw [← norm_mk', norm_eq_zero'] set_option linter.docPrime false in @[to_additive (attr := simp) nnnorm_mk] diff --git a/Mathlib/Analysis/Normed/Lp/lpSpace.lean b/Mathlib/Analysis/Normed/Lp/lpSpace.lean index 4797943bc7ec57..b2a36ecac89b56 100644 --- a/Mathlib/Analysis/Normed/Lp/lpSpace.lean +++ b/Mathlib/Analysis/Normed/Lp/lpSpace.lean @@ -183,7 +183,7 @@ theorem of_exponent_ge {p q : ℝ≥0∞} {f : ∀ i, E i} (hfq : Memℓp f q) ( have hf' := hfq.summable hq refine .of_norm_bounded_eventually _ hf' (@Set.Finite.subset _ { i | 1 ≤ ‖f i‖ } ?_ _ ?_) · have H : { x : α | 1 ≤ ‖f x‖ ^ q.toReal }.Finite := by - simpa using eventually_lt_of_tendsto_lt (by norm_num) hf'.tendsto_cofinite_zero + simpa using hf'.tendsto_cofinite_zero.eventually_lt_const (by norm_num) exact H.subset fun i hi => Real.one_le_rpow hi hq.le · show ∀ i, ¬|‖f i‖ ^ p.toReal| ≤ ‖f i‖ ^ q.toReal → 1 ≤ ‖f i‖ intro i hi diff --git a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean index 303247548cea2a..789c690f2042f9 100644 --- a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean +++ b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean @@ -54,8 +54,7 @@ namespace LinearIsometry open LinearMap -variable {R : Type*} [Semiring R] -variable {F E₁ : Type*} [SeminormedAddCommGroup F] [NormedAddCommGroup E₁] [Module R E₁] +variable {F E₁ : Type*} [SeminormedAddCommGroup F] [NormedAddCommGroup E₁] variable {R₁ : Type*} [Field R₁] [Module R₁ E₁] [Module R₁ F] [FiniteDimensional R₁ E₁] [FiniteDimensional R₁ F] @@ -110,9 +109,7 @@ end AffineIsometry section CompleteField variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type v} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {F : Type w} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {F' : Type x} - [AddCommGroup F'] [Module 𝕜 F'] [TopologicalSpace F'] [TopologicalAddGroup F'] - [ContinuousSMul 𝕜 F'] [CompleteSpace 𝕜] + [NormedSpace 𝕜 E] {F : Type w} [NormedAddCommGroup F] [NormedSpace 𝕜 F] [CompleteSpace 𝕜] section Affine diff --git a/Mathlib/Analysis/Normed/Operator/BanachSteinhaus.lean b/Mathlib/Analysis/Normed/Operator/BanachSteinhaus.lean index deb7cba16f499e..c112b860d93789 100644 --- a/Mathlib/Analysis/Normed/Operator/BanachSteinhaus.lean +++ b/Mathlib/Analysis/Normed/Operator/BanachSteinhaus.lean @@ -37,8 +37,6 @@ theorem banach_steinhaus {ι : Type*} [CompleteSpace E] {g : ι → E →SL[σ open ENNReal -open ENNReal - /-- This version of Banach-Steinhaus is stated in terms of suprema of `↑‖·‖₊ : ℝ≥0∞` for convenience. -/ theorem banach_steinhaus_iSup_nnnorm {ι : Type*} [CompleteSpace E] {g : ι → E →SL[σ₁₂] F} diff --git a/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean b/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean index a98f45db8cc036..4aeac560e1e53c 100644 --- a/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean +++ b/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean @@ -189,13 +189,13 @@ theorem seminormFromBounded_mul (f_nonneg : 0 ≤ f) simp_rw [mul_comm, hxyz, zero_div] exact div_nonneg (mul_nonneg (seminormFromBounded_nonneg f_nonneg f_mul y) (f_nonneg _)) (f_nonneg _) - · rw [div_le_div_right (lt_of_le_of_ne' (f_nonneg _) hz), mul_comm (f (x * z))] + · rw [div_le_div_iff_of_pos_right (lt_of_le_of_ne' (f_nonneg _) hz), mul_comm (f (x * z))] 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)] 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] + rw [div_le_div_iff_of_pos_right (lt_of_le_of_ne' (f_nonneg _) hxz), mul_comm x y, mul_assoc] /-- If `f : R → ℝ` is a nonzero, nonnegative, multiplicatively bounded function, then `seminormFromBounded' f 1 = 1`. -/ @@ -242,7 +242,7 @@ theorem seminormFromBounded_add (f_nonneg : 0 ≤ f) (le_ciSup_of_le (seminormFromBounded_bddAbove_range f_nonneg f_mul y) z (le_refl _))) by_cases hz : f z = 0 · simp only [hz, div_zero, zero_add, le_refl, or_self_iff] - · rw [div_add_div_same, div_le_div_right (lt_of_le_of_ne' (f_nonneg _) hz), add_mul] + · rw [div_add_div_same, div_le_div_iff_of_pos_right (lt_of_le_of_ne' (f_nonneg _) hz), add_mul] exact f_add _ _ /-- `seminormFromBounded'` is a ring seminorm on `R`. -/ @@ -268,8 +268,8 @@ theorem seminormFromBounded_isNonarchimedean (f_nonneg : 0 ≤ f) · exact Or.inr <| le_ciSup_of_le (seminormFromBounded_bddAbove_range f_nonneg f_mul y) z hfy by_cases hz : f z = 0 · simp only [hz, div_zero, le_refl, or_self_iff] - · rw [div_le_div_right (lt_of_le_of_ne' (f_nonneg _) hz), - div_le_div_right (lt_of_le_of_ne' (f_nonneg _) hz), add_mul, ← le_max_iff] + · rw [div_le_div_iff_of_pos_right (lt_of_le_of_ne' (f_nonneg _) hz), + div_le_div_iff_of_pos_right (lt_of_le_of_ne' (f_nonneg _) hz), add_mul, ← le_max_iff] exact hna _ _ /-- If `f : R → ℝ` is a nonnegative, multiplicatively bounded function and `x : R` is diff --git a/Mathlib/Analysis/Normed/Ring/SeminormFromConst.lean b/Mathlib/Analysis/Normed/Ring/SeminormFromConst.lean index c45e2c357f115d..91ff0ab51079ca 100644 --- a/Mathlib/Analysis/Normed/Ring/SeminormFromConst.lean +++ b/Mathlib/Analysis/Normed/Ring/SeminormFromConst.lean @@ -89,10 +89,10 @@ theorem seminormFromConst_seq_antitone (x : R) : Antitone (seminormFromConst_seq nth_rw 1 [← Nat.add_sub_of_le hmn] rw [pow_add, ← mul_assoc] have hc_pos : 0 < f c := lt_of_le_of_ne (apply_nonneg f _) hc.symm - apply le_trans ((div_le_div_right (pow_pos hc_pos _)).mpr (map_mul_le_mul f _ _)) + apply le_trans ((div_le_div_iff_of_pos_right (pow_pos hc_pos _)).mpr (map_mul_le_mul f _ _)) by_cases heq : m = n · have hnm : n - m = 0 := by rw [heq, Nat.sub_self n] - rw [hnm, heq, div_le_div_right (pow_pos hc_pos _), pow_zero] + rw [hnm, heq, div_le_div_iff_of_pos_right (pow_pos hc_pos _), pow_zero] conv_rhs => rw [← mul_one (f (x * c ^ n))] exact mul_le_mul_of_nonneg_left hf1 (apply_nonneg f _) · have h1 : 1 ≤ n - m := by @@ -150,7 +150,7 @@ def seminormFromConst : RingSeminorm R where (seminormFromConst_isLimit hf1 hc hpm y)) (fun n ↦ ?_) simp only [seminormFromConst_seq] rw [div_mul_div_comm, ← pow_add, two_mul, - div_le_div_right (pow_pos (lt_of_le_of_ne (apply_nonneg f _) hc.symm) _), pow_add, + div_le_div_iff_of_pos_right (pow_pos (lt_of_le_of_ne (apply_nonneg f _) hc.symm) _), pow_add, ← mul_assoc, mul_comm (x * y), ← mul_assoc, mul_assoc, mul_comm (c ^ n)] exact map_mul_le_mul f (x * c ^ n) (y * c ^ n) diff --git a/Mathlib/Analysis/NormedSpace/RCLike.lean b/Mathlib/Analysis/NormedSpace/RCLike.lean index 6b6b64a156b064..f578908f625ccf 100644 --- a/Mathlib/Analysis/NormedSpace/RCLike.lean +++ b/Mathlib/Analysis/NormedSpace/RCLike.lean @@ -65,7 +65,7 @@ theorem LinearMap.bound_of_sphere_bound {r : ℝ} (r_pos : 0 < r) (c : ℝ) (f : simp only [z_zero, RCLike.ofReal_eq_zero, norm_eq_zero, Ne, not_false_iff] rw [eq, norm_mul, norm_div, RCLike.norm_coe_norm, RCLike.norm_of_nonneg r_pos.le, div_mul_eq_mul_div, div_mul_eq_mul_div, mul_comm] - apply div_le_div _ _ r_pos rfl.ge + apply div_le_div₀ _ _ r_pos rfl.ge · exact mul_nonneg ((norm_nonneg _).trans norm_f_z₁) (norm_nonneg z) apply mul_le_mul norm_f_z₁ rfl.le (norm_nonneg z) ((norm_nonneg _).trans norm_f_z₁) diff --git a/Mathlib/Analysis/PSeries.lean b/Mathlib/Analysis/PSeries.lean index 0dc1b5b99f4d73..38fe34d857d764 100644 --- a/Mathlib/Analysis/PSeries.lean +++ b/Mathlib/Analysis/PSeries.lean @@ -386,14 +386,10 @@ theorem sum_Ioc_inv_sq_le_sub {k n : ℕ} (hk : k ≠ 0) (h : k ≤ n) : simp only [sub_eq_add_neg, add_assoc, Nat.cast_add, Nat.cast_one, le_add_neg_iff_add_le, add_le_iff_nonpos_right, neg_add_le_iff_le_add, add_zero] have A : 0 < (n : α) := by simpa using hk.bot_lt.trans_le hn - have B : 0 < (n : α) + 1 := by linarith field_simp - rw [div_le_div_iff _ A, ← sub_nonneg] - · ring_nf - rw [add_comm] - exact B.le - · -- Porting note: was `nlinarith` - positivity + rw [div_le_div_iff₀ _ A] + · linarith + · positivity theorem sum_Ioo_inv_sq_le (k n : ℕ) : (∑ i ∈ Ioo k n, (i ^ 2 : α)⁻¹) ≤ 2 / (k + 1) := calc diff --git a/Mathlib/Analysis/RCLike/Basic.lean b/Mathlib/Analysis/RCLike/Basic.lean index 5390b9d9b0b331..02a0ac58407503 100644 --- a/Mathlib/Analysis/RCLike/Basic.lean +++ b/Mathlib/Analysis/RCLike/Basic.lean @@ -469,7 +469,7 @@ theorem div_im (z w : K) : im (z / w) = im z * re w / normSq w - re z * im w / n @[rclike_simps] -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): was `simp` theorem conj_inv (x : K) : conj x⁻¹ = (conj x)⁻¹ := - star_inv' _ + star_inv₀ _ lemma conj_div (x y : K) : conj (x / y) = conj x / conj y := map_div' conj conj_inv _ _ diff --git a/Mathlib/Analysis/RCLike/Lemmas.lean b/Mathlib/Analysis/RCLike/Lemmas.lean index 0603a4fda4c16a..9ce1f0f40f0a54 100644 --- a/Mathlib/Analysis/RCLike/Lemmas.lean +++ b/Mathlib/Analysis/RCLike/Lemmas.lean @@ -13,8 +13,6 @@ variable {K E : Type*} [RCLike K] namespace Polynomial -open Polynomial - theorem ofReal_eval (p : ℝ[X]) (x : ℝ) : (↑(p.eval x) : K) = aeval (↑x) p := (@aeval_algebraMap_apply_eq_algebraMap_eval ℝ K _ _ _ x p).symm diff --git a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean index a38081bf155828..4f6e5c73f04c5e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean +++ b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean @@ -109,8 +109,8 @@ theorem probability (n : ℕ) (x : I) : (∑ k : Fin (n + 1), bernstein n k x) = theorem variance {n : ℕ} (h : 0 < (n : ℝ)) (x : I) : (∑ k : Fin (n + 1), (x - k/ₙ : ℝ) ^ 2 * bernstein n k x) = (x : ℝ) * (1 - x) / n := by have h' : (n : ℝ) ≠ 0 := ne_of_gt h - apply_fun fun x : ℝ => x * n using GroupWithZero.mul_right_injective h' - apply_fun fun x : ℝ => x * n using GroupWithZero.mul_right_injective h' + apply_fun fun x : ℝ => x * n using GroupWithZero.mul_left_injective h' + apply_fun fun x : ℝ => x * n using GroupWithZero.mul_left_injective h' dsimp conv_lhs => simp only [Finset.sum_mul, z] conv_rhs => rw [div_mul_cancel₀ _ h'] diff --git a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean index 3a485d339830b3..846339ecb2f00d 100644 --- a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean @@ -90,7 +90,7 @@ 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 := +theorem contDiff_exp {n : WithTop ℕ∞} : ContDiff 𝕜 n exp := analyticOnNhd_cexp.restrictScalars.contDiff theorem hasStrictDerivAt_exp (x : ℂ) : HasStrictDerivAt exp (exp x) x := @@ -230,7 +230,7 @@ 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 : WithTop ℕ∞} : ContDiff ℝ n exp := Complex.contDiff_exp.real_of_complex @[simp] diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean index 86a1929d236cc2..6a9a40ef2d4ff1 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean @@ -57,7 +57,7 @@ theorem Gamma_mul_add_mul_le_rpow_Gamma_mul_rpow_Gamma {s t a b : ℝ} (hs : 0 < let f : ℝ → ℝ → ℝ → ℝ := fun c u x => exp (-c * x) * x ^ (c * (u - 1)) have e : IsConjExponent (1 / a) (1 / b) := Real.isConjExponent_one_div ha hb hab have hab' : b = 1 - a := by linarith - have hst : 0 < a * s + b * t := add_pos (mul_pos ha hs) (mul_pos hb ht) + have hst : 0 < a * s + b * t := by positivity -- some properties of f: have posf : ∀ c u x : ℝ, x ∈ Ioi (0 : ℝ) → 0 ≤ f c u x := fun c u x hx => mul_nonneg (exp_pos _).le (rpow_pos_of_pos hx _).le diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean index 75fc9f00bf0db6..b88d8363dabf72 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_def, neg_sq, neg_preimage, preimage_neg_Iio, neg_neg, neg_zero] + simp only [Function.comp_def, neg_sq, neg_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 diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean index 1adccc79ae6dfb..5e688563f5ae74 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean @@ -177,7 +177,7 @@ private theorem b_ne_one' : b ≠ 1 := by linarith @[simp] theorem logb_le_logb (h : 0 < x) (h₁ : 0 < y) : logb b x ≤ logb b y ↔ x ≤ y := by - rw [logb, logb, div_le_div_right (log_pos hb), log_le_log_iff h h₁] + rw [logb, logb, div_le_div_iff_of_pos_right (log_pos hb), log_le_log_iff h h₁] @[gcongr] theorem logb_le_logb_of_le (h : 0 < x) (hxy : x ≤ y) : logb b x ≤ logb b y := @@ -185,12 +185,12 @@ theorem logb_le_logb_of_le (h : 0 < x) (hxy : x ≤ y) : logb b x ≤ logb b y : @[gcongr] theorem logb_lt_logb (hx : 0 < x) (hxy : x < y) : logb b x < logb b y := by - rw [logb, logb, div_lt_div_right (log_pos hb)] + rw [logb, logb, div_lt_div_iff_of_pos_right (log_pos hb)] exact log_lt_log hx hxy @[simp] theorem logb_lt_logb_iff (hx : 0 < x) (hy : 0 < y) : logb b x < logb b y ↔ x < y := by - rw [logb, logb, div_lt_div_right (log_pos hb)] + rw [logb, logb, div_lt_div_iff_of_pos_right (log_pos hb)] exact log_lt_log_iff hx hy theorem logb_le_iff_le_rpow (hx : 0 < x) : logb b x ≤ y ↔ x ≤ b ^ y := by diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean index e9c7ca6362653c..b886b2c9660109 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean @@ -24,7 +24,7 @@ logarithm, derivative open Filter Finset Set -open scoped Topology +open scoped Topology ContDiff namespace Real @@ -66,12 +66,13 @@ theorem deriv_log (x : ℝ) : deriv log x = x⁻¹ := theorem deriv_log' : deriv log = Inv.inv := funext deriv_log -theorem contDiffOn_log {n : ℕ∞} : ContDiffOn ℝ n log {0}ᶜ := by - suffices ContDiffOn ℝ ⊤ log {0}ᶜ from this.of_le le_top +theorem contDiffOn_log {n : WithTop ℕ∞} : ContDiffOn ℝ n log {0}ᶜ := by + suffices ContDiffOn ℝ ω log {0}ᶜ from this.of_le le_top + rw [← contDiffOn_infty_iff_contDiffOn_omega] refine (contDiffOn_top_iff_deriv_of_isOpen isOpen_compl_singleton).2 ?_ simp [differentiableOn_log, contDiffOn_inv] -theorem contDiffAt_log {n : ℕ∞} : ContDiffAt ℝ n log x ↔ x ≠ 0 := +theorem contDiffAt_log {n : WithTop ℕ∞} : ContDiffAt ℝ n log x ↔ x ≠ 0 := ⟨fun h => continuousAt_log_iff.1 h.continuousAt, fun hx => (contDiffOn_log x hx).contDiffAt <| IsOpen.mem_nhds isOpen_compl_singleton hx⟩ diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean index 5aa71529e87e19..c6b70bd4eaffa0 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean @@ -53,11 +53,9 @@ theorem log_div_self_rpow_antitoneOn {a : ℝ} (ha : 0 < a) : intro x hex y _ hxy have x_pos : 0 < x := lt_of_lt_of_le (exp_pos (1 / a)) hex have y_pos : 0 < y := by linarith - have x_nonneg : 0 ≤ x := le_trans (le_of_lt (exp_pos (1 / a))) hex - have y_nonneg : 0 ≤ y := by linarith nth_rw 1 [← rpow_one y] nth_rw 1 [← rpow_one x] - rw [← div_self (ne_of_lt ha).symm, div_eq_mul_one_div a a, rpow_mul y_nonneg, rpow_mul x_nonneg, + rw [← div_self (ne_of_lt ha).symm, div_eq_mul_one_div a a, rpow_mul y_pos.le, rpow_mul x_pos.le, log_rpow (rpow_pos_of_pos y_pos a), log_rpow (rpow_pos_of_pos x_pos a), mul_div_assoc, mul_div_assoc, mul_le_mul_left (one_div_pos.mpr ha)] refine log_div_self_antitoneOn ?_ ?_ ?_ @@ -65,14 +63,14 @@ theorem log_div_self_rpow_antitoneOn {a : ℝ} (ha : 0 < a) : convert rpow_le_rpow _ hex (le_of_lt ha) using 1 · rw [← exp_mul] simp only [Real.exp_eq_exp] - field_simp [(ne_of_lt ha).symm] - exact le_of_lt (exp_pos (1 / a)) + field_simp + positivity · simp only [Set.mem_setOf_eq] convert rpow_le_rpow _ (_root_.trans hex hxy) (le_of_lt ha) using 1 · rw [← exp_mul] simp only [Real.exp_eq_exp] - field_simp [(ne_of_lt ha).symm] - exact le_of_lt (exp_pos (1 / a)) + field_simp + positivity gcongr theorem log_div_sqrt_antitoneOn : AntitoneOn (fun x : ℝ => log x / √x) { x | exp 2 ≤ x } := by diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean index 6a56975c150b06..0c619bd07f671f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean @@ -282,7 +282,7 @@ theorem hasStrictFDerivAt_rpow_of_neg (p : ℝ × ℝ) (hp : p.1 < 0) : rw [div_eq_mul_inv, add_comm]; congr 2 <;> ring /-- The function `fun (x, y) => x ^ y` is infinitely smooth at `(x, y)` unless `x = 0`. -/ -theorem contDiffAt_rpow_of_ne (p : ℝ × ℝ) (hp : p.1 ≠ 0) {n : ℕ∞} : +theorem contDiffAt_rpow_of_ne (p : ℝ × ℝ) (hp : p.1 ≠ 0) {n : WithTop ℕ∞} : ContDiffAt ℝ n (fun p : ℝ × ℝ => p.1 ^ p.2) p := by cases' hp.lt_or_lt with hneg hpos exacts @@ -358,7 +358,7 @@ theorem deriv_rpow_const' {p : ℝ} (h : 1 ≤ p) : (deriv fun x : ℝ => x ^ p) = fun x => p * x ^ (p - 1) := funext fun _ => deriv_rpow_const (Or.inr h) -theorem contDiffAt_rpow_const_of_ne {x p : ℝ} {n : ℕ∞} (h : x ≠ 0) : +theorem contDiffAt_rpow_const_of_ne {x p : ℝ} {n : WithTop ℕ∞} (h : x ≠ 0) : ContDiffAt ℝ n (fun x => x ^ p) x := (contDiffAt_rpow_of_ne (x, p) h).comp x (contDiffAt_id.prod contDiffAt_const) @@ -368,7 +368,8 @@ theorem contDiff_rpow_const_of_le {p : ℝ} {n : ℕ} (h : ↑n ≤ p) : · exact contDiff_zero.2 (continuous_id.rpow_const fun x => Or.inr <| by simpa using h) · have h1 : 1 ≤ p := le_trans (by simp) h rw [Nat.cast_succ, ← le_sub_iff_add_le] at h - rw [contDiff_succ_iff_deriv, deriv_rpow_const' h1] + rw [show ((n + 1 : ℕ) : WithTop ℕ∞) = n + 1 from rfl, contDiff_succ_iff_deriv, + deriv_rpow_const' h1] exact ⟨differentiable_rpow_const h1, contDiff_const.mul (ihn h)⟩ theorem contDiffAt_rpow_const_of_le {x p : ℝ} {n : ℕ} (h : ↑n ≤ p) : @@ -589,10 +590,10 @@ open Real Filter theorem tendsto_one_plus_div_rpow_exp (t : ℝ) : Tendsto (fun x : ℝ => (1 + t / x) ^ x) atTop (𝓝 (exp t)) := by apply ((Real.continuous_exp.tendsto _).comp (tendsto_mul_log_one_plus_div_atTop t)).congr' _ - have h₁ : (1 : ℝ) / 2 < 1 := by linarith + have h₁ : (1 : ℝ) / 2 < 1 := by norm_num have h₂ : Tendsto (fun x : ℝ => 1 + t / x) atTop (𝓝 1) := by simpa using (tendsto_inv_atTop_zero.const_mul t).const_add 1 - refine (eventually_ge_of_tendsto_gt h₁ h₂).mono fun x hx => ?_ + refine (h₂.eventually_const_le h₁).mono fun x hx => ?_ have hx' : 0 < 1 + t / x := by linarith simp [mul_comm x, exp_mul, exp_log hx'] diff --git a/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean b/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean index 20b9a0ce94d94b..a9815ec827dfa0 100644 --- a/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean +++ b/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean @@ -113,7 +113,7 @@ theorem contDiff_polynomial_eval_inv_mul {n : ℕ∞} (p : ℝ[X]) : exact (hasDerivAt_polynomial_eval_inv_mul p _).deriv /-- The function `expNegInvGlue` is smooth. -/ -protected theorem contDiff {n} : ContDiff ℝ n expNegInvGlue := by +protected theorem contDiff {n : ℕ∞} : ContDiff ℝ n expNegInvGlue := by simpa using contDiff_polynomial_eval_inv_mul 1 end expNegInvGlue @@ -174,12 +174,12 @@ theorem lt_one_of_lt_one (h : x < 1) : smoothTransition x < 1 := theorem pos_of_pos (h : 0 < x) : 0 < smoothTransition x := div_pos (expNegInvGlue.pos_of_pos h) (pos_denom x) -protected theorem contDiff {n} : ContDiff ℝ n smoothTransition := +protected theorem contDiff {n : ℕ∞} : ContDiff ℝ n smoothTransition := expNegInvGlue.contDiff.div (expNegInvGlue.contDiff.add <| expNegInvGlue.contDiff.comp <| contDiff_const.sub contDiff_id) fun x => (pos_denom x).ne' -protected theorem contDiffAt {x n} : ContDiffAt ℝ n smoothTransition x := +protected theorem contDiffAt {x : ℝ} {n : ℕ∞} : ContDiffAt ℝ n smoothTransition x := smoothTransition.contDiff.contDiffAt protected theorem continuous : Continuous smoothTransition := diff --git a/Mathlib/Analysis/SpecialFunctions/Stirling.lean b/Mathlib/Analysis/SpecialFunctions/Stirling.lean index 35d9ac4c47d5b3..c42129b43cc422 100644 --- a/Mathlib/Analysis/SpecialFunctions/Stirling.lean +++ b/Mathlib/Analysis/SpecialFunctions/Stirling.lean @@ -122,9 +122,9 @@ theorem log_stirlingSeq_sub_log_stirlingSeq_succ (n : ℕ) : convert H using 1 <;> field_simp [h₃.ne'] refine (log_stirlingSeq_diff_le_geo_sum n).trans ?_ push_cast - rw [div_le_div_iff h₂ h₁] + rw [div_le_div_iff₀ h₂ h₁] field_simp [h₃.ne'] - rw [div_le_div_right h₃] + rw [div_le_div_iff_of_pos_right h₃] ring_nf norm_cast omega diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean index 4c002f27c027ee..9dd56c0fcd5565 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Basic.lean @@ -137,11 +137,11 @@ theorem pi_div_two_le_two : π / 2 ≤ 2 := by exact (Classical.choose_spec exists_cos_eq_zero).1.2 theorem two_le_pi : (2 : ℝ) ≤ π := - (div_le_div_right (show (0 : ℝ) < 2 by norm_num)).1 + (div_le_div_iff_of_pos_right (show (0 : ℝ) < 2 by norm_num)).1 (by rw [div_self (two_ne_zero' ℝ)]; exact one_le_pi_div_two) theorem pi_le_four : π ≤ 4 := - (div_le_div_right (show (0 : ℝ) < 2 by norm_num)).1 + (div_le_div_iff_of_pos_right (show (0 : ℝ) < 2 by norm_num)).1 (calc π / 2 ≤ 2 := pi_div_two_le_two _ = 4 / 2 := by norm_num) @@ -201,8 +201,6 @@ end NNReal namespace Real -open Real - @[simp] theorem sin_pi : sin π = 0 := by rw [← mul_div_cancel_left₀ π (two_ne_zero' ℝ), two_mul, add_div, sin_add, cos_pi_div_two]; simp @@ -887,7 +885,7 @@ theorem tan_nonpos_of_nonpos_of_neg_pi_div_two_le {x : ℝ} (hx0 : x ≤ 0) (hpx theorem strictMonoOn_tan : StrictMonoOn tan (Ioo (-(π / 2)) (π / 2)) := by rintro x hx y hy hlt rw [tan_eq_sin_div_cos, tan_eq_sin_div_cos, - div_lt_div_iff (cos_pos_of_mem_Ioo hx) (cos_pos_of_mem_Ioo hy), mul_comm, ← sub_pos, ← sin_sub] + div_lt_div_iff₀ (cos_pos_of_mem_Ioo hx) (cos_pos_of_mem_Ioo hy), mul_comm, ← sub_pos, ← sin_sub] exact sin_pos_of_pos_of_lt_pi (sub_pos.2 hlt) <| by linarith [hx.1, hy.2] theorem tan_lt_tan_of_lt_of_lt_pi_div_two {x y : ℝ} (hx₁ : -(π / 2) < x) (hy₂ : y < π / 2) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean index e414b1421381a1..a06b4a537e0392 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean @@ -62,7 +62,7 @@ theorem deriv_tan (x : ℂ) : deriv tan x = 1 / cos x ^ 2 := else (hasDerivAt_tan h).deriv @[simp] -theorem contDiffAt_tan {x : ℂ} {n : ℕ∞} : ContDiffAt ℂ n tan x ↔ cos x ≠ 0 := +theorem contDiffAt_tan {x : ℂ} {n : WithTop ℕ∞} : ContDiffAt ℂ n tan x ↔ cos x ≠ 0 := ⟨fun h => continuousAt_tan.1 h.continuousAt, contDiff_sin.contDiffAt.div contDiff_cos.contDiffAt⟩ end Complex diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean index 6ade7f02ca3368..d9efa5b942979e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/InverseDeriv.lean @@ -14,7 +14,7 @@ Derivatives of `arcsin` and `arccos`. noncomputable section -open scoped Topology Filter Real +open scoped Topology Filter Real ContDiff open Set namespace Real @@ -22,7 +22,7 @@ namespace Real section Arcsin theorem deriv_arcsin_aux {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) : - HasStrictDerivAt arcsin (1 / √(1 - x ^ 2)) x ∧ ContDiffAt ℝ ⊤ arcsin x := by + HasStrictDerivAt arcsin (1 / √(1 - x ^ 2)) x ∧ ContDiffAt ℝ ω arcsin x := by cases' h₁.lt_or_lt with h₁ h₁ · have : 1 - x ^ 2 < 0 := by nlinarith [h₁] rw [sqrt_eq_zero'.2 this.le, div_zero] @@ -50,7 +50,8 @@ theorem hasDerivAt_arcsin {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) : HasDerivAt arcsin (1 / √(1 - x ^ 2)) x := (hasStrictDerivAt_arcsin h₁ h₂).hasDerivAt -theorem contDiffAt_arcsin {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) {n : ℕ∞} : ContDiffAt ℝ n arcsin x := +theorem contDiffAt_arcsin {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) {n : WithTop ℕ∞} : + ContDiffAt ℝ n arcsin x := (deriv_arcsin_aux h₁ h₂).2.of_le le_top theorem hasDerivWithinAt_arcsin_Ici {x : ℝ} (h : x ≠ -1) : @@ -102,12 +103,13 @@ theorem differentiableOn_arcsin : DifferentiableOn ℝ arcsin {-1, 1}ᶜ := fun (differentiableAt_arcsin.2 ⟨fun h => hx (Or.inl h), fun h => hx (Or.inr h)⟩).differentiableWithinAt -theorem contDiffOn_arcsin {n : ℕ∞} : ContDiffOn ℝ n arcsin {-1, 1}ᶜ := fun _x hx => +theorem contDiffOn_arcsin {n : WithTop ℕ∞} : ContDiffOn ℝ n arcsin {-1, 1}ᶜ := fun _x hx => (contDiffAt_arcsin (mt Or.inl hx) (mt Or.inr hx)).contDiffWithinAt -theorem contDiffAt_arcsin_iff {x : ℝ} {n : ℕ∞} : ContDiffAt ℝ n arcsin x ↔ n = 0 ∨ x ≠ -1 ∧ x ≠ 1 := +theorem contDiffAt_arcsin_iff {x : ℝ} {n : WithTop ℕ∞} : + ContDiffAt ℝ n arcsin x ↔ n = 0 ∨ x ≠ -1 ∧ x ≠ 1 := ⟨fun h => or_iff_not_imp_left.2 fun hn => differentiableAt_arcsin.1 <| h.differentiableAt <| - ENat.one_le_iff_ne_zero.2 hn, + ENat.one_le_iff_ne_zero_withTop.mpr hn, fun h => h.elim (fun hn => hn.symm ▸ (contDiff_zero.2 continuous_arcsin).contDiffAt) fun hx => contDiffAt_arcsin hx.1 hx.2⟩ @@ -123,7 +125,8 @@ theorem hasDerivAt_arccos {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) : HasDerivAt arccos (-(1 / √(1 - x ^ 2))) x := (hasDerivAt_arcsin h₁ h₂).const_sub (π / 2) -theorem contDiffAt_arccos {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) {n : ℕ∞} : ContDiffAt ℝ n arccos x := +theorem contDiffAt_arccos {x : ℝ} (h₁ : x ≠ -1) (h₂ : x ≠ 1) {n : WithTop ℕ∞} : + ContDiffAt ℝ n arccos x := contDiffAt_const.sub (contDiffAt_arcsin h₁ h₂) theorem hasDerivWithinAt_arccos_Ici {x : ℝ} (h : x ≠ -1) : @@ -152,10 +155,10 @@ theorem deriv_arccos : deriv arccos = fun x => -(1 / √(1 - x ^ 2)) := theorem differentiableOn_arccos : DifferentiableOn ℝ arccos {-1, 1}ᶜ := differentiableOn_arcsin.const_sub _ -theorem contDiffOn_arccos {n : ℕ∞} : ContDiffOn ℝ n arccos {-1, 1}ᶜ := +theorem contDiffOn_arccos {n : WithTop ℕ∞} : ContDiffOn ℝ n arccos {-1, 1}ᶜ := contDiffOn_const.sub contDiffOn_arcsin -theorem contDiffAt_arccos_iff {x : ℝ} {n : ℕ∞} : +theorem contDiffAt_arccos_iff {x : ℝ} {n : WithTop ℕ∞} : ContDiffAt ℝ n arccos x ↔ n = 0 ∨ x ≠ -1 ∧ x ≠ 1 := by refine Iff.trans ⟨fun h => ?_, fun h => ?_⟩ contDiffAt_arcsin_iff <;> simpa [arccos] using (contDiffAt_const (c := π / 2)).sub h diff --git a/Mathlib/Analysis/SpecificLimits/Basic.lean b/Mathlib/Analysis/SpecificLimits/Basic.lean index 3d759d9f3fb336..e9bbbad7a0c521 100644 --- a/Mathlib/Analysis/SpecificLimits/Basic.lean +++ b/Mathlib/Analysis/SpecificLimits/Basic.lean @@ -623,7 +623,7 @@ theorem tendsto_factorial_div_pow_self_atTop : refine (eventually_gt_atTop 0).mono fun n hn ↦ ?_ rcases Nat.exists_eq_succ_of_ne_zero hn.ne.symm with ⟨k, rfl⟩ rw [← prod_range_add_one_eq_factorial, pow_eq_prod_const, div_eq_mul_inv, ← inv_eq_one_div, - prod_natCast, Nat.cast_succ, ← prod_inv_distrib, ← prod_mul_distrib, + prod_natCast, Nat.cast_succ, ← Finset.prod_inv_distrib, ← prod_mul_distrib, Finset.prod_range_succ'] simp only [prod_range_succ', one_mul, Nat.cast_add, zero_add, Nat.cast_one] refine diff --git a/Mathlib/Analysis/SpecificLimits/FloorPow.lean b/Mathlib/Analysis/SpecificLimits/FloorPow.lean index 819d71a7534dab..d03aabb125742c 100644 --- a/Mathlib/Analysis/SpecificLimits/FloorPow.lean +++ b/Mathlib/Analysis/SpecificLimits/FloorPow.lean @@ -220,7 +220,7 @@ theorem sum_div_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc have cpos : 0 < c := zero_lt_one.trans hc have A : (0 : ℝ) < c⁻¹ ^ 2 := sq_pos_of_pos (inv_pos.2 cpos) have B : c ^ 2 * ((1 : ℝ) - c⁻¹ ^ 2)⁻¹ ≤ c ^ 3 * (c - 1)⁻¹ := by - rw [← div_eq_mul_inv, ← div_eq_mul_inv, div_le_div_iff _ (sub_pos.2 hc)] + 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_of_one_lt₀ hc) two_ne_zero) have : c ^ 3 = c ^ 2 * c := by ring @@ -287,7 +287,7 @@ theorem sum_div_nat_floor_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : exact fun k hk ↦ hk.trans_le <| Nat.floor_le (by positivity) _ ≤ ∑ i ∈ range N with j < c ^ i, (1 - c⁻¹)⁻¹ ^ 2 * ((1 : ℝ) / (c ^ i) ^ 2) := by refine sum_le_sum fun i _hi => ?_ - rw [mul_div_assoc', mul_one, div_le_div_iff]; rotate_left + 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₀, hc.le, Nat.one_le_cast, Nat.cast_one] diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index 69992fdb4a1131..cf5f9286f5bd2a 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -601,7 +601,7 @@ theorem summable_of_ratio_test_tendsto_lt_one {α : Type*} [NormedAddCommGroup (h : Tendsto (fun n ↦ ‖f (n + 1)‖ / ‖f n‖) atTop (𝓝 l)) : Summable f := by 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₁ + filter_upwards [h.eventually_le_const hr₀, hf] with _ _ h₁ rwa [← div_le_iff₀ (norm_pos_iff.mpr h₁)] theorem not_summable_of_ratio_norm_eventually_ge {α : Type*} [SeminormedAddCommGroup α] {f : ℕ → α} @@ -629,12 +629,12 @@ theorem not_summable_of_ratio_test_tendsto_gt_one {α : Type*} [SeminormedAddCom {f : ℕ → α} {l : ℝ} (hl : 1 < l) (h : Tendsto (fun n ↦ ‖f (n + 1)‖ / ‖f n‖) atTop (𝓝 l)) : ¬Summable f := by have key : ∀ᶠ n in atTop, ‖f n‖ ≠ 0 := by - filter_upwards [eventually_ge_of_tendsto_gt hl h] with _ hn hc + filter_upwards [h.eventually_const_le hl] with _ hn hc rw [hc, _root_.div_zero] at hn linarith 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₁ + filter_upwards [h.eventually_const_le hr₁, key] with _ _ h₁ rwa [← le_div_iff₀ (lt_of_le_of_ne (norm_nonneg _) h₁.symm)] section NormedDivisionRing diff --git a/Mathlib/CategoryTheory/Adjunction/Evaluation.lean b/Mathlib/CategoryTheory/Adjunction/Evaluation.lean index d11a3d4ac62c1d..ffb59cad14a86a 100644 --- a/Mathlib/CategoryTheory/Adjunction/Evaluation.lean +++ b/Mathlib/CategoryTheory/Adjunction/Evaluation.lean @@ -22,7 +22,6 @@ open CategoryTheory.Limits universe v₁ v₂ v₃ u₁ u₂ u₃ variable {C : Type u₁} [Category.{v₁} C] (D : Type u₂) [Category.{v₂} D] - (E : Type u₃) [Category.{v₃} E] noncomputable section diff --git a/Mathlib/CategoryTheory/Adjunction/Limits.lean b/Mathlib/CategoryTheory/Adjunction/Limits.lean index dd86591976534a..2db2c795ef2c2f 100644 --- a/Mathlib/CategoryTheory/Adjunction/Limits.lean +++ b/Mathlib/CategoryTheory/Adjunction/Limits.lean @@ -92,7 +92,7 @@ lemma leftAdjoint_preservesColimits : PreservesColimitsOfSize.{v, u} F where ((adj.functorialityAdjunction _).homEquiv _ _)⟩ } } include adj in -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma leftAdjointPreservesColimits : PreservesColimitsOfSize.{v, u} F := adj.leftAdjoint_preservesColimits @@ -117,7 +117,7 @@ noncomputable instance (priority := 100) { reflects := fun t => ⟨(isColimitOfPreserves E.inv t).mapCoconeEquiv E.asEquivalence.unitIso.symm⟩ } } -@[deprecated (since := "2024-11-18")] +@[deprecated "No deprecation message was provided." (since := "2024-11-18")] lemma isEquivalenceReflectsColimits (E : D ⥤ C) [E.IsEquivalence] : ReflectsColimitsOfSize.{v, u} E := Functor.reflectsColimits_of_isEquivalence E @@ -216,7 +216,7 @@ lemma rightAdjoint_preservesLimits : PreservesLimitsOfSize.{v, u} G where ((adj.functorialityAdjunction' _).homEquiv _ _).symm⟩ } } include adj in -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma rightAdjointPreservesLimits : PreservesLimitsOfSize.{v, u} G := adj.rightAdjoint_preservesLimits @@ -240,7 +240,7 @@ noncomputable instance (priority := 100) { reflects := fun t => ⟨(isLimitOfPreserves E.inv t).mapConeEquiv E.asEquivalence.unitIso.symm⟩ } } -@[deprecated (since := "2024-11-18")] +@[deprecated "No deprecation message was provided." (since := "2024-11-18")] lemma isEquivalenceReflectsLimits (E : D ⥤ C) [E.IsEquivalence] : ReflectsLimitsOfSize.{v, u} E := Functor.reflectsLimits_of_isEquivalence E diff --git a/Mathlib/CategoryTheory/Closed/Cartesian.lean b/Mathlib/CategoryTheory/Closed/Cartesian.lean index 6b72829dd536d5..0607788f02110b 100644 --- a/Mathlib/CategoryTheory/Closed/Cartesian.lean +++ b/Mathlib/CategoryTheory/Closed/Cartesian.lean @@ -44,7 +44,7 @@ noncomputable section namespace CategoryTheory -open CategoryTheory Category Limits MonoidalCategory +open Category Limits MonoidalCategory /-- An object `X` is *exponentiable* if `(X × -)` is a left adjoint. We define this as being `Closed` in the cartesian monoidal structure. diff --git a/Mathlib/CategoryTheory/Comma/Over.lean b/Mathlib/CategoryTheory/Comma/Over.lean index e37bf7ec998664..305664eb69cad9 100644 --- a/Mathlib/CategoryTheory/Comma/Over.lean +++ b/Mathlib/CategoryTheory/Comma/Over.lean @@ -161,6 +161,13 @@ theorem map_map_left : ((map f).map g).left = g.left := rfl end +/-- If `f` is an isomorphism, `map f` is an equivalence of categories. -/ +def mapIso {Y : T} (f : X ≅ Y) : Over X ≌ Over Y := + Comma.mapRightIso _ <| Discrete.natIso fun _ ↦ f + +@[simp] lemma mapIso_functor {Y : T} (f : X ≅ Y) : (mapIso f).functor = map f.hom := rfl +@[simp] lemma mapIso_inverse {Y : T} (f : X ≅ Y) : (mapIso f).inverse = map f.inv := rfl + section coherences /-! This section proves various equalities between functors that @@ -186,6 +193,7 @@ theorem mapId_eq (Y : T) : map (𝟙 Y) = 𝟭 _ := by simp /-- The natural isomorphism arising from `mapForget_eq`. -/ +@[simps!] def mapId (Y : T) : map (𝟙 Y) ≅ 𝟭 _ := eqToIso (mapId_eq Y) -- NatIso.ofComponents fun X => isoMk (Iso.refl _) @@ -215,9 +223,16 @@ theorem mapComp_eq {X Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : simp /-- The natural isomorphism arising from `mapComp_eq`. -/ +@[simps!] def mapComp {X Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : map (f ≫ g) ≅ (map f) ⋙ (map g) := eqToIso (mapComp_eq f g) +/-- If `f = g`, then `map f` is naturally isomorphic to `map g`. -/ +@[simps!] +def mapCongr {X Y : T} (f g : X ⟶ Y) (h : f = g) : + map f ≅ map g := + NatIso.ofComponents (fun A ↦ eqToIso (by rw [h])) + variable (T) in /-- The functor defined by the over categories.-/ @[simps] def mapFunctor : T ⥤ Cat where @@ -317,6 +332,57 @@ 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]) +lemma post_comp {E : Type*} [Category E] (F : T ⥤ D) (G : D ⥤ E) : + post (X := X) (F ⋙ G) = post (X := X) F ⋙ post G := + rfl + +/-- `post (F ⋙ G)` is isomorphic (actually equal) to `post F ⋙ post G`. -/ +@[simps!] +def postComp {E : Type*} [Category E] (F : T ⥤ D) (G : D ⥤ E) : + post (X := X) (F ⋙ G) ≅ post F ⋙ post G := + NatIso.ofComponents (fun X ↦ Iso.refl _) + +/-- A natural transformation `F ⟶ G` induces a natural transformation on +`Over X` up to `Under.map`. -/ +@[simps] +def postMap {F G : T ⥤ D} (e : F ⟶ G) : post F ⋙ map (e.app X) ⟶ post G where + app Y := Over.homMk (e.app Y.left) + +/-- If `F` and `G` are naturally isomorphic, then `Over.post F` and `Over.post G` are also naturally +isomorphic up to `Over.map` -/ +@[simps!] +def postCongr {F G : T ⥤ D} (e : F ≅ G) : post F ⋙ map (e.hom.app X) ≅ post G := + NatIso.ofComponents (fun A ↦ Over.isoMk (e.app A.left)) + +variable (X) (F : T ⥤ D) + +instance [F.Faithful] : (Over.post (X := X) F).Faithful where + map_injective {A B} f g h := by + ext + exact F.map_injective (congrArg CommaMorphism.left h) + +instance [F.Faithful] [F.Full] : (Over.post (X := X) F).Full where + map_surjective {A B} f := by + obtain ⟨a, ha⟩ := F.map_surjective f.left + have w : a ≫ B.hom = A.hom := F.map_injective <| by simpa [ha] using Over.w _ + exact ⟨Over.homMk a, by ext; simpa⟩ + +instance [F.Full] [F.EssSurj] : (Over.post (X := X) F).EssSurj where + mem_essImage B := by + obtain ⟨A', ⟨e⟩⟩ := Functor.EssSurj.mem_essImage (F := F) B.left + obtain ⟨f, hf⟩ := F.map_surjective (e.hom ≫ B.hom) + exact ⟨Over.mk f, ⟨Over.isoMk e⟩⟩ + +instance [F.IsEquivalence] : (Over.post (X := X) F).IsEquivalence where + +/-- An equivalence of categories induces an equivalence on over categories. -/ +@[simps] +def postEquiv (F : T ≌ D) : Over X ≌ Over (F.functor.obj X) where + functor := Over.post F.functor + inverse := Over.post (X := F.functor.obj X) F.inverse ⋙ Over.map (F.unitIso.inv.app X) + unitIso := NatIso.ofComponents (fun A ↦ Over.isoMk (F.unitIso.app A.left)) + counitIso := NatIso.ofComponents (fun A ↦ Over.isoMk (F.counitIso.app A.left)) + end Over namespace CostructuredArrow @@ -457,6 +523,13 @@ theorem map_map_right : ((map f).map g).right = g.right := rfl end +/-- If `f` is an isomorphism, `map f` is an equivalence of categories. -/ +def mapIso {Y : T} (f : X ≅ Y) : Under Y ≌ Under X := + Comma.mapLeftIso _ <| Discrete.natIso fun _ ↦ f.symm + +@[simp] lemma mapIso_functor {Y : T} (f : X ≅ Y) : (mapIso f).functor = map f.hom := rfl +@[simp] lemma mapIso_inverse {Y : T} (f : X ≅ Y) : (mapIso f).inverse = map f.inv := rfl + section coherences /-! This section proves various equalities between functors that @@ -476,6 +549,7 @@ theorem mapId_eq (Y : T) : map (𝟙 Y) = 𝟭 _ := by simp /-- Mapping by the identity morphism is just the identity functor. -/ +@[simps!] def mapId (Y : T) : map (𝟙 Y) ≅ 𝟭 _ := eqToIso (mapId_eq Y) /-- Mapping by `f` and then forgetting is the same as forgetting. -/ @@ -504,9 +578,16 @@ theorem mapComp_eq {X Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : simp /-- The natural isomorphism arising from `mapComp_eq`. -/ +@[simps!] def mapComp {Y Z : T} (f : X ⟶ Y) (g : Y ⟶ Z) : map (f ≫ g) ≅ map g ⋙ map f := eqToIso (mapComp_eq f g) +/-- If `f = g`, then `map f` is naturally isomorphic to `map g`. -/ +@[simps!] +def mapCongr {X Y : T} (f g : X ⟶ Y) (h : f = g) : + map f ≅ map g := + NatIso.ofComponents (fun A ↦ eqToIso (by rw [h])) + variable (T) in /-- The functor defined by the under categories.-/ @[simps] def mapFunctor : Tᵒᵖ ⥤ Cat where @@ -570,6 +651,58 @@ 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]) +lemma post_comp {E : Type*} [Category E] (F : T ⥤ D) (G : D ⥤ E) : + post (X := X) (F ⋙ G) = post (X := X) F ⋙ post G := + rfl + +/-- `post (F ⋙ G)` is isomorphic (actually equal) to `post F ⋙ post G`. -/ +@[simps!] +def postComp {E : Type*} [Category E] (F : T ⥤ D) (G : D ⥤ E) : + post (X := X) (F ⋙ G) ≅ post F ⋙ post G := + NatIso.ofComponents (fun X ↦ Iso.refl _) + +/-- A natural transformation `F ⟶ G` induces a natural transformation on +`Under X` up to `Under.map`. -/ +@[simps] +def postMap {F G : T ⥤ D} (e : F ⟶ G) : post (X := X) F ⟶ post G ⋙ map (e.app X) where + app Y := Under.homMk (e.app Y.right) + +/-- If `F` and `G` are naturally isomorphic, then `Under.post F` and `Under.post G` are also +naturally isomorphic up to `Under.map` -/ +@[simps!] +def postCongr {F G : T ⥤ D} (e : F ≅ G) : post F ≅ post G ⋙ map (e.hom.app X) := + NatIso.ofComponents (fun A ↦ Under.isoMk (e.app A.right)) + +variable (X) (F : T ⥤ D) + +instance [F.Faithful] : (Under.post (X := X) F).Faithful where + map_injective {A B} f g h := by + ext + exact F.map_injective (congrArg CommaMorphism.right h) + +instance [F.Faithful] [F.Full] : (Under.post (X := X) F).Full where + map_surjective {A B} f := by + obtain ⟨a, ha⟩ := F.map_surjective f.right + dsimp at a + have w : A.hom ≫ a = B.hom := F.map_injective <| by simpa [ha] using Under.w f + exact ⟨Under.homMk a, by ext; simpa⟩ + +instance [F.Full] [F.EssSurj] : (Under.post (X := X) F).EssSurj where + mem_essImage B := by + obtain ⟨B', ⟨e⟩⟩ := Functor.EssSurj.mem_essImage (F := F) B.right + obtain ⟨f, hf⟩ := F.map_surjective (B.hom ≫ e.inv) + exact ⟨Under.mk f, ⟨Under.isoMk e⟩⟩ + +instance [F.IsEquivalence] : (Under.post (X := X) F).IsEquivalence where + +/-- An equivalence of categories induces an equivalence on under categories. -/ +@[simps] +def postEquiv (F : T ≌ D) : Under X ≌ Under (F.functor.obj X) where + functor := post F.functor + inverse := post (X := F.functor.obj X) F.inverse ⋙ Under.map (F.unitIso.hom.app X) + unitIso := NatIso.ofComponents (fun A ↦ Under.isoMk (F.unitIso.app A.right)) + counitIso := NatIso.ofComponents (fun A ↦ Under.isoMk (F.counitIso.app A.right)) + end Under namespace StructuredArrow @@ -774,4 +907,52 @@ def ofDiagEquivalence' (X : T × T) : end CostructuredArrow +section Opposite + +open Opposite + +variable (X : T) + +/-- The canonical functor by reversing structure arrows. -/ +@[simps] +def Over.opToOpUnder : Over (op X) ⥤ (Under X)ᵒᵖ where + obj Y := ⟨Under.mk Y.hom.unop⟩ + map {Z Y} f := ⟨Under.homMk (f.left.unop) (by dsimp; rw [← unop_comp, Over.w])⟩ + +/-- The canonical functor by reversing structure arrows. -/ +@[simps] +def Under.opToOverOp : (Under X)ᵒᵖ ⥤ Over (op X) where + obj Y := Over.mk (Y.unop.hom.op) + map {Z Y} f := Over.homMk f.unop.right.op <| by dsimp; rw [← Under.w f.unop, op_comp] + +/-- `Over.opToOpUnder` is an equivalence of categories. -/ +@[simps] +def Over.opEquivOpUnder : Over (op X) ≌ (Under X)ᵒᵖ where + functor := Over.opToOpUnder X + inverse := Under.opToOverOp X + unitIso := Iso.refl _ + counitIso := Iso.refl _ + +/-- The canonical functor by reversing structure arrows. -/ +@[simps] +def Under.opToOpOver : Under (op X) ⥤ (Over X)ᵒᵖ where + obj Y := ⟨Over.mk Y.hom.unop⟩ + map {Z Y} f := ⟨Over.homMk (f.right.unop) (by dsimp; rw [← unop_comp, Under.w])⟩ + +/-- The canonical functor by reversing structure arrows. -/ +@[simps] +def Over.opToUnderOp : (Over X)ᵒᵖ ⥤ Under (op X) where + obj Y := Under.mk (Y.unop.hom.op) + map {Z Y} f := Under.homMk f.unop.left.op <| by dsimp; rw [← Over.w f.unop, op_comp] + +/-- `Under.opToOpOver` is an equivalence of categories. -/ +@[simps] +def Under.opEquivOpOver : Under (op X) ≌ (Over X)ᵒᵖ where + functor := Under.opToOpOver X + inverse := Over.opToUnderOp X + unitIso := Iso.refl _ + counitIso := Iso.refl _ + +end Opposite + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/OverClass.lean b/Mathlib/CategoryTheory/Comma/OverClass.lean index bfe80651c00034..a6b1fc35caeb25 100644 --- a/Mathlib/CategoryTheory/Comma/OverClass.lean +++ b/Mathlib/CategoryTheory/Comma/OverClass.lean @@ -31,7 +31,7 @@ universe v u variable {C : Type u} [Category.{v} C] -variable {X Y : C} (f : X ⟶ Y) (S S' : C) +variable {X Y Z : C} (f : X ⟶ Y) (S S' : C) /-- `OverClass X S` is the typeclass containing the data of a structure morphism `X ↘ S : X ⟶ S`. @@ -68,27 +68,39 @@ def CanonicallyOverClass.Simps.over (X S : C) [CanonicallyOverClass X S] : X ⟶ initialize_simps_projections CanonicallyOverClass (hom → over) @[simps] -instance (priority := 100) : OverClass X X := ⟨𝟙 _⟩ +instance : OverClass X X := ⟨𝟙 _⟩ -@[simps] +instance : IsIso (S ↘ S) := inferInstanceAs (IsIso (𝟙 S)) + +-- This cannot be a simp lemma be cause it loops with `comp_over`. +@[simps (config := .lemmasOnly)] instance (priority := 900) [CanonicallyOverClass X Y] [OverClass Y S] : OverClass X S := ⟨X ↘ Y ≫ Y ↘ S⟩ /-- Given `OverClass X S` and `OverClass Y S` and `f : X ⟶ Y`, `HomIsOver f S` is the typeclass asserting `f` commutes with the structure morphisms. -/ class HomIsOver (f : X ⟶ Y) (S : C) [OverClass X S] [OverClass Y S] : Prop where - comp_over : f ≫ Y ↘ S = X ↘ S := by simp + comp_over : f ≫ Y ↘ S = X ↘ S := by aesop @[reassoc (attr := simp)] lemma comp_over [OverClass X S] [OverClass Y S] [HomIsOver f S] : f ≫ Y ↘ S = X ↘ S := HomIsOver.comp_over +instance [OverClass X S] : HomIsOver (𝟙 X) S where + +instance [OverClass X S] [OverClass Y S] [OverClass Z S] + (f : X ⟶ Y) (g : Y ⟶ Z) [HomIsOver f S] [HomIsOver g S] : + HomIsOver (f ≫ g) S where + /-- `Scheme.IsOverTower X Y S` is the typeclass asserting that the structure morphisms `X ↘ Y`, `Y ↘ S`, and `X ↘ S` commute. -/ abbrev IsOverTower (X Y S : C) [OverClass X S] [OverClass Y S] [OverClass X Y] := HomIsOver (X ↘ Y) S +instance [OverClass X S] : IsOverTower X X S where +instance [OverClass X S] : IsOverTower X S S where + instance [CanonicallyOverClass X Y] [OverClass Y S] : IsOverTower X Y S := ⟨rfl⟩ @@ -108,7 +120,22 @@ instance [OverClass X S] [IsOverTower X S S'] [IsOverTower Y S S'] [HomIsOver f S] : HomIsOver f S' := homIsOver_of_isOverTower f S S' +variable (X) in /-- Bundle `X` with an `OverClass X S` instance into `Over S`. -/ +@[simps! hom left] def OverClass.asOver [OverClass X S] : Over S := Over.mk (X ↘ S) +/-- Bundle a morphism `f : X ⟶ Y` with `HomIsOver f S` into a morphism in `Over S`. -/ +@[simps! left] +def OverClass.asOverHom [OverClass X S] [OverClass Y S] (f : X ⟶ Y) [HomIsOver f S] : + OverClass.asOver X S ⟶ OverClass.asOver Y S := + Over.homMk f (comp_over f S) + +@[simps] +instance OverClass.fromOver {S : C} (X : Over S) : OverClass X.left S where + hom := X.hom + +instance {S : C} {X Y : Over S} (f : X ⟶ Y) : HomIsOver f.left S where + comp_over := Over.w f + end CategoryTheory diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean index 38882d4e9f4481..ebeea719fe2dc3 100644 --- a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean +++ b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean @@ -55,7 +55,7 @@ class ConcreteCategory (C : Type u) [Category.{v} C] where /-- That functor is faithful -/ [forget_faithful : forget.Faithful] -attribute [reducible] ConcreteCategory.forget +attribute [inline, reducible] ConcreteCategory.forget attribute [instance] ConcreteCategory.forget_faithful /-- The forgetful functor from a concrete category to `Type u`. -/ diff --git a/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean b/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean index 53193088726606..1f67ad02341c38 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean @@ -29,7 +29,7 @@ universe v₅ u₅ v₄ u₄ v₃ u₃ v₂ u₂ v₁ u₁ namespace CategoryTheory -open CategoryTheory Functor Category NatTrans IsHomLift +open Functor Category NatTrans IsHomLift variable {𝒮 : Type u₁} [Category.{v₁} 𝒮] diff --git a/Mathlib/CategoryTheory/Filtered/Basic.lean b/Mathlib/CategoryTheory/Filtered/Basic.lean index 28de77ac9e3bbb..584411d3326a49 100644 --- a/Mathlib/CategoryTheory/Filtered/Basic.lean +++ b/Mathlib/CategoryTheory/Filtered/Basic.lean @@ -616,6 +616,26 @@ theorem _root_.CategoryTheory.Functor.ranges_directed (F : C ⥤ Type*) (j : C) let ⟨l, li, lk, e⟩ := cospan ij kj refine ⟨⟨l, lk ≫ kj⟩, e ▸ ?_, ?_⟩ <;> simp_rw [F.map_comp] <;> apply Set.range_comp_subset_range +/-- Given a "bowtie" of morphisms +``` + k₁ k₂ + |\ /| + | \/ | + | /\ | + |/ \∣ + vv vv + j₁ j₂ +``` +in a cofiltered category, we can construct an object `s` and two morphisms +from `s` to `k₁` and `k₂`, making the resulting squares commute. +-/ +theorem bowtie {j₁ j₂ k₁ k₂ : C} (f₁ : k₁ ⟶ j₁) (g₁ : k₂ ⟶ j₁) (f₂ : k₁ ⟶ j₂) (g₂ : k₂ ⟶ j₂) : + ∃ (s : C) (α : s ⟶ k₁) (β : s ⟶ k₂), α ≫ f₁ = β ≫ g₁ ∧ α ≫ f₂ = β ≫ g₂ := by + obtain ⟨t, k₁t, k₂t, ht⟩ := cospan f₁ g₁ + obtain ⟨s, ts, hs⟩ := IsCofilteredOrEmpty.cone_maps (k₁t ≫ f₂) (k₂t ≫ g₂) + exact ⟨s, ts ≫ k₁t, ts ≫ k₂t, by simp only [Category.assoc, ht], + by simp only [Category.assoc, hs]⟩ + end AllowEmpty end IsCofiltered diff --git a/Mathlib/CategoryTheory/Functor/OfSequence.lean b/Mathlib/CategoryTheory/Functor/OfSequence.lean index ba70972cf1661a..c1f5788cec33b7 100644 --- a/Mathlib/CategoryTheory/Functor/OfSequence.lean +++ b/Mathlib/CategoryTheory/Functor/OfSequence.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Joël Riou. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ -import Mathlib.Algebra.Order.Group.Nat import Mathlib.CategoryTheory.Category.Preorder import Mathlib.CategoryTheory.EqToHom diff --git a/Mathlib/CategoryTheory/GradedObject.lean b/Mathlib/CategoryTheory/GradedObject.lean index b6e2df434c2b95..2bc160aeba95d7 100644 --- a/Mathlib/CategoryTheory/GradedObject.lean +++ b/Mathlib/CategoryTheory/GradedObject.lean @@ -316,7 +316,7 @@ lemma hasMap_of_iso (e : X ≅ Y) (p: I → J) [HasMap X p] : HasMap Y p := fun exact hasColimitOfIso α.symm section -variable [X.HasMap p] [Y.HasMap p] [Z.HasMap p] +variable [X.HasMap p] [Y.HasMap p] /-- Given `X : GradedObject I C` and `p : I → J`, `X.mapObj p` is the graded object by `J` which in degree `j` consists of the coproduct of the `X i` such that `p i = j`. -/ diff --git a/Mathlib/CategoryTheory/GradedObject/Monoidal.lean b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean index 34da9a269a20b5..b10fab11e47d85 100644 --- a/Mathlib/CategoryTheory/GradedObject/Monoidal.lean +++ b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean @@ -38,6 +38,14 @@ the coproduct of the objects `X₁ i ⊗ X₂ j` for `i + j = n` exists. -/ abbrev HasTensor (X₁ X₂ : GradedObject I C) : Prop := HasMap (((mapBifunctor (curriedTensor C) I I).obj X₁).obj X₂) (fun ⟨i, j⟩ => i + j) +lemma hasTensor_of_iso {X₁ X₂ Y₁ Y₂ : GradedObject I C} + (e₁ : X₁ ≅ Y₁) (e₂ : X₂ ≅ Y₂) [HasTensor X₁ X₂] : + HasTensor Y₁ Y₂ := by + let e : ((mapBifunctor (curriedTensor C) I I).obj X₁).obj X₂ ≅ + ((mapBifunctor (curriedTensor C) I I).obj Y₁).obj Y₂ := isoMk _ _ + (fun ⟨i, j⟩ ↦ (eval i).mapIso e₁ ⊗ (eval j).mapIso e₂) + exact hasMap_of_iso e _ + namespace Monoidal /-- The tensor product of two graded objects. -/ @@ -120,6 +128,17 @@ lemma tensor_comp {X₁ X₂ X₃ Y₁ Y₂ Y₃ : GradedObject I C} (f₁ : X apply congr_mapMap simp +/-- The isomorphism `tensorObj X₁ Y₁ ≅ tensorObj X₂ Y₂` induced by isomorphisms of graded +objects `e : X₁ ≅ X₂` and `e' : Y₁ ≅ Y₂`. -/ +@[simps] +noncomputable def tensorIso {X₁ X₂ Y₁ Y₂ : GradedObject I C} (e : X₁ ≅ X₂) (e' : Y₁ ≅ Y₂) + [HasTensor X₁ Y₁] [HasTensor X₂ Y₂] : + tensorObj X₁ Y₁ ≅ tensorObj X₂ Y₂ where + hom := tensorHom e.hom e'.hom + inv := tensorHom e.inv e'.inv + hom_inv_id := by simp only [← tensor_comp, Iso.hom_inv_id, tensor_id] + inv_hom_id := by simp only [← tensor_comp, Iso.inv_hom_id, tensor_id] + lemma tensorHom_def {X₁ X₂ Y₁ Y₂ : GradedObject I C} (f : X₁ ⟶ X₂) (g : Y₁ ⟶ Y₂) [HasTensor X₁ Y₁] [HasTensor X₂ Y₂] [HasTensor X₂ Y₁] : tensorHom f g = whiskerRight f Y₁ ≫ whiskerLeft X₂ g := by diff --git a/Mathlib/CategoryTheory/Groupoid/Discrete.lean b/Mathlib/CategoryTheory/Groupoid/Discrete.lean index ffface43770695..3ce9a350831bf4 100644 --- a/Mathlib/CategoryTheory/Groupoid/Discrete.lean +++ b/Mathlib/CategoryTheory/Groupoid/Discrete.lean @@ -12,7 +12,7 @@ import Mathlib.CategoryTheory.DiscreteCategory namespace CategoryTheory -variable {C : Type*} [Category C] +variable {C : Type*} instance : Groupoid (Discrete C) := { inv := fun h ↦ ⟨⟨h.1.1.symm⟩⟩ } diff --git a/Mathlib/CategoryTheory/GuitartExact/Basic.lean b/Mathlib/CategoryTheory/GuitartExact/Basic.lean index cb64500850d994..b697c1ee0f1a1a 100644 --- a/Mathlib/CategoryTheory/GuitartExact/Basic.lean +++ b/Mathlib/CategoryTheory/GuitartExact/Basic.lean @@ -128,7 +128,6 @@ abbrev CostructuredArrowDownwards.mk (comm : R.map a ≫ w.app X₁ ≫ B.map b CostructuredArrow.mk (Y := StructuredArrow.mk a) (StructuredArrow.homMk b (by simpa using comm)) -variable (comm : R.map a ≫ w.app X₁ ≫ B.map b = g) variable {w g} lemma StructuredArrowRightwards.mk_surjective diff --git a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean index 1c0f0936e00c6a..d4b4fc8a4f69e4 100644 --- a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean +++ b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean @@ -111,7 +111,7 @@ theorem comp_f {P Q R : Karoubi C} (f : P ⟶ Q) (g : Q ⟶ R) : (f ≫ g).f = f @[simp] theorem id_f {P : Karoubi C} : Hom.f (𝟙 P) = P.p := rfl -@[deprecated (since := "2024-07-15")] +@[deprecated "No deprecation message was provided." (since := "2024-07-15")] theorem id_eq {P : Karoubi C} : 𝟙 P = ⟨P.p, by repeat' rw [P.idem]⟩ := rfl /-- It is possible to coerce an object of `C` into an object of `Karoubi C`. diff --git a/Mathlib/CategoryTheory/IsConnected.lean b/Mathlib/CategoryTheory/IsConnected.lean index 96bb16ce5927a3..f4fa03b9c28a60 100644 --- a/Mathlib/CategoryTheory/IsConnected.lean +++ b/Mathlib/CategoryTheory/IsConnected.lean @@ -263,11 +263,11 @@ theorem isConnected_of_isConnected_op [IsConnected Jᵒᵖ] : IsConnected J := def Zag (j₁ j₂ : J) : Prop := Nonempty (j₁ ⟶ j₂) ∨ Nonempty (j₂ ⟶ j₁) -theorem Zag.refl (X : J) : Zag X X := Or.inl ⟨𝟙 _⟩ +@[refl] theorem Zag.refl (X : J) : Zag X X := Or.inl ⟨𝟙 _⟩ theorem zag_symmetric : Symmetric (@Zag J _) := fun _ _ h => h.symm -theorem Zag.symm {j₁ j₂ : J} (h : Zag j₁ j₂) : Zag j₂ j₁ := zag_symmetric h +@[symm] theorem Zag.symm {j₁ j₂ : J} (h : Zag j₁ j₂) : Zag j₂ j₁ := zag_symmetric h theorem Zag.of_hom {j₁ j₂ : J} (f : j₁ ⟶ j₂) : Zag j₁ j₂ := Or.inl ⟨f⟩ @@ -286,11 +286,12 @@ theorem zigzag_equivalence : _root_.Equivalence (@Zigzag J _) := _root_.Equivalence.mk Relation.reflexive_reflTransGen (fun h => zigzag_symmetric h) (fun h g => Relation.transitive_reflTransGen h g) -theorem Zigzag.refl (X : J) : Zigzag X X := zigzag_equivalence.refl _ +@[refl] theorem Zigzag.refl (X : J) : Zigzag X X := zigzag_equivalence.refl _ -theorem Zigzag.symm {j₁ j₂ : J} (h : Zigzag j₁ j₂) : Zigzag j₂ j₁ := zigzag_symmetric h +@[symm] theorem Zigzag.symm {j₁ j₂ : J} (h : Zigzag j₁ j₂) : Zigzag j₂ j₁ := zigzag_symmetric h -theorem Zigzag.trans {j₁ j₂ j₃ : J} (h₁ : Zigzag j₁ j₂) (h₂ : Zigzag j₂ j₃) : Zigzag j₁ j₃ := +@[trans] theorem Zigzag.trans {j₁ j₂ j₃ : J} (h₁ : Zigzag j₁ j₂) (h₂ : Zigzag j₂ j₃) : + Zigzag j₁ j₃ := zigzag_equivalence.trans h₁ h₂ theorem Zigzag.of_zag {j₁ j₂ : J} (h : Zag j₁ j₂) : Zigzag j₁ j₂ := diff --git a/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean b/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean new file mode 100644 index 00000000000000..9ae75d85d62ae0 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/Constructions/EventuallyConstant.lean @@ -0,0 +1,260 @@ +/- +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.Filtered.Basic +import Mathlib.CategoryTheory.Limits.HasLimits + +/-! +# Limits of eventually constant functors + +If `F : J ⥤ C` is a functor from a cofiltered category, and `j : J`, +we introduce a property `F.IsEventuallyConstantTo j` which says +that for any `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. +Under this assumption, it is shown that `F` admits `F.obj j` as a limit +(`Functor.IsEventuallyConstantTo.isLimitCone`). + +A typeclass `Cofiltered.IsEventuallyConstant` is also introduced, and +the dual results for filtered categories and colimits are also obtained. + +-/ + +namespace CategoryTheory + +open Category Limits + +variable {J C : Type*} [Category J] [Category C] (F : J ⥤ C) + +namespace Functor + +/-- A functor `F : J ⥤ C` is eventually constant to `j : J` if +for any map `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. +If `J` is cofiltered, this implies `F` has a limit. -/ +def IsEventuallyConstantTo (j : J) : Prop := + ∀ ⦃i : J⦄ (f : i ⟶ j), IsIso (F.map f) + +/-- A functor `F : J ⥤ C` is eventually constant from `i : J` if +for any map `f : i ⟶ j`, the induced morphism `F.map f` is an isomorphism. +If `J` is filtered, this implies `F` has a colimit. -/ +def IsEventuallyConstantFrom (i : J) : Prop := + ∀ ⦃j : J⦄ (f : i ⟶ j), IsIso (F.map f) + +namespace IsEventuallyConstantTo + +variable {F} {i₀ : J} (h : F.IsEventuallyConstantTo i₀) + +include h + +lemma isIso_map {i j : J} (φ : i ⟶ j) (π : j ⟶ i₀) : IsIso (F.map φ) := by + have := h π + have := h (φ ≫ π) + exact IsIso.of_isIso_fac_right (F.map_comp φ π).symm + +lemma precomp {j : J} (f : j ⟶ i₀) : F.IsEventuallyConstantTo j := + fun _ φ ↦ h.isIso_map φ f + +section + +variable {i j : J} (φ : i ⟶ j) (hφ : Nonempty (j ⟶ i₀)) + +/-- The isomorphism `F.obj i ≅ F.obj j` induced by `φ : i ⟶ j`, +when `h : F.IsEventuallyConstantTo i₀` and there exists a map `j ⟶ i₀`. -/ +@[simps! hom] +noncomputable def isoMap : F.obj i ≅ F.obj j := + have := h.isIso_map φ hφ.some + asIso (F.map φ) + +@[reassoc (attr := simp)] +lemma isoMap_hom_inv_id : F.map φ ≫ (h.isoMap φ hφ).inv = 𝟙 _ := + (h.isoMap φ hφ).hom_inv_id + +@[reassoc (attr := simp)] +lemma isoMap_inv_hom_id : (h.isoMap φ hφ).inv ≫ F.map φ = 𝟙 _ := + (h.isoMap φ hφ).inv_hom_id + +end + +variable [IsCofiltered J] +open IsCofiltered + +/-- Auxiliary definition for `IsEventuallyConstantTo.cone`. -/ +noncomputable def coneπApp (j : J) : F.obj i₀ ⟶ F.obj j := + (h.isoMap (minToLeft i₀ j) ⟨𝟙 _⟩).inv ≫ F.map (minToRight i₀ j) + +lemma coneπApp_eq (j j' : J) (α : j' ⟶ i₀) (β : j' ⟶ j) : + h.coneπApp j = (h.isoMap α ⟨𝟙 _⟩).inv ≫ F.map β := by + obtain ⟨s, γ, δ, h₁, h₂⟩ := IsCofiltered.bowtie + (IsCofiltered.minToRight i₀ j) β (IsCofiltered.minToLeft i₀ j) α + dsimp [coneπApp] + rw [← cancel_epi ((h.isoMap α ⟨𝟙 _⟩).hom), isoMap_hom, isoMap_hom_inv_id_assoc, + ← cancel_epi (h.isoMap δ ⟨α⟩).hom, isoMap_hom, + ← F.map_comp δ β, ← h₁, F.map_comp, ← F.map_comp_assoc, ← h₂, F.map_comp_assoc, + isoMap_hom_inv_id_assoc] + +@[simp] +lemma coneπApp_eq_id : h.coneπApp i₀ = 𝟙 _ := by + rw [h.coneπApp_eq i₀ i₀ (𝟙 _) (𝟙 _), h.isoMap_inv_hom_id] + +/-- Given `h : F.IsEventuallyConstantTo i₀`, this is the (limit) cone for `F` whose +point is `F.obj i₀`. -/ +@[simps] +noncomputable def cone : Cone F where + pt := F.obj i₀ + π := + { app := h.coneπApp + naturality := fun j j' φ ↦ by + dsimp + rw [id_comp] + let i := IsCofiltered.min i₀ j + let α : i ⟶ i₀ := IsCofiltered.minToLeft _ _ + let β : i ⟶ j := IsCofiltered.minToRight _ _ + rw [h.coneπApp_eq j _ α β, assoc, h.coneπApp_eq j' _ α (β ≫ φ), map_comp] } + +/-- When `h : F.IsEventuallyConstantTo i₀`, the limit of `F` exists and is `F.obj i₀`. -/ +def isLimitCone : IsLimit h.cone where + lift s := s.π.app i₀ + fac s j := by + dsimp [coneπApp] + rw [← s.w (IsCofiltered.minToLeft i₀ j), ← s.w (IsCofiltered.minToRight i₀ j), assoc, + isoMap_hom_inv_id_assoc] + uniq s m hm := by simp only [← hm i₀, cone_π_app, coneπApp_eq_id, cone_pt, comp_id] + +lemma hasLimit : HasLimit F := ⟨_, h.isLimitCone⟩ + +lemma isIso_π_of_isLimit {c : Cone F} (hc : IsLimit c) : + IsIso (c.π.app i₀) := by + simp only [← IsLimit.conePointUniqueUpToIso_hom_comp hc h.isLimitCone i₀, + cone_π_app, coneπApp_eq_id, cone_pt, comp_id] + infer_instance + +/-- More general version of `isIso_π_of_isLimit`. -/ +lemma isIso_π_of_isLimit' {c : Cone F} (hc : IsLimit c) (j : J) (π : j ⟶ i₀) : + IsIso (c.π.app j) := + (h.precomp π).isIso_π_of_isLimit hc + +end IsEventuallyConstantTo + +namespace IsEventuallyConstantFrom + +variable {F} {i₀ : J} (h : F.IsEventuallyConstantFrom i₀) + +include h + +lemma isIso_map {i j : J} (φ : i ⟶ j) (ι : i₀ ⟶ i) : IsIso (F.map φ) := by + have := h ι + have := h (ι ≫ φ) + exact IsIso.of_isIso_fac_left (F.map_comp ι φ).symm + +lemma postcomp {j : J} (f : i₀ ⟶ j) : F.IsEventuallyConstantFrom j := + fun _ φ ↦ h.isIso_map φ f + +section + +variable {i j : J} (φ : i ⟶ j) (hφ : Nonempty (i₀ ⟶ i)) + +/-- The isomorphism `F.obj i ≅ F.obj j` induced by `φ : i ⟶ j`, +when `h : F.IsEventuallyConstantFrom i₀` and there exists a map `i₀ ⟶ i`. -/ +@[simps! hom] +noncomputable def isoMap : F.obj i ≅ F.obj j := + have := h.isIso_map φ hφ.some + asIso (F.map φ) + +@[reassoc (attr := simp)] +lemma isoMap_hom_inv_id : F.map φ ≫ (h.isoMap φ hφ).inv = 𝟙 _ := + (h.isoMap φ hφ).hom_inv_id + +@[reassoc (attr := simp)] +lemma isoMap_inv_hom_id : (h.isoMap φ hφ).inv ≫ F.map φ = 𝟙 _ := + (h.isoMap φ hφ).inv_hom_id + +end + +variable [IsFiltered J] +open IsFiltered + +/-- Auxiliary definition for `IsEventuallyConstantFrom.cocone`. -/ +noncomputable def coconeιApp (j : J) : F.obj j ⟶ F.obj i₀ := + F.map (rightToMax i₀ j) ≫ (h.isoMap (leftToMax i₀ j) ⟨𝟙 _⟩).inv + +lemma coconeιApp_eq (j j' : J) (α : j ⟶ j') (β : i₀ ⟶ j') : + h.coconeιApp j = F.map α ≫ (h.isoMap β ⟨𝟙 _⟩).inv := by + obtain ⟨s, γ, δ, h₁, h₂⟩ := IsFiltered.bowtie + (IsFiltered.leftToMax i₀ j) β (IsFiltered.rightToMax i₀ j) α + dsimp [coconeιApp] + rw [← cancel_mono ((h.isoMap β ⟨𝟙 _⟩).hom), assoc, assoc, isoMap_hom, isoMap_inv_hom_id, + comp_id, ← cancel_mono (h.isoMap δ ⟨β⟩).hom, isoMap_hom, assoc, assoc, ← F.map_comp α δ, + ← h₂, F.map_comp, ← F.map_comp β δ, ← h₁, F.map_comp, isoMap_inv_hom_id_assoc] + +@[simp] +lemma coconeιApp_eq_id : h.coconeιApp i₀ = 𝟙 _ := by + rw [h.coconeιApp_eq i₀ i₀ (𝟙 _) (𝟙 _), h.isoMap_hom_inv_id] + +/-- Given `h : F.IsEventuallyConstantFrom i₀`, this is the (limit) cocone for `F` whose +point is `F.obj i₀`. -/ +@[simps] +noncomputable def cocone : Cocone F where + pt := F.obj i₀ + ι := + { app := h.coconeιApp + naturality := fun j j' φ ↦ by + dsimp + rw [comp_id] + let i := IsFiltered.max i₀ j' + let α : i₀ ⟶ i := IsFiltered.leftToMax _ _ + let β : j' ⟶ i := IsFiltered.rightToMax _ _ + rw [h.coconeιApp_eq j' _ β α, h.coconeιApp_eq j _ (φ ≫ β) α, map_comp, assoc] } + +/-- When `h : F.IsEventuallyConstantFrom i₀`, the colimit of `F` exists and is `F.obj i₀`. -/ +def isColimitCocone : IsColimit h.cocone where + desc s := s.ι.app i₀ + fac s j := by + dsimp [coconeιApp] + rw [← s.w (IsFiltered.rightToMax i₀ j), ← s.w (IsFiltered.leftToMax i₀ j), assoc, + isoMap_inv_hom_id_assoc] + uniq s m hm := by simp only [← hm i₀, cocone_ι_app, coconeιApp_eq_id, id_comp] + +lemma hasColimit : HasColimit F := ⟨_, h.isColimitCocone⟩ + +lemma isIso_ι_of_isColimit {c : Cocone F} (hc : IsColimit c) : + IsIso (c.ι.app i₀) := by + simp only [← IsColimit.comp_coconePointUniqueUpToIso_inv hc h.isColimitCocone i₀, + cocone_ι_app, coconeιApp_eq_id, id_comp] + infer_instance + +/-- More general version of `isIso_ι_of_isColimit`. -/ +lemma isIso_ι_of_isColimit' {c : Cocone F} (hc : IsColimit c) (j : J) (ι : i₀ ⟶ j) : + IsIso (c.ι.app j) := + (h.postcomp ι).isIso_ι_of_isColimit hc + +end IsEventuallyConstantFrom + +end Functor + +namespace IsCofiltered + +/-- A functor `F : J ⥤ C` from a cofiltered category is eventually constant if there +exists `j : J`, such that for any `f : i ⟶ j`, the induced map `F.map f` is an isomorphism. -/ +class IsEventuallyConstant : Prop where + exists_isEventuallyConstantTo : ∃ (j : J), F.IsEventuallyConstantTo j + +instance [hF : IsEventuallyConstant F] [IsCofiltered J] : HasLimit F := by + obtain ⟨j, h⟩ := hF.exists_isEventuallyConstantTo + exact h.hasLimit + +end IsCofiltered + +namespace IsFiltered + +/-- A functor `F : J ⥤ C` from a filtered category is eventually constant if there +exists `i : J`, such that for any `f : i ⟶ j`, the induced map `F.map f` is an isomorphism. -/ +class IsEventuallyConstant : Prop where + exists_isEventuallyConstantFrom : ∃ (i : J), F.IsEventuallyConstantFrom i + +instance [hF : IsEventuallyConstant F] [IsFiltered J] : HasColimit F := by + obtain ⟨j, h⟩ := hF.exists_isEventuallyConstantFrom + exact h.hasColimit + +end IsFiltered + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Creates.lean b/Mathlib/CategoryTheory/Limits/Creates.lean index 148eafbe8efa17..9769ea25200006 100644 --- a/Mathlib/CategoryTheory/Limits/Creates.lean +++ b/Mathlib/CategoryTheory/Limits/Creates.lean @@ -332,7 +332,7 @@ instance (priority := 100) preservesLimit_of_createsLimit_and_hasLimit (K : J ((liftedLimitMapsToOriginal (limit.isLimit _)).symm ≪≫ (Cones.functoriality K F).mapIso ((liftedLimitIsLimit (limit.isLimit _)).uniqueUpToIso t))⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitOfCreatesLimitAndHasLimit (K : J ⥤ C) (F : C ⥤ D) [CreatesLimit K F] [HasLimit (K ⋙ F)] : PreservesLimit K F := preservesLimit_of_createsLimit_and_hasLimit _ _ @@ -342,7 +342,7 @@ lemma preservesLimitOfCreatesLimitAndHasLimit (K : J ⥤ C) (F : C ⥤ D) instance (priority := 100) preservesLimitOfShape_of_createsLimitsOfShape_and_hasLimitsOfShape (F : C ⥤ D) [CreatesLimitsOfShape J F] [HasLimitsOfShape J D] : PreservesLimitsOfShape J F where -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitOfShapeOfCreatesLimitsOfShapeAndHasLimitsOfShape (F : C ⥤ D) [CreatesLimitsOfShape J F] [HasLimitsOfShape J D] : PreservesLimitsOfShape J F := @@ -354,7 +354,7 @@ instance (priority := 100) preservesLimits_of_createsLimits_and_hasLimits (F : C [CreatesLimitsOfSize.{w, w'} F] [HasLimitsOfSize.{w, w'} D] : PreservesLimitsOfSize.{w, w'} F where -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitsOfCreatesLimitsAndHasLimits (F : C ⥤ D) [CreatesLimitsOfSize.{w, w'} F] [HasLimitsOfSize.{w, w'} D] : PreservesLimitsOfSize.{w, w'} F := @@ -466,7 +466,7 @@ instance (priority := 100) preservesColimit_of_createsColimit_and_hasColimit (K (Cocones.functoriality K F).mapIso ((liftedColimitIsColimit (colimit.isColimit _)).uniqueUpToIso t))⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesColimitOfCreatesColimitAndHasColimit (K : J ⥤ C) (F : C ⥤ D) [CreatesColimit K F] [HasColimit (K ⋙ F)] : PreservesColimit K F := preservesColimit_of_createsColimit_and_hasColimit _ _ @@ -477,7 +477,7 @@ instance (priority := 100) preservesColimitOfShape_of_createsColimitsOfShape_and (F : C ⥤ D) [CreatesColimitsOfShape J F] [HasColimitsOfShape J D] : PreservesColimitsOfShape J F where -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesColimitOfShapeOfCreatesColimitsOfShapeAndHasColimitsOfShape (F : C ⥤ D) [CreatesColimitsOfShape J F] [HasColimitsOfShape J D] : PreservesColimitsOfShape J F := @@ -489,7 +489,7 @@ instance (priority := 100) preservesColimits_of_createsColimits_and_hasColimits [CreatesColimitsOfSize.{w, w'} F] [HasColimitsOfSize.{w, w'} D] : PreservesColimitsOfSize.{w, w'} F where -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesColimitsOfCreatesColimitsAndHasColimits (F : C ⥤ D) [CreatesColimitsOfSize.{w, w'} F] [HasColimitsOfSize.{w, w'} D] : PreservesColimitsOfSize.{w, w'} F := diff --git a/Mathlib/CategoryTheory/Limits/Final.lean b/Mathlib/CategoryTheory/Limits/Final.lean index 69444f0842058e..6719a13bc510a3 100644 --- a/Mathlib/CategoryTheory/Limits/Final.lean +++ b/Mathlib/CategoryTheory/Limits/Final.lean @@ -65,7 +65,7 @@ Dualise condition 3 above and the implications 2 ⇒ 3 and 3 ⇒ 1 to initial fu noncomputable section -universe v v₁ v₂ v₃ u₁ u₂ u₃ +universe v v₁ v₂ v₃ v₄ u₁ u₂ u₃ u₄ namespace CategoryTheory @@ -305,6 +305,27 @@ def colimitCoconeComp (t : ColimitCocone G) : ColimitCocone (F ⋙ G) where instance (priority := 100) comp_hasColimit [HasColimit G] : HasColimit (F ⋙ G) := HasColimit.mk (colimitCoconeComp F (getColimitCocone G)) +instance (priority := 100) comp_preservesColimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [PreservesColimit G H] : PreservesColimit (F ⋙ G) H where + preserves {c} hc := by + refine ⟨isColimitExtendCoconeEquiv (G := G ⋙ H) F (H.mapCocone c) ?_⟩ + let hc' := isColimitOfPreserves H ((isColimitExtendCoconeEquiv F c).symm hc) + exact IsColimit.ofIsoColimit hc' (Cocones.ext (Iso.refl _) (by simp)) + +instance (priority := 100) comp_reflectsColimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [ReflectsColimit G H] : ReflectsColimit (F ⋙ G) H where + reflects {c} hc := by + refine ⟨isColimitExtendCoconeEquiv F _ (isColimitOfReflects H ?_)⟩ + let hc' := (isColimitExtendCoconeEquiv (G := G ⋙ H) F _).symm hc + exact IsColimit.ofIsoColimit hc' (Cocones.ext (Iso.refl _) (by simp)) + +instance (priority := 100) compCreatesColimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [CreatesColimit G H] : CreatesColimit (F ⋙ G) H where + lifts {c} hc := by + refine ⟨(liftColimit ((isColimitExtendCoconeEquiv F (G := G ⋙ H) _).symm hc)).whisker F, ?_⟩ + let i := liftedColimitMapsToOriginal ((isColimitExtendCoconeEquiv F (G := G ⋙ H) _).symm hc) + exact (Cocones.whiskering F).mapIso i ≪≫ ((coconesEquiv F (G ⋙ H)).unitIso.app _).symm + instance colimit_pre_isIso [HasColimit G] : IsIso (colimit.pre G F) := by rw [colimit.pre_eq (colimitCoconeComp F (getColimitCocone G)) (getColimitCocone G)] erw [IsColimit.desc_self] @@ -361,10 +382,51 @@ We can't make this an instance, because `F` is not determined by the goal. theorem hasColimit_of_comp [HasColimit (F ⋙ G)] : HasColimit G := HasColimit.mk (colimitCoconeOfComp F (getColimitCocone (F ⋙ G))) +theorem preservesColimit_of_comp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [PreservesColimit (F ⋙ G) H] : PreservesColimit G H where + preserves {c} hc := by + refine ⟨isColimitWhiskerEquiv F _ ?_⟩ + let hc' := isColimitOfPreserves H ((isColimitWhiskerEquiv F _).symm hc) + exact IsColimit.ofIsoColimit hc' (Cocones.ext (Iso.refl _) (by simp)) + +theorem reflectsColimit_of_comp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [ReflectsColimit (F ⋙ G) H] : ReflectsColimit G H where + reflects {c} hc := by + refine ⟨isColimitWhiskerEquiv F _ (isColimitOfReflects H ?_)⟩ + let hc' := (isColimitWhiskerEquiv F _).symm hc + exact IsColimit.ofIsoColimit hc' (Cocones.ext (Iso.refl _) (by simp)) + +/-- If `F` is final and `F ⋙ G` creates colimits of `H`, then so does `G`. -/ +def createsColimitOfComp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [CreatesColimit (F ⋙ G) H] : CreatesColimit G H where + reflects := (reflectsColimit_of_comp F).reflects + lifts {c} hc := by + refine ⟨(extendCocone (F := F)).obj (liftColimit ((isColimitWhiskerEquiv F _).symm hc)), ?_⟩ + let i := liftedColimitMapsToOriginal (K := (F ⋙ G)) ((isColimitWhiskerEquiv F _).symm hc) + refine ?_ ≪≫ ((extendCocone (F := F)).mapIso i) ≪≫ ((coconesEquiv F (G ⋙ H)).counitIso.app _) + exact Cocones.ext (Iso.refl _) + include F in theorem hasColimitsOfShape_of_final [HasColimitsOfShape C E] : HasColimitsOfShape D E where has_colimit := fun _ => hasColimit_of_comp F +include F in +theorem preservesColimitsOfShape_of_final {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [PreservesColimitsOfShape C H] : PreservesColimitsOfShape D H where + preservesColimit := preservesColimit_of_comp F + +include F in +theorem reflectsColimitsOfShape_of_final {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [ReflectsColimitsOfShape C H] : ReflectsColimitsOfShape D H where + reflectsColimit := reflectsColimit_of_comp F + +include F in +/-- If `H` creates colimits of shape `C` and `F : C ⥤ D` is final, then `H` creates colimits of +shape `D`. -/ +def createsColimitsOfShapeOfFinal {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [CreatesColimitsOfShape C H] : CreatesColimitsOfShape D H where + CreatesColimit := createsColimitOfComp F + end Final end ArbitraryUniverse @@ -592,6 +654,27 @@ def limitConeComp (t : LimitCone G) : LimitCone (F ⋙ G) where instance (priority := 100) comp_hasLimit [HasLimit G] : HasLimit (F ⋙ G) := HasLimit.mk (limitConeComp F (getLimitCone G)) +instance (priority := 100) comp_preservesLimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [PreservesLimit G H] : PreservesLimit (F ⋙ G) H where + preserves {c} hc := by + refine ⟨isLimitExtendConeEquiv (G := G ⋙ H) F (H.mapCone c) ?_⟩ + let hc' := isLimitOfPreserves H ((isLimitExtendConeEquiv F c).symm hc) + exact IsLimit.ofIsoLimit hc' (Cones.ext (Iso.refl _) (by simp)) + +instance (priority := 100) comp_reflectsLimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [ReflectsLimit G H] : ReflectsLimit (F ⋙ G) H where + reflects {c} hc := by + refine ⟨isLimitExtendConeEquiv F _ (isLimitOfReflects H ?_)⟩ + let hc' := (isLimitExtendConeEquiv (G := G ⋙ H) F _).symm hc + exact IsLimit.ofIsoLimit hc' (Cones.ext (Iso.refl _) (by simp)) + +instance (priority := 100) compCreatesLimit {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [CreatesLimit G H] : CreatesLimit (F ⋙ G) H where + lifts {c} hc := by + refine ⟨(liftLimit ((isLimitExtendConeEquiv F (G := G ⋙ H) _).symm hc)).whisker F, ?_⟩ + let i := liftedLimitMapsToOriginal ((isLimitExtendConeEquiv F (G := G ⋙ H) _).symm hc) + exact (Cones.whiskering F).mapIso i ≪≫ ((conesEquiv F (G ⋙ H)).unitIso.app _).symm + instance limit_pre_isIso [HasLimit G] : IsIso (limit.pre G F) := by rw [limit.pre_eq (limitConeComp F (getLimitCone G)) (getLimitCone G)] erw [IsLimit.lift_self] @@ -637,10 +720,51 @@ We can't make this an instance, because `F` is not determined by the goal. theorem hasLimit_of_comp [HasLimit (F ⋙ G)] : HasLimit G := HasLimit.mk (limitConeOfComp F (getLimitCone (F ⋙ G))) +theorem preservesLimit_of_comp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [PreservesLimit (F ⋙ G) H] : PreservesLimit G H where + preserves {c} hc := by + refine ⟨isLimitWhiskerEquiv F _ ?_⟩ + let hc' := isLimitOfPreserves H ((isLimitWhiskerEquiv F _).symm hc) + exact IsLimit.ofIsoLimit hc' (Cones.ext (Iso.refl _) (by simp)) + +theorem reflectsLimit_of_comp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [ReflectsLimit (F ⋙ G) H] : ReflectsLimit G H where + reflects {c} hc := by + refine ⟨isLimitWhiskerEquiv F _ (isLimitOfReflects H ?_)⟩ + let hc' := (isLimitWhiskerEquiv F _).symm hc + exact IsLimit.ofIsoLimit hc' (Cones.ext (Iso.refl _) (by simp)) + +/-- If `F` is initial and `F ⋙ G` creates limits of `H`, then so does `G`. -/ +def createsLimitOfComp {B : Type u₄} [Category.{v₄} B] {H : E ⥤ B} + [CreatesLimit (F ⋙ G) H] : CreatesLimit G H where + reflects := (reflectsLimit_of_comp F).reflects + lifts {c} hc := by + refine ⟨(extendCone (F := F)).obj (liftLimit ((isLimitWhiskerEquiv F _).symm hc)), ?_⟩ + let i := liftedLimitMapsToOriginal (K := (F ⋙ G)) ((isLimitWhiskerEquiv F _).symm hc) + refine ?_ ≪≫ ((extendCone (F := F)).mapIso i) ≪≫ ((conesEquiv F (G ⋙ H)).counitIso.app _) + exact Cones.ext (Iso.refl _) + include F in theorem hasLimitsOfShape_of_initial [HasLimitsOfShape C E] : HasLimitsOfShape D E where has_limit := fun _ => hasLimit_of_comp F +include F in +theorem preservesLimitsOfShape_of_initial {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [PreservesLimitsOfShape C H] : PreservesLimitsOfShape D H where + preservesLimit := preservesLimit_of_comp F + +include F in +theorem reflectsLimitsOfShape_of_initial {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [ReflectsLimitsOfShape C H] : ReflectsLimitsOfShape D H where + reflectsLimit := reflectsLimit_of_comp F + +include F in +/-- If `H` creates limits of shape `C` and `F : C ⥤ D` is initial, then `H` creates limits of shape +`D`. -/ +def createsLimitsOfShapeOfInitial {B : Type u₄} [Category.{v₄} B] (H : E ⥤ B) + [CreatesLimitsOfShape C H] : CreatesLimitsOfShape D H where + CreatesLimit := createsLimitOfComp F + end Initial section diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean index 357916b1fe01e0..603001e9e6ce67 100644 --- a/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean +++ b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean @@ -362,7 +362,7 @@ lemma preservesLimit_of_evaluation (F : D ⥤ K ⥤ C) (G : J ⥤ D) change IsLimit ((F ⋙ (evaluation K C).obj X).mapCone c) exact isLimitOfPreserves _ hc⟩⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitOfEvaluation (F : D ⥤ K ⥤ C) (G : J ⥤ D) (H : ∀ k : K, PreservesLimit G (F ⋙ (evaluation K C).obj k : D ⥤ C)) : PreservesLimit G F := @@ -374,7 +374,7 @@ lemma preservesLimitsOfShape_of_evaluation (F : D ⥤ K ⥤ C) (J : Type*) [Cate PreservesLimitsOfShape J F := ⟨fun {G} => preservesLimit_of_evaluation F G fun _ => PreservesLimitsOfShape.preservesLimit⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitsOfShapeOfEvaluation (F : D ⥤ K ⥤ C) (J : Type*) [Category J] (H : ∀ k : K, PreservesLimitsOfShape J (F ⋙ (evaluation K C).obj k)) : PreservesLimitsOfShape J F := @@ -387,7 +387,7 @@ lemma preservesLimits_of_evaluation (F : D ⥤ K ⥤ C) ⟨fun {L} _ => preservesLimitsOfShape_of_evaluation F L fun _ => PreservesLimitsOfSize.preservesLimitsOfShape⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesLimitsOfEvaluation (F : D ⥤ K ⥤ C) (H : ∀ k : K, PreservesLimitsOfSize.{w', w} (F ⋙ (evaluation K C).obj k)) : PreservesLimitsOfSize.{w', w} F := @@ -412,7 +412,7 @@ lemma preservesColimit_of_evaluation (F : D ⥤ K ⥤ C) (G : J ⥤ D) change IsColimit ((F ⋙ (evaluation K C).obj X).mapCocone c) exact isColimitOfPreserves _ hc⟩⟩ -@[deprecated (since := "2024-11-19")] +@[deprecated "No deprecation message was provided." (since := "2024-11-19")] lemma preservesColimitOfEvaluation (F : D ⥤ K ⥤ C) (G : J ⥤ D) (H : ∀ k, PreservesColimit G (F ⋙ (evaluation K C).obj k)) : PreservesColimit G F := preservesColimit_of_evaluation _ _ H diff --git a/Mathlib/CategoryTheory/Limits/MorphismProperty.lean b/Mathlib/CategoryTheory/Limits/MorphismProperty.lean index 8f764982cf3621..b4bb842c72dd28 100644 --- a/Mathlib/CategoryTheory/Limits/MorphismProperty.lean +++ b/Mathlib/CategoryTheory/Limits/MorphismProperty.lean @@ -134,7 +134,7 @@ instance [P.ContainsIdentities] : HasTerminal (P.Over ⊤ X) := /-- If `P` is stable under composition, base change and satisfies post-cancellation, `Over.forget P ⊤ X` creates pullbacks. -/ -noncomputable def createsLimitsOfShape_walkingCospan [HasPullbacks T] +noncomputable instance createsLimitsOfShape_walkingCospan [HasPullbacks T] [P.IsStableUnderComposition] [P.IsStableUnderBaseChange] [P.HasOfPostcompProperty P] : CreatesLimitsOfShape WalkingCospan (Over.forget P ⊤ X) := haveI : HasLimitsOfShape WalkingCospan (Comma (𝟭 T) (Functor.fromPUnit X)) := diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean b/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean index a50342b46d933e..6f0db0a360ddbb 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ import Mathlib.CategoryTheory.Limits.Final -import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits +import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts import Mathlib.CategoryTheory.Countable import Mathlib.Data.Countable.Defs /-! @@ -52,6 +52,29 @@ instance [Category.{v} J] [CountableCategory J] [HasCountableLimits C] : HasLimi have : HasLimitsOfShape (HomAsType J) C := HasCountableLimits.out (HomAsType J) hasLimitsOfShape_of_equivalence (homAsTypeEquiv J) +/-- A category has countable products if it has all products indexed by countable types. -/ +class HasCountableProducts where + out (J : Type) [Countable J] : HasProductsOfShape J C + +instance [HasCountableProducts C] : HasProductsOfShape J C := + have : Countable (Shrink.{0} J) := Countable.of_equiv _ (equivShrink.{0} J) + have : HasLimitsOfShape (Discrete (Shrink.{0} J)) C := HasCountableProducts.out _ + hasLimitsOfShape_of_equivalence (Discrete.equivalence (equivShrink.{0} J)).symm + +instance (priority := 100) hasCountableProducts_of_hasProducts [HasProducts C] : + HasCountableProducts C where + out _ := + have : HasProducts.{0} C := has_smallest_products_of_hasProducts + inferInstance + +instance (priority := 100) hasCountableProducts_of_hasCountableLimits [HasCountableLimits C] : + HasCountableProducts C where + out _ := inferInstance + +instance (priority := 100) hasFiniteProducts_of_hasCountableProducts [HasCountableProducts C] : + HasFiniteProducts C where + out _ := inferInstance + /-- A category has all countable colimits if every functor `J ⥤ C` with a `CountableCategory J` instance and `J : Type` has a colimit. @@ -74,8 +97,81 @@ instance [Category.{v} J] [CountableCategory J] [HasCountableColimits C] : HasCo have : HasColimitsOfShape (HomAsType J) C := HasCountableColimits.out (HomAsType J) hasColimitsOfShape_of_equivalence (homAsTypeEquiv J) +/-- A category has countable coproducts if it has all coproducts indexed by countable types. -/ +class HasCountableCoproducts where + out (J : Type) [Countable J] : HasCoproductsOfShape J C + +instance (priority := 100) hasCountableCoproducts_of_hasCoproducts [HasCoproducts C] : + HasCountableCoproducts C where + out _ := + have : HasCoproducts.{0} C := has_smallest_coproducts_of_hasCoproducts + inferInstance + +instance [HasCountableCoproducts C] : HasCoproductsOfShape J C := + have : Countable (Shrink.{0} J) := Countable.of_equiv _ (equivShrink.{0} J) + have : HasColimitsOfShape (Discrete (Shrink.{0} J)) C := HasCountableCoproducts.out _ + hasColimitsOfShape_of_equivalence (Discrete.equivalence (equivShrink.{0} J)).symm + +instance (priority := 100) hasCountableCoproducts_of_hasCountableColimits [HasCountableColimits C] : + HasCountableCoproducts C where + out _ := inferInstance + +instance (priority := 100) hasFiniteCoproducts_of_hasCountableCoproducts + [HasCountableCoproducts C] : HasFiniteCoproducts C where + out _ := inferInstance + section Preorder +namespace IsFiltered + +attribute [local instance] IsFiltered.nonempty + +variable {C} [Preorder J] [IsFiltered J] + +/-- The object part of the initial functor `ℕᵒᵖ ⥤ J` -/ +noncomputable def sequentialFunctor_obj : ℕ → J := fun + | .zero => (exists_surjective_nat _).choose 0 + | .succ n => (IsFilteredOrEmpty.cocone_objs ((exists_surjective_nat _).choose n) + (sequentialFunctor_obj n)).choose + +theorem sequentialFunctor_map : Monotone (sequentialFunctor_obj J) := + monotone_nat_of_le_succ fun n ↦ + leOfHom (IsFilteredOrEmpty.cocone_objs ((exists_surjective_nat _).choose n) + (sequentialFunctor_obj J n)).choose_spec.choose_spec.choose + +/-- +The initial functor `ℕᵒᵖ ⥤ J`, which allows us to turn cofiltered limits over countable preorders +into sequential limits. +-/ +noncomputable def sequentialFunctor : ℕ ⥤ J where + obj n := sequentialFunctor_obj J n + map h := homOfLE (sequentialFunctor_map J (leOfHom h)) + +theorem sequentialFunctor_final_aux (j : J) : ∃ (n : ℕ), j ≤ sequentialFunctor_obj J n := by + obtain ⟨m, h⟩ := (exists_surjective_nat _).choose_spec j + refine ⟨m + 1, ?_⟩ + simpa only [h] using leOfHom (IsFilteredOrEmpty.cocone_objs ((exists_surjective_nat _).choose m) + (sequentialFunctor_obj J m)).choose_spec.choose + +instance sequentialFunctor_final : (sequentialFunctor J).Final where + out d := by + obtain ⟨n, (g : d ≤ (sequentialFunctor J).obj n)⟩ := sequentialFunctor_final_aux J d + have : Nonempty (StructuredArrow d (sequentialFunctor J)) := + ⟨StructuredArrow.mk (homOfLE g)⟩ + 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', reduceCtorEq] + clear! C + wlog h : j.right ≤ i.right + · exact or_comm.1 (this J d n g inferInstance j i (le_of_lt (not_le.mp h))) + · right + exact ⟨StructuredArrow.homMk (homOfLE h) rfl⟩ + +end IsFiltered + +namespace IsCofiltered + attribute [local instance] IsCofiltered.nonempty variable {C} [Preorder J] [IsCofiltered J] @@ -94,6 +190,9 @@ theorem sequentialFunctor_map : Antitone (sequentialFunctor_obj J) := /-- The initial functor `ℕᵒᵖ ⥤ J`, which allows us to turn cofiltered limits over countable preorders into sequential limits. + +TODO: redefine this as `(IsFiltered.sequentialFunctor Jᵒᵖ).leftOp`. This would need API for initial/ +final functors of the form `leftOp`/`rightOp`. -/ noncomputable def sequentialFunctor : ℕᵒᵖ ⥤ J where obj n := sequentialFunctor_obj J (unop n) @@ -153,6 +252,19 @@ For this we need to dualize this whole section. proof_wanted hasCountableColimits_of_hasFiniteColimits_and_hasSequentialColimits [HasFiniteColimits C] [HasLimitsOfShape ℕ C] : HasCountableColimits C +end IsCofiltered + end Preorder +@[deprecated (since := "2024-11-01")] alias sequentialFunctor := IsCofiltered.sequentialFunctor +@[deprecated (since := "2024-11-01")] alias sequentialFunctor_obj := + IsCofiltered.sequentialFunctor_obj +@[deprecated (since := "2024-11-01")] alias sequentialFunctor_map := + IsCofiltered.sequentialFunctor_map +@[deprecated (since := "2024-11-01")] alias sequentialFunctor_initial_aux := + IsCofiltered.sequentialFunctor_initial_aux +@[deprecated (since := "2024-11-01")] alias sequentialFunctor_initial := + IsCofiltered.sequentialFunctor_initial +attribute [nolint defLemma] sequentialFunctor_initial + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean index 0bf114008f136d..ed9bd8a77cbda7 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean @@ -373,6 +373,10 @@ from a family of isomorphisms between the factors. abbrev Pi.mapIso {f g : β → C} [HasProductsOfShape β C] (p : ∀ b, f b ≅ g b) : ∏ᶜ f ≅ ∏ᶜ g := lim.mapIso (Discrete.natIso fun X => p X.as) +instance Pi.map_isIso {f g : β → C} [HasProductsOfShape β C] (p : ∀ b, f b ⟶ g b) + [∀ b, IsIso <| p b] : IsIso <| Pi.map p := + inferInstanceAs (IsIso (Pi.mapIso (fun b ↦ asIso (p b))).hom) + section /- In this section, we provide some API for products when we are given a functor @@ -487,6 +491,10 @@ 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) +instance Sigma.map_isIso {f g : β → C} [HasCoproductsOfShape β C] (p : ∀ b, f b ⟶ g b) + [∀ b, IsIso <| p b] : IsIso (Sigma.map p) := + inferInstanceAs (IsIso (Sigma.mapIso (fun b ↦ asIso (p b))).hom) + section /- In this section, we provide some API for coproducts when we are given a functor @@ -660,6 +668,12 @@ theorem hasProducts_of_limit_fans (lf : ∀ {J : Type w} (f : J → C), Fan f) ⟨(Cones.postcompose Discrete.natIsoFunctor.inv).obj (lf fun j => F.obj ⟨j⟩), (IsLimit.postcomposeInvEquiv _ _).symm (lf_isLimit _)⟩ } +instance (priority := 100) hasProductsOfShape_of_hasProducts [HasProducts.{w} C] (J : Type w) : + HasProductsOfShape J C := inferInstance + +instance (priority := 100) hasCoproductsOfShape_of_hasCoproducts [HasCoproducts.{w} C] + (J : Type w) : HasCoproductsOfShape J C := inferInstance + /-! (Co)products over a type with a unique term. -/ diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean index 59747539342922..9341953c585185 100644 --- a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean +++ b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean @@ -88,7 +88,7 @@ theorem algebraMap (A : Mon_ (ModuleCat.{u} R)) (r : R) : algebraMap R A.X r = A @[simps!] def functor : Mon_ (ModuleCat.{u} R) ⥤ AlgebraCat R where obj A := AlgebraCat.of R A.X - map {_ _} f := + map {_ _} f := AlgebraCat.ofHom { f.hom.toAddMonoidHom with toFun := f.hom map_one' := LinearMap.congr_fun f.one_hom (1 : R) @@ -134,9 +134,7 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext <| TensorProduct.ext <| LinearMap.ext fun x => LinearMap.ext fun y => LinearMap.ext fun z => ?_ - dsimp only [AlgebraCat.id_apply, TensorProduct.mk_apply, LinearMap.compr₂_apply, - Function.comp_apply, ModuleCat.MonoidalCategory.tensorHom_tmul, AlgebraCat.coe_comp, - MonoidalCategory.associator_hom_apply] + dsimp only [compr₂_apply, TensorProduct.mk_apply] rw [compr₂_apply, compr₂_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [CategoryTheory.comp_apply, @@ -152,9 +150,9 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where def inverse : AlgebraCat.{u} R ⥤ Mon_ (ModuleCat.{u} R) where obj := inverseObj map f := - { hom := f.toLinearMap - one_hom := LinearMap.ext f.commutes - mul_hom := TensorProduct.ext <| LinearMap.ext₂ <| map_mul f } + { hom := f.hom.toLinearMap + one_hom := LinearMap.ext f.hom.commutes + mul_hom := TensorProduct.ext <| LinearMap.ext₂ <| map_mul f.hom } end MonModuleEquivalenceAlgebra @@ -193,14 +191,14 @@ def monModuleEquivalenceAlgebra : Mon_ (ModuleCat.{u} R) ≌ AlgebraCat R where counitIso := NatIso.ofComponents (fun A => - { hom := + { hom := AlgebraCat.ofHom { toFun := _root_.id map_zero' := rfl map_add' := fun _ _ => rfl map_one' := (algebraMap R A).map_one map_mul' := fun x y => @LinearMap.mul'_apply R _ _ _ _ _ _ x y commutes' := fun _ => rfl } - inv := + inv := AlgebraCat.ofHom { toFun := _root_.id map_zero' := rfl map_add' := fun _ _ => rfl @@ -208,9 +206,6 @@ def monModuleEquivalenceAlgebra : Mon_ (ModuleCat.{u} R) ≌ AlgebraCat R where map_mul' := fun x y => (@LinearMap.mul'_apply R _ _ _ _ _ _ x y).symm commutes' := fun _ => rfl } }) --- These lemmas have always been bad (https://github.com/leanprover-community/mathlib4/issues/7657), but https://github.com/leanprover/lean4/pull/2644 made `simp` start noticing -attribute [nolint simpNF] ModuleCat.MonModuleEquivalenceAlgebra.functor_map_apply - /-- The equivalence `Mon_ (ModuleCat R) ≌ AlgebraCat R` is naturally compatible with the forgetful functors to `ModuleCat R`. -/ diff --git a/Mathlib/CategoryTheory/MorphismProperty/Comma.lean b/Mathlib/CategoryTheory/MorphismProperty/Comma.lean index 0662c8046f1200..6b093565af86f8 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Comma.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Comma.lean @@ -117,6 +117,8 @@ instance : Category (P.Comma L R Q W) where id X := X.id comp f g := f.comp g +lemma toCommaMorphism_eq_hom {X Y : P.Comma L R Q W} (f : X ⟶ Y) : f.toCommaMorphism = f.hom := rfl + /-- Alternative `ext` lemma for `Comma.Hom`. -/ @[ext] lemma Hom.ext' {X Y : P.Comma L R Q W} {f g : X ⟶ Y} (h : f.hom = g.hom) : @@ -220,6 +222,9 @@ protected abbrev Over : Type _ := protected abbrev Over.forget : P.Over Q X ⥤ Over X := Comma.forget (Functor.id T) (Functor.fromPUnit.{0} X) P Q ⊤ +instance : (Over.forget P ⊤ X).Faithful := inferInstanceAs <| (Comma.forget _ _ _ _ _).Faithful +instance : (Over.forget P ⊤ X).Full := inferInstanceAs <| (Comma.forget _ _ _ _ _).Full + variable {P Q X} /-- Construct a morphism in `P.Over Q X` from a morphism in `Over.X`. -/ @@ -261,6 +266,9 @@ protected abbrev Under : Type _ := protected abbrev Under.forget : P.Under Q X ⥤ Under X := Comma.forget (Functor.fromPUnit.{0} X) (Functor.id T) P ⊤ Q +instance : (Under.forget P ⊤ X).Faithful := inferInstanceAs <| (Comma.forget _ _ _ _ _).Faithful +instance : (Under.forget P ⊤ X).Full := inferInstanceAs <| (Comma.forget _ _ _ _ _).Full + variable {P Q X} /-- Construct a morphism in `P.Under Q X` from a morphism in `Under.X`. -/ diff --git a/Mathlib/CategoryTheory/Preadditive/Basic.lean b/Mathlib/CategoryTheory/Preadditive/Basic.lean index 0ddcb0081738ba..7fade9b2835ebd 100644 --- a/Mathlib/CategoryTheory/Preadditive/Basic.lean +++ b/Mathlib/CategoryTheory/Preadditive/Basic.lean @@ -5,6 +5,7 @@ Authors: Markus Himmel, Jakob von Raumer -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.Algebra.GroupWithZero.Action.Units import Mathlib.Algebra.Module.End import Mathlib.CategoryTheory.Endomorphism import Mathlib.CategoryTheory.Limits.Shapes.Kernels diff --git a/Mathlib/CategoryTheory/Sites/Grothendieck.lean b/Mathlib/CategoryTheory/Sites/Grothendieck.lean index 28c48a20268def..5570569b02e2bc 100644 --- a/Mathlib/CategoryTheory/Sites/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Sites/Grothendieck.lean @@ -53,7 +53,7 @@ universe v₁ u₁ v u namespace CategoryTheory -open CategoryTheory Category +open Category variable (C : Type u) [Category.{v} C] diff --git a/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean b/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean index 44a948a9222b1d..b15c8b4f9117fa 100644 --- a/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean +++ b/Mathlib/CategoryTheory/Sites/NonabelianCohomology/H1.lean @@ -48,7 +48,7 @@ variable {C : Type u} [Category.{v} C] namespace PresheafOfGroups -variable (G : Cᵒᵖ ⥤ Grp.{w}) {X : C} {I : Type w'} (U : I → C) +variable (G : Cᵒᵖ ⥤ Grp.{w}) {I : Type w'} (U : I → C) /-- A zero cochain consists of a family of sections. -/ def ZeroCochain := ∀ (i : I), G.obj (Opposite.op (U i)) diff --git a/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean b/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean index 52f8413c10939c..2c7a0002cec284 100644 --- a/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean +++ b/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean @@ -43,7 +43,7 @@ universe v u namespace CategoryTheory -open CategoryTheory Category Limits +open Category Limits variable {C : Type u} [Category.{v} C] (J : GrothendieckTopology C) {A B : Type*} [Category A] [Category B] (F : A ⥤ B) diff --git a/Mathlib/CategoryTheory/Sites/Pretopology.lean b/Mathlib/CategoryTheory/Sites/Pretopology.lean index f2f7dfc06495ce..d888a2611acf2a 100644 --- a/Mathlib/CategoryTheory/Sites/Pretopology.lean +++ b/Mathlib/CategoryTheory/Sites/Pretopology.lean @@ -35,7 +35,7 @@ noncomputable section namespace CategoryTheory -open CategoryTheory Category Limits Presieve +open Category Limits Presieve variable {C : Type u} [Category.{v} C] [HasPullbacks C] variable (C) diff --git a/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean b/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean index 0dc3527d3bad65..5d0d0f094055a4 100644 --- a/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean +++ b/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean @@ -6,7 +6,6 @@ Authors: Yaël Dillies import Mathlib.Algebra.BigOperators.Ring import Mathlib.Data.Multiset.Fintype import Mathlib.FieldTheory.ChevalleyWarning -import Mathlib.RingTheory.UniqueFactorizationDomain /-! # The Erdős–Ginzburg–Ziv theorem diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index 286aa6a7482872..0a386abf7a0f99 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -4,14 +4,12 @@ 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.Tactic.FieldSimp import Mathlib.Tactic.GCongr import Mathlib.Tactic.Positivity -import Mathlib.Tactic.Positivity.Finset import Mathlib.Tactic.Ring /-! @@ -164,7 +162,7 @@ private theorem mul_aux (hA : A.Nonempty) (hAB : A ⊆ B) have hA₀ : (0 : ℚ≥0) < #A := cast_pos.2 hA.card_pos have hA₀' : (0 : ℚ≥0) < #A' := cast_pos.2 hA'.card_pos exact mod_cast - (div_le_div_iff hA₀ hA₀').1 + (div_le_div_iff₀ hA₀ hA₀').1 (h _ <| mem_erase_of_ne_of_mem hA'.ne_empty <| mem_powerset.2 <| hAA'.trans hAB) /-- **Ruzsa's triangle inequality**. Multiplication version. -/ diff --git a/Mathlib/Combinatorics/Derangements/Basic.lean b/Mathlib/Combinatorics/Derangements/Basic.lean index 9620588f454866..ac4e2f3b842760 100644 --- a/Mathlib/Combinatorics/Derangements/Basic.lean +++ b/Mathlib/Combinatorics/Derangements/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Dynamics.FixedPoints.Basic import Mathlib.GroupTheory.Perm.Option import Mathlib.Logic.Equiv.Defs import Mathlib.Logic.Equiv.Option +import Mathlib.Tactic.ApplyFun /-! # Derangements on types diff --git a/Mathlib/Combinatorics/Enumerative/Catalan.lean b/Mathlib/Combinatorics/Enumerative/Catalan.lean index c2ae512bb889fd..21a578fab89bff 100644 --- a/Mathlib/Combinatorics/Enumerative/Catalan.lean +++ b/Mathlib/Combinatorics/Enumerative/Catalan.lean @@ -140,8 +140,6 @@ theorem catalan_three : catalan 3 = 5 := by namespace Tree -open Tree - /-- Given two finsets, find all trees that can be formed with left child in `a` and right child in `b` -/ abbrev pairwiseNode (a b : Finset (Tree Unit)) : Finset (Tree Unit) := diff --git a/Mathlib/Combinatorics/Enumerative/InclusionExclusion.lean b/Mathlib/Combinatorics/Enumerative/InclusionExclusion.lean new file mode 100644 index 00000000000000..314e4eea70693a --- /dev/null +++ b/Mathlib/Combinatorics/Enumerative/InclusionExclusion.lean @@ -0,0 +1,129 @@ +/- +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.BigOperators.Ring +import Mathlib.Algebra.Module.BigOperators + +/-! +# Inclusion-exclusion principle + +This file proves several variants of the inclusion-exclusion principle. + +The inclusion-exclusion principle says that the sum/integral of a function over a finite union of +sets can be calculated as the alternating sum over `n > 0` of the sum/integral of the function over +the intersection of `n` of the sets. + +By taking complements, it also says that the sum/integral of a function over a finite intersection +of complements of sets can be calculated as the alternating sum over `n ≥ 0` of the sum/integral of +the function over the intersection of `n` of the sets. + +By taking the function to be constant `1`, we instead get a result about the cardinality/measure of +the sets. + +## Main declarations + +Per the above explanation, this file contains the following variants of inclusion-exclusion: +* `Finset.inclusion_exclusion_sum_biUnion`: Sum of a function over a finite union of sets +* `Finset.inclusion_exclusion_card_biUnion`: Cardinality of a finite union of sets +* `Finset.inclusion_exclusion_sum_inf_compl`: Sum of a function over a finite intersection of + complements of sets +* `Finset.inclusion_exclusion_card_inf_compl`: Cardinality of a finite intersection of + complements of sets + +## TODO + +* Use (a slight variant of) `Finset.prod_indicator_biUnion_sub_indicator` to prove the integral + version of inclusion-exclusion. +* Prove that truncating the series alternatively gives an upper/lower bound to the true value. +-/ + +namespace Finset +variable {ι α G : Type*} [DecidableEq α] [AddCommGroup G] {s : Finset ι} + +lemma prod_indicator_biUnion_sub_indicator (hs : s.Nonempty) (S : ι → Finset α) (a : α) : + ∏ i ∈ s, (Set.indicator (s.biUnion S) 1 a - Set.indicator (S i) 1 a) = (0 : ℤ) := by + by_cases ha : a ∈ s.biUnion S + · obtain ⟨i, hi, ha⟩ := mem_biUnion.1 ha + exact prod_eq_zero hi <| by simp [*, -coe_biUnion] + · obtain ⟨i, hi⟩ := hs + have ha : a ∉ S i := fun h ↦ ha <| subset_biUnion_of_mem _ hi h + exact prod_eq_zero hi <| by simp [*, -coe_biUnion] + +/-- **Inclusion-exclusion principle** for the sum of a function over a union. + +The sum of a function `f` over the union of the `S i` over `i ∈ s` is the alternating sum of the +sums of `f` over the intersections of the `S i`. -/ +theorem inclusion_exclusion_sum_biUnion (s : Finset ι) (S : ι → Finset α) (f : α → G) : + ∑ a ∈ s.biUnion S, f a = ∑ t : s.powerset.filter (·.Nonempty), + (-1) ^ (#t.1 + 1) • ∑ a ∈ t.1.inf' (mem_filter.1 t.2).2 S, f a := by + classical + rw [← sub_eq_zero] + calc + ∑ a ∈ s.biUnion S, f a - ∑ t : s.powerset.filter (·.Nonempty), + (-1) ^ (#t.1 + 1) • ∑ a ∈ t.1.inf' (mem_filter.1 t.2).2 S, f a + = ∑ t : s.powerset.filter (·.Nonempty), + (-1) ^ #t.1 • ∑ a ∈ t.1.inf' (mem_filter.1 t.2).2 S, f a + + ∑ t ∈ s.powerset.filter (¬ ·.Nonempty), (-1) ^ #t • ∑ a ∈ s.biUnion S, f a := by + simp [sub_eq_neg_add, ← sum_neg_distrib, filter_eq', pow_succ] + _ = ∑ t ∈ s.powerset, (-1) ^ #t • + if ht : t.Nonempty then ∑ a ∈ t.inf' ht S, f a else ∑ a ∈ s.biUnion S, f a := by + rw [← sum_attach (filter ..)]; simp [sum_dite, filter_eq', sum_attach] + _ = ∑ a ∈ s.biUnion S, (∏ i ∈ s, (1 - Set.indicator (S i) 1 a : ℤ)) • f a := by + simp only [Int.reduceNeg, mem_coe, prod_sub, sum_comm (s := s.biUnion S), sum_smul, mul_assoc] + congr! with t + split_ifs with ht + · obtain ⟨i, hi⟩ := ht + simp only [prod_const_one, mul_one, prod_indicator_apply] + simp only [smul_sum, Set.indicator, Set.mem_iInter, mem_coe, Pi.one_apply, mul_ite, mul_one, + mul_zero, ite_smul, zero_smul, sum_ite, not_forall, sum_const_zero, add_zero] + congr + aesop + · obtain rfl := not_nonempty_iff_eq_empty.1 ht + simp + _ = ∑ a ∈ s.biUnion S, (∏ i ∈ s, + (Set.indicator (s.biUnion S) 1 a - Set.indicator (S i) 1 a) : ℤ) • f a := by + congr! with t; rw [Set.indicator_of_mem ‹_›, Pi.one_apply] + _ = 0 := by + obtain rfl | hs := s.eq_empty_or_nonempty <;> + simp [-coe_biUnion, prod_indicator_biUnion_sub_indicator, *] + +/-- **Inclusion-exclusion principle** for the cardinality of a union. + +The cardinality of the union of the `S i` over `i ∈ s` is the alternating sum of the cardinalities +of the intersections of the `S i`. -/ +theorem inclusion_exclusion_card_biUnion (s : Finset ι) (S : ι → Finset α) : + #(s.biUnion S) = ∑ t : s.powerset.filter (·.Nonempty), + (-1 : ℤ) ^ (#t.1 + 1) * #(t.1.inf' (mem_filter.1 t.2).2 S) := by + simpa using inclusion_exclusion_sum_biUnion (G := ℤ) s S (f := 1) + +variable [Fintype α] + +/-- **Inclusion-exclusion principle** for the sum of a function over an intersection of complements. + +The sum of a function `f` over the intersection of the complements of the `S i` over `i ∈ s` is the +alternating sum of the sums of `f` over the intersections of the `S i`. -/ +theorem inclusion_exclusion_sum_inf_compl (s : Finset ι) (S : ι → Finset α) (f : α → G) : + ∑ a ∈ s.inf fun i ↦ (S i)ᶜ, f a = ∑ t ∈ s.powerset, (-1) ^ #t • ∑ a ∈ t.inf S, f a := by + classical + calc + ∑ a ∈ s.inf fun i ↦ (S i)ᶜ, f a + = ∑ a, f a - ∑ a ∈ s.biUnion S, f a := by + rw [← Finset.compl_sup, sup_eq_biUnion, eq_sub_iff_add_eq, sum_compl_add_sum] + _ = ∑ t ∈ s.powerset.filter (¬ ·.Nonempty), (-1) ^ #t • ∑ a ∈ t.inf S, f a + + ∑ t ∈ s.powerset.filter (·.Nonempty), (-1) ^ #t • ∑ a ∈ t.inf S, f a := by + simp [← sum_attach (filter ..), inclusion_exclusion_sum_biUnion, inf'_eq_inf, filter_eq', + sub_eq_add_neg, pow_succ] + _ = ∑ t ∈ s.powerset, (-1) ^ #t • ∑ a ∈ t.inf S, f a := sum_filter_not_add_sum_filter .. + +/-- **Inclusion-exclusion principle** for the cardinality of an intersection of complements. + +The cardinality of the intersection of the complements of the `S i` over `i ∈ s` is the +alternating sum of the cardinalities of the intersections of the `S i`. -/ +theorem inclusion_exclusion_card_inf_compl (s : Finset ι) (S : ι → Finset α) : + #(s.inf fun i ↦ (S i)ᶜ) = ∑ t ∈ s.powerset, (-1 : ℤ) ^ #t * #(t.inf S) := by + simpa using inclusion_exclusion_sum_inf_compl (G := ℤ) s S (f := 1) + +end Finset diff --git a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean index d2173e136b1479..be6ce35efc01ef 100644 --- a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean +++ b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean @@ -6,6 +6,7 @@ Authors: Yaël Dillies, Vladimir Ivanov import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Order.BigOperators.Group.Finset +import Mathlib.Algebra.Order.Field.Basic import Mathlib.Data.Finset.Sups import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.Ring diff --git a/Mathlib/Combinatorics/SetFamily/LYM.lean b/Mathlib/Combinatorics/SetFamily/LYM.lean index 4f771b1d441627..67a603abd4165b 100644 --- a/Mathlib/Combinatorics/SetFamily/LYM.lean +++ b/Mathlib/Combinatorics/SetFamily/LYM.lean @@ -93,7 +93,7 @@ theorem card_div_choose_le_card_shadow_div_choose (hr : r ≠ 0) · rw [choose_eq_zero_of_lt hr', cast_zero, div_zero] exact div_nonneg (cast_nonneg _) (cast_nonneg _) replace h𝒜 := card_mul_le_card_shadow_mul h𝒜 - rw [div_le_div_iff] <;> norm_cast + rw [div_le_div_iff₀] <;> norm_cast · cases' r with r · exact (hr rfl).elim rw [tsub_add_eq_add_tsub hr', add_tsub_add_eq_tsub_right] at h𝒜 diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean index 452746aebd488c..ec9fd519eeeeb4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yaël Dillies, Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Bhavik Mehta -/ -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.Order.BigOperators.Group.Finset import Mathlib.Combinatorics.SimpleGraph.Density import Mathlib.Data.Rat.BigOperators diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean index a5d36c33b508b2..2924a54b4d5303 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean @@ -10,7 +10,6 @@ import Mathlib.Combinatorics.SimpleGraph.Clique import Mathlib.Data.Finset.Sym import Mathlib.Tactic.GCongr import Mathlib.Tactic.Positivity -import Mathlib.Tactic.Positivity.Finset /-! # Triangles in graphs @@ -35,8 +34,7 @@ open Fintype (card) namespace SimpleGraph -variable {α β 𝕜 : Type*} [LinearOrderedField 𝕜] {G H : SimpleGraph α} {ε δ : 𝕜} {n : ℕ} - {s : Finset α} +variable {α β 𝕜 : Type*} [LinearOrderedField 𝕜] {G H : SimpleGraph α} {ε δ : 𝕜} section LocallyLinear diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean index bff996c3fa38c1..3de98cd5194b3d 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean @@ -23,7 +23,7 @@ attribute [-instance] decidableEq_of_subsingleton open Finset Fintype -variable {α : Type*} (G G' : SimpleGraph α) [DecidableRel G.Adj] {ε : ℝ} {s t u : Finset α} +variable {α : Type*} (G : SimpleGraph α) [DecidableRel G.Adj] {ε : ℝ} {s t u : Finset α} namespace SimpleGraph @@ -146,7 +146,7 @@ private lemma triple_eq_triple_of_mem (hst : Disjoint s t) (hsu : Disjoint s u) · rintro rfl solve_by_elim -variable [Fintype α] {P : Finpartition (univ : Finset α)} +variable [Fintype α] /-- The **Triangle Counting Lemma**. If `G` is a graph and `s`, `t`, `u` are disjoint sets of vertices such that each pair is `ε`-uniform and `2 * ε`-dense, then `G` contains at least diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean index 3135218de5e3dc..c911166bc53ac3 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean @@ -38,7 +38,7 @@ This construction shows up unrelatedly twice in the theory of Roth numbers: open Finset Function Sum3 variable {α β γ 𝕜 : Type*} [LinearOrderedField 𝕜] {t : Finset (α × β × γ)} {a a' : α} {b b' : β} - {c c' : γ} {x : α × β × γ} {ε : 𝕜} + {c c' : γ} {x : α × β × γ} namespace SimpleGraph namespace TripartiteFromTriangles diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index 9cfbcd713b62a1..7cd217fadb8cf0 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -544,9 +544,9 @@ lemma tendsto_atTop_sumCoeffsExp : Tendsto (fun (p : ℝ) => ∑ i, a i * (b i) lemma one_mem_range_sumCoeffsExp : 1 ∈ Set.range (fun (p : ℝ) => ∑ i, a i * (b i) ^ p) := by refine mem_range_of_exists_le_of_exists_ge R.continuous_sumCoeffsExp ?le_one ?ge_one case le_one => - exact Eventually.exists <| eventually_le_of_tendsto_lt zero_lt_one R.tendsto_zero_sumCoeffsExp + exact R.tendsto_zero_sumCoeffsExp.eventually_le_const zero_lt_one |>.exists case ge_one => - exact Eventually.exists <| R.tendsto_atTop_sumCoeffsExp.eventually_ge_atTop _ + exact R.tendsto_atTop_sumCoeffsExp.eventually_ge_atTop _ |>.exists /-- The function x ↦ ∑ a_i b_i^x is injective. This implies the uniqueness of `p`. -/ lemma injective_sumCoeffsExp : Function.Injective (fun (p : ℝ) => ∑ i, a i * (b i) ^ p) := diff --git a/Mathlib/Data/Complex/Abs.lean b/Mathlib/Data/Complex/Abs.lean index 99319c9d298b3c..18f2f48e1b5251 100644 --- a/Mathlib/Data/Complex/Abs.lean +++ b/Mathlib/Data/Complex/Abs.lean @@ -199,7 +199,7 @@ theorem abs_im_div_abs_le_one (z : ℂ) : |z.im / Complex.abs z| ≤ 1 := @[simp, norm_cast] lemma abs_intCast (n : ℤ) : abs n = |↑n| := by rw [← ofReal_intCast, abs_ofReal] -@[deprecated (since := "2024-02-14")] +@[deprecated "No deprecation message was provided." (since := "2024-02-14")] lemma int_cast_abs (n : ℤ) : |↑n| = Complex.abs n := (abs_intCast _).symm theorem normSq_eq_abs (x : ℂ) : normSq x = (Complex.abs x) ^ 2 := by diff --git a/Mathlib/Data/Complex/Basic.lean b/Mathlib/Data/Complex/Basic.lean index 1762273d53338d..e1d6851ed9e2f9 100644 --- a/Mathlib/Data/Complex/Basic.lean +++ b/Mathlib/Data/Complex/Basic.lean @@ -741,7 +741,7 @@ lemma ofReal_nnqsmul (q : ℚ≥0) (r : ℝ) : ofReal (q • r) = q • r := by lemma ofReal_qsmul (q : ℚ) (r : ℝ) : ofReal (q • r) = q • r := by simp [Rat.smul_def] theorem conj_inv (x : ℂ) : conj x⁻¹ = (conj x)⁻¹ := - star_inv' _ + star_inv₀ _ @[simp, norm_cast] theorem ofReal_div (r s : ℝ) : ((r / s : ℝ) : ℂ) = r / s := map_div₀ ofRealHom r s diff --git a/Mathlib/Data/Complex/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index 87be1b9c712d28..f789146aa28842 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -188,7 +188,7 @@ theorem exp_add : exp (x + y) = exp x * exp y := by /-- the exponential function as a monoid hom from `Multiplicative ℂ` to `ℂ` -/ @[simps] noncomputable def expMonoidHom : MonoidHom (Multiplicative ℂ) ℂ := - { toFun := fun z => exp (Multiplicative.toAdd z), + { toFun := fun z => exp z.toAdd, map_one' := by simp, map_mul' := by simp [exp_add] } @@ -456,9 +456,6 @@ theorem cos_zero : cos 0 = 1 := by simp [cos] @[simp] theorem cos_neg : cos (-x) = cos x := by simp [cos, sub_eq_add_neg, exp_neg, add_comm] -private theorem cos_add_aux {a b c d : ℂ} : - (a + b) * (c + d) - (b - a) * (d - c) * -1 = 2 * (a * c + b * d) := by ring - theorem cos_add : cos (x + y) = cos x * cos y - sin x * sin y := by rw [← cosh_mul_I, add_mul, cosh_add, cosh_mul_I, cosh_mul_I, sinh_mul_I, sinh_mul_I, mul_mul_mul_comm, I_mul_I, mul_neg_one, sub_eq_add_neg] @@ -692,7 +689,7 @@ nonrec theorem exp_add : exp (x + y) = exp x * exp y := by simp [exp_add, exp] /-- the exponential function as a monoid hom from `Multiplicative ℝ` to `ℝ` -/ @[simps] noncomputable def expMonoidHom : MonoidHom (Multiplicative ℝ) ℝ := - { toFun := fun x => exp (Multiplicative.toAdd x), + { toFun := fun x => exp x.toAdd, map_one' := by simp, map_mul' := by simp [exp_add] } @@ -1498,5 +1495,3 @@ theorem abs_exp_eq_iff_re_eq {x y : ℂ} : abs (exp x) = abs (exp y) ↔ x.re = rw [abs_exp, abs_exp, Real.exp_eq_exp] end Complex - -set_option linter.style.longFile 1700 diff --git a/Mathlib/Data/ENNReal/Basic.lean b/Mathlib/Data/ENNReal/Basic.lean index 96836f66517c48..120674ea5f0009 100644 --- a/Mathlib/Data/ENNReal/Basic.lean +++ b/Mathlib/Data/ENNReal/Basic.lean @@ -85,6 +85,7 @@ context, or if we have `(f : α → ℝ≥0∞) (hf : ∀ x, f x ≠ ∞)`. -/ +assert_not_exists Finset open Function Set NNReal diff --git a/Mathlib/Data/ENNReal/Inv.lean b/Mathlib/Data/ENNReal/Inv.lean index 36003f724d580a..bccdde7f1f4ab5 100644 --- a/Mathlib/Data/ENNReal/Inv.lean +++ b/Mathlib/Data/ENNReal/Inv.lean @@ -173,6 +173,16 @@ protected theorem inv_div {a b : ℝ≥0∞} (htop : b ≠ ∞ ∨ a ≠ ∞) (h rw [← ENNReal.inv_ne_top] at hzero rw [ENNReal.div_eq_inv_mul, ENNReal.div_eq_inv_mul, ENNReal.mul_inv htop hzero, mul_comm, inv_inv] +lemma prod_inv_distrib {ι : Type*} {f : ι → ℝ≥0∞} {s : Finset ι} + (hf : s.toSet.Pairwise fun i j ↦ f i ≠ 0 ∨ f j ≠ ∞) : (∏ i ∈ s, f i)⁻¹ = ∏ i ∈ s, (f i)⁻¹ := by + induction' s using Finset.cons_induction with i s hi ih + · simp + simp [← ih (hf.mono <| by simp)] + refine ENNReal.mul_inv (not_or_of_imp fun hi₀ ↦ prod_ne_top fun j hj ↦ ?_) + (not_or_of_imp fun hi₀ ↦ Finset.prod_ne_zero_iff.2 fun j hj ↦ ?_) + · exact imp_iff_not_or.2 (hf (by simp) (by simp [hj]) <| .symm <| ne_of_mem_of_not_mem hj hi) hi₀ + · exact imp_iff_not_or.2 (hf (by simp [hj]) (by simp) <| ne_of_mem_of_not_mem hj hi).symm hi₀ + protected theorem mul_div_mul_left (a b : ℝ≥0∞) (hc : c ≠ 0) (hc' : c ≠ ⊤) : c * a / (c * b) = a / b := by rw [div_eq_mul_inv, div_eq_mul_inv, ENNReal.mul_inv (Or.inl hc) (Or.inl hc'), mul_mul_mul_comm, diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean index 2c4dde0e12e6a2..663a5824cbe31f 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -269,6 +269,15 @@ theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ · exact htop A · exact A _ +lemma add_one_pos : 0 < n + 1 := + succ_def n ▸ Order.bot_lt_succ n + +lemma add_lt_add_iff_right {k : ℕ∞} (h : k ≠ ⊤) : n + k < m + k ↔ n < m := + WithTop.add_lt_add_iff_right h + +lemma add_lt_add_iff_left {k : ℕ∞} (h : k ≠ ⊤) : k + n < k + m ↔ n < m := + WithTop.add_lt_add_iff_left h + protected lemma exists_nat_gt {n : ℕ∞} (hn : n ≠ ⊤) : ∃ m : ℕ, n < m := by lift n to ℕ using hn obtain ⟨m, hm⟩ := exists_gt n @@ -286,6 +295,8 @@ protected lemma le_sub_of_add_le_left (ha : a ≠ ⊤) : a + b ≤ c → b ≤ c protected lemma sub_sub_cancel (h : a ≠ ⊤) (h2 : b ≤ a) : a - (a - b) = b := (addLECancellable_of_ne_top <| ne_top_of_le_ne_top h tsub_le_self).tsub_tsub_cancel_of_le h2 +section withTop_enat + lemma add_one_natCast_le_withTop_of_lt {m : ℕ} {n : WithTop ℕ∞} (h : m < n) : (m + 1 : ℕ) ≤ n := by match n with | ⊤ => exact le_top @@ -294,9 +305,10 @@ lemma add_one_natCast_le_withTop_of_lt {m : ℕ} {n : WithTop ℕ∞} (h : m < n @[simp] lemma coe_top_add_one : ((⊤ : ℕ∞) : WithTop ℕ∞) + 1 = (⊤ : ℕ∞) := rfl -@[simp] lemma add_one_eq_coe_top_iff : n + 1 = (⊤ : ℕ∞) ↔ n = (⊤ : ℕ∞) := by +@[simp] lemma add_one_eq_coe_top_iff {n : WithTop ℕ∞} : n + 1 = (⊤ : ℕ∞) ↔ n = (⊤ : ℕ∞) := by match n with | ⊤ => exact Iff.rfl + | (⊤ : ℕ∞) => simp | (n : ℕ) => norm_cast; simp only [coe_ne_top, iff_false, ne_eq] @[simp] lemma natCast_ne_coe_top (n : ℕ) : (n : WithTop ℕ∞) ≠ (⊤ : ℕ∞) := nofun @@ -308,13 +320,12 @@ 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_natCast_le_withTop_of_lt (pos_iff_ne_zero.mpr h)⟩ -lemma add_one_pos : 0 < n + 1 := - succ_def n ▸ Order.bot_lt_succ n +lemma natCast_le_of_coe_top_le_withTop {N : WithTop ℕ∞} (hN : (⊤ : ℕ∞) ≤ N) (n : ℕ) : n ≤ N := + le_trans (mod_cast le_top) hN -lemma add_lt_add_iff_right {k : ℕ∞} (h : k ≠ ⊤) : n + k < m + k ↔ n < m := - WithTop.add_lt_add_iff_right h +lemma natCast_lt_of_coe_top_le_withTop {N : WithTop ℕ∞} (hN : (⊤ : ℕ∞) ≤ N) (n : ℕ) : n < N := + lt_of_lt_of_le (mod_cast lt_add_one n) (natCast_le_of_coe_top_le_withTop hN (n + 1)) -lemma add_lt_add_iff_left {k : ℕ∞} (h : k ≠ ⊤) : k + n < k + m ↔ n < m := - WithTop.add_lt_add_iff_left h +end withTop_enat end ENat diff --git a/Mathlib/Data/ENat/Lattice.lean b/Mathlib/Data/ENat/Lattice.lean index d56040d7d9e213..fd0d60e48e317b 100644 --- a/Mathlib/Data/ENat/Lattice.lean +++ b/Mathlib/Data/ENat/Lattice.lean @@ -106,7 +106,7 @@ lemma finite_of_sSup_lt_top (h : sSup s < ⊤) : s.Finite := by exact sSup_eq_top_of_infinite h 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') + Nonempty.csSup_mem .of_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 := diff --git a/Mathlib/Data/FP/Basic.lean b/Mathlib/Data/FP/Basic.lean index ebd1995796919b..492cf4ffcd6045 100644 --- a/Mathlib/Data/FP/Basic.lean +++ b/Mathlib/Data/FP/Basic.lean @@ -146,7 +146,6 @@ unsafe def nextUpPos (e m) (v : ValidFinite e m) : Float := Float.finite false e m' (by unfold ValidFinite at *; rw [ss]; exact v) else if h : e = emax then Float.inf false else Float.finite false e.succ (Nat.div2 m') lcProof -set_option linter.deprecated false in -- Porting note: remove this line when you dropped 'lcProof' set_option linter.unusedVariables false in @[nolint docBlame] diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index 21c9e27353985c..4fcd6469077693 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -1115,7 +1115,7 @@ lemma succAbove_ne_last {a : Fin (n + 2)} {b : Fin (n + 1)} (ha : a ≠ last _) lemma succAbove_last_apply (i : Fin n) : succAbove (last n) i = castSucc i := by rw [succAbove_last] -@[deprecated (since := "2024-05-30")] +@[deprecated "No deprecation message was provided." (since := "2024-05-30")] lemma succAbove_lt_ge (p : Fin (n + 1)) (i : Fin n) : castSucc i < p ∨ p ≤ castSucc i := Nat.lt_or_ge (castSucc i) p diff --git a/Mathlib/Data/Finite/Defs.lean b/Mathlib/Data/Finite/Defs.lean index 784e71e12e4f63..dce5c020d7baf3 100644 --- a/Mathlib/Data/Finite/Defs.lean +++ b/Mathlib/Data/Finite/Defs.lean @@ -162,6 +162,9 @@ protected theorem Infinite.false [Finite α] (_ : Infinite α) : False := alias ⟨Finite.of_not_infinite, Finite.not_infinite⟩ := not_infinite_iff_finite +instance Bool.instFinite : Finite Bool := .intro finTwoEquiv.symm +instance Prop.instFinite : Finite Prop := .of_equiv _ Equiv.propEquivBool.symm + section Set /-! diff --git a/Mathlib/Data/Finite/Prod.lean b/Mathlib/Data/Finite/Prod.lean index 42d9d71fa3edb2..c0dbebd034aaaa 100644 --- a/Mathlib/Data/Finite/Prod.lean +++ b/Mathlib/Data/Finite/Prod.lean @@ -65,6 +65,14 @@ instance Equiv.finite_right {α β : Sort*} [Finite β] : Finite (α ≃ β) := instance Equiv.finite_left {α β : Sort*} [Finite α] : Finite (α ≃ β) := Finite.of_equiv _ ⟨Equiv.symm, Equiv.symm, Equiv.symm_symm, Equiv.symm_symm⟩ +@[to_additive] +instance MulEquiv.finite_left {α β : Type*} [Mul α] [Mul β] [Finite α] : Finite (α ≃* β) := + Finite.of_injective toEquiv toEquiv_injective + +@[to_additive] +instance MulEquiv.finite_right {α β : Type*} [Mul α] [Mul β] [Finite β] : Finite (α ≃* β) := + Finite.of_injective toEquiv toEquiv_injective + open Set Function variable {γ : Type*} diff --git a/Mathlib/Data/Finset/Density.lean b/Mathlib/Data/Finset/Density.lean index b8fcbb8dcf9b90..29e19adc50a21c 100644 --- a/Mathlib/Data/Finset/Density.lean +++ b/Mathlib/Data/Finset/Density.lean @@ -3,11 +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.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 +import Mathlib.Tactic.Positivity.Basic /-! # Density of a finite set diff --git a/Mathlib/Data/Finset/Fold.lean b/Mathlib/Data/Finset/Fold.lean index 931d4b86e5a6b9..fb9ed13966a4df 100644 --- a/Mathlib/Data/Finset/Fold.lean +++ b/Mathlib/Data/Finset/Fold.lean @@ -3,8 +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.Algebra.Order.Monoid.Unbundled.MinMax -import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop import Mathlib.Data.Finset.Image import Mathlib.Data.Multiset.Fold @@ -231,11 +229,6 @@ theorem fold_max_lt : s.fold max b f < c ↔ b < c ∧ ∀ x ∈ s, f x < c := b theorem lt_fold_max : c < s.fold max b f ↔ c < b ∨ ∃ x ∈ s, c < f x := fold_op_rel_iff_or lt_max_iff -theorem fold_max_add [Add β] [AddRightMono β] (n : WithBot β) - (s : Finset α) : (s.fold max ⊥ fun x : α => ↑(f x) + n) = s.fold max ⊥ ((↑) ∘ f) + n := by - classical - induction' s using Finset.induction_on with a s _ ih <;> simp [*, max_add_add_right] - end Order end Fold diff --git a/Mathlib/Data/Finset/Lattice/Basic.lean b/Mathlib/Data/Finset/Lattice/Basic.lean index aeb27e8cc20298..14fc97ad843717 100644 --- a/Mathlib/Data/Finset/Lattice/Basic.lean +++ b/Mathlib/Data/Finset/Lattice/Basic.lean @@ -123,9 +123,8 @@ theorem coe_union (s₁ s₂ : Finset α) : ↑(s₁ ∪ s₂) = (s₁ ∪ s₂ theorem union_subset (hs : s ⊆ u) : t ⊆ u → s ∪ t ⊆ u := sup_le <| le_iff_subset.2 hs -theorem subset_union_left {s₁ s₂ : Finset α} : s₁ ⊆ s₁ ∪ s₂ := fun _x => mem_union_left _ - -theorem subset_union_right {s₁ s₂ : Finset α} : s₂ ⊆ s₁ ∪ s₂ := fun _x => mem_union_right _ +@[simp] lemma subset_union_left : s₁ ⊆ s₁ ∪ s₂ := fun _ ↦ mem_union_left _ +@[simp] lemma subset_union_right : s₂ ⊆ s₁ ∪ s₂ := fun _ ↦ mem_union_right _ @[gcongr] theorem union_subset_union (hsu : s ⊆ u) (htv : t ⊆ v) : s ∪ t ⊆ u ∪ v := @@ -212,9 +211,8 @@ theorem mem_of_mem_inter_right {a : α} {s₁ s₂ : Finset α} (h : a ∈ s₁ theorem mem_inter_of_mem {a : α} {s₁ s₂ : Finset α} : a ∈ s₁ → a ∈ s₂ → a ∈ s₁ ∩ s₂ := and_imp.1 mem_inter.2 -theorem inter_subset_left {s₁ s₂ : Finset α} : s₁ ∩ s₂ ⊆ s₁ := fun _a => mem_of_mem_inter_left - -theorem inter_subset_right {s₁ s₂ : Finset α} : s₁ ∩ s₂ ⊆ s₂ := fun _a => mem_of_mem_inter_right +@[simp] lemma inter_subset_left : s₁ ∩ s₂ ⊆ s₁ := fun _ ↦ mem_of_mem_inter_left +@[simp] lemma inter_subset_right : s₁ ∩ s₂ ⊆ s₂ := fun _ ↦ mem_of_mem_inter_right theorem subset_inter {s₁ s₂ u : Finset α} : s₁ ⊆ s₂ → s₁ ⊆ u → s₁ ⊆ s₂ ∩ u := by simp +contextual [subset_iff, mem_inter] diff --git a/Mathlib/Data/Finset/Lattice/Fold.lean b/Mathlib/Data/Finset/Lattice/Fold.lean index 4c0a9c4e8b587e..404b2ac9105b33 100644 --- a/Mathlib/Data/Finset/Lattice/Fold.lean +++ b/Mathlib/Data/Finset/Lattice/Fold.lean @@ -3,7 +3,6 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Algebra.Order.Monoid.Unbundled.Pow import Mathlib.Data.Finset.Fold import Mathlib.Data.Finset.Pi import Mathlib.Data.Finset.Prod @@ -819,13 +818,6 @@ 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' {α β : Type*} [AddMonoid β] [LinearOrder β] - [AddLeftMono β] [AddRightMono β] - {s : Finset α} (hs : s.Nonempty) (f : α → β) (n : ℕ) : - s.sup' hs (fun a => n • f a) = n • s.sup' hs f := - let ns : SupHom β β := { toFun := (n • ·), map_sup' := fun _ _ => (nsmul_right_mono n).map_max } - (map_finset_sup' ns hs _).symm - /-- To rewrite from right to left, use `Finset.sup'_comp_eq_image`. -/ @[simp] theorem sup'_image [DecidableEq β] {s : Finset γ} {f : γ → β} (hs : (s.image f).Nonempty) @@ -857,6 +849,11 @@ lemma sup'_comp_eq_map {s : Finset γ} {f : γ ↪ β} (g : β → α) (hs : s.N theorem sup'_mono {s₁ s₂ : Finset β} (h : s₁ ⊆ s₂) (h₁ : s₁.Nonempty) : s₁.sup' h₁ f ≤ s₂.sup' (h₁.mono h) f := Finset.sup'_le h₁ _ (fun _ hb => le_sup' _ (h hb)) + +@[gcongr] +lemma sup'_mono_fun {hs : s.Nonempty} {f g : β → α} (h : ∀ b ∈ s, f b ≤ g b) : + s.sup' hs f ≤ s.sup' hs g := sup'_le _ _ fun b hb ↦ (h b hb).trans (le_sup' _ hb) + end Sup' section Inf' @@ -974,13 +971,6 @@ 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' {α β : Type*} [AddMonoid β] [LinearOrder β] - [AddLeftMono β] [AddRightMono β] - {s : Finset α} (hs : s.Nonempty) (f : α → β) (n : ℕ) : - s.inf' hs (fun a => n • f a) = n • s.inf' hs f := - let ns : InfHom β β := { toFun := (n • ·), map_inf' := fun _ _ => (nsmul_right_mono n).map_min } - (map_finset_inf' ns hs _).symm - /-- To rewrite from right to left, use `Finset.inf'_comp_eq_image`. -/ @[simp] theorem inf'_image [DecidableEq β] {s : Finset γ} {f : γ → β} (hs : (s.image f).Nonempty) diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index 7ac40e922fd7bf..be9894c31daf0a 100644 --- a/Mathlib/Data/Finsupp/Defs.lean +++ b/Mathlib/Data/Finsupp/Defs.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Group.Indicator import Mathlib.Algebra.Group.Submonoid.Basic import Mathlib.Data.Finset.Max import Mathlib.Data.Set.Finite.Basic +import Mathlib.Algebra.Group.TypeTags.Hom /-! # Type of functions with finite support diff --git a/Mathlib/Data/Finsupp/Fin.lean b/Mathlib/Data/Finsupp/Fin.lean index b75198493ebe5d..4e7868d955fcf2 100644 --- a/Mathlib/Data/Finsupp/Fin.lean +++ b/Mathlib/Data/Finsupp/Fin.lean @@ -17,6 +17,7 @@ In this context, we prove some usual properties of `tail` and `cons`, analogous `Data.Fin.Tuple.Basic`. -/ +open Function noncomputable section @@ -86,4 +87,8 @@ lemma cons_support : (s.cons y).support ⊆ insert 0 (s.support.map (Fin.succEmb rintro i rfl simpa [Finsupp.mem_support_iff] using hi +lemma cons_right_injective {n : ℕ} {M : Type*} [Zero M] (y : M) : + Injective (Finsupp.cons y : (Fin n →₀ M) → Fin (n + 1) →₀ M) := + (equivFunOnFinite.symm.injective.comp ((Fin.cons_right_injective _).comp DFunLike.coe_injective)) + end Finsupp diff --git a/Mathlib/Data/Finsupp/MonomialOrder.lean b/Mathlib/Data/Finsupp/MonomialOrder.lean new file mode 100644 index 00000000000000..431fcb7d3ce342 --- /dev/null +++ b/Mathlib/Data/Finsupp/MonomialOrder.lean @@ -0,0 +1,156 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ +import Mathlib.Data.Finsupp.Lex +import Mathlib.Data.Finsupp.WellFounded +import Mathlib.Data.List.TFAE + +/-! # Monomial orders + +## Monomial orders + +A *monomial order* is well ordering relation on a type of the form `σ →₀ ℕ` which +is compatible with addition and for which `0` is the smallest element. +Since several monomial orders may have to be used simultaneously, one cannot +get them as instances. +In this formalization, they are presented as a structure `MonomialOrder` which encapsulates +`MonomialOrder.toSyn`, an additive and monotone isomorphism to a linearly ordered cancellative +additive commutative monoid. +The entry `MonomialOrder.wf` asserts that `MonomialOrder.syn` is well founded. + +The terminology comes from commutative algebra and algebraic geometry, especially Gröbner bases, +where `c : σ →₀ ℕ` are exponents of monomials. + +Given a monomial order `m : MonomialOrder σ`, we provide the notation +`c ≼[m] d` and `c ≺[m] d` to compare `c d : σ →₀ ℕ` with respect to `m`. +It is activated using `open scoped MonomialOrder`. + +## Examples + +Commutative algebra defines many monomial orders, with different usefulness ranges. +In this file, we provide the basic example of lexicographic ordering. +For the graded lexicographic ordering, see `Mathlib/Data/Finsupp/DegLex.lean` + +* `MonomialOrder.lex` : the lexicographic ordering on `σ →₀ ℕ`. +For this, `σ` needs to be embedded with an ordering relation which satisfies `WellFoundedGT σ`. +(This last property is automatic when `σ` is finite). + +The type synonym is `Lex (σ →₀ ℕ)` and the two lemmas `MonomialOrder.lex_le_iff` +and `MonomialOrder.lex_lt_iff` rewrite the ordering as comparisons in the type `Lex (σ →₀ ℕ)`. + +## References + +* [Cox, Little and O'Shea, *Ideals, varieties, and algorithms*][coxlittleoshea1997] +* [Becker and Weispfenning, *Gröbner bases*][Becker-Weispfenning1993] + +## Note + +In algebraic geometry, when the finitely many variables are indexed by integers, +it is customary to order them using the opposite order : `MvPolynomial.X 0 > MvPolynomial.X 1 > … ` + +-/ + +/-- Monomial orders : equivalence of `σ →₀ ℕ` with a well ordered type -/ +structure MonomialOrder (σ : Type*) where + /-- The synonym type -/ + syn : Type* + /-- `syn` is a linearly ordered cancellative additive commutative monoid -/ + locacm : LinearOrderedCancelAddCommMonoid syn := by infer_instance + /-- the additive equivalence from `σ →₀ ℕ` to `syn` -/ + toSyn : (σ →₀ ℕ) ≃+ syn + /-- `toSyn` is monotone -/ + toSyn_monotone : Monotone toSyn + /-- `syn` is a well ordering -/ + wf : WellFoundedLT syn := by infer_instance + +attribute [instance] MonomialOrder.locacm MonomialOrder.wf + +namespace MonomialOrder + +variable {σ : Type*} (m : MonomialOrder σ) + +lemma le_add_right (a b : σ →₀ ℕ) : + m.toSyn a ≤ m.toSyn a + m.toSyn b := by + rw [← map_add] + exact m.toSyn_monotone le_self_add + +instance orderBot : OrderBot (m.syn) where + bot := 0 + bot_le a := by + have := m.le_add_right 0 (m.toSyn.symm a) + simp [map_add, zero_add] at this + exact this + +@[simp] +theorem bot_eq_zero : (⊥ : m.syn) = 0 := rfl + +theorem eq_zero_iff {a : m.syn} : a = 0 ↔ a ≤ 0 := eq_bot_iff + +lemma toSyn_strictMono : StrictMono (m.toSyn) := by + apply m.toSyn_monotone.strictMono_of_injective m.toSyn.injective + +/-- Given a monomial order, notation for the corresponding strict order relation on `σ →₀ ℕ` -/ +scoped +notation:25 c "≺[" m:25 "]" d:25 => (MonomialOrder.toSyn m c < MonomialOrder.toSyn m d) + +/-- Given a monomial order, notation for the corresponding order relation on `σ →₀ ℕ` -/ +scoped +notation:25 c "≼[" m:25 "]" d:25 => (MonomialOrder.toSyn m c ≤ MonomialOrder.toSyn m d) + +end MonomialOrder + +section Lex + +open Finsupp + +open scoped MonomialOrder + +-- The linear order on `Finsupp`s obtained by the lexicographic ordering. -/ +noncomputable instance {α N : Type*} [LinearOrder α] [OrderedCancelAddCommMonoid N] : + OrderedCancelAddCommMonoid (Lex (α →₀ N)) where + le_of_add_le_add_left a b c h := by simpa only [add_le_add_iff_left] using h + add_le_add_left a b h c := by simpa only [add_le_add_iff_left] using h + +theorem Finsupp.lex_lt_iff {α N : Type*} [LinearOrder α] [LinearOrder N] [Zero N] + {a b : Lex (α →₀ N)} : + a < b ↔ ∃ i, (∀ j, j< i → ofLex a j = ofLex b j) ∧ ofLex a i < ofLex b i := + Finsupp.lex_def + +theorem Finsupp.lex_le_iff {α N : Type*} [LinearOrder α] [LinearOrder N] [Zero N] + {a b : Lex (α →₀ N)} : + a ≤ b ↔ a = b ∨ ∃ i, (∀ j, j< i → ofLex a j = ofLex b j) ∧ ofLex a i < ofLex b i := by + rw [le_iff_eq_or_lt, Finsupp.lex_lt_iff] + +/-- for the lexicographic ordering, X 0 * X 1 < X 0 ^ 2 -/ +example : toLex (Finsupp.single 0 2) > toLex (Finsupp.single 0 1 + Finsupp.single 1 1) := by + use 0; simp + +/-- for the lexicographic ordering, X 1 < X 0 -/ +example : toLex (Finsupp.single 1 1) < toLex (Finsupp.single 0 1) := by + use 0; simp + +/-- for the lexicographic ordering, X 1 < X 0 ^ 2 -/ +example : toLex (Finsupp.single 1 1) < toLex (Finsupp.single 0 2) := by + use 0; simp + + +variable {σ : Type*} [LinearOrder σ] + +/-- The lexicographic order on `σ →₀ ℕ`, as a `MonomialOrder` -/ +noncomputable def MonomialOrder.lex [WellFoundedGT σ] : + MonomialOrder σ where + syn := Lex (σ →₀ ℕ) + toSyn := + { toEquiv := toLex + map_add' := toLex_add } + toSyn_monotone := Finsupp.toLex_monotone + +theorem MonomialOrder.lex_le_iff [WellFoundedGT σ] {c d : σ →₀ ℕ} : + c ≼[lex] d ↔ toLex c ≤ toLex d := Iff.rfl + +theorem MonomialOrder.lex_lt_iff [WellFoundedGT σ] {c d : σ →₀ ℕ} : + c ≺[lex] d ↔ toLex c < toLex d := Iff.rfl + +end Lex diff --git a/Mathlib/Data/Finsupp/Pointwise.lean b/Mathlib/Data/Finsupp/Pointwise.lean index 059bf76ad5eed8..04b6b2a36e9d5e 100644 --- a/Mathlib/Data/Finsupp/Pointwise.lean +++ b/Mathlib/Data/Finsupp/Pointwise.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Ring.InjSurj import Mathlib.Algebra.Ring.Pi import Mathlib.Data.Finsupp.Defs diff --git a/Mathlib/Data/Fintype/Basic.lean b/Mathlib/Data/Fintype/Basic.lean index 8c7c59209f26dd..5bcb08e453e9cb 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro -/ import Mathlib.Data.Finset.Image import Mathlib.Data.List.FinRange +import Mathlib.Data.Finite.Defs /-! # Finite types @@ -139,7 +140,7 @@ theorem codisjoint_left : Codisjoint s t ↔ ∀ ⦃a⦄, a ∉ s → a ∈ t := classical simp [codisjoint_iff, eq_univ_iff_forall, or_iff_not_imp_left] theorem codisjoint_right : Codisjoint s t ↔ ∀ ⦃a⦄, a ∉ t → a ∈ s := - Codisjoint_comm.trans codisjoint_left + codisjoint_comm.trans codisjoint_left instance booleanAlgebra [DecidableEq α] : BooleanAlgebra (Finset α) := GeneralizedBooleanAlgebra.toBooleanAlgebra @@ -400,6 +401,11 @@ instance decidableEqEquivFintype [DecidableEq β] [Fintype α] : DecidableEq (α instance decidableEqEmbeddingFintype [DecidableEq β] [Fintype α] : DecidableEq (α ↪ β) := fun a b => decidable_of_iff ((a : α → β) = b) Function.Embedding.coe_injective.eq_iff +@[to_additive] +instance decidableEqMulEquivFintype {α β : Type*} [DecidableEq β] [Fintype α] [Mul α] [Mul β] : + DecidableEq (α ≃* β) := + fun a b => decidable_of_iff ((a : α → β) = b) (Injective.eq_iff DFunLike.coe_injective) + end BundledHoms instance decidableInjectiveFintype [DecidableEq α] [DecidableEq β] [Fintype α] : diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index dc1e60e25f55da..59e57330eb779d 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -841,6 +841,13 @@ instance (priority := 100) to_wellFoundedGT [Preorder α] : WellFoundedGT α := end Finite +-- Shortcut instances to make sure those are found even in the presence of other instances +-- See https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/WellFoundedLT.20Prop.20is.20not.20found.20when.20importing.20too.20much +instance Bool.instWellFoundedLT : WellFoundedLT Bool := inferInstance +instance Bool.instWellFoundedGT : WellFoundedGT Bool := inferInstance +instance Prop.instWellFoundedLT : WellFoundedLT Prop := inferInstance +instance Prop.instWellFoundedGT : WellFoundedGT Prop := inferInstance + -- @[nolint fintype_finite] -- Porting note: do we need this? protected theorem Fintype.false [Infinite α] (_h : Fintype α) : False := not_finite α diff --git a/Mathlib/Data/Fintype/Perm.lean b/Mathlib/Data/Fintype/Perm.lean index 4a354e6071e5f8..0c2dc9cbbd6df8 100644 --- a/Mathlib/Data/Fintype/Perm.lean +++ b/Mathlib/Data/Fintype/Perm.lean @@ -140,7 +140,7 @@ theorem card_perms_of_finset : ∀ s : Finset α, #(permsOfFinset s) = (#s)! := def fintypePerm [Fintype α] : Fintype (Perm α) := ⟨permsOfFinset (@Finset.univ α _), by simp [mem_perms_of_finset_iff]⟩ -instance equivFintype [Fintype α] [Fintype β] : Fintype (α ≃ β) := +instance Equiv.instFintype [Fintype α] [Fintype β] : Fintype (α ≃ β) := if h : Fintype.card β = Fintype.card α then Trunc.recOnSubsingleton (Fintype.truncEquivFin α) fun eα => Trunc.recOnSubsingleton (Fintype.truncEquivFin β) fun eβ => @@ -148,8 +148,18 @@ instance equivFintype [Fintype α] [Fintype β] : Fintype (α ≃ β) := (equivCongr (Equiv.refl α) (eα.trans (Eq.recOn h eβ.symm)) : α ≃ α ≃ (α ≃ β)) else ⟨∅, fun x => False.elim (h (Fintype.card_eq.2 ⟨x.symm⟩))⟩ +@[deprecated (since := "2024-11-19")] alias equivFintype := Equiv.instFintype + +@[to_additive] +instance MulEquiv.instFintype + {α β : Type*} [Mul α] [Mul β] [DecidableEq α] [DecidableEq β] [Fintype α] [Fintype β] : + Fintype (α ≃* β) where + elems := Equiv.instFintype.elems.filterMap + (fun e => if h : ∀ a b : α, e (a * b) = e a * e b then (⟨e, h⟩ : α ≃* β) else none) (by aesop) + complete me := (Finset.mem_filterMap ..).mpr ⟨me.toEquiv, Finset.mem_univ _, by {simp; rfl}⟩ + theorem Fintype.card_perm [Fintype α] : Fintype.card (Perm α) = (Fintype.card α)! := - Subsingleton.elim (@fintypePerm α _ _) (@equivFintype α α _ _ _ _) ▸ card_perms_of_finset _ + Subsingleton.elim (@fintypePerm α _ _) (@Equiv.instFintype α α _ _ _ _) ▸ card_perms_of_finset _ theorem Fintype.card_equiv [Fintype α] [Fintype β] (e : α ≃ β) : Fintype.card (α ≃ β) = (Fintype.card α)! := diff --git a/Mathlib/Data/Int/AbsoluteValue.lean b/Mathlib/Data/Int/AbsoluteValue.lean index f061b555444e8b..f37f06dffef6aa 100644 --- a/Mathlib/Data/Int/AbsoluteValue.lean +++ b/Mathlib/Data/Int/AbsoluteValue.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.Algebra.GroupWithZero.Action.Units -import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Order.AbsoluteValue import Mathlib.Algebra.Ring.Int.Units import Mathlib.Data.Int.Cast.Lemmas diff --git a/Mathlib/Data/Int/Cast/Lemmas.lean b/Mathlib/Data/Int/Cast/Lemmas.lean index edf29c1a81e492..d887d52523d54c 100644 --- a/Mathlib/Data/Int/Cast/Lemmas.lean +++ b/Mathlib/Data/Int/Cast/Lemmas.lean @@ -295,14 +295,14 @@ lemma zmultiplesHom_apply (x : β) (n : ℤ) : zmultiplesHom β x n = n • x := lemma zmultiplesHom_symm_apply (f : ℤ →+ β) : (zmultiplesHom β).symm f = f 1 := rfl @[to_additive existing (attr := simp)] -lemma zpowersHom_apply (x : α) (n : Multiplicative ℤ) : zpowersHom α x n = x ^ toAdd n := rfl +lemma zpowersHom_apply (x : α) (n : Multiplicative ℤ) : zpowersHom α x n = x ^ n.toAdd := rfl @[to_additive existing (attr := simp)] lemma zpowersHom_symm_apply (f : Multiplicative ℤ →* α) : (zpowersHom α).symm f = f (ofAdd 1) := rfl lemma MonoidHom.apply_mint (f : Multiplicative ℤ →* α) (n : Multiplicative ℤ) : - f n = f (ofAdd 1) ^ (toAdd n) := by + f n = f (ofAdd 1) ^ n.toAdd := by rw [← zpowersHom_symm_apply, ← zpowersHom_apply, Equiv.apply_symm_apply] lemma AddMonoidHom.apply_int (f : ℤ →+ β) (n : ℤ) : f n = n • f 1 := by @@ -324,7 +324,7 @@ def zpowersMulHom : α ≃* (Multiplicative ℤ →* α) := variable {α} @[simp] -lemma zpowersMulHom_apply (x : α) (n : Multiplicative ℤ) : zpowersMulHom α x n = x ^ toAdd n := rfl +lemma zpowersMulHom_apply (x : α) (n : Multiplicative ℤ) : zpowersMulHom α x n = x ^ n.toAdd := rfl @[simp] lemma zpowersMulHom_symm_apply (f : Multiplicative ℤ →* α) : diff --git a/Mathlib/Data/Int/Defs.lean b/Mathlib/Data/Int/Defs.lean index 6bf06c9ff023ab..9fd2c581ce8e9c 100644 --- a/Mathlib/Data/Int/Defs.lean +++ b/Mathlib/Data/Int/Defs.lean @@ -114,7 +114,8 @@ lemma natCast_ne_zero_iff_pos {n : ℕ} : (n : ℤ) ≠ 0 ↔ 0 < n := by omega lemma natCast_succ_pos (n : ℕ) : 0 < (n.succ : ℤ) := natCast_pos.2 n.succ_pos -@[simp] lemma natCast_nonpos_iff {n : ℕ} : (n : ℤ) ≤ 0 ↔ n = 0 := by omega +-- We want to use this lemma earlier than the lemmas simp can prove it with +@[simp, nolint simpNF] lemma natCast_nonpos_iff {n : ℕ} : (n : ℤ) ≤ 0 ↔ n = 0 := by omega lemma natCast_nonneg (n : ℕ) : 0 ≤ (n : ℤ) := ofNat_le.2 (Nat.zero_le _) diff --git a/Mathlib/Data/Int/GCD.lean b/Mathlib/Data/Int/GCD.lean index eccc02d840c40e..e6b7b6ec9f4e80 100644 --- a/Mathlib/Data/Int/GCD.lean +++ b/Mathlib/Data/Int/GCD.lean @@ -7,8 +7,8 @@ import Mathlib.Algebra.Group.Int import Mathlib.Algebra.GroupWithZero.Semiconj import Mathlib.Algebra.Group.Commute.Units import Mathlib.Data.Nat.GCD.Basic -import Mathlib.Order.Lattice import Mathlib.Data.Set.Operations +import Mathlib.Order.Basic import Mathlib.Order.Bounds.Defs /-! diff --git a/Mathlib/Data/Int/Interval.lean b/Mathlib/Data/Int/Interval.lean index a93f1ff49aa84d..cd94ea340d1c55 100644 --- a/Mathlib/Data/Int/Interval.lean +++ b/Mathlib/Data/Int/Interval.lean @@ -129,6 +129,11 @@ theorem card_Ioc_of_le (h : a ≤ b) : (#(Ioc a b) : ℤ) = b - a := by theorem card_Ioo_of_lt (h : a < b) : (#(Ioo a b) : ℤ) = b - a - 1 := by rw [card_Ioo, sub_sub, toNat_sub_of_le h] +theorem Icc_eq_pair : Finset.Icc a (a + 1) = {a, a + 1} := by + ext + simp + omega + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it theorem card_fintype_Icc : Fintype.card (Set.Icc a b) = (b + 1 - a).toNat := by rw [← card_Icc, Fintype.card_ofFinset] diff --git a/Mathlib/Data/Int/Log.lean b/Mathlib/Data/Int/Log.lean index e6f5f9f4571594..4d5f3c0e387221 100644 --- a/Mathlib/Data/Int/Log.lean +++ b/Mathlib/Data/Int/Log.lean @@ -46,6 +46,7 @@ def digits (b : ℕ) (q : ℚ) (n : ℕ) : ℕ := * `Int.neg_log_inv_eq_clog`, `Int.neg_clog_inv_eq_log`: the link between the two definitions. -/ +assert_not_exists Finset variable {R : Type*} [LinearOrderedSemifield R] [FloorSemiring R] diff --git a/Mathlib/Data/Int/WithZero.lean b/Mathlib/Data/Int/WithZero.lean index 4a74559dbbf983..de4c3c41435388 100644 --- a/Mathlib/Data/Int/WithZero.lean +++ b/Mathlib/Data/Int/WithZero.lean @@ -14,7 +14,7 @@ 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`. + `x ↦ e^((WithZero.unzero hx).toAdd)` when `x ≠ 0`, for a nonzero `e : ℝ≥0`. ## Main Results @@ -26,6 +26,8 @@ the morphism `WithZeroMultInt.toNNReal`. WithZero, multiplicative, nnreal -/ +assert_not_exists Finset + noncomputable section open scoped NNReal @@ -35,9 +37,9 @@ 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`. -/ + `x ↦ e^(WithZero.unzero hx).toAdd` when `x ≠ 0` as a `MonoidWithZeroHom`. -/ def toNNReal {e : ℝ≥0} (he : e ≠ 0) : ℤₘ₀ →*₀ ℝ≥0 where - toFun := fun x ↦ if hx : x = 0 then 0 else e ^ Multiplicative.toAdd (WithZero.unzero hx) + toFun := fun x ↦ if hx : x = 0 then 0 else e ^ (WithZero.unzero hx).toAdd map_zero' := rfl map_one' := by simp only [dif_neg one_ne_zero] @@ -61,7 +63,7 @@ theorem toNNReal_pos_apply {e : ℝ≥0} (he : e ≠ 0) {x : ℤₘ₀} (hx : x split_ifs; rfl theorem toNNReal_neg_apply {e : ℝ≥0} (he : e ≠ 0) {x : ℤₘ₀} (hx : x ≠ 0) : - toNNReal he x = e ^ Multiplicative.toAdd (WithZero.unzero hx) := by + toNNReal he x = e ^ (WithZero.unzero hx).toAdd := by simp only [toNNReal, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk] split_ifs · tauto diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index fac7238168886c..3f51c9f665d12c 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -34,7 +34,7 @@ universe u v w variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : List α} /-- `≤` implies not `>` for lists. -/ -@[deprecated (since := "2024-07-27")] +@[deprecated "No deprecation message was provided." (since := "2024-07-27")] theorem le_eq_not_gt [LT α] : ∀ l₁ l₂ : List α, (l₁ ≤ l₂) = ¬l₂ < l₁ := fun _ _ => rfl -- Porting note: Delete this attribute @@ -496,7 +496,7 @@ theorem get_tail (l : List α) (i) (h : i < l.tail.length) l.tail.get ⟨i, h⟩ = l.get ⟨i + 1, h'⟩ := by cases l <;> [cases h; rfl] -@[deprecated (since := "2024-08-22")] +@[deprecated "No deprecation message was provided." (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⟩ := @@ -627,7 +627,7 @@ 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 _ -@[deprecated (since := "2024-04-07")] +@[deprecated "No deprecation message was provided." (since := "2024-04-07")] theorem sublist_of_cons_sublist_cons {a} (h : a :: l₁ <+ a :: l₂) : l₁ <+ l₂ := h.of_cons_cons @[deprecated (since := "2024-04-07")] alias cons_sublist_cons_iff := cons_sublist_cons @@ -737,7 +737,6 @@ end IndexOf /-! ### nth element -/ section deprecated -set_option linter.deprecated false @[simp] theorem getElem?_length (l : List α) : l[l.length]? = none := getElem?_len_le le_rfl @@ -754,19 +753,20 @@ theorem getElem_map_rev (f : α → β) {l} {n : Nat} {h : n < l.length} : /-- A version of `get_map` that can be used for rewriting. -/ @[deprecated getElem_map_rev (since := "2024-06-12")] 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 _) + f (get l n) = get (map f l) ⟨n.1, (l.length_map f).symm ▸ n.2⟩ := Eq.symm (getElem_map _) 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 + (getLast_eq_getElem l _).symm 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] + rw [drop_eq_getElem_cons h, take, take] + simp theorem ext_get?' {l₁ l₂ : List α} (h' : ∀ n < max l₁.length l₂.length, l₁.get? n = l₂.get? n) : l₁ = l₂ := by - apply ext + apply ext_get? intro n rcases Nat.lt_or_ge n <| max l₁.length l₂.length with hn | hn · exact h' n hn @@ -831,6 +831,8 @@ theorem get_reverse (l : List α) (i : Nat) (h1 h2) : dsimp omega +set_option linter.deprecated false + theorem get_reverse' (l : List α) (n) (hn') : l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by rw [eq_comm] @@ -2279,7 +2281,7 @@ theorem length_dropSlice_lt (i j : ℕ) (hj : 0 < j) (xs : List α) (hi : i < xs simp; omega set_option linter.deprecated false in -@[deprecated (since := "2024-07-25")] +@[deprecated "No deprecation message was provided." (since := "2024-07-25")] theorem sizeOf_dropSlice_lt [SizeOf α] (i j : ℕ) (hj : 0 < j) (xs : List α) (hi : i < xs.length) : SizeOf.sizeOf (List.dropSlice i j xs) < SizeOf.sizeOf xs := by induction xs generalizing i j hj with diff --git a/Mathlib/Data/List/FinRange.lean b/Mathlib/Data/List/FinRange.lean index 412a600d7fbdb7..80f4cc196b69d8 100644 --- a/Mathlib/Data/List/FinRange.lean +++ b/Mathlib/Data/List/FinRange.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kenny Lau, Kim Morrison, Alex Keizer -/ import Mathlib.Data.List.OfFn -import Mathlib.Data.List.Range import Batteries.Data.List.Perm +import Mathlib.Data.List.Nodup /-! # Lists of elements of `Fin n` @@ -21,6 +21,63 @@ namespace List variable {α : Type u} + +theorem finRange_eq_pmap_range (n : ℕ) : finRange n = (range n).pmap Fin.mk (by simp) := by + apply List.ext_getElem <;> simp [finRange] + +@[simp] +theorem finRange_zero : finRange 0 = [] := rfl + +@[simp] +theorem mem_finRange {n : ℕ} (a : Fin n) : a ∈ finRange n := by + rw [finRange_eq_pmap_range] + exact mem_pmap.2 + ⟨a.1, mem_range.2 a.2, by + cases a + rfl⟩ + +theorem nodup_finRange (n : ℕ) : (finRange n).Nodup := by + rw [finRange_eq_pmap_range] + exact (Pairwise.pmap (nodup_range n) _) fun _ _ _ _ => @Fin.ne_of_val_ne _ ⟨_, _⟩ ⟨_, _⟩ + +@[simp] +theorem length_finRange (n : ℕ) : (finRange n).length = n := by + simp [finRange] + +@[simp] +theorem finRange_eq_nil {n : ℕ} : finRange n = [] ↔ n = 0 := by + rw [← length_eq_zero, length_finRange] + +theorem pairwise_lt_finRange (n : ℕ) : Pairwise (· < ·) (finRange n) := by + rw [finRange_eq_pmap_range] + exact (List.pairwise_lt_range n).pmap (by simp) (by simp) + +theorem pairwise_le_finRange (n : ℕ) : Pairwise (· ≤ ·) (finRange n) := by + rw [finRange_eq_pmap_range] + exact (List.pairwise_le_range n).pmap (by simp) (by simp) + +@[simp] +theorem getElem_finRange {n : ℕ} {i : ℕ} (h) : + (finRange n)[i] = ⟨i, length_finRange n ▸ h⟩ := by + simp [finRange, getElem_range, getElem_pmap] + +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/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_finRange := get_finRange + +@[simp] +theorem finRange_map_get (l : List α) : (finRange l.length).map l.get = l := + List.ext_get (by simp) (by simp) + +@[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 + have h₂ : (finRange k).get ⟨i, by simp⟩ = i := get_finRange _ + simpa using (Nodup.get_inj_iff (nodup_finRange k)).mp (Eq.trans h₁ h₂.symm) + @[simp] theorem map_coe_finRange (n : ℕ) : ((finRange n) : List (Fin n)).map (Fin.val) = List.range n := by sorry diff --git a/Mathlib/Data/List/Flatten.lean b/Mathlib/Data/List/Flatten.lean index f6fbc8e3044fc3..797ba9dc5c2976 100644 --- a/Mathlib/Data/List/Flatten.lean +++ b/Mathlib/Data/List/Flatten.lean @@ -158,7 +158,8 @@ theorem append_flatten_map_append (L : List (List α)) (x : List α) : @[deprecated (since := "2024-10-15")] alias append_join_map_append := append_flatten_map_append -@[deprecated (since := "2024-08-15")] theorem sublist_join {l} {L : List (List α)} (h : l ∈ L) : +@[deprecated "No deprecation message was provided." (since := "2024-08-15")] +theorem sublist_join {l} {L : List (List α)} (h : l ∈ L) : l <+ L.flatten := sublist_flatten_of_mem h diff --git a/Mathlib/Data/List/Indexes.lean b/Mathlib/Data/List/Indexes.lean index a1b935a65e0cc1..fdbe9168bfa47b 100644 --- a/Mathlib/Data/List/Indexes.lean +++ b/Mathlib/Data/List/Indexes.lean @@ -89,7 +89,7 @@ theorem mapIdx_eq_ofFn (l : List α) (f : ℕ → α → β) : section deprecated /-- Lean3 `map_with_index` helper function -/ -@[deprecated (since := "2024-08-15")] +@[deprecated "No deprecation message was provided." (since := "2024-08-15")] protected def oldMapIdxCore (f : ℕ → α → β) : ℕ → List α → List β | _, [] => [] | k, a :: as => f k a :: List.oldMapIdxCore f (k + 1) as @@ -97,12 +97,12 @@ protected def oldMapIdxCore (f : ℕ → α → β) : ℕ → List α → List 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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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 @@ -111,7 +111,7 @@ protected theorem oldMapIdxCore_eq (l : List α) (f : ℕ → α → β) (n : 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")] +@[deprecated "No deprecation message was provided." (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 @@ -139,7 +139,7 @@ protected theorem oldMapIdxCore_append : ∀ (f : ℕ → α → β) (n : ℕ) ( rw [Nat.add_assoc]; simp only [Nat.add_comm] set_option linter.deprecated false in -@[deprecated (since := "2024-08-15")] +@[deprecated "No deprecation message was provided." (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 @@ -148,7 +148,7 @@ protected theorem oldMapIdx_append : ∀ (f : ℕ → α → β) (l : List α) ( simp only [Nat.zero_add]; rfl set_option linter.deprecated false in -@[deprecated (since := "2024-08-15")] +@[deprecated "No deprecation message was provided." (since := "2024-08-15")] protected theorem new_def_eq_old_def : ∀ (f : ℕ → α → β) (l : List α), l.mapIdx f = List.oldMapIdx f l := by intro f diff --git a/Mathlib/Data/List/Lex.lean b/Mathlib/Data/List/Lex.lean index fef097d96a69f9..69566d9aa5d915 100644 --- a/Mathlib/Data/List/Lex.lean +++ b/Mathlib/Data/List/Lex.lean @@ -99,7 +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")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance isStrictTotalOrder (r : α → α → Prop) [IsStrictTotalOrder α r] : IsStrictTotalOrder (List α) (Lex r) := { isStrictWeakOrder_of_isOrderConnected with } diff --git a/Mathlib/Data/List/Pairwise.lean b/Mathlib/Data/List/Pairwise.lean index 4682916a610a01..be4f87bb84be68 100644 --- a/Mathlib/Data/List/Pairwise.lean +++ b/Mathlib/Data/List/Pairwise.lean @@ -50,7 +50,8 @@ theorem Pairwise.set_pairwise (hl : Pairwise R l) (hr : Symmetric R) : { x | x hl.forall hr -- Porting note: Duplicate of `pairwise_map` but with `f` explicit. -@[deprecated (since := "2024-02-25")] theorem pairwise_map' (f : β → α) : +@[deprecated "No deprecation message was provided." (since := "2024-02-25")] +theorem pairwise_map' (f : β → α) : ∀ {l : List β}, Pairwise R (map f l) ↔ Pairwise (R on f) l | [] => by simp only [map, Pairwise.nil] | b :: l => by diff --git a/Mathlib/Data/List/Permutation.lean b/Mathlib/Data/List/Permutation.lean index 2ce7b4ce525f3e..3e0073e3e20494 100644 --- a/Mathlib/Data/List/Permutation.lean +++ b/Mathlib/Data/List/Permutation.lean @@ -419,7 +419,7 @@ theorem length_permutations'Aux (s : List α) (x : α) : · simp · simpa using IH -@[deprecated (since := "2024-06-12")] +@[deprecated "No deprecation message was provided." (since := "2024-06-12")] theorem permutations'Aux_get_zero (s : List α) (x : α) (hn : 0 < length (permutations'Aux x s) := (by simp)) : (permutations'Aux x s).get ⟨0, hn⟩ = x :: s := diff --git a/Mathlib/Data/List/Range.lean b/Mathlib/Data/List/Range.lean index bd25ff2ae95385..b04ae807f88c87 100644 --- a/Mathlib/Data/List/Range.lean +++ b/Mathlib/Data/List/Range.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Kenny Lau, Kim Morrison -/ import Batteries.Data.List.FinRange import Mathlib.Data.List.Chain -import Mathlib.Data.List.Nodup /-! # Ranges of naturals as lists @@ -67,17 +66,7 @@ theorem get_finRange {n : ℕ} {i : ℕ} (h) : @[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) - -@[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 - have h₂ : (finRange k).get ⟨i, by simp⟩ = i := get_finRange _ - simpa using (Nodup.get_inj_iff (nodup_finRange k)).mp (Eq.trans h₁ h₂.symm) section Ranges @@ -133,6 +122,7 @@ lemma ranges_flatten' : ∀ l : List ℕ, l.ranges.flatten = range (Nat.sum l) set_option linter.deprecated false in /-- Any entry of any member of `l.ranges` is strictly smaller than `Nat.sum l`. See `List.mem_mem_ranges_iff_lt_sum` for the version about `List.sum`. -/ +@[deprecated "Use `List.mem_mem_ranges_iff_lt_sum`." (since := "2024-11-18")] lemma mem_mem_ranges_iff_lt_natSum (l : List ℕ) {n : ℕ} : (∃ s ∈ l.ranges, n ∈ s) ↔ n < Nat.sum l := by rw [← mem_range, ← ranges_flatten', mem_flatten] diff --git a/Mathlib/Data/List/SplitLengths.lean b/Mathlib/Data/List/SplitLengths.lean index e41894fe16e0cc..ae9a0052291fa4 100644 --- a/Mathlib/Data/List/SplitLengths.lean +++ b/Mathlib/Data/List/SplitLengths.lean @@ -3,8 +3,8 @@ 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.Group.Nat.Basic import Mathlib.Order.MinMax -import Mathlib.Algebra.Group.Nat /-! # Splitting a list to chunks of specified lengths diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index cc89adca8c9e81..9a2c8391406a82 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Data.Nat.Choose.Basic -import Mathlib.Data.List.Range +import Mathlib.Data.List.FinRange import Mathlib.Data.List.Perm.Basic +import Mathlib.Data.List.Lex /-! # sublists diff --git a/Mathlib/Data/Matrix/Basis.lean b/Mathlib/Data/Matrix/Basis.lean index f9d9157fe86453..7c49644844bcd0 100644 --- a/Mathlib/Data/Matrix/Basis.lean +++ b/Mathlib/Data/Matrix/Basis.lean @@ -19,8 +19,6 @@ variable {R α : Type*} namespace Matrix -open Matrix - variable [DecidableEq l] [DecidableEq m] [DecidableEq n] section Zero diff --git a/Mathlib/Data/Matrix/Block.lean b/Mathlib/Data/Matrix/Block.lean index d572c642d2bcaf..cb4875d44825f0 100644 --- a/Mathlib/Data/Matrix/Block.lean +++ b/Mathlib/Data/Matrix/Block.lean @@ -40,7 +40,7 @@ dimensions. -/ @[pp_nodot] def fromBlocks (A : Matrix n l α) (B : Matrix n m α) (C : Matrix o l α) (D : Matrix o m α) : Matrix (n ⊕ o) (l ⊕ m) α := - of <| Sum.elim (fun i => Sum.elim (A i) (B i)) fun i => Sum.elim (C i) (D i) + of <| Sum.elim (fun i => Sum.elim (A i) (B i)) (fun j => Sum.elim (C j) (D j)) @[simp] theorem fromBlocks_apply₁₁ (A : Matrix n l α) (B : Matrix n m α) (C : Matrix o l α) diff --git a/Mathlib/Data/Matrix/Diagonal.lean b/Mathlib/Data/Matrix/Diagonal.lean index d9d2d31a41ec1f..6e226513da3409 100644 --- a/Mathlib/Data/Matrix/Diagonal.lean +++ b/Mathlib/Data/Matrix/Diagonal.lean @@ -3,7 +3,9 @@ Copyright (c) 2018 Ellen Arlt. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Ellen Arlt, Blair Shi, Sean Leather, Mario Carneiro, Johan Commelin, Lu-Ming Zhang -/ +import Mathlib.Data.Int.Cast.Lemmas import Mathlib.Data.Matrix.Defs +import Mathlib.Data.Nat.Cast.Basic /-! # Diagonal matrices diff --git a/Mathlib/Data/Matrix/Hadamard.lean b/Mathlib/Data/Matrix/Hadamard.lean index d94a90b94b7366..cdaa2360b95c58 100644 --- a/Mathlib/Data/Matrix/Hadamard.lean +++ b/Mathlib/Data/Matrix/Hadamard.lean @@ -34,8 +34,6 @@ variable {α m n R : Type*} namespace Matrix -open Matrix - /-- `Matrix.hadamard` defines the Hadamard product, which is the pointwise product of two matrices of the same size. -/ def hadamard [Mul α] (A : Matrix m n α) (B : Matrix m n α) : Matrix m n α := diff --git a/Mathlib/Data/Matrix/Kronecker.lean b/Mathlib/Data/Matrix/Kronecker.lean index bbbe63c6841d97..1d108492e89cf7 100644 --- a/Mathlib/Data/Matrix/Kronecker.lean +++ b/Mathlib/Data/Matrix/Kronecker.lean @@ -43,8 +43,6 @@ These require `open Kronecker`: namespace Matrix - -open Matrix open scoped RightActions variable {R α α' β β' γ γ' : Type*} diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index cebed32a1d12af..e364da53cefecc 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -3,13 +3,14 @@ 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.Algebra.Group.Nat +import Mathlib.Algebra.Group.Hom.Defs +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Algebra.Order.Sub.Unbundled.Basic +import Mathlib.Data.List.Perm.Basic +import Mathlib.Data.List.Perm.Lattice import Mathlib.Data.List.Perm.Subperm import Mathlib.Data.Set.List import Mathlib.Order.Hom.Basic -import Mathlib.Data.List.Perm.Lattice -import Mathlib.Data.List.Perm.Basic /-! # Multisets @@ -412,7 +413,7 @@ section ToList /-- Produces a list of the elements in the multiset using choice. -/ noncomputable def toList (s : Multiset α) := - s.out' + s.out @[simp, norm_cast] theorem coe_toList (s : Multiset α) : (s.toList : Multiset α) = s := @@ -1719,15 +1720,10 @@ def filter (s : Multiset α) : Multiset α := theorem filter_zero : filter p 0 = 0 := rfl -#adaptation_note -/-- -Please re-enable the linter once we moved to `nightly-2024-06-22` or later. --/ -set_option linter.deprecated false in @[congr] theorem filter_congr {p q : α → Prop} [DecidablePred p] [DecidablePred q] {s : Multiset α} : (∀ x ∈ s, p x ↔ q x) → filter p s = filter q s := - Quot.inductionOn s fun _l h => congr_arg ofList <| filter_congr' <| by simpa using h + Quot.inductionOn s fun _l h => congr_arg ofList <| List.filter_congr <| by simpa using h @[simp] theorem filter_add (s t : Multiset α) : filter p (s + t) = filter p s + filter p t := diff --git a/Mathlib/Data/NNRat/Floor.lean b/Mathlib/Data/NNRat/Floor.lean index 9fffafbea69950..02d70c2c3d1235 100644 --- a/Mathlib/Data/NNRat/Floor.lean +++ b/Mathlib/Data/NNRat/Floor.lean @@ -19,6 +19,8 @@ Note that we cannot talk about `Int.fract`, which currently only works for rings nnrat, rationals, ℚ≥0, floor -/ +assert_not_exists Finset + namespace NNRat instance : FloorSemiring ℚ≥0 where diff --git a/Mathlib/Data/NNReal/Defs.lean b/Mathlib/Data/NNReal/Defs.lean index ae12ffd52c40f0..9c117c2ed6f81c 100644 --- a/Mathlib/Data/NNReal/Defs.lean +++ b/Mathlib/Data/NNReal/Defs.lean @@ -791,13 +791,15 @@ theorem lt_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a < b / r ↔ r * a < b : theorem mul_lt_of_lt_div {a b r : ℝ≥0} (h : a < b / r) : a * r < b := (lt_div_iff₀ <| pos_iff_ne_zero.2 fun hr => False.elim <| by simp [hr] at h).1 h +@[deprecated div_le_div_of_nonneg_left (since := "2024-11-12")] theorem div_le_div_left_of_le {a b c : ℝ≥0} (c0 : c ≠ 0) (cb : c ≤ b) : a / b ≤ a / c := div_le_div_of_nonneg_left (zero_le _) c0.bot_lt cb +@[deprecated div_le_div_iff_of_pos_left (since := "2024-11-12")] nonrec theorem div_le_div_left {a b c : ℝ≥0} (a0 : 0 < a) (b0 : 0 < b) (c0 : 0 < c) : a / b ≤ a / c ↔ c ≤ b := - div_le_div_left a0 b0 c0 + div_le_div_iff_of_pos_left a0 b0 c0 theorem le_of_forall_lt_one_mul_le {x y : ℝ≥0} (h : ∀ a < 1, a * x ≤ y) : x ≤ y := le_of_forall_ge_of_dense fun a ha => by @@ -915,7 +917,7 @@ namespace Real /-- The absolute value on `ℝ` as a map to `ℝ≥0`. -/ -- Porting note (kmill): `pp_nodot` has no affect here --- unless RFC https://github.com/leanprover/lean4/issues/1910 leads to dot notation for CoeFun +-- unless RFC https://github.com/leanprover/lean4/issues/6178 leads to dot notation pp for CoeFun @[pp_nodot] def nnabs : ℝ →*₀ ℝ≥0 where toFun x := ⟨|x|, abs_nonneg x⟩ diff --git a/Mathlib/Data/NNReal/Star.lean b/Mathlib/Data/NNReal/Star.lean index c1f11b1539a4e0..47c6a75c178498 100644 --- a/Mathlib/Data/NNReal/Star.lean +++ b/Mathlib/Data/NNReal/Star.lean @@ -10,6 +10,8 @@ import Mathlib.Data.Real.Star # The non-negative real numbers are a `*`-ring, with the trivial `*`-structure -/ +assert_not_exists Finset + open scoped NNReal instance : StarRing ℝ≥0 := starRingOfComm diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index 7079602da88d92..fcc0bc2b460779 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -3,8 +3,7 @@ Copyright (c) 2022 Praneeth Kolichala. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Praneeth Kolichala -/ -import Mathlib.Algebra.Group.Basic -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Data.Nat.Defs import Mathlib.Data.Nat.BinaryRec import Mathlib.Data.List.Defs diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean index 2de92522a8e9a5..e3b32b271b9508 100644 --- a/Mathlib/Data/Nat/Bitwise.lean +++ b/Mathlib/Data/Nat/Bitwise.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Markus Himmel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel, Alex Keizer -/ -import Mathlib.Algebra.Group.Units.Basic +import Mathlib.Algebra.Group.Nat.Even import Mathlib.Algebra.NeZero import Mathlib.Algebra.Ring.Nat import Mathlib.Data.List.GetD diff --git a/Mathlib/Data/Nat/Cast/Basic.lean b/Mathlib/Data/Nat/Cast/Basic.lean index d4f2aa9e4fd081..c494b68c050670 100644 --- a/Mathlib/Data/Nat/Cast/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Basic.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Group.Even +import Mathlib.Algebra.Group.TypeTags.Hom import Mathlib.Algebra.Ring.Hom.Defs import Mathlib.Algebra.Ring.Nat @@ -157,6 +159,11 @@ theorem eq_natCast [FunLike F ℕ R] [RingHomClass F ℕ R] (f : F) : ∀ n, f n theorem map_natCast [FunLike F R S] [RingHomClass F R S] (f : F) : ∀ n : ℕ, f (n : R) = n := map_natCast' f <| map_one f +/-- This lemma is not marked `@[simp]` lemma because its `#discr_tree_key` (for the LHS) would just +be `DFunLike.coe _ _`, due to the `no_index` that https://github.com/leanprover/lean4/issues/2867 +forces us to include, and therefore it would negatively impact performance. + +If that issue is resolved, this can be marked `@[simp]`. -/ theorem map_ofNat [FunLike F R S] [RingHomClass F R S] (f : F) (n : ℕ) [Nat.AtLeastTwo n] : (f (no_index (OfNat.ofNat n)) : S) = OfNat.ofNat n := map_natCast f n @@ -220,7 +227,7 @@ lemma multiplesHom_apply (x : β) (n : ℕ) : multiplesHom β x n = n • x := r @[to_additive existing (attr := simp)] lemma powersHom_apply (x : α) (n : Multiplicative ℕ) : - powersHom α x n = x ^ Multiplicative.toAdd n := rfl + powersHom α x n = x ^ n.toAdd := rfl lemma multiplesHom_symm_apply (f : ℕ →+ β) : (multiplesHom β).symm f = f 1 := rfl @@ -229,7 +236,7 @@ lemma powersHom_symm_apply (f : Multiplicative ℕ →* α) : (powersHom α).symm f = f (Multiplicative.ofAdd 1) := rfl lemma MonoidHom.apply_mnat (f : Multiplicative ℕ →* α) (n : Multiplicative ℕ) : - f n = f (Multiplicative.ofAdd 1) ^ (Multiplicative.toAdd n) := by + f n = f (Multiplicative.ofAdd 1) ^ n.toAdd := by rw [← powersHom_symm_apply, ← powersHom_apply, Equiv.apply_symm_apply] @[ext] @@ -256,7 +263,7 @@ def powersMulHom : α ≃* (Multiplicative ℕ →* α) := @[simp] lemma multiplesAddHom_apply (x : β) (n : ℕ) : multiplesAddHom β x n = n • x := rfl @[simp] -lemma powersMulHom_apply (x : α) (n : Multiplicative ℕ) : powersMulHom α x n = x ^ toAdd n := rfl +lemma powersMulHom_apply (x : α) (n : Multiplicative ℕ) : powersMulHom α x n = x ^ n.toAdd := rfl @[simp] lemma multiplesAddHom_symm_apply (f : ℕ →+ β) : (multiplesAddHom β).symm f = f 1 := rfl diff --git a/Mathlib/Data/Nat/Cast/Order/Basic.lean b/Mathlib/Data/Nat/Cast/Order/Basic.lean index 21129456cd441f..eec03f2914acb9 100644 --- a/Mathlib/Data/Nat/Cast/Order/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Order/Basic.lean @@ -98,6 +98,8 @@ theorem cast_lt_one : (n : α) < 1 ↔ n = 0 := by @[simp, norm_cast] theorem cast_le_one : (n : α) ≤ 1 ↔ n ≤ 1 := by rw [← cast_one, cast_le] +@[simp] lemma cast_nonpos : (n : α) ≤ 0 ↔ n = 0 := by norm_cast; omega + section variable [m.AtLeastTwo] diff --git a/Mathlib/Data/Nat/Choose/Dvd.lean b/Mathlib/Data/Nat/Choose/Dvd.lean index 0272d236dd30a4..37ff1fb69906d1 100644 --- a/Mathlib/Data/Nat/Choose/Dvd.lean +++ b/Mathlib/Data/Nat/Choose/Dvd.lean @@ -13,8 +13,6 @@ import Mathlib.Data.Nat.Prime.Factorial namespace Nat -open Nat - namespace Prime variable {p a b k : ℕ} diff --git a/Mathlib/Data/Nat/Defs.lean b/Mathlib/Data/Nat/Defs.lean index 9063d971434fff..20c3db731c333b 100644 --- a/Mathlib/Data/Nat/Defs.lean +++ b/Mathlib/Data/Nat/Defs.lean @@ -72,6 +72,13 @@ instance instLinearOrder : LinearOrder ℕ where decidableLE := inferInstance decidableEq := inferInstance +-- Shortcut instances +instance : Preorder ℕ := inferInstance +instance : PartialOrder ℕ := inferInstance +instance : Min ℕ := inferInstance +instance : Max ℕ := inferInstance +instance : Ord ℕ := inferInstance + instance instNontrivial : Nontrivial ℕ := ⟨⟨0, 1, Nat.zero_ne_one⟩⟩ @[simp] theorem default_eq_zero : default = 0 := rfl @@ -1085,7 +1092,7 @@ lemma sub_mod_eq_zero_of_mod_eq (h : m % k = n % k) : (m - n) % k = 0 := by lemma one_mod_eq_one : ∀ {n : ℕ}, 1 % n = 1 ↔ n ≠ 1 | 0 | 1 | n + 2 => by simp -@[deprecated (since := "2024-08-28")] +@[deprecated "No deprecation message was provided." (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 := @@ -1161,7 +1168,6 @@ lemma mul_add_mod' (a b c : ℕ) : (a * b + c) % b = c % b := by rw [Nat.mul_com lemma mul_add_mod_of_lt (h : c < b) : (a * b + c) % b = c := by rw [Nat.mul_add_mod', Nat.mod_eq_of_lt h] -set_option linter.deprecated false in @[simp] protected theorem not_two_dvd_bit1 (n : ℕ) : ¬2 ∣ 2 * n + 1 := by omega diff --git a/Mathlib/Data/Nat/Factorization/PrimePow.lean b/Mathlib/Data/Nat/Factorization/PrimePow.lean index 3d33d3f1dbd080..be263eea0756e4 100644 --- a/Mathlib/Data/Nat/Factorization/PrimePow.lean +++ b/Mathlib/Data/Nat/Factorization/PrimePow.lean @@ -145,3 +145,41 @@ theorem Nat.mul_divisors_filter_prime_pow {a b : ℕ} (hab : a.Coprime b) : 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 + +lemma IsPrimePow.factorization_minFac_ne_zero {n : ℕ} (hn : IsPrimePow n) : + n.factorization n.minFac ≠ 0 := by + refine mt (Nat.factorization_eq_zero_iff _ _).mp ?_ + push_neg + exact ⟨n.minFac_prime hn.ne_one, n.minFac_dvd, hn.ne_zero⟩ + +/-- The canonical equivalence between pairs `(p, k)` with `p` a prime and `k : ℕ` +and the set of prime powers given by `(p, k) ↦ p^(k+1)`. -/ +def Nat.Primes.prodNatEquiv : Nat.Primes × ℕ ≃ {n : ℕ // IsPrimePow n} where + toFun pk := + ⟨pk.1 ^ (pk.2 + 1), ⟨pk.1, pk.2 + 1, prime_iff.mp pk.1.prop, pk.2.add_one_pos, rfl⟩⟩ + invFun n := + (⟨n.val.minFac, minFac_prime n.prop.ne_one⟩, n.val.factorization n.val.minFac - 1) + left_inv := fun (p, k) ↦ by + simp only [p.prop.pow_minFac k.add_one_ne_zero, Subtype.coe_eta, factorization_pow, p.prop, + Prime.factorization, Finsupp.smul_single, smul_eq_mul, mul_one, Finsupp.single_add, + Finsupp.coe_add, Pi.add_apply, Finsupp.single_eq_same, add_tsub_cancel_right] + right_inv n := by + ext1 + dsimp only + rw [sub_one_add_one n.prop.factorization_minFac_ne_zero, n.prop.minFac_pow_factorization_eq] + +@[simp] +lemma Nat.Primes.prodNatEquiv_apply (p : Nat.Primes) (k : ℕ) : + prodNatEquiv (p, k) = ⟨p ^ (k + 1), p, k + 1, prime_iff.mp p.prop, k.add_one_pos, rfl⟩ := by + rfl + +@[simp] +lemma Nat.Primes.coe_prodNatEquiv_apply (p : Nat.Primes) (k : ℕ) : + (prodNatEquiv (p, k) : ℕ) = p ^ (k + 1) := + rfl + +@[simp] +lemma Nat.Primes.prodNatEquiv_symm_apply {n : ℕ} (hn : IsPrimePow n) : + prodNatEquiv.symm ⟨n, hn⟩ = + (⟨n.minFac, minFac_prime hn.ne_one⟩, n.factorization n.minFac - 1) := + rfl diff --git a/Mathlib/Data/Nat/GCD/Basic.lean b/Mathlib/Data/Nat/GCD/Basic.lean index ff926c64b40058..2adab886eac342 100644 --- a/Mathlib/Data/Nat/GCD/Basic.lean +++ b/Mathlib/Data/Nat/GCD/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura -/ import Batteries.Data.Nat.Gcd +import Mathlib.Algebra.Group.Nat.Units import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Ring.Nat diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index fc11e395a0c419..1d16748dda19ef 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -3,11 +3,11 @@ 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.Order.Interval.Set.Defs +import Mathlib.Order.Monotone.Basic import Mathlib.Tactic.Bound.Attribute -import Mathlib.Tactic.Monotonicity.Attr -import Mathlib.Order.Lattice import Mathlib.Tactic.Contrapose -import Mathlib.Order.Interval.Set.Defs +import Mathlib.Tactic.Monotonicity.Attr /-! # Natural number logarithms diff --git a/Mathlib/Data/Nat/MaxPowDiv.lean b/Mathlib/Data/Nat/MaxPowDiv.lean index 34905e14209127..c9ea1fcff18cf8 100644 --- a/Mathlib/Data/Nat/MaxPowDiv.lean +++ b/Mathlib/Data/Nat/MaxPowDiv.lean @@ -21,8 +21,6 @@ The implementation of `maxPowDiv` improves on the speed of `padicValNat`. namespace Nat -open Nat - /-- Tail recursive function which returns the largest `k : ℕ` such that `p ^ k ∣ n` for any `p : ℕ`. `padicValNat_eq_maxPowDiv` allows the code generator to use this definition for `padicValNat` diff --git a/Mathlib/Data/Nat/Nth.lean b/Mathlib/Data/Nat/Nth.lean index fe2658ba4d8085..243d52d17d6f6b 100644 --- a/Mathlib/Data/Nat/Nth.lean +++ b/Mathlib/Data/Nat/Nth.lean @@ -237,10 +237,21 @@ theorem nth_eq_zero {n} : · rintro (⟨h₀, rfl⟩ | ⟨hf, hle⟩) exacts [nth_zero_of_zero h₀, nth_of_card_le hf hle] +lemma lt_card_toFinset_of_nth_ne_zero {n : ℕ} (h : nth p n ≠ 0) (hf : (setOf p).Finite) : + n < #hf.toFinset := by + simp only [ne_eq, nth_eq_zero, not_or, not_exists, not_le] at h + exact h.2 hf + +lemma nth_mem_of_ne_zero {n : ℕ} (h : nth p n ≠ 0) : p (Nat.nth p n) := + nth_mem n (lt_card_toFinset_of_nth_ne_zero h) + 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, false_or] at ha ⊢ exact ha.imp fun hf hle => hle.trans hab +lemma nth_ne_zero_anti (h₀ : ¬p 0) {a b : ℕ} (hab : a ≤ b) (hb : nth p b ≠ 0) : nth p a ≠ 0 := + mt (nth_eq_zero_mono h₀ hab) hb + theorem le_nth_of_lt_nth_succ {k a : ℕ} (h : a < nth p (k + 1)) (ha : p a) : a ≤ nth p k := by cases' (setOf p).finite_or_infinite with hf hf · rcases exists_lt_card_finite_nth_eq hf ha with ⟨n, hn, rfl⟩ @@ -252,6 +263,18 @@ theorem le_nth_of_lt_nth_succ {k a : ℕ} (h : a < nth p (k + 1)) (ha : p a) : a · rcases subset_range_nth ha with ⟨n, rfl⟩ rwa [nth_lt_nth hf, Nat.lt_succ_iff, ← nth_le_nth hf] at h +lemma nth_mem_anti {a b : ℕ} (hab : a ≤ b) (h : p (nth p b)) : p (nth p a) := by + by_cases h' : ∀ hf : (setOf p).Finite, a < #hf.toFinset + · exact nth_mem a h' + · simp only [not_forall, not_lt] at h' + have h'b : ∃ hf : (setOf p).Finite, #hf.toFinset ≤ b := by + rcases h' with ⟨hf, ha⟩ + exact ⟨hf, ha.trans hab⟩ + have ha0 : nth p a = 0 := by simp [nth_eq_zero, h'] + have hb0 : nth p b = 0 := by simp [nth_eq_zero, h'b] + rw [ha0] + rwa [hb0] at h + section Count variable (p) [DecidablePred p] diff --git a/Mathlib/Data/Nat/PSub.lean b/Mathlib/Data/Nat/PSub.lean index e4d0b1efeaaae8..dce691789a710d 100644 --- a/Mathlib/Data/Nat/PSub.lean +++ b/Mathlib/Data/Nat/PSub.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Group.Basic -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic /-! # Partial predecessor and partial subtraction on the natural numbers diff --git a/Mathlib/Data/Nat/Periodic.lean b/Mathlib/Data/Nat/Periodic.lean index 1e2e335bec9762..0165a52cf2c768 100644 --- a/Mathlib/Data/Nat/Periodic.lean +++ b/Mathlib/Data/Nat/Periodic.lean @@ -18,7 +18,7 @@ periodic predicates which helps determine their cardinality when filtering inter namespace Nat -open Nat Function +open Function theorem periodic_gcd (a : ℕ) : Periodic (gcd a) a := by simp only [forall_const, gcd_add_self_right, eq_self_iff_true, Periodic] diff --git a/Mathlib/Data/Nat/Prime/Defs.lean b/Mathlib/Data/Nat/Prime/Defs.lean index e6a3e5bd1a467d..d062858f5ac796 100644 --- a/Mathlib/Data/Nat/Prime/Defs.lean +++ b/Mathlib/Data/Nat/Prime/Defs.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Batteries.Data.Nat.Gcd +import Mathlib.Algebra.Group.Nat.Units import Mathlib.Algebra.Prime.Defs import Mathlib.Algebra.Ring.Nat -import Mathlib.Order.Lattice +import Mathlib.Data.Nat.Sqrt +import Mathlib.Order.Basic /-! # Prime numbers @@ -32,7 +34,8 @@ namespace Nat variable {n : ℕ} /-- `Nat.Prime p` means that `p` is a prime number, that is, a natural number - at least 2 whose only divisors are `p` and `1`. -/ + at least 2 whose only divisors are `p` and `1`. + The theorem `Nat.prime_def` witnesses this description of a prime number. -/ @[pp_nodot] def Prime (p : ℕ) := Irreducible p @@ -77,7 +80,8 @@ theorem Prime.eq_one_or_self_of_dvd {p : ℕ} (pp : p.Prime) (m : ℕ) (hm : m rintro rfl rw [hn, mul_one] -theorem prime_def_lt'' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, m ∣ p → m = 1 ∨ m = p := by +@[inherit_doc Nat.Prime] +theorem prime_def {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, m ∣ p → m = 1 ∨ m = p := by refine ⟨fun h => ⟨h.two_le, h.eq_one_or_self_of_dvd⟩, fun h => ?_⟩ have h1 := Nat.one_lt_two.trans_le h.1 refine ⟨mt Nat.isUnit_iff.mp h1.ne', fun a b hab => ?_⟩ @@ -88,8 +92,11 @@ theorem prime_def_lt'' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, m ∣ p → m · rw [hab] exact dvd_mul_right _ _ +@[deprecated (since := "2024-11-19")] +alias prime_def_lt'' := prime_def + theorem prime_def_lt {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m < p, m ∣ p → m = 1 := - prime_def_lt''.trans <| + prime_def.trans <| and_congr_right fun p2 => forall_congr' fun _ => ⟨fun h l d => (h d).resolve_right (ne_of_lt l), fun h d => diff --git a/Mathlib/Data/Nat/Size.lean b/Mathlib/Data/Nat/Size.lean index fec3892450d06e..63929ccf4f5d84 100644 --- a/Mathlib/Data/Nat/Size.lean +++ b/Mathlib/Data/Nat/Size.lean @@ -3,8 +3,8 @@ Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights r Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ +import Mathlib.Algebra.Group.Basic import Mathlib.Data.Nat.Bits -import Mathlib.Order.Lattice /-! Lemmas about `size`. -/ diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 40e3df63b05fc3..53bb8bb29fec50 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -5,6 +5,7 @@ Authors: Aaron Anderson -/ import Mathlib.Algebra.Squarefree.Basic import Mathlib.Data.Nat.Factorization.PrimePow +import Mathlib.RingTheory.UniqueFactorizationDomain.Nat /-! # Lemmas about squarefreeness of natural numbers diff --git a/Mathlib/Data/Num/Lemmas.lean b/Mathlib/Data/Num/Lemmas.lean index 04f10c375c5b9b..c7e98484c0e1c4 100644 --- a/Mathlib/Data/Num/Lemmas.lean +++ b/Mathlib/Data/Num/Lemmas.lean @@ -308,7 +308,6 @@ theorem of_to_nat' : ∀ n : Num, Num.ofNat' (n : ℕ) = n | 0 => ofNat'_zero | pos p => p.of_to_nat' -set_option linter.deprecated false in lemma toNat_injective : Injective (castNum : Num → ℕ) := LeftInverse.injective of_to_nat' @[norm_cast] diff --git a/Mathlib/Data/Num/Prime.lean b/Mathlib/Data/Num/Prime.lean index 6b3a141d151398..c183f23216e120 100644 --- a/Mathlib/Data/Num/Prime.lean +++ b/Mathlib/Data/Num/Prime.lean @@ -37,7 +37,6 @@ def minFacAux (n : PosNum) : ℕ → PosNum → PosNum | fuel + 1, k => if n < k.bit1 * k.bit1 then n else if k.bit1 ∣ n then k.bit1 else minFacAux n fuel k.succ -set_option linter.deprecated false in theorem minFacAux_to_nat {fuel : ℕ} {n k : PosNum} (h : Nat.sqrt n < fuel + k.bit1) : (minFacAux n fuel k : ℕ) = Nat.minFacAux n k.bit1 := by induction' fuel with fuel ih generalizing k <;> rw [minFacAux, Nat.minFacAux] diff --git a/Mathlib/Data/Part.lean b/Mathlib/Data/Part.lean index 58395794466e5e..842a9414123572 100644 --- a/Mathlib/Data/Part.lean +++ b/Mathlib/Data/Part.lean @@ -5,7 +5,7 @@ Authors: Mario Carneiro, Jeremy Avigad, Simon Hudon -/ import Mathlib.Data.Set.Subsingleton import Mathlib.Logic.Equiv.Defs -import Mathlib.Algebra.Group.Defs +import Mathlib.Algebra.Group.Operations /-! # Partial values of a type diff --git a/Mathlib/Data/Prod/Basic.lean b/Mathlib/Data/Prod/Basic.lean index f42386ead90429..98f729aaec3e6b 100644 --- a/Mathlib/Data/Prod/Basic.lean +++ b/Mathlib/Data/Prod/Basic.lean @@ -5,12 +5,13 @@ Authors: Johannes Hölzl -/ import Mathlib.Logic.Function.Defs import Mathlib.Logic.Function.Iterate +import Aesop import Mathlib.Tactic.Inhabit /-! # Extra facts about `Prod` -This file defines `Prod.swap : α × β → β × α` and proves various simple lemmas about `Prod`. +This file proves various simple lemmas about `Prod`. It also defines better delaborators for product projections. -/ @@ -20,6 +21,8 @@ variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} namespace Prod +lemma swap_eq_iff_eq_swap {x : α × β} {y : β × α} : x.swap = y ↔ x = y.swap := by aesop + 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₂ diff --git a/Mathlib/Data/Quot.lean b/Mathlib/Data/Quot.lean index 253f9ac3dded97..9508faa6a1ad65 100644 --- a/Mathlib/Data/Quot.lean +++ b/Mathlib/Data/Quot.lean @@ -727,16 +727,12 @@ protected theorem eq' {s₁ : Setoid α} {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 -instance argument. -/ -noncomputable def out' (a : Quotient s₁) : α := - Quotient.out a +@[deprecated (since := "2024-10-19")] alias out' := out -@[simp] -theorem out_eq' (q : Quotient s₁) : Quotient.mk'' q.out' = q := +theorem out_eq' (q : Quotient s₁) : Quotient.mk'' q.out = q := q.out_eq -theorem mk_out' (a : α) : 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 diff --git a/Mathlib/Data/Rat/Cast/Order.lean b/Mathlib/Data/Rat/Cast/Order.lean index 637675c471ea09..618e76fd323755 100644 --- a/Mathlib/Data/Rat/Cast/Order.lean +++ b/Mathlib/Data/Rat/Cast/Order.lean @@ -6,7 +6,6 @@ Authors: Johannes Hölzl, Mario Carneiro import Mathlib.Algebra.Order.Field.Rat import Mathlib.Data.Rat.Cast.CharZero import Mathlib.Tactic.Positivity.Core -import Mathlib.Algebra.Order.Field.Basic /-! # Casts of rational numbers into linear ordered fields. @@ -147,7 +146,7 @@ namespace NNRat variable {K} [LinearOrderedSemifield K] {p q : ℚ≥0} theorem cast_strictMono : StrictMono ((↑) : ℚ≥0 → K) := fun p q h => by - rwa [NNRat.cast_def, NNRat.cast_def, div_lt_div_iff, ← Nat.cast_mul, ← Nat.cast_mul, + rwa [NNRat.cast_def, NNRat.cast_def, div_lt_div_iff₀, ← Nat.cast_mul, ← Nat.cast_mul, Nat.cast_lt (α := K), ← NNRat.lt_def] · simp · simp diff --git a/Mathlib/Data/Rat/Floor.lean b/Mathlib/Data/Rat/Floor.lean index 66006dd0fc0628..7b67abd6348874 100644 --- a/Mathlib/Data/Rat/Floor.lean +++ b/Mathlib/Data/Rat/Floor.lean @@ -21,6 +21,7 @@ division and modulo arithmetic are derived as well as some simple inequalities. rat, rationals, ℚ, floor -/ +assert_not_exists Finset open Int diff --git a/Mathlib/Data/Rat/Lemmas.lean b/Mathlib/Data/Rat/Lemmas.lean index f12050bbcfeaf3..dd45de30bdee30 100644 --- a/Mathlib/Data/Rat/Lemmas.lean +++ b/Mathlib/Data/Rat/Lemmas.lean @@ -16,8 +16,6 @@ import Mathlib.Data.PNat.Defs namespace Rat -open Rat - theorem num_dvd (a) {b : ℤ} (b0 : b ≠ 0) : (a /. b).num ∣ a := by cases' e : a /. b with n d h c rw [Rat.mk'_eq_divInt, divInt_eq_iff b0 (mod_cast h)] at e diff --git a/Mathlib/Data/Real/Archimedean.lean b/Mathlib/Data/Real/Archimedean.lean index 55226e28d84b8b..a42f86a9939169 100644 --- a/Mathlib/Data/Real/Archimedean.lean +++ b/Mathlib/Data/Real/Archimedean.lean @@ -14,6 +14,8 @@ import Mathlib.Order.Interval.Set.Disjoint -/ +assert_not_exists Finset + open scoped Classical open Pointwise CauSeq diff --git a/Mathlib/Data/Real/Cardinality.lean b/Mathlib/Data/Real/Cardinality.lean index b0a7e99a26fb2d..b41af8e41d56f1 100644 --- a/Mathlib/Data/Real/Cardinality.lean +++ b/Mathlib/Data/Real/Cardinality.lean @@ -3,9 +3,9 @@ Copyright (c) 2019 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.Group.Pointwise.Interval import Mathlib.Analysis.SpecificLimits.Basic import Mathlib.Data.Rat.Cardinal -import Mathlib.Data.Set.Pointwise.Interval import Mathlib.SetTheory.Cardinal.Continuum /-! diff --git a/Mathlib/Data/Real/ENatENNReal.lean b/Mathlib/Data/Real/ENatENNReal.lean index 9385bd57ec2119..f022dc59fe0b47 100644 --- a/Mathlib/Data/Real/ENatENNReal.lean +++ b/Mathlib/Data/Real/ENatENNReal.lean @@ -12,6 +12,7 @@ import Mathlib.Data.ENNReal.Basic In this file we define a coercion from `ℕ∞` to `ℝ≥0∞` and prove some basic lemmas about this map. -/ +assert_not_exists Finset open scoped Classical open NNReal ENNReal diff --git a/Mathlib/Data/Real/EReal.lean b/Mathlib/Data/Real/EReal.lean index 4727e2cbbcc785..723fbe073737f1 100644 --- a/Mathlib/Data/Real/EReal.lean +++ b/Mathlib/Data/Real/EReal.lean @@ -923,10 +923,16 @@ def negOrderIso : EReal ≃o ERealᵒᵈ := invFun := fun x => -OrderDual.ofDual x map_rel_iff' := neg_le_neg_iff } -theorem neg_lt_iff_neg_lt {a b : EReal} : -a < b ↔ -b < a := by +theorem neg_lt_comm {a b : EReal} : -a < b ↔ -b < a := by rw [← neg_lt_neg_iff, neg_neg] + +@[deprecated (since := "2024-11-19")] alias neg_lt_iff_neg_lt := neg_lt_comm + +theorem neg_lt_of_neg_lt {a b : EReal} (h : -a < b) : -b < a := neg_lt_comm.1 h + +theorem lt_neg_comm {a b : EReal} : a < -b ↔ b < -a := by rw [← neg_lt_neg_iff, neg_neg] -theorem neg_lt_of_neg_lt {a b : EReal} (h : -a < b) : -b < a := neg_lt_iff_neg_lt.1 h +theorem lt_neg_of_lt_neg {a b : EReal} (h : a < -b) : b < -a := lt_neg_comm.1 h lemma neg_add {x y : EReal} (h1 : x ≠ ⊥ ∨ y ≠ ⊤) (h2 : x ≠ ⊤ ∨ y ≠ ⊥) : - (x + y) = - x - y := by @@ -937,64 +943,6 @@ 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 @@ -1023,6 +971,12 @@ theorem top_sub_coe (x : ℝ) : (⊤ : EReal) - x = ⊤ := theorem coe_sub_bot (x : ℝ) : (x : EReal) - ⊥ = ⊤ := rfl +lemma sub_bot {a : EReal} (h : a ≠ ⊥) : a - ⊥ = ⊤ := by + induction a + · simp only [ne_eq, not_true_eq_false] at h + · rw [coe_sub_bot] + · rw [top_sub_bot] + theorem sub_le_sub {x y z t : EReal} (h : x ≤ y) (h' : t ≤ z) : x - z ≤ y - t := add_le_add h (neg_le_neg_iff.2 h') @@ -1047,11 +1001,105 @@ theorem toReal_sub {x y : EReal} (hx : x ≠ ⊤) (h'x : x ≠ ⊥) (hy : y ≠ lift y to ℝ using ⟨hy, h'y⟩ rfl -lemma add_sub_cancel_right {a : EReal} {b : Real} : a + b - b = a := by +lemma sub_add_cancel_left {a : EReal} {b : Real} : a - b + b = a := by induction a - · rw [bot_add b, bot_sub b] + · rw [bot_sub b, bot_add b] · norm_cast; linarith - · rw [top_add_of_ne_bot (coe_ne_bot b), top_sub_coe] + · rw [top_sub_coe b, top_add_coe b] + +lemma add_sub_cancel_right {a : EReal} {b : Real} : a + b - b = a := by + rw [sub_eq_add_neg, add_assoc, add_comm (b : EReal), ← add_assoc, ← sub_eq_add_neg] + exact sub_add_cancel_left + +lemma le_sub_iff_add_le {a b c : EReal} (hb : b ≠ ⊥ ∨ c ≠ ⊥) (ht : b ≠ ⊤ ∨ c ≠ ⊤) : + a ≤ c - b ↔ a + b ≤ c := by + induction b with + | h_bot => + simp only [ne_eq, not_true_eq_false, false_or] at hb + simp only [sub_bot hb, le_top, add_bot, bot_le] + | h_real b => + rw [← (addLECancellable_coe b).add_le_add_iff_right, sub_add_cancel_left] + | h_top => + simp only [ne_eq, not_true_eq_false, false_or, sub_top, le_bot_iff] at ht ⊢ + refine ⟨fun h ↦ h ▸ (bot_add ⊤).symm ▸ bot_le, fun h ↦ ?_⟩ + by_contra ha + exact (h.trans_lt (Ne.lt_top ht)).ne (add_top_iff_ne_bot.2 ha) + +lemma sub_le_iff_le_add {a b c : EReal} (h₁ : b ≠ ⊥ ∨ c ≠ ⊤) (h₂ : b ≠ ⊤ ∨ c ≠ ⊥) : + a - b ≤ c ↔ a ≤ c + b := by + suffices a + (-b) ≤ c ↔ a ≤ c - (-b) by simpa [sub_eq_add_neg] + refine (le_sub_iff_add_le ?_ ?_).symm <;> simpa + +protected theorem lt_sub_iff_add_lt {a b c : EReal} (h₁ : b ≠ ⊥ ∨ c ≠ ⊤) (h₂ : b ≠ ⊤ ∨ c ≠ ⊥) : + c < a - b ↔ c + b < a := + lt_iff_lt_of_le_iff_le (sub_le_iff_le_add h₁ h₂) + +theorem sub_le_of_le_add {a b c : EReal} (h : a ≤ b + c) : a - c ≤ b := by + induction c with + | h_bot => rw [add_bot, le_bot_iff] at h; simp only [h, bot_sub, bot_le] + | h_real c => exact (sub_le_iff_le_add (.inl (coe_ne_bot c)) (.inl (coe_ne_top c))).2 h + | h_top => simp only [sub_top, bot_le] + +/-- See also `EReal.sub_le_of_le_add`.-/ +theorem sub_le_of_le_add' {a b c : EReal} (h : a ≤ b + c) : a - b ≤ c := + sub_le_of_le_add (add_comm b c ▸ h) + +lemma add_le_of_le_sub {a b c : EReal} (h : a ≤ b - c) : a + c ≤ b := by + rw [← neg_neg c] + exact sub_le_of_le_add h + +lemma sub_lt_iff {a b c : EReal} (h₁ : b ≠ ⊥ ∨ c ≠ ⊥) (h₂ : b ≠ ⊤ ∨ c ≠ ⊤) : + c - b < a ↔ c < a + b := + lt_iff_lt_of_le_iff_le (le_sub_iff_add_le h₁ h₂) + +lemma add_lt_of_lt_sub {a b c : EReal} (h : a < b - c) : a + c < b := by + contrapose! h + exact sub_le_of_le_add h + +lemma sub_lt_of_lt_add {a b c : EReal} (h : a < b + c) : a - c < b := + add_lt_of_lt_sub <| by rwa [sub_eq_add_neg, neg_neg] + +/-- See also `EReal.sub_lt_of_lt_add`.-/ +lemma sub_lt_of_lt_add' {a b c : EReal} (h : a < b + c) : a - b < c := + sub_lt_of_lt_add <| by rwa [add_comm] + +/-! ### 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 + +private lemma exists_lt_add_left {a b c : EReal} (hc : c < a + b) : ∃ a' < a, c < a' + b := by + obtain ⟨a', hc', ha'⟩ := exists_between (sub_lt_of_lt_add hc) + refine ⟨a', ha', (sub_lt_iff (.inl ?_) (.inr hc.ne_top)).1 hc'⟩ + contrapose! hc + exact hc ▸ (add_bot a).symm ▸ bot_le + +private lemma exists_lt_add_right {a b c : EReal} (hc : c < a + b) : ∃ b' < b, c < a + b' := by + simp_rw [add_comm a] at hc ⊢; exact exists_lt_add_left hc + +lemma add_le_of_forall_lt {a b c : EReal} (h : ∀ a' < a, ∀ b' < b, a' + b' ≤ c) : a + b ≤ c := by + refine le_of_forall_ge_of_dense fun d hd ↦ ?_ + obtain ⟨a', ha', hd⟩ := exists_lt_add_left hd + obtain ⟨b', hb', hd⟩ := exists_lt_add_right hd + exact hd.le.trans (h _ ha' _ hb') + +lemma le_add_of_forall_gt {a b c : EReal} (h₁ : a ≠ ⊥ ∨ b ≠ ⊤) (h₂ : a ≠ ⊤ ∨ b ≠ ⊥) + (h : ∀ a' > a, ∀ b' > b, c ≤ a' + b') : c ≤ a + b := by + rw [← neg_le_neg_iff, neg_add h₁ h₂] + exact add_le_of_forall_lt fun a' ha' b' hb' ↦ le_neg_of_le_neg + <| (h (-a') (lt_neg_of_lt_neg ha') (-b') (lt_neg_of_lt_neg hb')).trans_eq + (neg_add (.inr hb'.ne_top) (.inl ha'.ne_top)).symm + +@[deprecated (since := "2024-11-19")] alias top_add_le_of_forall_add_le := add_le_of_forall_lt +@[deprecated (since := "2024-11-19")] alias add_le_of_forall_add_le := add_le_of_forall_lt +@[deprecated (since := "2024-11-19")] alias le_add_of_forall_le_add := le_add_of_forall_gt lemma _root_.ENNReal.toEReal_sub {x y : ℝ≥0∞} (hy_top : y ≠ ∞) (h_le : y ≤ x) : (x - y).toEReal = x.toEReal - y.toEReal := by @@ -1576,7 +1624,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 -/ 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) diff --git a/Mathlib/Data/Real/Irrational.lean b/Mathlib/Data/Real/Irrational.lean index 62ea491e087231..59bde31ad07877 100644 --- a/Mathlib/Data/Real/Irrational.lean +++ b/Mathlib/Data/Real/Irrational.lean @@ -452,8 +452,6 @@ section Polynomial open Polynomial -open Polynomial - variable (x : ℝ) (p : ℤ[X]) theorem one_lt_natDegree_of_irrational_root (hx : Irrational x) (p_nonzero : p ≠ 0) diff --git a/Mathlib/Data/Real/Pi/Bounds.lean b/Mathlib/Data/Real/Pi/Bounds.lean index d04c703754a532..14e62e0f82c7c8 100644 --- a/Mathlib/Data/Real/Pi/Bounds.lean +++ b/Mathlib/Data/Real/Pi/Bounds.lean @@ -68,7 +68,7 @@ theorem sqrtTwoAddSeries_step_up (c d : ℕ) {a b n : ℕ} {z : ℝ} (hz : sqrtT have hb' : 0 < (b : ℝ) := Nat.cast_pos.2 hb have hd' : 0 < (d : ℝ) := Nat.cast_pos.2 hd rw [sqrt_le_left (div_nonneg c.cast_nonneg d.cast_nonneg), div_pow, - add_div_eq_mul_add_div _ _ (ne_of_gt hb'), div_le_div_iff hb' (pow_pos hd' _)] + add_div_eq_mul_add_div _ _ (ne_of_gt hb'), div_le_div_iff₀ hb' (pow_pos hd' _)] exact mod_cast h /-- From a lower bound on `sqrtTwoAddSeries 0 n = 2 cos (π / 2 ^ (n+1))` of the form @@ -91,7 +91,7 @@ theorem sqrtTwoAddSeries_step_down (a b : ℕ) {c d n : ℕ} {z : ℝ} apply le_sqrt_of_sq_le have hb' : 0 < (b : ℝ) := Nat.cast_pos.2 hb have hd' : 0 < (d : ℝ) := Nat.cast_pos.2 hd - rw [div_pow, add_div_eq_mul_add_div _ _ (ne_of_gt hd'), div_le_div_iff (pow_pos hb' _) hd'] + rw [div_pow, add_div_eq_mul_add_div _ _ (ne_of_gt hd'), div_le_div_iff₀ (pow_pos hb' _) hd'] exact mod_cast h section Tactic diff --git a/Mathlib/Data/Real/Pi/Irrational.lean b/Mathlib/Data/Real/Pi/Irrational.lean index e3884b774698da..afebb88a105b22 100644 --- a/Mathlib/Data/Real/Pi/Irrational.lean +++ b/Mathlib/Data/Real/Pi/Irrational.lean @@ -283,8 +283,8 @@ private lemma not_irrational_exists_rep {x : ℝ} : 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) + have := (tendsto_pow_div_factorial_at_top_aux a).eventually_lt_const + (show (0 : ℝ) < 1 / 2 by norm_num) 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)) diff --git a/Mathlib/Data/Real/Pointwise.lean b/Mathlib/Data/Real/Pointwise.lean index 8672dab314d366..e071edd0c5ddc8 100644 --- a/Mathlib/Data/Real/Pointwise.lean +++ b/Mathlib/Data/Real/Pointwise.lean @@ -22,6 +22,7 @@ This is true more generally for conditionally complete linear order whose defaul don't have those yet. -/ +assert_not_exists Finset open Set diff --git a/Mathlib/Data/Real/Sqrt.lean b/Mathlib/Data/Real/Sqrt.lean index b07597c19dedab..5b1193b70b4044 100644 --- a/Mathlib/Data/Real/Sqrt.lean +++ b/Mathlib/Data/Real/Sqrt.lean @@ -39,7 +39,7 @@ variable {x y : ℝ≥0} /-- Square root of a nonnegative real number. -/ -- Porting note (kmill): `pp_nodot` has no affect here --- unless RFC https://github.com/leanprover/lean4/issues/1910 leads to dot notation for CoeFun +-- unless RFC https://github.com/leanprover/lean4/issues/6178 leads to dot notation pp for CoeFun @[pp_nodot] noncomputable def sqrt : ℝ≥0 ≃o ℝ≥0 := OrderIso.symm <| powOrderIso 2 two_ne_zero @@ -311,8 +311,6 @@ end Mathlib.Meta.Positivity namespace Real -variable {x y : ℝ} - @[simp] theorem sqrt_mul {x : ℝ} (hx : 0 ≤ x) (y : ℝ) : √(x * y) = √x * √y := by simp_rw [Real.sqrt, ← NNReal.coe_mul, NNReal.coe_inj, Real.toNNReal_mul hx, NNReal.sqrt_mul] diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index d5e0c9c761f33f..8d28bac27f0b0a 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -436,8 +436,9 @@ instance univ.nonempty [Nonempty α] : Nonempty (↥(Set.univ : Set α)) := instance instNonemptyTop [Nonempty α] : Nonempty (⊤ : Set α) := inferInstanceAs (Nonempty (univ : Set α)) -theorem nonempty_of_nonempty_subtype [Nonempty (↥s)] : s.Nonempty := - nonempty_subtype.mp ‹_› +theorem Nonempty.of_subtype [Nonempty (↥s)] : s.Nonempty := nonempty_subtype.mp ‹_› + +@[deprecated (since := "2024-11-23")] alias nonempty_of_nonempty_subtype := Nonempty.of_subtype /-! ### Lemmas about the empty set -/ @@ -1204,7 +1205,7 @@ theorem eq_empty_of_ssubset_singleton {s : Set α} {x : α} (hs : s ⊂ {x}) : s theorem eq_of_nonempty_of_subsingleton {α} [Subsingleton α] (s t : Set α) [Nonempty s] [Nonempty t] : s = t := - nonempty_of_nonempty_subtype.eq_univ.trans nonempty_of_nonempty_subtype.eq_univ.symm + Nonempty.of_subtype.eq_univ.trans Nonempty.of_subtype.eq_univ.symm theorem eq_of_nonempty_of_subsingleton' {α} [Subsingleton α] {s : Set α} (t : Set α) (hs : s.Nonempty) [Nonempty t] : s = t := diff --git a/Mathlib/Data/Set/Enumerate.lean b/Mathlib/Data/Set/Enumerate.lean index 908974989a9e32..c5858d0c5e375f 100644 --- a/Mathlib/Data/Set/Enumerate.lean +++ b/Mathlib/Data/Set/Enumerate.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import Mathlib.Algebra.Group.Basic -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic import Mathlib.Tactic.Common import Mathlib.Data.Set.Basic diff --git a/Mathlib/Data/Set/Function.lean b/Mathlib/Data/Set/Function.lean index 0a7bacfba799b2..77dbaaa1720016 100644 --- a/Mathlib/Data/Set/Function.lean +++ b/Mathlib/Data/Set/Function.lean @@ -1665,4 +1665,55 @@ lemma bijOn_swap (ha : a ∈ s) (hb : b ∈ s) : BijOn (swap a b) s s := end Equiv +/-! ### Vertical line test -/ + +namespace Set + +/-- **Vertical line test** for functions. + +Let `f : α → β × γ` be a function to a product. Assume that `f` is surjective on the first factor +and that the image of `f` intersects every "vertical line" `{(b, c) | c : γ}` at most once. +Then the image of `f` is the graph of some monoid homomorphism `f' : β → γ`. -/ +lemma exists_range_eq_graphOn_univ {f : α → β × γ} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 → (f g₁).2 = (f g₂).2) : + ∃ f' : β → γ, range f = univ.graphOn f' := by + refine ⟨fun h ↦ (f (hf₁ h).choose).snd, ?_⟩ + ext x + simp only [mem_range, comp_apply, mem_graphOn, mem_univ, true_and] + refine ⟨?_, fun hi ↦ ⟨(hf₁ x.1).choose, Prod.ext (hf₁ x.1).choose_spec hi⟩⟩ + rintro ⟨g, rfl⟩ + exact hf _ _ (hf₁ (f g).1).choose_spec + +/-- **Line test** for equivalences. + +Let `f : α → β × γ` be a homomorphism to a product of monoids. Assume that `f` is surjective on both +factors and that the image of `f` intersects every "vertical line" `{(b, c) | c : γ}` and every +"horizontal line" `{(b, c) | b : β}` at most once. Then the image of `f` is the graph of some +equivalence `f' : β ≃ γ`. -/ +lemma exists_equiv_range_eq_graphOn_univ {f : α → β × γ} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf₂ : Surjective (Prod.snd ∘ f)) (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 ↔ (f g₁).2 = (f g₂).2) : + ∃ e : β ≃ γ, range f = univ.graphOn e := by + obtain ⟨e₁, he₁⟩ := exists_range_eq_graphOn_univ hf₁ fun _ _ ↦ (hf _ _).1 + obtain ⟨e₂, he₂⟩ := exists_range_eq_graphOn_univ (f := Equiv.prodComm _ _ ∘ f) (by simpa) <| + by simp [hf] + have he₁₂ h i : e₁ h = i ↔ e₂ i = h := by + rw [Set.ext_iff] at he₁ he₂ + aesop (add simp [Prod.swap_eq_iff_eq_swap]) + exact ⟨ + { toFun := e₁ + invFun := e₂ + left_inv := fun h ↦ by rw [← he₁₂] + right_inv := fun i ↦ by rw [he₁₂] }, he₁⟩ + +/-- **Vertical line test** for functions. + +Let `s : Set (β × γ)` be a set in a product. Assume that `s` maps bijectively to the first factor. +Then `s` is the graph of some function `f : β → γ`. -/ +lemma exists_eq_mgraphOn_univ {s : Set (β × γ)} + (hs₁ : Bijective (Prod.fst ∘ (Subtype.val : s → β × γ))) : ∃ f : β → γ, s = univ.graphOn f := by + simpa using exists_range_eq_graphOn_univ hs₁.surjective + fun a b h ↦ congr_arg (Prod.snd ∘ (Subtype.val : s → β × γ)) (hs₁.injective h) + +end Set + set_option linter.style.longFile 1800 diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index 11aa60b7641a2f..16c6dcc43e64f9 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -408,7 +408,7 @@ theorem Nonempty.preimage {s : Set β} (hs : s.Nonempty) {f : α → β} (hf : S ⟨x, mem_preimage.2 <| hx.symm ▸ hy⟩ instance (f : α → β) (s : Set α) [Nonempty s] : Nonempty (f '' s) := - (Set.Nonempty.image f nonempty_of_nonempty_subtype).to_subtype + (Set.Nonempty.image f .of_subtype).to_subtype /-- image and preimage are a Galois connection -/ @[simp] diff --git a/Mathlib/Data/Set/Pointwise/SMul.lean b/Mathlib/Data/Set/Pointwise/SMul.lean index 68200c4096290d..e7008d4c67fbf6 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -6,6 +6,7 @@ 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.GroupWithZero.Action.Units import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.Ring.Opposite import Mathlib.Algebra.NoZeroSMulDivisors.Defs @@ -414,8 +415,13 @@ lemma disjoint_smul_set_left : Disjoint (a • s) t ↔ Disjoint s (a⁻¹ • t lemma disjoint_smul_set_right : Disjoint s (a • t) ↔ Disjoint (a⁻¹ • s) t := by simpa using disjoint_smul_set (a := a) (s := a⁻¹ • s) -@[to_additive (attr := deprecated (since := "2024-10-18"))] -alias smul_set_disjoint_iff := disjoint_smul_set +@[to_additive] alias smul_set_disjoint_iff := disjoint_smul_set + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated disjoint_smul_set (since := "2024-10-18")] smul_set_disjoint_iff +attribute [deprecated disjoint_vadd_set (since := "2024-10-18")] vadd_set_disjoint_iff + end Group diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index 5774b37a49f86d..bbaa5b239fbfe1 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -36,12 +36,12 @@ attribute [trans] Setoid.trans variable {α : Type*} {β : Type*} /-- A version of `Setoid.r` that takes the equivalence relation as an explicit argument. -/ -@[deprecated (since := "2024-08-29")] +@[deprecated "No deprecation message was provided." (since := "2024-08-29")] def Setoid.Rel (r : Setoid α) : α → α → Prop := @Setoid.r _ r set_option linter.deprecated false in -@[deprecated (since := "2024-10-09")] +@[deprecated "No deprecation message was provided." (since := "2024-10-09")] instance Setoid.decidableRel (r : Setoid α) [h : DecidableRel r.r] : DecidableRel r.Rel := h @@ -101,6 +101,8 @@ theorem ker_mk_eq (r : Setoid α) : ker (@Quotient.mk'' _ r) = r := theorem ker_apply_mk_out {f : α → β} (a : α) : f (⟦a⟧ : Quotient (Setoid.ker f)).out = f a := @Quotient.mk_out _ (Setoid.ker f) a +set_option linter.deprecated false in +@[deprecated ker_apply_mk_out (since := "2024-10-19")] theorem ker_apply_mk_out' {f : α → β} (a : α) : f (Quotient.mk _ a : Quotient <| Setoid.ker f).out' = f a := @Quotient.mk_out' _ (Setoid.ker f) a @@ -146,7 +148,7 @@ 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' + 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 diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index 92f2964a06ba70..1aa847fee7ff88 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -405,7 +405,7 @@ theorem equivQuotient_index : hs.equivQuotient ∘ hs.index = hs.proj := funext hs.equivQuotient_index_apply /-- A map choosing a representative for each element of the quotient associated to an indexed -partition. This is a computable version of `Quotient.out'` using `IndexedPartition.some`. -/ +partition. This is a computable version of `Quotient.out` using `IndexedPartition.some`. -/ def out : hs.Quotient ↪ α := hs.equivQuotient.symm.toEmbedding.trans ⟨hs.some, Function.LeftInverse.injective hs.index_some⟩ @@ -414,9 +414,11 @@ def out : hs.Quotient ↪ α := theorem out_proj (x : α) : hs.out (hs.proj x) = hs.some (hs.index x) := rfl -/-- The indices of `Quotient.out'` and `IndexedPartition.out` are equal. -/ -theorem index_out' (x : hs.Quotient) : hs.index x.out' = hs.index (hs.out x) := - Quotient.inductionOn' x fun x => (Setoid.ker_apply_mk_out' x).trans (hs.index_some _).symm +/-- The indices of `Quotient.out` and `IndexedPartition.out` are equal. -/ +theorem index_out (x : hs.Quotient) : hs.index x.out = hs.index (hs.out x) := + Quotient.inductionOn' x fun x => (Setoid.ker_apply_mk_out x).trans (hs.index_some _).symm + +@[deprecated (since := "2024-10-19")] alias index_out' := index_out /-- This lemma is analogous to `Quotient.out_eq'`. -/ @[simp] diff --git a/Mathlib/Data/ZMod/IntUnitsPower.lean b/Mathlib/Data/ZMod/IntUnitsPower.lean index 3927a7e59bb960..4b5cace9f38cd8 100644 --- a/Mathlib/Data/ZMod/IntUnitsPower.lean +++ b/Mathlib/Data/ZMod/IntUnitsPower.lean @@ -24,7 +24,7 @@ by using `Module R (Additive M)` in its place, especially since this already has -/ instance : SMul (ZMod 2) (Additive ℤˣ) where - smul z au := .ofMul <| Additive.toMul au ^ z.val + smul z au := .ofMul <| au.toMul ^ z.val lemma ZMod.smul_units_def (z : ZMod 2) (au : Additive ℤˣ) : z • au = z.val • au := rfl @@ -34,7 +34,7 @@ lemma ZMod.natCast_smul_units (n : ℕ) (au : Additive ℤˣ) : (n : ZMod 2) • /-- This is an indirect way of saying that `ℤˣ` has a power operation by `ZMod 2`. -/ instance : Module (ZMod 2) (Additive ℤˣ) where - smul z au := .ofMul <| Additive.toMul au ^ z.val + smul z au := .ofMul <| au.toMul ^ z.val one_smul _ := Additive.toMul.injective <| pow_one _ mul_smul z₁ z₂ au := Additive.toMul.injective <| by dsimp only [ZMod.smul_units_def, toMul_nsmul] @@ -44,7 +44,7 @@ instance : Module (ZMod 2) (Additive ℤˣ) where add_smul z₁ z₂ au := Additive.toMul.injective <| by dsimp only [ZMod.smul_units_def, toMul_nsmul, toMul_add] rw [← pow_add, ZMod.val_add, ← Int.units_pow_eq_pow_mod_two] - zero_smul au := Additive.toMul.injective <| pow_zero (Additive.toMul au) + zero_smul au := Additive.toMul.injective <| pow_zero au.toMul section CommSemiring variable {R : Type*} [CommSemiring R] [Module R (Additive ℤˣ)] @@ -55,7 +55,7 @@ In lemma names, this operations is called `uzpow` to match `zpow`. Notably this is satisfied by `R ∈ {ℕ, ℤ, ZMod 2}`. -/ instance Int.instUnitsPow : Pow ℤˣ R where - pow u r := Additive.toMul (r • Additive.ofMul u) + pow u r := (r • Additive.ofMul u).toMul -- The above instances form no typeclass diamonds with the standard power operators -- but we will need `reducible_and_instances` which currently fails https://github.com/leanprover-community/mathlib4/issues/10906 @@ -65,10 +65,10 @@ example : Int.instUnitsPow = DivInvMonoid.Pow := rfl @[simp] lemma ofMul_uzpow (u : ℤˣ) (r : R) : Additive.ofMul (u ^ r) = r • Additive.ofMul u := rfl @[simp] lemma toMul_uzpow (u : Additive ℤˣ) (r : R) : - Additive.toMul (r • u) = Additive.toMul u ^ r := rfl + (r • u).toMul = u.toMul ^ r := rfl @[norm_cast] lemma uzpow_natCast (u : ℤˣ) (n : ℕ) : u ^ (n : R) = u ^ n := by - change Additive.toMul ((n : R) • Additive.ofMul u) = _ + change ((n : R) • Additive.ofMul u).toMul = _ rw [Nat.cast_smul_eq_nsmul, toMul_nsmul, toMul_ofMul] -- See note [no_index around OfNat.ofNat] @@ -106,7 +106,7 @@ lemma uzpow_neg (s : ℤˣ) (x : R) : s ^ (-x) = (s ^ x)⁻¹ := Additive.ofMul.injective <| neg_smul x (Additive.ofMul s) @[norm_cast] lemma uzpow_intCast (u : ℤˣ) (z : ℤ) : u ^ (z : R) = u ^ z := by - change Additive.toMul ((z : R) • Additive.ofMul u) = _ + change ((z : R) • Additive.ofMul u).toMul = _ rw [Int.cast_smul_eq_zsmul, toMul_zsmul, toMul_ofMul] end CommRing diff --git a/Mathlib/Deprecated/AlgebraClasses.lean b/Mathlib/Deprecated/AlgebraClasses.lean index cc26f497422b29..bb6f9488719132 100644 --- a/Mathlib/Deprecated/AlgebraClasses.lean +++ b/Mathlib/Deprecated/AlgebraClasses.lean @@ -25,16 +25,16 @@ universe u v variable {α : Sort u} -@[deprecated (since := "2024-09-11")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (since := "2024-09-11")] class IsRightCancel (α : Sort u) (op : α → α → α) : Prop where right_cancel : ∀ a b c, op a b = op c b → a = c /-- `IsTotalPreorder X r` means that the binary relation `r` on `X` is total and a preorder. -/ -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] class IsTotalPreorder (α : Sort u) (r : α → α → Prop) extends IsTrans α r, IsTotal α r : Prop /-- Every total pre-order is a pre-order. -/ @@ -45,11 +45,11 @@ instance (priority := 100) isTotalPreorder_isPreorder (α : Sort u) (r : α → /-- `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")] +@[deprecated "No deprecation message was provided." (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 -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance (priority := 100) (α : Sort u) (lt : α → α → Prop) [IsStrictWeakOrder α lt] : IsIncompTrans α lt := { ‹IsStrictWeakOrder α lt› with } @@ -59,7 +59,7 @@ variable {r : α → α → Prop} local infixl:50 " ≺ " => r -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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 _ _ _ @@ -68,7 +68,8 @@ section ExplicitRelationVariants variable (r) -@[elab_without_expected_type, deprecated (since := "2024-07-30")] +@[elab_without_expected_type, + deprecated "No deprecation message was provided." (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 @@ -85,32 +86,32 @@ variable {r : α → α → Prop} local infixl:50 " ≺ " => r -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] def Equiv (a b : α) : Prop := ¬a ≺ b ∧ ¬b ≺ a local infixl:50 " ≈ " => @Equiv _ r -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem esymm {a b : α} : a ≈ b → b ≈ a := fun ⟨h₁, h₂⟩ => ⟨h₂, h₁⟩ -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem not_lt_of_equiv {a b : α} : a ≈ b → ¬a ≺ b := fun h => h.1 -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem erefl (a : α) : a ≈ a := ⟨irrefl a, irrefl a⟩ -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem etrans {a b c : α} : a ≈ b → b ≈ c → a ≈ c := incomp_trans -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance isEquiv : IsEquiv α (@Equiv _ r) where refl := erefl trans _ _ _ := etrans @@ -123,7 +124,7 @@ notation:50 a " ≈[" lt "]" b:50 => @Equiv _ lt a b end StrictWeakOrder -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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 := @@ -149,20 +150,20 @@ section LinearOrder variable {α : Type*} [LinearOrder α] set_option linter.deprecated false in -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance : IsTotalPreorder α (· ≤ ·) where trans := @le_trans _ _ total := le_total set_option linter.deprecated false in -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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⟩ => @@ -171,7 +172,7 @@ theorem lt_of_lt_of_incomp {α : Sort u} {lt : α → α → Prop} [IsStrictWeak have : ¬lt a b ∧ ¬lt b a := incomp_trans_of lt ⟨nac, nca⟩ ⟨ncb, nbc⟩ absurd hab this.1 -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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 => @@ -180,7 +181,7 @@ theorem lt_of_incomp_of_lt {α : Sort u} {lt : α → α → Prop} [IsStrictWeak have : ¬lt b c ∧ ¬lt c b := incomp_trans_of lt ⟨nba, nab⟩ ⟨nac, nca⟩ absurd hbc this.1 -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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 @@ -188,17 +189,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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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 diff --git a/Mathlib/Deprecated/ByteArray.lean b/Mathlib/Deprecated/ByteArray.lean index c199be41b3f7ca..b7146dbf289c66 100644 --- a/Mathlib/Deprecated/ByteArray.lean +++ b/Mathlib/Deprecated/ByteArray.lean @@ -19,7 +19,7 @@ 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")] +@[deprecated "No deprecation message was provided." (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⟩ @@ -28,13 +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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (since := "2024-08-19")] structure ByteSliceT := (arr : ByteArray) (off : Nat) namespace ByteSliceT @@ -66,7 +66,7 @@ def toArray : ByteSlice → ByteArray universe u v /-- The inner loop of the `forIn` implementation for byte slices. -/ -@[deprecated (since := "2024-08-19")] +@[deprecated "No deprecation message was provided." (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 @@ -75,7 +75,7 @@ def forIn.loop {m : Type u → Type v} {β : Type u} [Monad m] (f : UInt8 → β | ForInStep.yield b => have := Nat.Up.next h; loop f arr off _end (i+1) b else pure b -@[deprecated (since := "2024-08-19")] +@[deprecated "No deprecation message was provided." (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⟩ diff --git a/Mathlib/Deprecated/Combinator.lean b/Mathlib/Deprecated/Combinator.lean index 5c79bf0837a597..366fd5997f9829 100644 --- a/Mathlib/Deprecated/Combinator.lean +++ b/Mathlib/Deprecated/Combinator.lean @@ -15,8 +15,11 @@ 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) +@[deprecated "No deprecation message was provided." (since := "2024-07-27")] +def I (a : α) := a +@[deprecated "No deprecation message was provided." (since := "2024-07-27")] +def K (a : α) (_b : β) := a +@[deprecated "No deprecation message was provided." (since := "2024-07-27")] +def S (x : α → β → γ) (y : α → β) (z : α) := x z (y z) end Combinator diff --git a/Mathlib/Deprecated/Equiv.lean b/Mathlib/Deprecated/Equiv.lean index 74bc9b68ecdd34..b31fe578386cc3 100644 --- a/Mathlib/Deprecated/Equiv.lean +++ b/Mathlib/Deprecated/Equiv.lean @@ -21,10 +21,10 @@ variable {α₁ β₁ : Type*} (e : α₁ ≃ β₁) (f : α₁ → α₁ → α set_option linter.deprecated false -@[deprecated (since := "2024-09-11")] +@[deprecated "No deprecation message was provided." (since := "2024-09-11")] instance [IsLeftCancel α₁ f] : IsLeftCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsLeftCancel.left_cancel _ f _ x y z⟩ -@[deprecated (since := "2024-09-11")] +@[deprecated "No deprecation message was provided." (since := "2024-09-11")] instance [IsRightCancel α₁ f] : IsRightCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsRightCancel.right_cancel _ f _ x y z⟩ diff --git a/Mathlib/Deprecated/Group.lean b/Mathlib/Deprecated/Group.lean index 539782f49e7252..66bc94fe1317e3 100644 --- a/Mathlib/Deprecated/Group.lean +++ b/Mathlib/Deprecated/Group.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Group.Equiv.Basic -import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Group.Units.Hom import Mathlib.Algebra.Ring.Hom.Defs +import Mathlib.Algebra.Group.TypeTags.Basic /-! # Unbundled monoid and group homomorphisms diff --git a/Mathlib/Data/LazyList/Basic.lean b/Mathlib/Deprecated/LazyList.lean similarity index 91% rename from Mathlib/Data/LazyList/Basic.lean rename to Mathlib/Deprecated/LazyList.lean index 7a9b8203365054..5ba81d38999a8e 100644 --- a/Mathlib/Data/LazyList/Basic.lean +++ b/Mathlib/Deprecated/LazyList.lean @@ -24,7 +24,7 @@ namespace LazyList open Function /-- Isomorphism between strict and lazy lists. -/ -@[deprecated (since := "2024-07-22")] +@[deprecated "No deprecation message was provided." (since := "2024-07-22")] def listEquivLazyList (α : Type*) : List α ≃ LazyList α where toFun := LazyList.ofList invFun := LazyList.toList @@ -39,12 +39,12 @@ def listEquivLazyList (α : Type*) : List α ≃ LazyList α where · simp [toList, ofList] · simpa [ofList, toList] -@[deprecated (since := "2024-07-22")] +@[deprecated "No deprecation message was provided." (since := "2024-07-22")] instance : Traversable LazyList where map := @LazyList.traverse Id _ traverse := @LazyList.traverse -@[deprecated (since := "2024-07-22")] +@[deprecated "No deprecation message was provided." (since := "2024-07-22")] instance : LawfulTraversable LazyList := by apply Equiv.isLawfulTraversable' listEquivLazyList <;> intros <;> ext <;> rename_i f xs · induction xs using LazyList.rec with @@ -71,7 +71,7 @@ instance : LawfulTraversable LazyList := by Function.comp_def, Thunk.pure, ofList] | mk _ ih => apply ih -@[deprecated (since := "2024-07-22"), simp] +@[deprecated "No deprecation message was provided." (since := "2024-07-22"), simp] theorem bind_singleton {α} (x : LazyList α) : x.bind singleton = x := by induction x using LazyList.rec (motive_2 := fun xs => xs.get.bind singleton = xs.get) with | nil => simp [LazyList.bind] @@ -81,7 +81,7 @@ theorem bind_singleton {α} (x : LazyList α) : x.bind singleton = x := by simp [ih] | mk f ih => simp_all -@[deprecated (since := "2024-07-22")] +@[deprecated "No deprecation message was provided." (since := "2024-07-22")] instance : LawfulMonad LazyList := LawfulMonad.mk' (id_map := by intro α xs diff --git a/Mathlib/Deprecated/Logic.lean b/Mathlib/Deprecated/Logic.lean index f88642ec745a7e..52d03620dc96a3 100644 --- a/Mathlib/Deprecated/Logic.lean +++ b/Mathlib/Deprecated/Logic.lean @@ -37,43 +37,43 @@ local infix:65 (priority := high) " + " => g 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 +@[deprecated "No deprecation message was provided." (since := "2024-09-03")] -- unused in Mathlib def LeftIdentity := ∀ a, one * a = a -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (since := "2024-09-03")] -- unused in Mathlib def RightIdentity := ∀ a, a * one = a -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (since := "2024-09-03")] -- unused in Mathlib def RightInverse := ∀ a, a * a⁻¹ = one -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (since := "2024-09-03")] -- unused in Mathlib def RightDistributive := ∀ a b c, (a + b) * c = a * c + b * c end Binary @[deprecated (since := "2024-09-03")] alias not_of_eq_false := of_eq_false -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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 @@ -114,20 +114,20 @@ theorem iff_self_iff (a : Prop) : (a ↔ a) ↔ True := iff_of_eq (iff_self _) /- decidable -/ -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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₄ @@ -145,25 +145,25 @@ end Decidable @[deprecated (since := "2024-09-03")] alias decidableTrue := instDecidableTrue @[deprecated (since := "2024-09-03")] alias decidableFalse := instDecidableFalse -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 @@ -171,7 +171,7 @@ theorem decidableEq_inr_neg {α : Sort u} [h : DecidableEq α] {a b : α} /- subsingleton -/ -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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₁) := @@ -179,15 +179,15 @@ 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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 :) -@[deprecated (since := "2024-09-11")] +@[deprecated "No deprecation message was provided." (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) @@ -199,7 +199,7 @@ theorem dif_ctx_congr {α : Sort u} {b c : Prop} [dec_b : Decidable b] [dec_c : | 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 +@[deprecated "No deprecation message was provided." (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 @@ -209,12 +209,12 @@ theorem if_ctx_congr_prop {b c x y u v : Prop} [dec_b : Decidable b] [dec_c : De | isTrue h₁, isFalse h₂ => absurd h₁ (Iff.mpr (not_congr h_c) h₂) -- @[congr] -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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: @@ -222,7 +222,7 @@ theorem if_ctx_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c (h_e : ¬c → (y ↔ v)) : ite b x y ↔ @ite _ c (decidable_of_decidable_of_iff h_c) u v := if_ctx_congr_prop (dec_c := decidable_of_decidable_of_iff h_c) h_c h_t h_e -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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: @@ -230,7 +230,7 @@ theorem if_simp_congr_prop {b c x y u v : Prop} [Decidable b] (h_c : b ↔ c) (h (h_e : y ↔ v) : ite b x y ↔ (@ite _ c (decidable_of_decidable_of_iff h_c) u v) := if_ctx_simp_congr_prop h_c (fun _ ↦ h_t) (fun _ ↦ h_e) -@[deprecated (since := "2024-09-03")] -- unused in Mathlib +@[deprecated "No deprecation message was provided." (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) @@ -241,31 +241,31 @@ theorem dif_ctx_simp_congr {α : Sort u} {b c : Prop} [Decidable b] dite b x y = @dite _ c (decidable_of_decidable_of_iff h_c) u v := dif_ctx_congr (dec_c := decidable_of_decidable_of_iff h_c) h_c h_t h_e -@[deprecated (since := "2024-09-03")] +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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 +@[deprecated "No deprecation message was provided." (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₂] diff --git a/Mathlib/Deprecated/NatLemmas.lean b/Mathlib/Deprecated/NatLemmas.lean index 37fd557b3fec3f..81b124b4476cd4 100644 --- a/Mathlib/Deprecated/NatLemmas.lean +++ b/Mathlib/Deprecated/NatLemmas.lean @@ -28,7 +28,7 @@ namespace Nat /-! successor and predecessor -/ -@[deprecated (since := "2024-08-23")] +@[deprecated "No deprecation message was provided." (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 @@ -36,7 +36,7 @@ def discriminate {B : Sort u} {n : ℕ} (H1 : n = 0 → B) (H2 : ∀ m, n = succ -- Unused in Mathlib; -- if downstream projects find this essential please copy it or remove the deprecation. -@[deprecated (since := "2024-07-27")] +@[deprecated "No deprecation message was provided." (since := "2024-07-27")] theorem one_eq_succ_zero : 1 = succ 0 := rfl @@ -44,7 +44,7 @@ theorem one_eq_succ_zero : 1 = succ 0 := -- Unused in Mathlib; -- if downstream projects find this essential please copy it or remove the deprecation. -@[deprecated (since := "2024-07-27")] +@[deprecated "No deprecation message was provided." (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 _ @@ -55,7 +55,7 @@ def subInduction {P : ℕ → ℕ → Sort u} (H1 : ∀ m, P 0 m) (H2 : ∀ n, P -- Unused in Mathlib; -- if downstream projects find this essential please copy it or remove the deprecation. -@[deprecated (since := "2024-07-27")] +@[deprecated "No deprecation message was provided." (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 simp only [cond_eq_if, decide_eq_true_eq] diff --git a/Mathlib/Deprecated/RelClasses.lean b/Mathlib/Deprecated/RelClasses.lean index 357b10283c2d5c..8d5f647030d5d1 100644 --- a/Mathlib/Deprecated/RelClasses.lean +++ b/Mathlib/Deprecated/RelClasses.lean @@ -27,12 +27,14 @@ variable {α : Type u} open Function -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem IsTotalPreorder.swap (r) [IsTotalPreorder α r] : IsTotalPreorder α (swap r) := { @IsPreorder.swap α r _, @IsTotal.swap α r _ with } -@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where -@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where +@[deprecated "No deprecation message was provided." (since := "2024-08-22")] +instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where +@[deprecated "No deprecation message was provided." (since := "2024-08-22")] +instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance [LinearOrder α] : IsIncompTrans α (· < ·) := by infer_instance diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean index 64702155e24771..e403b3b59936a7 100644 --- a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean +++ b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean @@ -253,7 +253,7 @@ theorem commute_iff_commute {f g : CircleDeg1Lift} : Commute f g ↔ Function.Co `translation (Multiplicative.ofAdd x)`. -/ def translate : Multiplicative ℝ →* CircleDeg1Liftˣ := MonoidHom.toHomUnits <| { toFun := fun x => - ⟨⟨fun y => Multiplicative.toAdd x + y, fun _ _ h => add_le_add_left h _⟩, fun _ => + ⟨⟨fun y => x.toAdd + y, fun _ _ h => add_le_add_left h _⟩, fun _ => (add_assoc _ _ _).symm⟩ map_one' := ext <| zero_add map_mul' := fun _ _ => ext <| add_assoc _ _ } @@ -600,7 +600,7 @@ theorem tendsto_translationNumber_of_dist_bounded_aux (x : ℕ → ℝ) (C : ℝ · exact fun n => C / 2 ^ n · intro n have : 0 < (2 ^ n : ℝ) := pow_pos zero_lt_two _ - convert (div_le_div_right this).2 (H (2 ^ n)) using 1 + convert (div_le_div_iff_of_pos_right this).2 (H (2 ^ n)) using 1 rw [transnumAuxSeq, Real.dist_eq, ← sub_div, abs_div, abs_of_pos this, Real.dist_eq] · exact mul_zero C ▸ tendsto_const_nhds.mul <| tendsto_inv_atTop_zero.comp <| tendsto_pow_atTop_atTop_of_one_lt one_lt_two @@ -673,7 +673,7 @@ theorem tendsto_translation_number₀' : dsimp have : (0 : ℝ) < n + 1 := n.cast_add_one_pos rw [Real.dist_eq, div_sub' _ _ _ (ne_of_gt this), abs_div, ← Real.dist_eq, abs_of_pos this, - Nat.cast_add_one, div_le_div_right this, ← Nat.cast_add_one] + Nat.cast_add_one, div_le_div_iff_of_pos_right this, ← Nat.cast_add_one] apply dist_pow_map_zero_mul_translationNumber_le theorem tendsto_translation_number₀ : Tendsto (fun n : ℕ => (f ^ n) 0 / n) atTop (𝓝 <| τ f) := diff --git a/Mathlib/Dynamics/Ergodic/Ergodic.lean b/Mathlib/Dynamics/Ergodic/Ergodic.lean index b7bd2016eeee44..cc9abb51e71986 100644 --- a/Mathlib/Dynamics/Ergodic/Ergodic.lean +++ b/Mathlib/Dynamics/Ergodic/Ergodic.lean @@ -80,6 +80,9 @@ theorem smul_measure {R : Type*} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ (hf : PreErgodic f μ) (c : R) : PreErgodic f (c • μ) where aeconst_set _s hs hfs := (hf.aeconst_set hs hfs).anti <| ae_smul_measure_le _ +theorem zero_measure (f : α → α) : @PreErgodic α m f 0 where + aeconst_set _ _ _ := by simp + end PreErgodic namespace MeasureTheory.MeasurePreserving @@ -137,6 +140,11 @@ theorem smul_measure {R : Type*} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ (hf : QuasiErgodic f μ) (c : R) : QuasiErgodic f (c • μ) := ⟨hf.1.smul_measure _, hf.2.smul_measure _⟩ +theorem zero_measure {f : α → α} (hf : Measurable f) : @QuasiErgodic α m f 0 where + measurable := hf + absolutelyContinuous := by simp + toPreErgodic := .zero_measure f + end QuasiErgodic namespace Ergodic @@ -171,6 +179,11 @@ theorem smul_measure {R : Type*} [SMul R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ (hf : Ergodic f μ) (c : R) : Ergodic f (c • μ) := ⟨hf.1.smul_measure _, hf.2.smul_measure _⟩ +theorem zero_measure {f : α → α} (hf : Measurable f) : @Ergodic α m f 0 where + measurable := hf + map_eq := by simp + toPreErgodic := .zero_measure f + section IsFiniteMeasure variable [IsFiniteMeasure μ] diff --git a/Mathlib/Dynamics/Minimal.lean b/Mathlib/Dynamics/Minimal.lean index ce019b475eaf41..c29a7f2fce92e0 100644 --- a/Mathlib/Dynamics/Minimal.lean +++ b/Mathlib/Dynamics/Minimal.lean @@ -93,7 +93,7 @@ theorem eq_empty_or_univ_of_smul_invariant_closed [IsMinimal M α] {s : Set α} hs.closure_eq ▸ (dense_of_nonempty_smul_invariant M hne hsmul).closure_eq @[to_additive] -theorem isMinimal_iff_closed_smul_invariant [ContinuousConstSMul M α] : +theorem isMinimal_iff_isClosed_smul_invariant [ContinuousConstSMul M α] : IsMinimal M α ↔ ∀ s : Set α, IsClosed s → (∀ c : M, c • s ⊆ s) → s = ∅ ∨ s = univ := by constructor · intro _ _ @@ -101,3 +101,5 @@ theorem isMinimal_iff_closed_smul_invariant [ContinuousConstSMul M α] : refine fun H ↦ ⟨fun _ ↦ dense_iff_closure_eq.2 <| (H _ ?_ ?_).resolve_left ?_⟩ exacts [isClosed_closure, fun _ ↦ smul_closure_orbit_subset _ _, (orbit_nonempty _).closure.ne_empty] +@[deprecated (since := "2024-11-19")] alias +isMinimal_iff_closed_smul_invariant := isMinimal_iff_isClosed_smul_invariant diff --git a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean index b5c4368d3eecde..f12dd6c32afc64 100644 --- a/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean +++ b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean @@ -483,7 +483,7 @@ lemma coverEntropyEntourage_le_log_coverMincard_div {T : X → X} {F : Set X} (F 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 + have := @limsup_add_le ℕ 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)) diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index e53c89cf4befba..51d8f9c940bb76 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -11,6 +11,7 @@ import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition import Mathlib.RingTheory.Adjoin.Dimension import Mathlib.RingTheory.Finiteness.TensorProduct import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.SetTheory.Cardinal.Subfield /-! # Adjoining Elements to Fields @@ -1663,6 +1664,44 @@ theorem algHom_fieldRange_eq_of_comp_eq_of_range_eq refine ringHom_fieldRange_eq_of_comp_eq_of_range_eq h ?_ rw [← Algebra.adjoin_eq_ring_closure, ← hs]; rfl +variable [IsScalarTower F A K] + +/-- The image of `IsFractionRing.liftAlgHom` is the intermediate field generated by the image +of the algebra hom. -/ +theorem liftAlgHom_fieldRange (hg : Function.Injective g) : + (liftAlgHom hg : K →ₐ[F] L).fieldRange = IntermediateField.adjoin F g.range := + algHom_fieldRange_eq_of_comp_eq (by ext; simp) + +/-- The image of `IsFractionRing.liftAlgHom` is the intermediate field generated by `s`, +if the image of the algebra hom is the subalgebra generated by `s`. -/ +theorem liftAlgHom_fieldRange_eq_of_range_eq (hg : Function.Injective g) + {s : Set L} (hs : g.range = Algebra.adjoin F s) : + (liftAlgHom hg : K →ₐ[F] L).fieldRange = IntermediateField.adjoin F s := + algHom_fieldRange_eq_of_comp_eq_of_range_eq (by ext; simp) hs + end IsFractionRing -set_option linter.style.longFile 1700 +namespace IntermediateField + +universe u v + +open Cardinal + +variable (F : Type u) [Field F] + +theorem lift_cardinalMk_adjoin_le {E : Type v} [Field E] [Algebra F E] (s : Set E) : + Cardinal.lift.{u} #(adjoin F s) ≤ Cardinal.lift.{v} #F ⊔ Cardinal.lift.{u} #s ⊔ ℵ₀ := by + rw [show ↥(adjoin F s) = (adjoin F s).toSubfield from rfl, adjoin_toSubfield] + apply (Cardinal.lift_le.mpr (Subfield.cardinalMk_closure_le_max _)).trans + rw [lift_max, sup_le_iff, lift_aleph0] + refine ⟨(Cardinal.lift_le.mpr ((mk_union_le _ _).trans <| add_le_max _ _)).trans ?_, le_sup_right⟩ + simp_rw [lift_max, lift_aleph0, sup_assoc] + exact sup_le_sup_right mk_range_le_lift _ + +theorem cardinalMk_adjoin_le {E : Type u} [Field E] [Algebra F E] (s : Set E) : + #(adjoin F s) ≤ #F ⊔ #s ⊔ ℵ₀ := by + simpa using lift_cardinalMk_adjoin_le F s + +end IntermediateField + +set_option linter.style.longFile 1800 diff --git a/Mathlib/FieldTheory/AxGrothendieck.lean b/Mathlib/FieldTheory/AxGrothendieck.lean index 9ddfa55c77de33..b3ce93355bef97 100644 --- a/Mathlib/FieldTheory/AxGrothendieck.lean +++ b/Mathlib/FieldTheory/AxGrothendieck.lean @@ -3,61 +3,244 @@ 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.Algebra.MvPolynomial.Basic -import Mathlib.Data.Fintype.Card + import Mathlib.RingTheory.Algebraic +import Mathlib.Data.Fintype.Card +import Mathlib.ModelTheory.Algebra.Field.IsAlgClosed +import Mathlib.ModelTheory.Algebra.Ring.Definability +import Mathlib.RingTheory.Polynomial.Basic /-! -# Ax-Grothendieck for algebraic extensions of `ZMod p` +# Ax-Grothendieck -This file proves that if `R` is an algebraic extension of a finite field, -then any injective polynomial map `R^n → R^n` is also surjective. +This file proves that if `K` is an algebraically closed field, +then any injective polynomial map `K^n → K^n` is also surjective. -This proof is required for the true Ax-Grothendieck theorem, which proves the same result -for any algebraically closed field of characteristic zero. +## Main results -## TODO +* `ax_grothendieck_zeroLocus`: If `K` is algebraically closed, `ι` is a finite type, and +`S : Set (ι → K)` is the `zeroLocus` of some ideal of `MvPolynomial ι K`, then any injective +polynomial map `S → S` is also surjective on `S`. +* `ax_grothendieck_univ`: Any injective polynomial map `K^n → K^n` is also surjective if `K` is an +algberaically closed field. +* `ax_grothendieck_of_definable`: Any injective polynomial map `S → S` is also surjective on `S` if +`K` is an algebraically closed field and `S` is a definable subset of `K^n`. +* `ax_grothendieck_of_locally_finite`: any injective polynomial map `R^n → R^n` is also surjective +whenever `R` is an algebraic extension of a finite field. + +## 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) -The proof of the theorem for characteristic zero is not in mathlib, but it is at -https://github.com/Jlh18/ModelTheoryInLean8 -/ noncomputable section -open MvPolynomial Finset Function +open MvPolynomial Finset /-- Any injective polynomial map over an algebraic extension of a finite field is surjective. -/ theorem ax_grothendieck_of_locally_finite {ι K R : Type*} [Field K] [Finite K] [CommRing R] - [Finite ι] [Algebra K R] [Algebra.IsAlgebraic K R] (ps : ι → MvPolynomial ι R) - (hinj : Injective fun v i => MvPolynomial.eval v (ps i)) : - Surjective fun v i => MvPolynomial.eval v (ps i) := by + [Finite ι] [Algebra K R] [alg : Algebra.IsAlgebraic K R] (ps : ι → MvPolynomial ι R) + (S : Set (ι → R)) + (hm : S.MapsTo (fun v i => eval v (ps i)) S) + (hinj : S.InjOn (fun v i => eval v (ps i))) : + S.SurjOn (fun v i => eval v (ps i)) S := by + have is_int : ∀ x : R, IsIntegral K x := fun x => isAlgebraic_iff_isIntegral.1 + (alg.isAlgebraic x) + classical + intro v hvS + cases nonempty_fintype ι + /- `s` is the set of all coefficients of the polynomial, as well as all of + the coordinates of `v`, the point I am trying to find the preimage of. -/ + let s : Finset R := + (Finset.biUnion (univ : Finset ι) fun i => (ps i).support.image fun x => coeff x (ps i)) ∪ + (univ : Finset ι).image v + have hv : ∀ i, v i ∈ Algebra.adjoin K (s : Set R) := fun j => + Algebra.subset_adjoin (mem_union_right _ (mem_image.2 ⟨j, mem_univ _, rfl⟩)) + have hs₁ : ∀ (i : ι) (k : ι →₀ ℕ), + k ∈ (ps i).support → coeff k (ps i) ∈ Algebra.adjoin K (s : Set R) := + fun i k hk => Algebra.subset_adjoin + (mem_union_left _ (mem_biUnion.2 ⟨i, mem_univ _, mem_image_of_mem _ hk⟩)) + have := isNoetherian_adjoin_finset s fun x _ => is_int x + have := Module.IsNoetherian.finite K (Algebra.adjoin K (s : Set R)) + have : Finite (Algebra.adjoin K (s : Set R)) := Module.finite_of_finite K + -- The restriction of the polynomial map, `ps`, to the subalgebra generated by `s` + let S' : Set (ι → Algebra.adjoin K (s : Set R)) := + (fun v => Subtype.val ∘ v) ⁻¹' S + let res : S' → S' := fun x => ⟨fun i => + ⟨eval (fun j : ι => (x.1 j : R)) (ps i), eval_mem (hs₁ _) fun i => (x.1 i).2⟩, + hm x.2⟩ + have hres_surj : Function.Surjective res := by + rw [← Finite.injective_iff_surjective] + intro x y hxy + ext i + simp only [Subtype.ext_iff, funext_iff] at hxy + exact congr_fun (hinj x.2 y.2 (funext hxy)) i + rcases hres_surj ⟨fun i => ⟨v i, hv i⟩, hvS⟩ with ⟨⟨w, hwS'⟩, hw⟩ + refine ⟨fun i => w i, hwS', ?_⟩ + simpa [Subtype.ext_iff, funext_iff] using hw + +end + +namespace FirstOrder + +open MvPolynomial FreeCommRing Language Field Ring BoundedFormula + +variable {ι α : Type*} [Finite α] {K : Type*} [Field K] [CompatibleRing K] + +/-- The collection of first order formulas corresponding to the Ax-Grothendieck theorem. -/ +noncomputable def genericPolyMapSurjOnOfInjOn [Fintype ι] + (φ : ring.Formula (α ⊕ ι)) + (mons : ι → Finset (ι →₀ ℕ)) : Language.ring.Sentence := + let l1 : ι → Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + fun i => + (termOfFreeCommRing (genericPolyMap mons i)).relabel + (Sum.inl ∘ Sum.map id (fun i => (0, i))) + =' (termOfFreeCommRing (genericPolyMap mons i)).relabel + (Sum.inl ∘ Sum.map id (fun i => (1, i))) + -- p(x) = p(y) as a formula + let f1 : Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + iInf Finset.univ l1 + let l2 : ι → Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + fun i => .var (Sum.inl (Sum.inr (0, i))) =' .var (Sum.inl (Sum.inr (1, i))) + -- x = y as a formula + let f2 : Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + iInf Finset.univ l2 + let injOn : Language.ring.Formula (α ⊕ Σ i : ι, mons i) := + Formula.iAlls (γ := Fin 2 × ι) id + (φ.relabel (Sum.map Sum.inl (fun i => (0, i))) ⟹ + φ.relabel (Sum.map Sum.inl (fun i => (1, i))) ⟹ + (f1.imp f2).relabel (fun x => (Equiv.sumAssoc _ _ _).symm (Sum.inr x))) + let l3 : ι → Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + fun i => (termOfFreeCommRing (genericPolyMap mons i)).relabel + (Sum.inl ∘ Sum.map id (fun i => (0, i))) =' + .var (Sum.inl (Sum.inr (1, i))) + let f3 : Language.ring.Formula ((Σ i : ι, mons i) ⊕ (Fin 2 × ι)) := + iInf Finset.univ l3 + let surjOn : Language.ring.Formula (α ⊕ Σ i : ι, mons i) := + Formula.iAlls (γ := ι) id + (Formula.imp (φ.relabel (Sum.map Sum.inl id)) <| + Formula.iExs (γ := ι) + (fun (i : (α ⊕ (Σ i : ι, mons i)) ⊕ (Fin 2 × ι)) => + show ((α ⊕ (Σ i : ι, mons i)) ⊕ ι) ⊕ ι + from Sum.elim (Sum.inl ∘ Sum.inl) + (fun i => if i.1 = 0 then Sum.inr i.2 else (Sum.inl (Sum.inr i.2))) i) + ((φ.relabel (Sum.map Sum.inl (fun i => (0, i)))) ⊓ + (f3.relabel (fun x => (Equiv.sumAssoc _ _ _).symm (Sum.inr x))))) + let mapsTo : Language.ring.Formula (α ⊕ Σ i : ι, mons i) := + Formula.iAlls (γ := ι) id + (Formula.imp (φ.relabel (Sum.map Sum.inl id)) + (φ.subst <| Sum.elim + (fun a => .var (Sum.inl (Sum.inl a))) + (fun i => (termOfFreeCommRing (genericPolyMap mons i)).relabel + (fun i => (Equiv.sumAssoc _ _ _).symm (Sum.inr i))))) + Formula.iAlls (γ := α ⊕ Σ i : ι, mons i) Sum.inr (mapsTo ⟹ injOn ⟹ surjOn) + +theorem realize_genericPolyMapSurjOnOfInjOn + [Fintype ι] (φ : ring.Formula (α ⊕ ι)) (mons : ι → Finset (ι →₀ ℕ)) : + (K ⊨ genericPolyMapSurjOnOfInjOn φ mons) ↔ + ∀ (v : α → K) (p : { p : ι → MvPolynomial ι K // (∀ i, (p i).support ⊆ mons i) }), + let f : (ι → K) → (ι → K) := fun v i => eval v (p.1 i) + let S : Set (ι → K) := fun x => φ.Realize (Sum.elim v x) + S.MapsTo f S → S.InjOn f → S.SurjOn f S := by classical - intro v - cases nonempty_fintype ι - /- `s` is the set of all coefficients of the polynomial, as well as all of - the coordinates of `v`, the point I am trying to find the preimage of. -/ - let s : Finset R := - (Finset.biUnion (univ : Finset ι) fun i => (ps i).support.image fun x => coeff x (ps i)) ∪ - (univ : Finset ι).image v - have hv : ∀ i, v i ∈ Algebra.adjoin K (s : Set R) := fun j => - Algebra.subset_adjoin (mem_union_right _ (mem_image.2 ⟨j, mem_univ _, rfl⟩)) - have hs₁ : ∀ (i : ι) (k : ι →₀ ℕ), - k ∈ (ps i).support → coeff k (ps i) ∈ Algebra.adjoin K (s : Set R) := - fun i k hk => Algebra.subset_adjoin - (mem_union_left _ (mem_biUnion.2 ⟨i, mem_univ _, mem_image_of_mem _ hk⟩)) - letI := isNoetherian_adjoin_finset s fun x _ => Algebra.IsIntegral.isIntegral (R := K) x - letI := Module.IsNoetherian.finite K (Algebra.adjoin K (s : Set R)) - letI : Finite (Algebra.adjoin K (s : Set R)) := Module.finite_of_finite K - -- The restriction of the polynomial map, `ps`, to the subalgebra generated by `s` - let res : (ι → Algebra.adjoin K (s : Set R)) → ι → Algebra.adjoin K (s : Set R) := fun x i => - ⟨eval (fun j : ι => (x j : R)) (ps i), eval_mem (hs₁ _) fun i => (x i).2⟩ - have hres_inj : Injective res := by - intro x y hxy - ext i - simp only [Subtype.ext_iff, funext_iff] at hxy - exact congr_fun (hinj (funext hxy)) i - have hres_surj : Surjective res := Finite.injective_iff_surjective.1 hres_inj - cases' hres_surj fun i => ⟨v i, hv i⟩ with w hw - use fun i => w i - simpa only [Subtype.ext_iff, funext_iff] using hw + have injOnAlt : ∀ {S : Set (ι → K)} (f : (ι → K) → (ι → K)), + S.InjOn f ↔ ∀ x y, x ∈ S → y ∈ S → f x = f y → x = y := by + simp [Set.InjOn]; tauto + simp only [Sentence.Realize, Formula.Realize, genericPolyMapSurjOnOfInjOn, Formula.relabel, + Function.comp_def, Sum.map, id_eq, Equiv.sumAssoc, Equiv.coe_fn_symm_mk, Sum.elim_inr, + realize_iAlls, realize_imp, realize_relabel, Fin.natAdd_zero, realize_subst, realize_iInf, + Finset.mem_univ, realize_bdEqual, Term.realize_relabel, true_imp_iff, + Equiv.forall_congr_left (Equiv.curry (Fin 2) ι K), Equiv.curry_symm_apply, Function.uncurry, + Fin.forall_fin_succ_pi, Fin.forall_fin_zero_pi, realize_iExs, realize_inf, Sum.forall_sum, + Set.MapsTo, Set.mem_def, injOnAlt, funext_iff, Set.SurjOn, Set.image, setOf, + Set.subset_def, Equiv.forall_congr_left (mvPolynomialSupportLEEquiv mons)] + simp +singlePass only [← Sum.elim_comp_inl_inr] + simp [Set.mem_def, Function.comp_def] + +theorem ACF_models_genericPolyMapSurjOnOfInjOn_of_prime [Fintype ι] + {p : ℕ} (hp : p.Prime) (φ : ring.Formula (α ⊕ ι)) (mons : ι → Finset (ι →₀ ℕ)) : + Theory.ACF p ⊨ᵇ genericPolyMapSurjOnOfInjOn φ mons := by + classical + have : Fact p.Prime := ⟨hp⟩ + letI := compatibleRingOfRing (AlgebraicClosure (ZMod p)) + have : CharP (AlgebraicClosure (ZMod p)) p := + charP_of_injective_algebraMap + (RingHom.injective (algebraMap (ZMod p) (AlgebraicClosure (ZMod p)))) p + rw [← (ACF_isComplete (Or.inl hp)).realize_sentence_iff _ + (AlgebraicClosure (ZMod p)), realize_genericPolyMapSurjOnOfInjOn] + rintro v ⟨f, _⟩ + exact ax_grothendieck_of_locally_finite (K := ZMod p) (ι := ι) f _ + +theorem ACF_models_genericPolyMapSurjOnOfInjOn_of_prime_or_zero + [Fintype ι] {p : ℕ} (hp : p.Prime ∨ p = 0) + (φ : ring.Formula (α ⊕ ι)) (mons : ι → Finset (ι →₀ ℕ)) : + Theory.ACF p ⊨ᵇ genericPolyMapSurjOnOfInjOn φ mons := by + rcases hp with hp | rfl + · exact ACF_models_genericPolyMapSurjOnOfInjOn_of_prime hp φ mons + · rw [ACF_zero_realize_iff_infinite_ACF_prime_realize] + convert Set.infinite_univ (α := Nat.Primes) + rw [Set.eq_univ_iff_forall] + intro ⟨p, hp⟩ + exact ACF_models_genericPolyMapSurjOnOfInjOn_of_prime hp φ mons + +end FirstOrder + +open FirstOrder Language Field Ring MvPolynomial + +variable {K ι : Type*} [Field K] [IsAlgClosed K] [Finite ι] + +/-- A slight generalization of the **Ax-Grothendieck** theorem + +If `K` is an algebraically closed field, `ι` is a finite type, and `S` is a definable subset of +`ι → K`, then any injective polynomial map `S → S` is also surjective on `S`. -/ +theorem ax_grothendieck_of_definable [CompatibleRing K] {c : Set K} + (S : Set (ι → K)) (hS : c.Definable Language.ring S) + (ps : ι → MvPolynomial ι K) : + S.MapsTo (fun v i => eval v (ps i)) S → + S.InjOn (fun v i => eval v (ps i)) → + S.SurjOn (fun v i => eval v (ps i)) S := by + letI := Fintype.ofFinite ι + let p : ℕ := ringChar K + have : CharP K p := ⟨ringChar.spec K⟩ + rw [Set.definable_iff_finitely_definable] at hS + rcases hS with ⟨c, _, hS⟩ + rw [Set.definable_iff_exists_formula_sum] at hS + rcases hS with ⟨φ, hφ⟩ + rw [hφ] + have := ACF_models_genericPolyMapSurjOnOfInjOn_of_prime_or_zero + (CharP.char_is_prime_or_zero K p) φ (fun i => (ps i).support) + rw [← (ACF_isComplete (CharP.char_is_prime_or_zero K p)).realize_sentence_iff _ K, + realize_genericPolyMapSurjOnOfInjOn] at this + exact this Subtype.val ⟨ps, fun i => Set.Subset.refl _⟩ + +/-- The **Ax-Grothendieck** theorem + +If `K` is an algebraically closed field, and `S : Set (ι → K)` is the `zeroLocus` of an ideal +of the multivariable polynomial ring, then any injective polynomial map `S → S` is also +surjective on `S`. -/ +theorem ax_grothendieck_zeroLocus + (I : Ideal (MvPolynomial ι K)) + (p : ι → MvPolynomial ι K) : + let S := zeroLocus I + S.MapsTo (fun v i => eval v (p i)) S → + S.InjOn (fun v i => eval v (p i)) → + S.SurjOn (fun v i => eval v (p i)) S := by + letI := compatibleRingOfRing K + intro S + obtain ⟨s, rfl⟩ : I.FG := IsNoetherian.noetherian I + exact ax_grothendieck_of_definable S (mvPolynomial_zeroLocus_definable s) p + +/-- A special case of the **Ax-Grothendieck** theorem + +Any injective polynomial map `K^n → K^n` is also surjective if `K` is an +algberaically closed field. -/ +theorem ax_grothendieck_univ (p : ι → MvPolynomial ι K) : + (fun v i => eval v (p i)).Injective → + (fun v i => eval v (p i)).Surjective := by + simpa [Set.injective_iff_injOn_univ, Set.surjective_iff_surjOn_univ] using + ax_grothendieck_zeroLocus 0 p diff --git a/Mathlib/FieldTheory/CardinalEmb.lean b/Mathlib/FieldTheory/CardinalEmb.lean new file mode 100644 index 00000000000000..1d4c21d21c8837 --- /dev/null +++ b/Mathlib/FieldTheory/CardinalEmb.lean @@ -0,0 +1,342 @@ +/- +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.FieldTheory.SeparableClosure +import Mathlib.FieldTheory.PurelyInseparable +import Mathlib.LinearAlgebra.FreeAlgebra +import Mathlib.Order.Interval.Set.WithBotTop +import Mathlib.Order.DirectedInverseSystem + +/-! +# Number of embeddings of an algebraic extension of infinite separable degree + +## Main results + +- `Field.Emb.cardinal_eq_two_pow_rank` : if `E/F` is an algebraic separable field extension +of infinite degree, then `#(Field.Emb F E) = 2 ^ Module.rank F E`. +This is in contrast to the case of finite degree, where `#(Field.Emb F E) = Module.rank F E`. + +- `Field.Emb.cardinal_eq_two_pow_sepDegree`: more generally, if `E/F` is an algebraic +extension of infinite separable degree, then `#(Field.Emb F E) = 2 ^ Field.sepDegree F E`. + +## Sketch of the proof + +We use a transfinite recursive construction that is fairly standard in set theory, but the author +has not seen similar arguments elsewhere in mathlib, and some parts proved tricky to formalize. + +The extension `E/F` can be filtered by intermediate fields indexed by a well-order: +simply put a well-order on a basis of `E/F`, and at each step, take the smallest basis element +that is not contained in the intermediate field generated by all previous elements, so that they +generate a strictly larger intermediate field together. This process can extend all the way +to the initial ordinal `ι` of the cardinal `Module.rank F E`, because the dimension of the +subalgebra generated by an infinite set cannot be greater than the cardinality of the set, and +in an algebraic extension, any subalgebra is a field. This is proven as `Algebra.rank_adjoin_le` +and used to show `leastExt` is a total function from `ι` to itself. It is probably +mathematically the most nontrivial part of the whole argument, but turned out easy to +formalize and was done the earliest. + +Once we have the filtration `E⟮ (Module.rank F E).ord.toType + +private local instance : SuccOrder ι := SuccOrder.ofLinearWellFoundedLT ι +local notation i"⁺" => succ i -- Note: conflicts with `PosPart` notation + +/-- A basis of E/F indexed by the initial ordinal. -/ +def wellOrderedBasis : Basis ι F E := + (chooseBasis F E).reindex + (Cardinal.eq.mp <| (mk_ord_toType _).trans <| rank_eq_card_chooseBasisIndex F E).some.symm + +local notation "b" => wellOrderedBasis F E +local notation "Ē" => AlgebraicClosure E + +variable {F E} + +theorem adjoin_basis_eq_top : adjoin F (range b) = ⊤ := + toSubalgebra_injective <| Subalgebra.toSubmodule_injective <| top_unique <| + (Basis.span_eq b).ge.trans <| (Algebra.span_le_adjoin F _).trans <| algebra_adjoin_le_adjoin _ _ + +section Algebraic + +variable [rank_inf : Fact (ℵ₀ ≤ Module.rank F E)] + +lemma noMaxOrder_rank_toType : NoMaxOrder ι := Cardinal.noMaxOrder Fact.out +attribute [local instance] noMaxOrder_rank_toType + +open _root_.Algebra (IsAlgebraic) +variable [IsAlgebraic F E] + +variable (F E) in +/-- `leastExt i` is defined to be the smallest `k : ι` that generates a nontrival extension over +(i.e. does not lie in) the subalgebra (= intermediate field) generated by all previous +`leastExt j`, `j < i`. For cardinality reasons, such `k` always exist if `ι` is infinite. -/ +def leastExt : ι → ι := + wellFounded_lt.fix fun i ih ↦ + let s := range fun j : Iio i ↦ b (ih j j.2) + wellFounded_lt.min {k | b k ∉ adjoin F s} <| by + rw [← compl_setOf, nonempty_compl]; by_contra! + simp_rw [eq_univ_iff_forall, mem_setOf] at this + have := adjoin_le_iff.mpr (range_subset_iff.mpr this) + rw [adjoin_basis_eq_top, ← eq_top_iff] at this + apply_fun Module.rank F at this + refine ne_of_lt ?_ this + conv_rhs => rw [topEquiv.toLinearEquiv.rank_eq] + have := mk_Iio_ord_toType i + obtain eq | lt := rank_inf.out.eq_or_lt + · replace this := mk_lt_aleph0_iff.mp (this.trans_eq eq.symm) + have : FiniteDimensional F (adjoin F s) := + finiteDimensional_adjoin fun x _ ↦ (IsAlgebraic.isAlgebraic x).isIntegral + exact (Module.rank_lt_aleph0 _ _).trans_eq eq + · exact (Subalgebra.equivOfEq _ _ <| adjoin_algebraic_toSubalgebra + fun x _ ↦ IsAlgebraic.isAlgebraic x)|>.toLinearEquiv.rank_eq.trans_lt <| + (Algebra.rank_adjoin_le _).trans_lt (max_lt (mk_range_le.trans_lt this) lt) + +local notation "φ" => leastExt F E + +section +local notation "E⟮<"i"⟯" => adjoin F (b ∘ φ '' Iio i) + +theorem isLeast_leastExt (i : ι) : IsLeast {k | b k ∉ E⟮ Field.Emb (E⟮ filtration i + +variable (F E) in +/-- The functor on `WithTop ι` given by embeddings of `E⟮ rw [← mk_ord_toType (Module.rank F E), ← prod_const'] + exact prod_le_prod _ _ fun i ↦ (Emb.Cardinal.deg_lt_aleph0 _).le + · conv_lhs => rw [← mk_ord_toType (Module.rank F E), ← prod_const'] + exact prod_le_prod _ _ Emb.Cardinal.two_le_deg + +theorem cardinal_eq_of_isSeparable [Algebra.IsSeparable F E] : + #(Field.Emb F E) = (fun c ↦ if ℵ₀ ≤ c then 2 ^ c else c) (Module.rank F E) := by + dsimp only; split_ifs with h + · exact cardinal_eq_two_pow_rank h + rw [not_le, ← IsNoetherian.iff_rank_lt_aleph0] at h + rw [← Module.finrank_eq_rank, ← toNat_eq_iff Module.finrank_pos.ne', + ← Nat.card, ← finSepDegree, finSepDegree_eq_finrank_of_isSeparable] + +theorem cardinal_eq_two_pow_sepDegree [Algebra.IsAlgebraic F E] + (rank_inf : ℵ₀ ≤ sepDegree F E) : #(Field.Emb F E) = 2 ^ sepDegree F E := by + rw [← cardinal_separableClosure, cardinal_eq_two_pow_rank rank_inf] + rfl + +theorem cardinal_eq [Algebra.IsAlgebraic F E] : + #(Field.Emb F E) = (fun c ↦ if ℵ₀ ≤ c then 2 ^ c else c) (sepDegree F E) := by + rw [← cardinal_separableClosure, cardinal_eq_of_isSeparable]; rfl + +end Field.Emb diff --git a/Mathlib/FieldTheory/Extension.lean b/Mathlib/FieldTheory/Extension.lean index da3e16176910d5..142e5ed48085b5 100644 --- a/Mathlib/FieldTheory/Extension.lean +++ b/Mathlib/FieldTheory/Extension.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2020 Thomas Browning. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Thomas Browning +Authors: Thomas Browning, Junyan Xu -/ +import Mathlib.Data.Fintype.Order import Mathlib.FieldTheory.Adjoin /-! @@ -12,6 +13,12 @@ import Mathlib.FieldTheory.Adjoin field extensions, K is another extension of F, and `f` is an embedding of L/F into K/F, such that the minimal polynomials of a set of generators of E/L splits in K (via `f`), then `f` extends to an embedding of E/F into K/F. + +## Reference + +[Isaacs1980] *Roots of Polynomials in Algebraic Extensions of Fields*, +The American Mathematical Monthly + -/ open Polynomial @@ -29,6 +36,8 @@ structure Lifts where variable {F E K} +namespace Lifts + instance : PartialOrder (Lifts F E K) where le L₁ L₂ := ∃ h : L₁.carrier ≤ L₂.carrier, ∀ x, L₂.emb (inclusion h x) = L₁.emb x le_refl L := ⟨le_rfl, by simp⟩ @@ -52,25 +61,144 @@ noncomputable instance : OrderBot (Lifts F E K) where noncomputable instance : Inhabited (Lifts F E K) := ⟨⊥⟩ -/-- A chain of lifts has an upper bound. -/ -theorem Lifts.exists_upper_bound (c : Set (Lifts F E K)) (hc : IsChain (· ≤ ·) c) : - ∃ ub, ∀ a ∈ c, a ≤ ub := by +variable {L₁ L₂ : Lifts F E K} + +theorem le_iff : L₁ ≤ L₂ ↔ + ∃ h : L₁.carrier ≤ L₂.carrier, L₂.emb.comp (inclusion h) = L₁.emb := by + simp_rw [AlgHom.ext_iff]; rfl + +theorem eq_iff_le_carrier_eq : L₁ = L₂ ↔ L₁ ≤ L₂ ∧ L₁.carrier = L₂.carrier := + ⟨fun eq ↦ ⟨eq.le, congr_arg _ eq⟩, fun ⟨le, eq⟩ ↦ le.antisymm ⟨eq.ge, fun x ↦ (le.2 ⟨x, _⟩).symm⟩⟩ + +theorem eq_iff : L₁ = L₂ ↔ + ∃ h : L₁.carrier = L₂.carrier, L₂.emb.comp (inclusion h.le) = L₁.emb := by + rw [eq_iff_le_carrier_eq, le_iff] + exact ⟨fun h ↦ ⟨h.2, h.1.2⟩, fun h ↦ ⟨⟨h.1.le, h.2⟩, h.1⟩⟩ + +theorem lt_iff_le_carrier_ne : L₁ < L₂ ↔ L₁ ≤ L₂ ∧ L₁.carrier ≠ L₂.carrier := by + rw [lt_iff_le_and_ne, and_congr_right]; intro h; simp_rw [Ne, eq_iff_le_carrier_eq, h, true_and] + +theorem lt_iff : L₁ < L₂ ↔ + ∃ h : L₁.carrier < L₂.carrier, L₂.emb.comp (inclusion h.le) = L₁.emb := by + rw [lt_iff_le_carrier_ne, le_iff] + exact ⟨fun h ↦ ⟨h.1.1.lt_of_ne h.2, h.1.2⟩, fun h ↦ ⟨⟨h.1.le, h.2⟩, h.1.ne⟩⟩ + +theorem le_of_carrier_le_iSup {ι} {ρ : ι → Lifts F E K} {σ τ : Lifts F E K} + (hσ : ∀ i, ρ i ≤ σ) (hτ : ∀ i, ρ i ≤ τ) (carrier_le : σ.carrier ≤ ⨆ i, (ρ i).carrier) : + σ ≤ τ := + le_iff.mpr ⟨carrier_le.trans (iSup_le fun i ↦ (hτ i).1), algHom_ext_of_eq_adjoin _ + (carrier_le.antisymm (iSup_le fun i ↦ (hσ i).1)|>.trans <| iSup_eq_adjoin _ _) fun x hx ↦ + have ⟨i, hx⟩ := Set.mem_iUnion.mp hx + ((hτ i).2 ⟨x, hx⟩).trans ((hσ i).2 ⟨x, hx⟩).symm⟩ + +/-- `σ : L →ₐ[F] K` is an extendible lift ("extendible pair" in [Isaacs1980]) if for every +intermediate field `M` that is finite-dimensional over `L`, `σ` extends to some `M →ₐ[F] K`. +In our definition we only require `M` to be finitely generated over `L`, which is equivalent +if the ambient field `E` is algebraic over `F` (which is the case in our main application). +We also allow the domain of the extension to be an intermediate field that properly contains `M`, +since one can always restrict the domain to `M`. -/ +def IsExtendible (σ : Lifts F E K) : Prop := + ∀ S : Finset E, ∃ τ ≥ σ, (S : Set E) ⊆ τ.carrier + +section Chain +variable (c : Set (Lifts F E K)) (hc : IsChain (· ≤ ·) c) + +/-- The union of a chain of lifts. -/ +noncomputable def union : Lifts F E K := let t (i : ↑(insert ⊥ c)) := i.val.carrier - let t' (i) := (t i).toSubalgebra have hc := hc.insert fun _ _ _ ↦ .inl bot_le have dir : Directed (· ≤ ·) t := hc.directedOn.directed_val.mono_comp _ fun _ _ h ↦ h.1 - refine ⟨⟨iSup t, (Subalgebra.iSupLift t' dir (fun i ↦ i.val.emb) (fun i j h ↦ ?_) _ rfl).comp - (Subalgebra.equivOfEq _ _ <| toSubalgebra_iSup_of_directed dir)⟩, - fun L hL ↦ have hL := Set.mem_insert_of_mem ⊥ hL; ⟨le_iSup t ⟨L, hL⟩, fun x ↦ ?_⟩⟩ - · refine AlgHom.ext fun x ↦ (hc.total i.2 j.2).elim (fun hij ↦ (hij.snd x).symm) fun hji ↦ ?_ - erw [AlgHom.comp_apply, ← hji.snd (Subalgebra.inclusion h x), - inclusion_inclusion, inclusion_self, AlgHom.id_apply x] - · dsimp only [AlgHom.comp_apply] - exact Subalgebra.iSupLift_inclusion (K := t') (i := ⟨L, hL⟩) x (le_iSup t' ⟨L, hL⟩) + ⟨iSup t, (Subalgebra.iSupLift (toSubalgebra <| t ·) dir (·.val.emb) (fun i j h ↦ + AlgHom.ext fun x ↦ (hc.total i.2 j.2).elim (fun hij ↦ (hij.snd x).symm) fun hji ↦ by + erw [AlgHom.comp_apply, ← hji.snd (Subalgebra.inclusion h x), + inclusion_inclusion, inclusion_self, AlgHom.id_apply x]) _ rfl).comp + (Subalgebra.equivOfEq _ _ <| toSubalgebra_iSup_of_directed dir)⟩ + +theorem le_union ⦃σ : Lifts F E K⦄ (hσ : σ ∈ c) : σ ≤ union c hc := + have hσ := Set.mem_insert_of_mem ⊥ hσ + let t (i : ↑(insert ⊥ c)) := i.val.carrier + ⟨le_iSup t ⟨σ, hσ⟩, fun x ↦ by + dsimp only [union, AlgHom.comp_apply] + exact Subalgebra.iSupLift_inclusion (K := (toSubalgebra <| t ·)) + (i := ⟨σ, hσ⟩) x (le_iSup (toSubalgebra <| t ·) ⟨σ, hσ⟩)⟩ + +theorem carrier_union : (union c hc).carrier = ⨆ i : c, i.1.carrier := + le_antisymm (iSup_le <| by rintro ⟨i, rfl|hi⟩; exacts [bot_le, le_iSup_of_le ⟨i, hi⟩ le_rfl]) <| + iSup_le fun i ↦ le_iSup_of_le ⟨i, .inr i.2⟩ le_rfl + +/-- A chain of lifts has an upper bound. -/ +theorem exists_upper_bound (c : Set (Lifts F E K)) (hc : IsChain (· ≤ ·) c) : + ∃ ub, ∀ a ∈ c, a ≤ ub := ⟨_, le_union c hc⟩ + +theorem union_isExtendible [alg : Algebra.IsAlgebraic F E] + [Nonempty c] (hext : ∀ σ ∈ c, σ.IsExtendible) : + (union c hc).IsExtendible := fun S ↦ by + let Ω := adjoin F (S : Set E) →ₐ[F] K + have ⟨ω, hω⟩ : ∃ ω : Ω, ∀ π : c, ∃ θ ≥ π.1, ⟨_, ω⟩ ≤ θ ∧ θ.carrier = π.1.1 ⊔ adjoin F S := by + by_contra!; choose π hπ using this + have := finiteDimensional_adjoin (S := (S : Set E)) fun _ _ ↦ (alg.isIntegral).1 _ + have ⟨π₀, hπ₀⟩ := hc.directed.finite_le π + have ⟨θ, hθπ, hθ⟩ := hext _ π₀.2 S + rw [← adjoin_le_iff] at hθ + let θ₀ := θ.emb.comp (inclusion hθ) + have := (hπ₀ θ₀).trans hθπ + exact hπ θ₀ ⟨_, θ.emb.comp <| inclusion <| sup_le this.1 hθ⟩ + ⟨le_sup_left, this.2⟩ ⟨le_sup_right, fun _ ↦ rfl⟩ rfl + choose θ ge hθ eq using hω + have : IsChain (· ≤ ·) (Set.range θ) := by + simp_rw [← restrictScalars_adjoin_eq_sup, restrictScalars_adjoin] at eq + rintro _ ⟨π₁, rfl⟩ _ ⟨π₂, rfl⟩ - + wlog h : π₁ ≤ π₂ generalizing π₁ π₂ + · exact (this _ _ <| (hc.total π₁.2 π₂.2).resolve_left h).symm + refine .inl (le_iff.mpr ⟨?_, algHom_ext_of_eq_adjoin _ (eq _) ?_⟩) + · rw [eq, eq]; exact adjoin.mono _ _ _ (Set.union_subset_union_left _ h.1) + rintro x (hx|hx) + · change (θ π₂).emb (inclusion (ge π₂).1 <| inclusion h.1 ⟨x, hx⟩) = + (θ π₁).emb (inclusion (ge π₁).1 ⟨x, hx⟩) + rw [(ge π₁).2, (ge π₂).2, h.2] + · change (θ π₂).emb (inclusion (hθ π₂).1 ⟨x, subset_adjoin _ _ hx⟩) = + (θ π₁).emb (inclusion (hθ π₁).1 ⟨x, subset_adjoin _ _ hx⟩) + rw [(hθ π₁).2, (hθ π₂).2] + refine ⟨union _ this, le_of_carrier_le_iSup (fun π ↦ le_union c hc π.2) + (fun π ↦ (ge π).trans <| le_union _ _ ⟨_, rfl⟩) (carrier_union _ _).le, ?_⟩ + simp_rw [carrier_union, iSup_range', eq] + exact (subset_adjoin _ _).trans (SetLike.coe_subset_coe.mpr <| + le_sup_right.trans <| le_iSup_of_le (Classical.arbitrary _) le_rfl) + +end Chain + +theorem nonempty_algHom_of_exist_lifts_finset [alg : Algebra.IsAlgebraic F E] + (h : ∀ S : Finset E, ∃ σ : Lifts F E K, (S : Set E) ⊆ σ.carrier) : + Nonempty (E →ₐ[F] K) := by + have : (⊥ : Lifts F E K).IsExtendible := fun S ↦ have ⟨σ, hσ⟩ := h S; ⟨σ, bot_le, hσ⟩ + have ⟨ϕ, hϕ⟩ := zorn_le₀ {ϕ : Lifts F E K | ϕ.IsExtendible} + fun c hext hc ↦ (isEmpty_or_nonempty c).elim + (fun _ ↦ ⟨⊥, this, fun ϕ hϕ ↦ isEmptyElim (⟨ϕ, hϕ⟩ : c)⟩) + fun _ ↦ ⟨_, union_isExtendible c hc hext, le_union c hc⟩ + suffices ϕ.carrier = ⊤ from ⟨ϕ.emb.comp <| ((equivOfEq this).trans topEquiv).symm⟩ + by_contra! + obtain ⟨α, -, hα⟩ := SetLike.exists_of_lt this.lt_top + let _ : Algebra ϕ.carrier K := ϕ.emb.toAlgebra + let Λ := ϕ.carrier⟮α⟯ →ₐ[ϕ.carrier] K + have := finiteDimensional_adjoin (S := {α}) fun _ _ ↦ ((alg.tower_top ϕ.carrier).isIntegral).1 _ + let L (σ : Λ) : Lifts F E K := ⟨ϕ.carrier⟮α⟯.restrictScalars F, σ.restrictScalars F⟩ + have hL (σ : Λ) : ϕ < L σ := lt_iff.mpr + ⟨by simpa only [restrictScalars_adjoin_eq_sup, left_lt_sup, adjoin_simple_le_iff], + AlgHom.coe_ringHom_injective σ.comp_algebraMap⟩ + have ⟨(ϕ_ext : ϕ.IsExtendible), ϕ_max⟩ := maximal_iff_forall_gt.mp hϕ + simp_rw [Set.mem_setOf, IsExtendible] at ϕ_max; push_neg at ϕ_max + choose S hS using fun σ : Λ ↦ ϕ_max (hL σ) + classical + have ⟨θ, hθϕ, hθ⟩ := ϕ_ext ({α} ∪ Finset.univ.biUnion S) + simp_rw [Finset.coe_union, Set.union_subset_iff, Finset.coe_singleton, Set.singleton_subset_iff, + Finset.coe_biUnion, Finset.coe_univ, Set.mem_univ, Set.iUnion_true, Set.iUnion_subset_iff] at hθ + have : ϕ.carrier⟮α⟯.restrictScalars F ≤ θ.carrier := by + rw [restrictScalars_adjoin_eq_sup, sup_le_iff, adjoin_simple_le_iff]; exact ⟨hθϕ.1, hθ.1⟩ + exact hS ⟨(θ.emb.comp <| inclusion this).toRingHom, hθϕ.2⟩ θ ⟨this, fun _ ↦ rfl⟩ (hθ.2 _) /-- Given a lift `x` and an integral element `s : E` over `x.carrier` whose conjugates over `x.carrier` are all in `K`, we can extend the lift to a lift whose carrier contains `s`. -/ -theorem Lifts.exists_lift_of_splits' (x : Lifts F E K) {s : E} (h1 : IsIntegral x.carrier s) +theorem exists_lift_of_splits' (x : Lifts F E K) {s : E} (h1 : IsIntegral x.carrier s) (h2 : (minpoly x.carrier s).Splits x.emb.toRingHom) : ∃ y, x ≤ y ∧ s ∈ y.carrier := have I2 := (minpoly.degree_pos h1).ne' letI : Algebra x.carrier K := x.emb.toRingHom.toAlgebra @@ -87,11 +215,13 @@ theorem Lifts.exists_lift_of_splits' (x : Lifts F E K) {s : E} (h1 : IsIntegral /-- Given an integral element `s : E` over `F` whose `F`-conjugates are all in `K`, any lift can be extended to one whose carrier contains `s`. -/ -theorem Lifts.exists_lift_of_splits (x : Lifts F E K) {s : E} (h1 : IsIntegral F s) +theorem exists_lift_of_splits (x : Lifts F E K) {s : E} (h1 : IsIntegral F s) (h2 : (minpoly F s).Splits (algebraMap F K)) : ∃ y, x ≤ y ∧ s ∈ y.carrier := - Lifts.exists_lift_of_splits' x h1.tower_top <| h1.minpoly_splits_tower_top' <| by + exists_lift_of_splits' x h1.tower_top <| h1.minpoly_splits_tower_top' <| by rwa [← x.emb.comp_algebraMap] at h2 +end Lifts + section private theorem exists_algHom_adjoin_of_splits'' {L : IntermediateField F E} diff --git a/Mathlib/FieldTheory/IntermediateField/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Basic.lean index 994c57c28bf6dc..33d4aa8b3bf974 100644 --- a/Mathlib/FieldTheory/IntermediateField/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Basic.lean @@ -37,8 +37,6 @@ intermediate field, field extension -/ -open Polynomial - open Polynomial variable (K L L' : Type*) [Field K] [Field L] [Field L'] [Algebra K L] [Algebra K L'] diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index 2ec4275183cac0..c164bdbac95217 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -32,10 +32,12 @@ polynomial in `k` splits. algebraic closure, algebraically closed -## TODO +## Main reults -- Prove that if `K / k` is algebraic, and any monic irreducible polynomial over `k` has a root - in `K`, then `K` is algebraically closed (in fact an algebraic closure of `k`). +- `IsAlgClosure.of_splits`: if `K / k` is algebraic, and every monic irreducible polynomial over + `k` splits in `K`, then `K` is algebraically closed (in fact an algebraic closure of `k`). + For the stronger fact that only requires every such polynomial has a root in `K`, + see `IsAlgClosure.of_exist_roots`. Reference: , Theorem 2 @@ -410,7 +412,7 @@ noncomputable def equivOfEquivAux (hSR : S ≃+* R) : haveI : IsScalarTower S R L := IsScalarTower.of_algebraMap_eq (by simp [RingHom.algebraMap_toAlgebra]) haveI : NoZeroSMulDivisors R S := NoZeroSMulDivisors.of_algebraMap_injective hSR.symm.injective - have : Algebra.IsAlgebraic R L := (IsAlgClosure.isAlgebraic.tower_top_of_injective + have : Algebra.IsAlgebraic R L := (IsAlgClosure.isAlgebraic.extendScalars (show Function.Injective (algebraMap S R) from hSR.injective)) refine ⟨equivOfAlgebraic' R S L M, ?_⟩ diff --git a/Mathlib/FieldTheory/Isaacs.lean b/Mathlib/FieldTheory/Isaacs.lean new file mode 100644 index 00000000000000..2219c66b3c0276 --- /dev/null +++ b/Mathlib/FieldTheory/Isaacs.lean @@ -0,0 +1,115 @@ +/- +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.FieldTheory.PrimitiveElement +import Mathlib.GroupTheory.CosetCover + +/-! +# Algebraic extensions are determined by their sets of minimal polynomials up to isomorphism + +## Main results + +`Field.nonempty_algHom_of_exist_roots` says if `E/F` and `K/F` are field extensions +with `E/F` algebraic, and if the minimal polynomial of every element of `E` over `F` has a root +in `K`, then there exists an `F`-embedding of `E` into `K`. If `E/F` and `K/F` have the same +set of minimal polynomials, then `E` and `K` are isomorphic as `F`-algebras. As a corollary: + +`IsAlgClosure.of_exist_roots`: if `E/F` is algebraic and every monic irreducible polynomial +in `F[X]` has a root in `E`, then `E` is an algebraic closure of `F`. + +## Reference + +[Isaacs1980] *Roots of Polynomials in Algebraic Extensions of Fields*, +The American Mathematical Monthly + +-/ + +namespace Field + +open Polynomial IntermediateField + +variable {F E K : Type*} [Field F] [Field E] [Field K] [Algebra F E] [Algebra F K] +variable [alg : Algebra.IsAlgebraic F E] + +theorem nonempty_algHom_of_exist_roots (h : ∀ x : E, ∃ y : K, aeval y (minpoly F x) = 0) : + Nonempty (E →ₐ[F] K) := by + refine Lifts.nonempty_algHom_of_exist_lifts_finset fun S ↦ ⟨⟨adjoin F S, ?_⟩, subset_adjoin _ _⟩ + let p := (S.prod <| minpoly F).map (algebraMap F K) + let K' := SplittingField p + have splits s (hs : s ∈ S) : (minpoly F s).Splits (algebraMap F K') := by + apply splits_of_splits_of_dvd _ + (Finset.prod_ne_zero_iff.mpr fun _ _ ↦ minpoly.ne_zero <| (alg.isIntegral).1 _) + ((splits_map_iff _ _).mp <| SplittingField.splits p) (Finset.dvd_prod_of_mem _ hs) + let K₀ := (⊥ : IntermediateField K K').restrictScalars F + let FS := adjoin F (S : Set E) + let Ω := FS →ₐ[F] K' + have := finiteDimensional_adjoin (S := (S : Set E)) fun _ _ ↦ (alg.isIntegral).1 _ + let M (ω : Ω) := Subalgebra.toSubmodule (K₀.comap ω).toSubalgebra + have : ⋃ ω : Ω, (M ω : Set FS) = Set.univ := + Set.eq_univ_of_forall fun ⟨α, hα⟩ ↦ Set.mem_iUnion.mpr <| by + have ⟨β, hβ⟩ := h α + let ϕ : F⟮α⟯ →ₐ[F] K' := (IsScalarTower.toAlgHom _ _ _).comp ((AdjoinRoot.liftHom _ _ hβ).comp + (adjoinRootEquivAdjoin F <| (alg.isIntegral).1 _).symm.toAlgHom) + have ⟨ω, hω⟩ := exists_algHom_adjoin_of_splits + (fun s hs ↦ ⟨(alg.isIntegral).1 _, splits s hs⟩) ϕ (adjoin_simple_le_iff.mpr hα) + refine ⟨ω, β, ((DFunLike.congr_fun hω <| AdjoinSimple.gen F α).trans ?_).symm⟩ + rw [AlgHom.comp_apply, AlgHom.comp_apply, AlgEquiv.coe_algHom, + adjoinRootEquivAdjoin_symm_apply_gen, AdjoinRoot.liftHom_root] + rfl + have ω : ∃ ω : Ω, ⊤ ≤ M ω := by + cases finite_or_infinite F + · have ⟨α, hα⟩ := exists_primitive_element_of_finite_bot F FS + have ⟨ω, hω⟩ := Set.mem_iUnion.mp (this ▸ Set.mem_univ α) + exact ⟨ω, show ⊤ ≤ K₀.comap ω by rwa [← hα, adjoin_simple_le_iff]⟩ + · simp_rw [top_le_iff, Subspace.exists_eq_top_of_iUnion_eq_univ this] + exact ((botEquiv K K').toAlgHom.restrictScalars F).comp + (ω.choose.codRestrict K₀.toSubalgebra fun x ↦ ω.choose_spec trivial) + +theorem nonempty_algHom_of_minpoly_eq + (h : ∀ x : E, ∃ y : K, minpoly F x = minpoly F y) : + Nonempty (E →ₐ[F] K) := + nonempty_algHom_of_exist_roots fun x ↦ have ⟨y, hy⟩ := h x; ⟨y, by rw [hy, minpoly.aeval]⟩ + +theorem nonempty_algHom_of_range_minpoly_subset + (h : Set.range (@minpoly F E _ _ _) ⊆ Set.range (@minpoly F K _ _ _)) : + Nonempty (E →ₐ[F] K) := + nonempty_algHom_of_minpoly_eq fun x ↦ have ⟨y, hy⟩ := h ⟨x, rfl⟩; ⟨y, hy.symm⟩ + +theorem nonempty_algEquiv_of_range_minpoly_eq + (h : Set.range (@minpoly F E _ _ _) = Set.range (@minpoly F K _ _ _)) : + Nonempty (E ≃ₐ[F] K) := + have ⟨σ⟩ := nonempty_algHom_of_range_minpoly_subset h.le + have : Algebra.IsAlgebraic F K := ⟨fun y ↦ IsIntegral.isAlgebraic <| by + by_contra hy + have ⟨x, hx⟩ := h.ge ⟨y, rfl⟩ + rw [minpoly.eq_zero hy] at hx + exact minpoly.ne_zero ((alg.isIntegral).1 x) hx⟩ + have ⟨τ⟩ := nonempty_algHom_of_range_minpoly_subset h.ge + ⟨.ofBijective _ (Algebra.IsAlgebraic.algHom_bijective₂ σ τ).1⟩ + +theorem nonempty_algHom_of_aeval_eq_zero_subset + (h : {p : F[X] | ∃ x : E, aeval x p = 0} ⊆ {p | ∃ y : K, aeval y p = 0}) : + Nonempty (E →ₐ[F] K) := + nonempty_algHom_of_minpoly_eq fun x ↦ + have ⟨y, hy⟩ := h ⟨_, minpoly.aeval F x⟩ + ⟨y, (minpoly.eq_iff_aeval_minpoly_eq_zero <| (alg.isIntegral).1 x).mpr hy⟩ + +theorem nonempty_algEquiv_of_aeval_eq_zero_eq [Algebra.IsAlgebraic F K] + (h : {p : F[X] | ∃ x : E, aeval x p = 0} = {p | ∃ y : K, aeval y p = 0}) : + Nonempty (E ≃ₐ[F] K) := + have ⟨σ⟩ := nonempty_algHom_of_aeval_eq_zero_subset h.le + have ⟨τ⟩ := nonempty_algHom_of_aeval_eq_zero_subset h.ge + ⟨.ofBijective _ (Algebra.IsAlgebraic.algHom_bijective₂ σ τ).1⟩ + +theorem _root_.IsAlgClosure.of_exist_roots + (h : ∀ p : F[X], p.Monic → Irreducible p → ∃ x : E, aeval x p = 0) : + IsAlgClosure F E := + .of_splits fun p _ _ ↦ + have ⟨σ⟩ := nonempty_algHom_of_exist_roots fun x : p.SplittingField ↦ + have := Algebra.IsAlgebraic.isIntegral (K := F).1 x + h _ (minpoly.monic this) (minpoly.irreducible this) + splits_of_algHom (SplittingField.splits _) σ + +end Field diff --git a/Mathlib/FieldTheory/JacobsonNoether.lean b/Mathlib/FieldTheory/JacobsonNoether.lean new file mode 100644 index 00000000000000..e019eaf9f42310 --- /dev/null +++ b/Mathlib/FieldTheory/JacobsonNoether.lean @@ -0,0 +1,195 @@ +/- +Copyright (c) 2024 F. Nuccio, H. Zheng, W. He, S. Wu, Y. Yuan, W. Jiao. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Filippo A. E. Nuccio, Huanyu Zheng, Sihan Wu, Wanyi He, Weichen Jiao, Yi Yuan +-/ +import Mathlib.Algebra.Central.Defs +import Mathlib.Algebra.CharP.LinearMaps +import Mathlib.Algebra.CharP.Subring +import Mathlib.Algebra.GroupWithZero.Conj +import Mathlib.Algebra.Lie.OfAssociative +import Mathlib.FieldTheory.PurelyInseparable + +/-! +# The Jacobson-Noether theorem + +This file contains a proof of the Jacobson-Noether theorem and some auxiliary lemmas. +Here we discuss different cases of characteristics of +the noncommutative division algebra `D` with center `k`. + +## Main Results + +- `exists_separable_and_not_isCentral` : (Jacobson-Noether theorem) For a + non-commutative algebraic division algebra `D` (with base ring + being its center `k`), then there exist an element `x` of + `D \ k` that is separable over its center. +- `exists_separable_and_not_isCentral'` : (Jacobson-Noether theorem) For a + non-commutative algebraic division algebra `D` (with base ring + being a field `L`), if the center of `D` over `L` is `L`, + then there exist an element `x` of `D \ L` that is separable over `L`. + +## Notations + +- `D` is a noncommutative division algebra +- `k` is the center of `D` + +## Implementation Notes + +Mathematically, `exists_separable_and_not_isCentral` and `exists_separable_and_not_isCentral'` +are equivalent. + +The difference however, is that the former takes `D` as the only variable +and fixing `D` would forces `k`. Whereas the later takes `D` and `L` as +separate variables constrained by certain relations. + +## Reference +* +-/ + +namespace JacobsonNoether + +variable {D : Type*} [DivisionRing D] [Algebra.IsAlgebraic (Subring.center D) D] + +local notation3 "k" => Subring.center D + +open Polynomial LinearMap LieAlgebra + +/-- If `D` is a purely inseparable extension of `k` with characteristic `p`, + then for every element `a` of `D`, there exists a natural number `n` + such that `a ^ (p ^ n)` is contained in `k`. -/ +lemma exists_pow_mem_center_of_inseparable (p : ℕ) [hchar : ExpChar D p] (a : D) + (hinsep : ∀ x : D, IsSeparable k x → x ∈ k) : ∃ n, a ^ (p ^ n) ∈ k := by + have := (@isPurelyInseparable_iff_pow_mem k D _ _ _ _ p (ExpChar.expChar_center_iff.2 hchar)).1 + have pure : IsPurelyInseparable k D := ⟨Algebra.IsAlgebraic.isIntegral, fun x hx ↦ by + rw [RingHom.mem_range, Subtype.exists] + exact ⟨x, ⟨hinsep x hx, rfl⟩⟩⟩ + obtain ⟨n, ⟨m, hm⟩⟩ := this pure a + have := Subalgebra.range_subset (R := k) ⟨(k).toSubsemiring, fun r ↦ r.2⟩ + exact ⟨n, Set.mem_of_subset_of_mem this <| Set.mem_range.2 ⟨m, hm⟩⟩ + +/-- If `D` is a purely inseparable extension of `k` with characteristic `p`, + then for every element `a` of `D \ k`, there exists a natural number `n` + **greater than 0** such that `a ^ (p ^ n)` is contained in `k`. -/ +lemma exists_pow_mem_center_of_inseparable' (p : ℕ) [ExpChar D p] {a : D} + (ha : a ∉ k) (hinsep : ∀ x : D, IsSeparable k x → x ∈ k) : ∃ n, 1 ≤ n ∧ a ^ (p ^ n) ∈ k := by + obtain ⟨n, hn⟩ := exists_pow_mem_center_of_inseparable p a hinsep + by_cases nzero : n = 0 + · rw [nzero, pow_zero, pow_one] at hn + exact (ha hn).elim + · exact ⟨n, ⟨Nat.one_le_iff_ne_zero.mpr nzero, hn⟩⟩ + +/-- If `D` is a purely inseparable extension of `k` of characteristic `p`, + then for every element `a` of `D \ k`, there exists a natural number `m` + greater than 0 such that `(a * x - x * a) ^ n = 0` (as linear maps) for + every `n` greater than `(p ^ m)`. -/ +lemma exist_pow_eq_zero_of_le (p : ℕ) [hchar : ExpChar D p] + {a : D} (ha : a ∉ k) (hinsep : ∀ x : D, IsSeparable k x → x ∈ k): + ∃ m, 1 ≤ m ∧ ∀ n, p ^ m ≤ n → (ad k D a)^[n] = 0 := by + obtain ⟨m, hm⟩ := exists_pow_mem_center_of_inseparable' p ha hinsep + refine ⟨m, ⟨hm.1, fun n hn ↦ ?_⟩⟩ + have inter : (ad k D a)^[p ^ m] = 0 := by + ext x + rw [ad_eq_lmul_left_sub_lmul_right, ← pow_apply, Pi.sub_apply, + sub_pow_expChar_pow_of_commute p m (commute_mulLeft_right a a), sub_apply, + pow_mulLeft, mulLeft_apply, pow_mulRight, mulRight_apply, Pi.zero_apply, + Subring.mem_center_iff.1 hm.2 x] + exact sub_eq_zero_of_eq rfl + rw [(Nat.sub_eq_iff_eq_add hn).1 rfl, Function.iterate_add, inter, Pi.comp_zero, + iterate_map_zero, Function.const_zero] + +variable (D) in +/-- Jacobson-Noether theorem: For a non-commutative division algebra + `D` that is algebraic over its center `k`, there exists an element + `x` of `D \ k` that is separable over `k`. -/ +theorem exists_separable_and_not_isCentral (H : k ≠ (⊤ : Subring D)) : + ∃ x : D, x ∉ k ∧ IsSeparable k x := by + obtain ⟨p, hp⟩ := ExpChar.exists D + by_contra! insep + replace insep : ∀ x : D, IsSeparable k x → x ∈ k := + fun x h ↦ Classical.byContradiction fun hx ↦ insep x hx h + -- The element `a` below is in `D` but not in `k`. + obtain ⟨a, ha⟩ := not_forall.mp <| mt (Subring.eq_top_iff' k).mpr H + have ha₀ : a ≠ 0 := fun nh ↦ nh ▸ ha <| Subring.zero_mem k + -- We construct another element `b` that does not commute with `a`. + obtain ⟨b, hb1⟩ : ∃ b : D , ad k D a b ≠ 0 := by + rw [Subring.mem_center_iff, not_forall] at ha + use ha.choose + show a * ha.choose - ha.choose * a ≠ 0 + simpa only [ne_eq, sub_eq_zero] using Ne.symm ha.choose_spec + -- We find a maximum natural number `n` such that `(a * x - x * a) ^ n b ≠ 0`. + obtain ⟨n, hn, hb⟩ : ∃ n, 0 < n ∧ (ad k D a)^[n] b ≠ 0 ∧ (ad k D a)^[n + 1] b = 0 := by + obtain ⟨m, -, hm2⟩ := exist_pow_eq_zero_of_le p ha insep + have h_exist : ∃ n, 0 < n ∧ (ad k D a)^[n + 1] b = 0 := ⟨p ^ m, + ⟨expChar_pow_pos D p m, by rw [hm2 (p ^ m + 1) (Nat.le_add_right _ _)]; rfl⟩⟩ + classical + refine ⟨Nat.find h_exist, ⟨(Nat.find_spec h_exist).1, ?_, (Nat.find_spec h_exist).2⟩⟩ + set t := (Nat.find h_exist - 1 : ℕ) with ht + by_cases h_pos : 0 < t + · convert (ne_eq _ _) ▸ not_and.mp (Nat.find_min h_exist (m := t) (by omega)) h_pos + omega + · suffices h_find: Nat.find h_exist = 1 by + rwa [h_find] + rw [not_lt, Nat.le_zero, ht, Nat.sub_eq_zero_iff_le] at h_pos + linarith [(Nat.find_spec h_exist).1] + -- We define `c` to be the value that we proved above to be non-zero. + set c := (ad k D a)^[n] b with hc_def + let _ : Invertible c := ⟨c⁻¹, inv_mul_cancel₀ hb.1, mul_inv_cancel₀ hb.1⟩ + -- We prove that `c` commutes with `a`. + have hc : a * c = c * a := by + apply eq_of_sub_eq_zero + rw [← mulLeft_apply (R := k), ← mulRight_apply (R := k)] + suffices ad k D a c = 0 from by + rw [← this]; rfl + rw [← Function.iterate_succ_apply' (ad k D a) n b, hb.2] + -- We now make some computation to obtain the final equation. + set d := c⁻¹ * a * (ad k D a)^[n - 1] b with hd_def + have hc': c⁻¹ * a = a * c⁻¹ := by + apply_fun (c⁻¹ * · * c⁻¹) at hc + rw [mul_assoc, mul_assoc, mul_inv_cancel₀ hb.1, mul_one, ← mul_assoc, + inv_mul_cancel₀ hb.1, one_mul] at hc + exact hc + have c_eq : a * (ad k D a)^[n - 1] b - (ad k D a)^[n - 1] b * a = c := by + rw [hc_def, ← Nat.sub_add_cancel hn, Function.iterate_succ_apply' (ad k D a) _ b]; rfl + have eq1 : c⁻¹ * a * (ad k D a)^[n - 1] b - c⁻¹ * (ad k D a)^[n - 1] b * a = 1 := by + simp_rw [mul_assoc, (mul_sub_left_distrib c⁻¹ _ _).symm, c_eq, inv_mul_cancel_of_invertible] + -- We show that `a` commutes with `d`. + have deq : a * d - d * a = a := by + nth_rw 3 [← mul_one a] + rw [hd_def, ← eq1, mul_sub, mul_assoc _ _ a, sub_right_inj, hc', + ← mul_assoc, ← mul_assoc, ← mul_assoc] + -- This then yields a contradiction. + apply_fun (a⁻¹ * · ) at deq + rw [mul_sub, ← mul_assoc, inv_mul_cancel₀ ha₀, one_mul, ← mul_assoc, sub_eq_iff_eq_add] at deq + obtain ⟨r, hr⟩ := exists_pow_mem_center_of_inseparable p d insep + apply_fun (· ^ (p ^ r)) at deq + rw [add_pow_expChar_pow_of_commute p r (Commute.one_left _) , one_pow, + GroupWithZero.conj_pow₀ ha₀, ← hr.comm, mul_assoc, inv_mul_cancel₀ ha₀, mul_one, + self_eq_add_left] at deq + exact one_ne_zero deq + +open Subring Algebra in +/-- Jacobson-Noether theorem: For a non-commutative division algebra `D` + that is algebraic over a field `L`, if the center of + `D` coincides with `L`, then there exist an element `x` of `D \ L` + that is separable over `L`. -/ +theorem exists_separable_and_not_isCentral' {L D : Type*} [Field L] [DivisionRing D] + [Algebra L D] [Algebra.IsAlgebraic L D] [Algebra.IsCentral L D] + (hneq : (⊥ : Subalgebra L D) ≠ ⊤) : + ∃ x : D, x ∉ (⊥ : Subalgebra L D) ∧ IsSeparable L x := by + have hcenter : Subalgebra.center L D = ⊥ := le_bot_iff.mp IsCentral.out + have ntrivial : Subring.center D ≠ ⊤ := + congr(Subalgebra.toSubring $hcenter).trans_ne (Subalgebra.toSubring_injective.ne hneq) + set φ := Subalgebra.equivOfEq (⊥ : Subalgebra L D) (.center L D) hcenter.symm + set equiv : L ≃+* (center D) := ((botEquiv L D).symm.trans φ).toRingEquiv + let _ : Algebra L (center D) := equiv.toRingHom.toAlgebra + let _ : Algebra (center D) L := equiv.symm.toRingHom.toAlgebra + have _ : IsScalarTower L (center D) D := .of_algebraMap_eq fun _ ↦ rfl + have _ : IsScalarTower (center D) L D := .of_algebraMap_eq fun x ↦ by + rw [IsScalarTower.algebraMap_apply L (center D)] + congr + exact (equiv.apply_symm_apply x).symm + have _ : Algebra.IsAlgebraic (center D) D := .tower_top (K := L) _ + obtain ⟨x, hxd, hx⟩ := exists_separable_and_not_isCentral D ntrivial + exact ⟨x, ⟨by rwa [← Subalgebra.center_toSubring L, hcenter] at hxd, IsSeparable.tower_top _ hx⟩⟩ + +end JacobsonNoether diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index 8025c4eff3c76c..c6a67370781a22 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -24,26 +24,21 @@ This file contains basics about the separable degree of a field extension. advantage that `Field.Emb F E` lies in the same universe as `E` rather than the maximum over `F` and `E`). Usually denoted by $\operatorname{Emb}_F(E)$ in textbooks. - **Remark:** if `E / F` is not algebraic, then this definition makes no mathematical sense, - and if it is infinite, then its cardinality doesn't behave as expected (namely, not equal to the - field extension degree of `separableClosure F E / F`). For example, if $F = \mathbb{Q}$ and - $E = \mathbb{Q}( \mu_{p^\infty} )$, then $\operatorname{Emb}_F (E)$ is in bijection with - $\operatorname{Gal}(E/F)$, which is isomorphic to - $\mathbb{Z}_p^\times$, which is uncountable, while $[E:F]$ is countable. - - **TODO:** prove or disprove that if `E / F` is algebraic and `Emb F E` is infinite, then - `Field.Emb F E` has cardinality `2 ^ Module.rank F (separableClosure F E)`. - -- `Field.finSepDegree F E`: the (finite) separable degree $[E:F]_s$ of an algebraic extension - `E / F` of fields, defined to be the number of `F`-algebra homomorphisms from `E` to the algebraic +- `Field.finSepDegree F E`: the (finite) separable degree $[E:F]_s$ of an extension `E / F` + of fields, defined to be the number of `F`-algebra homomorphisms from `E` to the algebraic closure of `E`, as a natural number. It is zero if `Field.Emb F E` is not finite. Note that if `E / F` is not algebraic, then this definition makes no mathematical sense. **Remark:** the `Cardinal`-valued, potentially infinite separable degree `Field.sepDegree F E` for a general algebraic extension `E / F` is defined to be the degree of `L / F`, where `L` is - the (relative) separable closure `separableClosure F E` of `F` in `E`, which is not defined in - this file yet. Later we will show that (`Field.finSepDegree_eq`), if `Field.Emb F E` is finite, - then these two definitions coincide. + the separable closure of `F` in `E`, which is not defined in this file yet. Later we + will show that (`Field.finSepDegree_eq`), if `Field.Emb F E` is finite, then these two + definitions coincide. If `E / F` is algebraic with infinite separable degree, we have + `#(Field.Emb F E) = 2 ^ Field.sepDegree F E` instead. + (See `Field.Emb.cardinal_eq_two_pow_sepDegree` in another file.) For example, if + $F = \mathbb{Q}$ and $E = \mathbb{Q}( \mu_{p^\infty} )$, then $\operatorname{Emb}_F (E)$ + is in bijection with $\operatorname{Gal}(E/F)$, which is isomorphic to + $\mathbb{Z}_p^\times$, which is uncountable, whereas $ [E:F] $ is countable. - `Polynomial.natSepDegree`: the separable degree of a polynomial is a natural number, defined to be the number of distinct roots of it over its splitting field. diff --git a/Mathlib/FieldTheory/Tower.lean b/Mathlib/FieldTheory/Tower.lean index dbe2c6efe3f027..59cdb775f2ec47 100644 --- a/Mathlib/FieldTheory/Tower.lean +++ b/Mathlib/FieldTheory/Tower.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic /-! # Finiteness of `IsScalarTower` diff --git a/Mathlib/Geometry/Euclidean/Inversion/Basic.lean b/Mathlib/Geometry/Euclidean/Inversion/Basic.lean index 4b75f996be8183..ef7c492a1d056c 100644 --- a/Mathlib/Geometry/Euclidean/Inversion/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Inversion/Basic.lean @@ -194,7 +194,7 @@ theorem mul_dist_le_mul_dist_add_mul_dist (a b c d : P) : rw [dist_inversion_inversion hb hd, dist_inversion_inversion hb hc, dist_inversion_inversion hc hd, one_pow] at H rw [← dist_pos] at hb hc hd - rw [← div_le_div_right (mul_pos hb (mul_pos hc hd))] + rw [← div_le_div_iff_of_pos_right (mul_pos hb (mul_pos hc hd))] convert H using 1 <;> (field_simp [hb.ne', hc.ne', hd.ne', dist_comm a]; ring) end EuclideanGeometry diff --git a/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean b/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean index 998cc71804f14e..9e2358ae486b10 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean @@ -23,6 +23,9 @@ implementing one of the possible definitions of the Lie algebra attached to a Li noncomputable section open scoped LieGroup Manifold Derivation +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) (G : Type*) diff --git a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean index c054be8efa60bf..c9dd661d44afd3 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean @@ -58,7 +58,7 @@ class LieAddGroup {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [Top {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) (G : Type*) [AddGroup G] [TopologicalSpace G] [ChartedSpace H G] extends SmoothAdd I G : Prop where /-- Negation is smooth in an additive Lie group. -/ - smooth_neg : Smooth I I fun a : G => -a + smooth_neg : ContMDiff I I ⊤ fun a : G => -a -- See note [Design choices about smooth algebraic structures] /-- A (multiplicative) Lie group is a group and a smooth manifold at the same time in which @@ -68,7 +68,7 @@ class LieGroup {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [Topolo {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) (G : Type*) [Group G] [TopologicalSpace G] [ChartedSpace H G] extends SmoothMul I G : Prop where /-- Inversion is smooth in a Lie group. -/ - smooth_inv : Smooth I I fun a : G => a⁻¹ + smooth_inv : ContMDiff I I ⊤ fun a : G => a⁻¹ /-! ### Smoothness of inversion, negation, division and subtraction @@ -91,28 +91,31 @@ variable (I) /-- In a Lie group, inversion is a smooth map. -/ @[to_additive "In an additive Lie group, inversion is a smooth map."] -theorem smooth_inv : Smooth I I fun x : G => x⁻¹ := +theorem contMDiff_inv : ContMDiff I I ⊤ fun x : G => x⁻¹ := LieGroup.smooth_inv +@[deprecated (since := "2024-11-21")] alias smooth_inv := contMDiff_inv +@[deprecated (since := "2024-11-21")] alias smooth_neg := contMDiff_neg + include I in /-- A Lie group is a topological group. This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]. -/ @[to_additive "An additive Lie group is an additive topological group. This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]."] theorem topologicalGroup_of_lieGroup : TopologicalGroup G := - { continuousMul_of_smooth I with continuous_inv := (smooth_inv I).continuous } + { continuousMul_of_smooth I with continuous_inv := (contMDiff_inv I).continuous } end @[to_additive] theorem ContMDiffWithinAt.inv {f : M → G} {s : Set M} {x₀ : M} (hf : ContMDiffWithinAt I' I n f s x₀) : ContMDiffWithinAt I' I n (fun x => (f x)⁻¹) s x₀ := - ((smooth_inv I).of_le le_top).contMDiffAt.contMDiffWithinAt.comp x₀ hf <| Set.mapsTo_univ _ _ + ((contMDiff_inv I).of_le le_top).contMDiffAt.contMDiffWithinAt.comp x₀ hf <| Set.mapsTo_univ _ _ @[to_additive] theorem ContMDiffAt.inv {f : M → G} {x₀ : M} (hf : ContMDiffAt I' I n f x₀) : ContMDiffAt I' I n (fun x => (f x)⁻¹) x₀ := - ((smooth_inv I).of_le le_top).contMDiffAt.comp x₀ hf + ((contMDiff_inv I).of_le le_top).contMDiffAt.comp x₀ hf @[to_additive] theorem ContMDiffOn.inv {f : M → G} {s : Set M} (hf : ContMDiffOn I' I n f s) : @@ -122,24 +125,15 @@ theorem ContMDiffOn.inv {f : M → G} {s : Set M} (hf : ContMDiffOn I' I n f s) theorem ContMDiff.inv {f : M → G} (hf : ContMDiff I' I n f) : ContMDiff I' I n fun x => (f x)⁻¹ := fun x => (hf x).inv -@[to_additive] -nonrec theorem SmoothWithinAt.inv {f : M → G} {s : Set M} {x₀ : M} - (hf : SmoothWithinAt I' I f s x₀) : SmoothWithinAt I' I (fun x => (f x)⁻¹) s x₀ := - hf.inv - -@[to_additive] -nonrec theorem SmoothAt.inv {f : M → G} {x₀ : M} (hf : SmoothAt I' I f x₀) : - SmoothAt I' I (fun x => (f x)⁻¹) x₀ := - hf.inv +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.inv := ContMDiffWithinAt.inv +@[deprecated (since := "2024-11-21")] alias SmoothAt.inv := ContMDiffAt.inv +@[deprecated (since := "2024-11-21")] alias SmoothOn.inv := ContMDiffOn.inv +@[deprecated (since := "2024-11-21")] alias Smooth.inv := ContMDiff.inv -@[to_additive] -nonrec theorem SmoothOn.inv {f : M → G} {s : Set M} (hf : SmoothOn I' I f s) : - SmoothOn I' I (fun x => (f x)⁻¹) s := - hf.inv - -@[to_additive] -nonrec theorem Smooth.inv {f : M → G} (hf : Smooth I' I f) : Smooth I' I fun x => (f x)⁻¹ := - hf.inv +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.neg := ContMDiffWithinAt.neg +@[deprecated (since := "2024-11-21")] alias SmoothAt.neg := ContMDiffAt.neg +@[deprecated (since := "2024-11-21")] alias SmoothOn.neg := ContMDiffOn.neg +@[deprecated (since := "2024-11-21")] alias Smooth.neg := ContMDiff.neg @[to_additive] theorem ContMDiffWithinAt.div {f g : M → G} {s : Set M} {x₀ : M} @@ -161,26 +155,15 @@ theorem ContMDiffOn.div {f g : M → G} {s : Set M} (hf : ContMDiffOn I' I n f s theorem ContMDiff.div {f g : M → G} (hf : ContMDiff I' I n f) (hg : ContMDiff I' I n g) : ContMDiff I' I n fun x => f x / g x := by simp_rw [div_eq_mul_inv]; exact hf.mul hg.inv -@[to_additive] -nonrec theorem SmoothWithinAt.div {f g : M → G} {s : Set M} {x₀ : M} - (hf : SmoothWithinAt I' I f s x₀) (hg : SmoothWithinAt I' I g s x₀) : - SmoothWithinAt I' I (fun x => f x / g x) s x₀ := - hf.div hg +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.div := ContMDiffWithinAt.div +@[deprecated (since := "2024-11-21")] alias SmoothAt.div := ContMDiffAt.div +@[deprecated (since := "2024-11-21")] alias SmoothOn.div := ContMDiffOn.div +@[deprecated (since := "2024-11-21")] alias Smooth.div := ContMDiff.div -@[to_additive] -nonrec theorem SmoothAt.div {f g : M → G} {x₀ : M} (hf : SmoothAt I' I f x₀) - (hg : SmoothAt I' I g x₀) : SmoothAt I' I (fun x => f x / g x) x₀ := - hf.div hg - -@[to_additive] -nonrec theorem SmoothOn.div {f g : M → G} {s : Set M} (hf : SmoothOn I' I f s) - (hg : SmoothOn I' I g s) : SmoothOn I' I (f / g) s := - hf.div hg - -@[to_additive] -nonrec theorem Smooth.div {f g : M → G} (hf : Smooth I' I f) (hg : Smooth I' I g) : - Smooth I' I (f / g) := - hf.div hg +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.sub := ContMDiffWithinAt.sub +@[deprecated (since := "2024-11-21")] alias SmoothAt.sub := ContMDiffAt.sub +@[deprecated (since := "2024-11-21")] alias SmoothOn.sub := ContMDiffOn.sub +@[deprecated (since := "2024-11-21")] alias Smooth.sub := ContMDiff.sub end PointwiseDivision @@ -195,7 +178,7 @@ instance {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalS [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {G' : Type*} [TopologicalSpace G'] [ChartedSpace H' G'] [Group G'] [LieGroup I' G'] : LieGroup (I.prod I') (G × G') := - { SmoothMul.prod _ _ _ _ with smooth_inv := smooth_fst.inv.prod_mk smooth_snd.inv } + { SmoothMul.prod _ _ _ _ with smooth_inv := contMDiff_fst.inv.prod_mk contMDiff_snd.inv } end Product @@ -219,7 +202,7 @@ class SmoothInv₀ {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [To {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) (G : Type*) [Inv G] [Zero G] [TopologicalSpace G] [ChartedSpace H G] : Prop where /-- Inversion is smooth away from `0`. -/ - smoothAt_inv₀ : ∀ ⦃x : G⦄, x ≠ 0 → SmoothAt I I (fun y ↦ y⁻¹) x + smoothAt_inv₀ : ∀ ⦃x : G⦄, x ≠ 0 → ContMDiffAt I I ⊤ (fun y ↦ y⁻¹) x instance {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] : SmoothInv₀ 𝓘(𝕜) 𝕜 := { smoothAt_inv₀ := by @@ -235,28 +218,33 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalS {I' : ModelWithCorners 𝕜 E' H'} {M : Type*} [TopologicalSpace M] [ChartedSpace H' M] {n : ℕ∞} {f : M → G} -theorem smoothAt_inv₀ {x : G} (hx : x ≠ 0) : SmoothAt I I (fun y ↦ y⁻¹) x := +theorem contMDiffAt_inv₀ {x : G} (hx : x ≠ 0) : ContMDiffAt I I ⊤ (fun y ↦ y⁻¹) x := SmoothInv₀.smoothAt_inv₀ hx +@[deprecated (since := "2024-11-21")] alias smoothAt_inv₀ := contMDiffAt_inv₀ + include I in /-- In a manifold with smooth inverse away from `0`, the inverse is continuous away from `0`. This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]. -/ theorem hasContinuousInv₀_of_hasSmoothInv₀ : HasContinuousInv₀ G := - { continuousAt_inv₀ := fun _ hx ↦ (smoothAt_inv₀ I hx).continuousAt } + { continuousAt_inv₀ := fun _ hx ↦ (contMDiffAt_inv₀ I hx).continuousAt } -theorem SmoothOn_inv₀ : SmoothOn I I (Inv.inv : G → G) {0}ᶜ := fun _x hx => - (smoothAt_inv₀ I hx).smoothWithinAt +theorem contMDiffOn_inv₀ : ContMDiffOn I I ⊤ (Inv.inv : G → G) {0}ᶜ := fun _x hx => + (contMDiffAt_inv₀ I hx).contMDiffWithinAt + +@[deprecated (since := "2024-11-21")] alias smoothOn_inv₀ := contMDiffOn_inv₀ +@[deprecated (since := "2024-11-21")] alias SmoothOn_inv₀ := contMDiffOn_inv₀ variable {I} {s : Set M} {a : M} theorem ContMDiffWithinAt.inv₀ (hf : ContMDiffWithinAt I' I n f s a) (ha : f a ≠ 0) : ContMDiffWithinAt I' I n (fun x => (f x)⁻¹) s a := - (smoothAt_inv₀ I ha).contMDiffAt.comp_contMDiffWithinAt a hf + ((contMDiffAt_inv₀ I ha).of_le le_top).comp_contMDiffWithinAt a hf theorem ContMDiffAt.inv₀ (hf : ContMDiffAt I' I n f a) (ha : f a ≠ 0) : ContMDiffAt I' I n (fun x ↦ (f x)⁻¹) a := - (smoothAt_inv₀ I ha).contMDiffAt.comp a hf + ((contMDiffAt_inv₀ I ha).of_le le_top).comp a hf theorem ContMDiff.inv₀ (hf : ContMDiff I' I n f) (h0 : ∀ x, f x ≠ 0) : ContMDiff I' I n (fun x ↦ (f x)⁻¹) := @@ -266,20 +254,10 @@ theorem ContMDiffOn.inv₀ (hf : ContMDiffOn I' I n f s) (h0 : ∀ x ∈ s, f x ContMDiffOn I' I n (fun x => (f x)⁻¹) s := fun x hx ↦ ContMDiffWithinAt.inv₀ (hf x hx) (h0 x hx) -theorem SmoothWithinAt.inv₀ (hf : SmoothWithinAt I' I f s a) (ha : f a ≠ 0) : - SmoothWithinAt I' I (fun x => (f x)⁻¹) s a := - ContMDiffWithinAt.inv₀ hf ha - -theorem SmoothAt.inv₀ (hf : SmoothAt I' I f a) (ha : f a ≠ 0) : - SmoothAt I' I (fun x => (f x)⁻¹) a := - ContMDiffAt.inv₀ hf ha - -theorem Smooth.inv₀ (hf : Smooth I' I f) (h0 : ∀ x, f x ≠ 0) : Smooth I' I fun x => (f x)⁻¹ := - ContMDiff.inv₀ hf h0 - -theorem SmoothOn.inv₀ (hf : SmoothOn I' I f s) (h0 : ∀ x ∈ s, f x ≠ 0) : - SmoothOn I' I (fun x => (f x)⁻¹) s := - ContMDiffOn.inv₀ hf h0 +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.inv₀ := ContMDiffWithinAt.inv₀ +@[deprecated (since := "2024-11-21")] alias SmoothAt.inv₀ := ContMDiffAt.inv₀ +@[deprecated (since := "2024-11-21")] alias SmoothOn.inv₀ := ContMDiffOn.inv₀ +@[deprecated (since := "2024-11-21")] alias Smooth.inv₀ := ContMDiff.inv₀ end SmoothInv₀ @@ -313,20 +291,9 @@ theorem ContMDiffAt.div₀ (hf : ContMDiffAt I' I n f a) (hg : ContMDiffAt I' I theorem ContMDiff.div₀ (hf : ContMDiff I' I n f) (hg : ContMDiff I' I n g) (h₀ : ∀ x, g x ≠ 0) : ContMDiff I' I n (f / g) := by simpa only [div_eq_mul_inv] using hf.mul (hg.inv₀ h₀) -theorem SmoothWithinAt.div₀ (hf : SmoothWithinAt I' I f s a) - (hg : SmoothWithinAt I' I g s a) (h₀ : g a ≠ 0) : SmoothWithinAt I' I (f / g) s a := - ContMDiffWithinAt.div₀ hf hg h₀ - -theorem SmoothOn.div₀ (hf : SmoothOn I' I f s) (hg : SmoothOn I' I g s) (h₀ : ∀ x ∈ s, g x ≠ 0) : - SmoothOn I' I (f / g) s := - ContMDiffOn.div₀ hf hg h₀ - -theorem SmoothAt.div₀ (hf : SmoothAt I' I f a) (hg : SmoothAt I' I g a) (h₀ : g a ≠ 0) : - SmoothAt I' I (f / g) a := - ContMDiffAt.div₀ hf hg h₀ - -theorem Smooth.div₀ (hf : Smooth I' I f) (hg : Smooth I' I g) (h₀ : ∀ x, g x ≠ 0) : - Smooth I' I (f / g) := - ContMDiff.div₀ hf hg h₀ +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.div₀ := ContMDiffWithinAt.div₀ +@[deprecated (since := "2024-11-21")] alias SmoothAt.div₀ := ContMDiffAt.div₀ +@[deprecated (since := "2024-11-21")] alias SmoothOn.div₀ := ContMDiffOn.div₀ +@[deprecated (since := "2024-11-21")] alias Smooth.div₀ := ContMDiff.div₀ end Div diff --git a/Mathlib/Geometry/Manifold/Algebra/Monoid.lean b/Mathlib/Geometry/Manifold/Algebra/Monoid.lean index 9202595ec5d949..7e6a90b613a228 100644 --- a/Mathlib/Geometry/Manifold/Algebra/Monoid.lean +++ b/Mathlib/Geometry/Manifold/Algebra/Monoid.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Nicolò Cavalleri -/ import Mathlib.Geometry.Manifold.ContMDiffMap +import Mathlib.Geometry.Manifold.MFDeriv.Basic /-! # Smooth monoid @@ -17,6 +18,9 @@ semigroups. open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) library_note "Design choices about smooth algebraic structures"/-- 1. All smooth algebraic structures on `G` are `Prop`-valued classes that extend @@ -44,7 +48,7 @@ class SmoothAdd {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [Topol {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) (G : Type*) [Add G] [TopologicalSpace G] [ChartedSpace H G] extends SmoothManifoldWithCorners I G : Prop where - smooth_add : Smooth (I.prod I) I fun p : G × G => p.1 + p.2 + smooth_add : ContMDiff (I.prod I) I ⊤ fun p : G × G => p.1 + p.2 -- See note [Design choices about smooth algebraic structures] /-- Basic hypothesis to talk about a smooth (Lie) monoid or a smooth semigroup. @@ -55,7 +59,7 @@ class SmoothMul {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [Topol {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) (G : Type*) [Mul G] [TopologicalSpace G] [ChartedSpace H G] extends SmoothManifoldWithCorners I G : Prop where - smooth_mul : Smooth (I.prod I) I fun p : G × G => p.1 * p.2 + smooth_mul : ContMDiff (I.prod I) I ⊤ fun p : G × G => p.1 * p.2 section SmoothMul @@ -70,16 +74,19 @@ section variable (I) @[to_additive] -theorem smooth_mul : Smooth (I.prod I) I fun p : G × G => p.1 * p.2 := +theorem contMDiff_mul : ContMDiff (I.prod I) I ⊤ fun p : G × G => p.1 * p.2 := SmoothMul.smooth_mul +@[deprecated (since := "2024-11-20")] alias smooth_mul := contMDiff_mul +@[deprecated (since := "2024-11-20")] alias smooth_add := contMDiff_add + include I in /-- If the multiplication is smooth, then it is continuous. This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]. -/ @[to_additive "If the addition is smooth, then it is continuous. This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]."] theorem continuousMul_of_smooth : ContinuousMul G := - ⟨(smooth_mul I).continuous⟩ + ⟨(contMDiff_mul I).continuous⟩ end @@ -90,7 +97,7 @@ variable {f g : M → G} {s : Set M} {x : M} {n : ℕ∞} @[to_additive] theorem ContMDiffWithinAt.mul (hf : ContMDiffWithinAt I' I n f s x) (hg : ContMDiffWithinAt I' I n g s x) : ContMDiffWithinAt I' I n (f * g) s x := - ((smooth_mul I).smoothAt.of_le le_top).comp_contMDiffWithinAt x (hf.prod_mk hg) + ((contMDiff_mul I).contMDiffAt.of_le le_top).comp_contMDiffWithinAt x (hf.prod_mk hg) @[to_additive] nonrec theorem ContMDiffAt.mul (hf : ContMDiffAt I' I n f x) (hg : ContMDiffAt I' I n g x) : @@ -105,32 +112,53 @@ theorem ContMDiffOn.mul (hf : ContMDiffOn I' I n f s) (hg : ContMDiffOn I' I n g theorem ContMDiff.mul (hf : ContMDiff I' I n f) (hg : ContMDiff I' I n g) : ContMDiff I' I n (f * g) := fun x => (hf x).mul (hg x) +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.mul := ContMDiffWithinAt.mul +@[deprecated (since := "2024-11-21")] alias SmoothAt.mul := ContMDiffAt.mul +@[deprecated (since := "2024-11-21")] alias SmoothOn.mul := ContMDiffOn.mul +@[deprecated (since := "2024-11-21")] alias Smooth.mul := ContMDiff.mul + +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.add := ContMDiffWithinAt.add +@[deprecated (since := "2024-11-21")] alias SmoothAt.add := ContMDiffAt.add +@[deprecated (since := "2024-11-21")] alias SmoothOn.add := ContMDiffOn.add +@[deprecated (since := "2024-11-21")] alias Smooth.add := ContMDiff.add + @[to_additive] -nonrec theorem SmoothWithinAt.mul (hf : SmoothWithinAt I' I f s x) - (hg : SmoothWithinAt I' I g s x) : SmoothWithinAt I' I (f * g) s x := - hf.mul hg +theorem contMDiff_mul_left {a : G} : ContMDiff I I n (a * ·) := + contMDiff_const.mul contMDiff_id + +@[deprecated (since := "2024-11-21")] alias smooth_mul_left := contMDiff_mul_left +@[deprecated (since := "2024-11-21")] alias smooth_add_left := contMDiff_add_left @[to_additive] -nonrec theorem SmoothAt.mul (hf : SmoothAt I' I f x) (hg : SmoothAt I' I g x) : - SmoothAt I' I (f * g) x := - hf.mul hg +theorem contMDiffAt_mul_left {a b : G} : ContMDiffAt I I n (a * ·) b := + contMDiff_mul_left.contMDiffAt @[to_additive] -nonrec theorem SmoothOn.mul (hf : SmoothOn I' I f s) (hg : SmoothOn I' I g s) : - SmoothOn I' I (f * g) s := - hf.mul hg +theorem mdifferentiable_mul_left {a : G} : MDifferentiable I I (a * ·) := + contMDiff_mul_left.mdifferentiable le_rfl @[to_additive] -nonrec theorem Smooth.mul (hf : Smooth I' I f) (hg : Smooth I' I g) : Smooth I' I (f * g) := - hf.mul hg +theorem mdifferentiableAt_mul_left {a b : G} : MDifferentiableAt I I (a * ·) b := + contMDiffAt_mul_left.mdifferentiableAt le_rfl + +@[to_additive] +theorem contMDiff_mul_right {a : G} : ContMDiff I I n (· * a) := + contMDiff_id.mul contMDiff_const + +@[deprecated (since := "2024-11-21")] alias smooth_mul_right := contMDiff_mul_right +@[deprecated (since := "2024-11-21")] alias smooth_add_right := contMDiff_add_right @[to_additive] -theorem smooth_mul_left {a : G} : Smooth I I fun b : G => a * b := - smooth_const.mul smooth_id +theorem contMDiffAt_mul_right {a b : G} : ContMDiffAt I I n (· * a) b := + contMDiff_mul_right.contMDiffAt @[to_additive] -theorem smooth_mul_right {a : G} : Smooth I I fun b : G => b * a := - smooth_id.mul smooth_const +theorem mdifferentiable_mul_right {a : G} : MDifferentiable I I (· * a) := + contMDiff_mul_right.mdifferentiable le_rfl + +@[to_additive] +theorem mdifferentiableAt_mul_right {a b : G} : MDifferentiableAt I I (· * a) b := + contMDiffAt_mul_right.mdifferentiableAt le_rfl end @@ -140,13 +168,13 @@ variable (I) (g h : G) Lemmas involving `smoothLeftMul` with the notation `𝑳` usually use `L` instead of `𝑳` in the names. -/ def smoothLeftMul : C^∞⟮I, G; I, G⟯ := - ⟨leftMul g, smooth_mul_left⟩ + ⟨leftMul g, contMDiff_mul_left⟩ /-- Right multiplication by `g`. It is meant to mimic the usual notation in Lie groups. Lemmas involving `smoothRightMul` with the notation `𝑹` usually use `R` instead of `𝑹` in the names. -/ def smoothRightMul : C^∞⟮I, G; I, G⟯ := - ⟨rightMul g, smooth_mul_right⟩ + ⟨rightMul g, contMDiff_mul_right⟩ -- Left multiplication. The abbreviation is `MIL`. scoped[LieGroup] notation "𝑳" => smoothLeftMul @@ -199,8 +227,8 @@ instance SmoothMul.prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type* [ChartedSpace H' G'] [Mul G'] [SmoothMul I' G'] : SmoothMul (I.prod I') (G × G') := { SmoothManifoldWithCorners.prod G G' with smooth_mul := - ((smooth_fst.comp smooth_fst).smooth.mul (smooth_fst.comp smooth_snd)).prod_mk - ((smooth_snd.comp smooth_fst).smooth.mul (smooth_snd.comp smooth_snd)) } + ((contMDiff_fst.comp contMDiff_fst).mul (contMDiff_fst.comp contMDiff_snd)).prod_mk + ((contMDiff_snd.comp contMDiff_fst).mul (contMDiff_snd.comp contMDiff_snd)) } end SmoothMul @@ -213,16 +241,19 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalS {G' : Type*} [Monoid G'] [TopologicalSpace G'] [ChartedSpace H' G'] [SmoothMul I' G'] @[to_additive] -theorem smooth_pow : ∀ n : ℕ, Smooth I I fun a : G => a ^ n - | 0 => by simp only [pow_zero]; exact smooth_const - | k + 1 => by simpa [pow_succ] using (smooth_pow _).mul smooth_id +theorem contMDiff_pow : ∀ n : ℕ, ContMDiff I I ⊤ fun a : G => a ^ n + | 0 => by simp only [pow_zero]; exact contMDiff_const + | k + 1 => by simpa [pow_succ] using (contMDiff_pow _).mul contMDiff_id + +@[deprecated (since := "2024-11-21")] alias smooth_pow := contMDiff_pow +@[deprecated (since := "2024-11-21")] alias smooth_nsmul := contMDiff_nsmul /-- Morphism of additive smooth monoids. -/ structure SmoothAddMonoidMorphism (I : ModelWithCorners 𝕜 E H) (I' : ModelWithCorners 𝕜 E' H') (G : Type*) [TopologicalSpace G] [ChartedSpace H G] [AddMonoid G] [SmoothAdd I G] (G' : Type*) [TopologicalSpace G'] [ChartedSpace H' G'] [AddMonoid G'] [SmoothAdd I' G'] extends G →+ G' where - smooth_toFun : Smooth I I' toFun + smooth_toFun : ContMDiff I I' ⊤ toFun /-- Morphism of smooth monoids. -/ @[to_additive] @@ -230,11 +261,11 @@ structure SmoothMonoidMorphism (I : ModelWithCorners 𝕜 E H) (I' : ModelWithCo (G : Type*) [TopologicalSpace G] [ChartedSpace H G] [Monoid G] [SmoothMul I G] (G' : Type*) [TopologicalSpace G'] [ChartedSpace H' G'] [Monoid G'] [SmoothMul I' G'] extends G →* G' where - smooth_toFun : Smooth I I' toFun + smooth_toFun : ContMDiff I I' ⊤ toFun @[to_additive] instance : One (SmoothMonoidMorphism I I' G G') := - ⟨{ smooth_toFun := smooth_const + ⟨{ smooth_toFun := contMDiff_const toMonoidHom := 1 }⟩ @[to_additive] @@ -366,61 +397,43 @@ theorem contMDiff_finprod_cond (hc : ∀ i, p i → ContMDiff I' I n (f i)) simp only [← finprod_subtype_eq_finprod_cond] exact contMDiff_finprod (fun i => hc i i.2) (hf.comp_injective Subtype.coe_injective) -@[to_additive] -theorem smoothAt_finprod - (lf : LocallyFinite fun i ↦ mulSupport <| f i) (h : ∀ i, SmoothAt I' I (f i) x₀) : - SmoothAt I' I (fun x ↦ ∏ᶠ i, f i x) x₀ := - contMDiffWithinAt_finprod lf h +@[deprecated (since := "2024-11-21")] alias smoothAt_finprod := contMDiffAt_finprod +@[deprecated (since := "2024-11-21")] alias smoothAt_finsum := contMDiffAt_finsum -@[to_additive] -theorem smoothWithinAt_finset_prod' (h : ∀ i ∈ t, SmoothWithinAt I' I (f i) s x) : - SmoothWithinAt I' I (∏ i ∈ t, f i) s x := - contMDiffWithinAt_finset_prod' h +@[deprecated (since := "2024-11-21")] +alias smoothWithinAt_finset_prod' := contMDiffWithinAt_finset_prod' +@[deprecated (since := "2024-11-21")] +alias smoothWithinAt_finset_sum' := contMDiffWithinAt_finset_sum' -@[to_additive] -theorem smoothWithinAt_finset_prod (h : ∀ i ∈ t, SmoothWithinAt I' I (f i) s x) : - SmoothWithinAt I' I (fun x => ∏ i ∈ t, f i x) s x := - contMDiffWithinAt_finset_prod h -@[to_additive] -theorem smoothAt_finset_prod' (h : ∀ i ∈ t, SmoothAt I' I (f i) x) : - SmoothAt I' I (∏ i ∈ t, f i) x := - contMDiffAt_finset_prod' h +@[deprecated (since := "2024-11-21")] +alias smoothWithinAt_finset_prod := contMDiffWithinAt_finset_prod +@[deprecated (since := "2024-11-21")] +alias smoothWithinAt_finset_sum := contMDiffWithinAt_finset_sum -@[to_additive] -theorem smoothAt_finset_prod (h : ∀ i ∈ t, SmoothAt I' I (f i) x) : - SmoothAt I' I (fun x => ∏ i ∈ t, f i x) x := - contMDiffAt_finset_prod h +@[deprecated (since := "2024-11-21")] alias smoothAt_finset_prod' := contMDiffAt_finset_prod' +@[deprecated (since := "2024-11-21")] alias smoothAt_finset_sum' := contMDiffAt_finset_sum' -@[to_additive] -theorem smoothOn_finset_prod' (h : ∀ i ∈ t, SmoothOn I' I (f i) s) : - SmoothOn I' I (∏ i ∈ t, f i) s := - contMDiffOn_finset_prod' h +@[deprecated (since := "2024-11-21")] alias smoothAt_finset_prod := contMDiffAt_finset_prod +@[deprecated (since := "2024-11-21")] alias smoothAt_finset_sum := contMDiffAt_finset_sum -@[to_additive] -theorem smoothOn_finset_prod (h : ∀ i ∈ t, SmoothOn I' I (f i) s) : - SmoothOn I' I (fun x => ∏ i ∈ t, f i x) s := - contMDiffOn_finset_prod h +@[deprecated (since := "2024-11-21")] alias smoothOn_finset_prod' := contMDiffOn_finset_prod' +@[deprecated (since := "2024-11-21")] alias smoothOn_finset_sum' := contMDiffOn_finset_sum' -@[to_additive] -theorem smooth_finset_prod' (h : ∀ i ∈ t, Smooth I' I (f i)) : Smooth I' I (∏ i ∈ t, f i) := - contMDiff_finset_prod' h +@[deprecated (since := "2024-11-21")] alias smoothOn_finset_prod := contMDiffOn_finset_prod +@[deprecated (since := "2024-11-21")] alias smoothOn_finset_sum := contMDiffOn_finset_sum -@[to_additive] -theorem smooth_finset_prod (h : ∀ i ∈ t, Smooth I' I (f i)) : - Smooth I' I fun x => ∏ i ∈ t, f i x := - contMDiff_finset_prod h +@[deprecated (since := "2024-11-21")] alias smooth_finset_prod' := contMDiffOn_finset_prod' +@[deprecated (since := "2024-11-21")] alias smooth_finset_sum' := contMDiffOn_finset_sum' -@[to_additive] -theorem smooth_finprod (h : ∀ i, Smooth I' I (f i)) - (hfin : LocallyFinite fun i => mulSupport (f i)) : Smooth I' I fun x => ∏ᶠ i, f i x := - contMDiff_finprod h hfin +@[deprecated (since := "2024-11-21")] alias smooth_finset_prod := contMDiff_finset_prod +@[deprecated (since := "2024-11-21")] alias smooth_finset_sum := contMDiff_finset_sum -@[to_additive] -theorem smooth_finprod_cond (hc : ∀ i, p i → Smooth I' I (f i)) - (hf : LocallyFinite fun i => mulSupport (f i)) : - Smooth I' I fun x => ∏ᶠ (i) (_ : p i), f i x := - contMDiff_finprod_cond hc hf +@[deprecated (since := "2024-11-21")] alias smooth_finprod := contMDiff_finprod +@[deprecated (since := "2024-11-21")] alias smooth_finsum := contMDiff_finsum + +@[deprecated (since := "2024-11-21")] alias smooth_finprod_cond := contMDiff_finprod_cond +@[deprecated (since := "2024-11-21")] alias smooth_finsum_cond := contMDiff_finsum_cond end CommMonoid @@ -465,23 +478,9 @@ theorem ContMDiffOn.div_const (hf : ContMDiffOn I' I n f s) : theorem ContMDiff.div_const (hf : ContMDiff I' I n f) : ContMDiff I' I n (fun x ↦ f x / c) := fun x => (hf x).div_const c -@[to_additive] -nonrec theorem SmoothWithinAt.div_const (hf : SmoothWithinAt I' I f s x) : - SmoothWithinAt I' I (fun x ↦ f x / c) s x := - hf.div_const c - -@[to_additive] -nonrec theorem SmoothAt.div_const (hf : SmoothAt I' I f x) : - SmoothAt I' I (fun x ↦ f x / c) x := - hf.div_const c - -@[to_additive] -nonrec theorem SmoothOn.div_const (hf : SmoothOn I' I f s) : - SmoothOn I' I (fun x ↦ f x / c) s := - hf.div_const c - -@[to_additive] -nonrec theorem Smooth.div_const (hf : Smooth I' I f) : Smooth I' I (fun x ↦ f x / c) := - hf.div_const c +@[deprecated (since := "2024-11-21")] alias SmoothWithinAt.div_const := ContMDiffWithinAt.div_const +@[deprecated (since := "2024-11-21")] alias SmoothAt.div_const := ContMDiffAt.div_const +@[deprecated (since := "2024-11-21")] alias SmoothOn.div_const := ContMDiffOn.div_const +@[deprecated (since := "2024-11-21")] alias Smooth.div_const := ContMDiff.div_const end DivConst diff --git a/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean b/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean index 002ad1cf560cfc..db675c91210d4e 100644 --- a/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean +++ b/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean @@ -15,6 +15,9 @@ In this file, we define instances of algebraic structures over smooth functions. noncomputable section open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) open TopologicalSpace @@ -30,7 +33,7 @@ namespace SmoothMap @[to_additive] protected instance instMul {G : Type*} [Mul G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothMul I' G] : Mul C^∞⟮I, N; I', G⟯ := - ⟨fun f g => ⟨f * g, f.smooth.mul g.smooth⟩⟩ + ⟨fun f g => ⟨f * g, f.contMDiff.mul g.contMDiff⟩⟩ @[to_additive (attr := simp)] theorem coe_mul {G : Type*} [Mul G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothMul I' G] @@ -54,12 +57,12 @@ theorem coe_one {G : Type*} [One G] [TopologicalSpace G] [ChartedSpace H' G] : instance instNSMul {G : Type*} [AddMonoid G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothAdd I' G] : SMul ℕ C^∞⟮I, N; I', G⟯ where - smul n f := ⟨n • (f : N → G), (smooth_nsmul n).comp f.smooth⟩ + smul n f := ⟨n • (f : N → G), (contMDiff_nsmul n).comp f.contMDiff⟩ @[to_additive existing] instance instPow {G : Type*} [Monoid G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothMul I' G] : Pow C^∞⟮I, N; I', G⟯ ℕ where - pow f n := ⟨(f : N → G) ^ n, (smooth_pow n).comp f.smooth⟩ + pow f n := ⟨(f : N → G) ^ n, (contMDiff_pow n).comp f.contMDiff⟩ @[to_additive (attr := simp)] theorem coe_pow {G : Type*} [Monoid G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothMul I' G] @@ -104,9 +107,9 @@ variable (I N) `C^∞⟮I, N; I'', G''⟯`."] def compLeftMonoidHom {G' : Type*} [Monoid G'] [TopologicalSpace G'] [ChartedSpace H' G'] [SmoothMul I' G'] {G'' : Type*} [Monoid G''] [TopologicalSpace G''] [ChartedSpace H'' G''] - [SmoothMul I'' G''] (φ : G' →* G'') (hφ : Smooth I' I'' φ) : + [SmoothMul I'' G''] (φ : G' →* G'') (hφ : ContMDiff I' I'' ⊤ φ) : C^∞⟮I, N; I', G'⟯ →* C^∞⟮I, N; I'', G''⟯ where - toFun f := ⟨φ ∘ f, fun x => (hφ.smooth _).comp x (f.contMDiff x)⟩ + toFun f := ⟨φ ∘ f, hφ.comp f.contMDiff⟩ map_one' := by ext; show φ 1 = 1; simp map_mul' f g := by ext x; show φ (f x * g x) = φ (f x) * φ (g x); simp @@ -119,7 +122,7 @@ variable (I') {N} homomorphism from `C^∞⟮I, V; I', G⟯` to `C^∞⟮I, U; I', G⟯`."] def restrictMonoidHom (G : Type*) [Monoid G] [TopologicalSpace G] [ChartedSpace H' G] [SmoothMul I' G] {U V : Opens N} (h : U ≤ V) : C^∞⟮I, V; I', G⟯ →* C^∞⟮I, U; I', G⟯ where - toFun f := ⟨f ∘ Set.inclusion h, f.smooth.comp (smooth_inclusion h)⟩ + toFun f := ⟨f ∘ Set.inclusion h, f.contMDiff.comp (contMDiff_inclusion h)⟩ map_one' := rfl map_mul' _ _ := rfl @@ -134,9 +137,9 @@ instance commMonoid {G : Type*} [CommMonoid G] [TopologicalSpace G] [ChartedSpac instance group {G : Type*} [Group G] [TopologicalSpace G] [ChartedSpace H' G] [LieGroup I' G] : Group C^∞⟮I, N; I', G⟯ := { SmoothMap.monoid with - inv := fun f => ⟨fun x => (f x)⁻¹, f.smooth.inv⟩ + inv := fun f => ⟨fun x => (f x)⁻¹, f.contMDiff.inv⟩ inv_mul_cancel := fun a => by ext; exact inv_mul_cancel _ - div := fun f g => ⟨f / g, f.smooth.div g.smooth⟩ + div := fun f g => ⟨f / g, f.contMDiff.div g.contMDiff⟩ div_eq_mul_inv := fun f g => by ext; exact div_eq_mul_inv _ _ } @[to_additive (attr := simp)] @@ -189,11 +192,11 @@ variable (I N) 'left-composition-by-`φ`' ring homomorphism from `C^∞⟮I, N; I', R'⟯` to `C^∞⟮I, N; I'', R''⟯`. -/ def compLeftRingHom {R' : Type*} [Ring R'] [TopologicalSpace R'] [ChartedSpace H' R'] [SmoothRing I' R'] {R'' : Type*} [Ring R''] [TopologicalSpace R''] [ChartedSpace H'' R''] - [SmoothRing I'' R''] (φ : R' →+* R'') (hφ : Smooth I' I'' φ) : + [SmoothRing I'' R''] (φ : R' →+* R'') (hφ : ContMDiff I' I'' ⊤ φ) : C^∞⟮I, N; I', R'⟯ →+* C^∞⟮I, N; I'', R''⟯ := { SmoothMap.compLeftMonoidHom I N φ.toMonoidHom hφ, SmoothMap.compLeftAddMonoidHom I N φ.toAddMonoidHom hφ with - toFun := fun f => ⟨φ ∘ f, fun x => (hφ.smooth _).comp x (f.contMDiff x)⟩ } + toFun := fun f => ⟨φ ∘ f, hφ.comp f.contMDiff⟩ } variable (I') {N} @@ -202,7 +205,7 @@ variable (I') {N} def restrictRingHom (R : Type*) [Ring R] [TopologicalSpace R] [ChartedSpace H' R] [SmoothRing I' R] {U V : Opens N} (h : U ≤ V) : C^∞⟮I, V; I', R⟯ →+* C^∞⟮I, U; I', R⟯ := { SmoothMap.restrictMonoidHom I I' R h, SmoothMap.restrictAddMonoidHom I I' R h with - toFun := fun f => ⟨f ∘ Set.inclusion h, f.smooth.comp (smooth_inclusion h)⟩ } + toFun := fun f => ⟨f ∘ Set.inclusion h, f.contMDiff.comp (contMDiff_inclusion h)⟩ } variable {I I'} @@ -232,7 +235,7 @@ field `𝕜` inherit a vector space structure. instance instSMul {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] : SMul 𝕜 C^∞⟮I, N; 𝓘(𝕜, V), V⟯ := - ⟨fun r f => ⟨r • ⇑f, smooth_const.smul f.smooth⟩⟩ + ⟨fun r f => ⟨r • ⇑f, contMDiff_const.smul f.contMDiff⟩⟩ @[simp] theorem coe_smul {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] (r : 𝕜) @@ -272,7 +275,7 @@ variable {A : Type*} [NormedRing A] [NormedAlgebra 𝕜 A] [SmoothRing 𝓘(𝕜 /-- Smooth constant functions as a `RingHom`. -/ def C : 𝕜 →+* C^∞⟮I, N; 𝓘(𝕜, A), A⟯ where - toFun := fun c : 𝕜 => ⟨fun _ => (algebraMap 𝕜 A) c, smooth_const⟩ + toFun := fun c : 𝕜 => ⟨fun _ => (algebraMap 𝕜 A) c, contMDiff_const⟩ map_one' := by ext; exact (algebraMap 𝕜 A).map_one map_mul' c₁ c₂ := by ext; exact (algebraMap 𝕜 A).map_mul _ _ map_zero' := by ext; exact (algebraMap 𝕜 A).map_zero @@ -280,7 +283,7 @@ def C : 𝕜 →+* C^∞⟮I, N; 𝓘(𝕜, A), A⟯ where instance algebra : Algebra 𝕜 C^∞⟮I, N; 𝓘(𝕜, A), A⟯ := { --SmoothMap.semiring with -- Porting note: Commented this out. - smul := fun r f => ⟨r • f, smooth_const.smul f.smooth⟩ + smul := fun r f => ⟨r • f, contMDiff_const.smul f.contMDiff⟩ toRingHom := SmoothMap.C commutes' := fun c f => by ext x; exact Algebra.commutes' _ _ smul_def' := fun c f => by ext x; exact Algebra.smul_def' _ _ } @@ -309,7 +312,7 @@ is naturally a vector space over the ring of smooth functions from `N` to `𝕜` instance instSMul' {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] : SMul C^∞⟮I, N; 𝕜⟯ C^∞⟮I, N; 𝓘(𝕜, V), V⟯ := - ⟨fun f g => ⟨fun x => f x • g x, Smooth.smul f.2 g.2⟩⟩ + ⟨fun f g => ⟨fun x => f x • g x, ContMDiff.smul f.2 g.2⟩⟩ @[simp] theorem smul_comp' {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] (f : C^∞⟮I'', N'; 𝕜⟯) diff --git a/Mathlib/Geometry/Manifold/Algebra/Structures.lean b/Mathlib/Geometry/Manifold/Algebra/Structures.lean index 11c9d9b1a863a9..a20f6b529acf86 100644 --- a/Mathlib/Geometry/Manifold/Algebra/Structures.lean +++ b/Mathlib/Geometry/Manifold/Algebra/Structures.lean @@ -12,7 +12,7 @@ In this file we define smooth structures that build on Lie groups. We prefer usi instead of Lie mainly because Lie ring has currently another use in mathematics. -/ -open scoped Manifold +open scoped Manifold ContDiff section SmoothRing @@ -24,7 +24,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalS If `R` is a ring, then negation is automatically smooth, as it is multiplication with `-1`. -/ class SmoothRing (I : ModelWithCorners 𝕜 E H) (R : Type*) [Semiring R] [TopologicalSpace R] [ChartedSpace H R] extends SmoothAdd I R : Prop where - smooth_mul : Smooth (I.prod I) I fun p : R × R => p.1 * p.2 + smooth_mul : ContMDiff (I.prod I) I ⊤ fun p : R × R => p.1 * p.2 -- see Note [lower instance priority] instance (priority := 100) SmoothRing.toSmoothMul (I : ModelWithCorners 𝕜 E H) (R : Type*) @@ -35,9 +35,9 @@ instance (priority := 100) SmoothRing.toSmoothMul (I : ModelWithCorners 𝕜 E H -- see Note [lower instance priority] instance (priority := 100) SmoothRing.toLieAddGroup (I : ModelWithCorners 𝕜 E H) (R : Type*) [Ring R] [TopologicalSpace R] [ChartedSpace H R] [SmoothRing I R] : LieAddGroup I R where - compatible := StructureGroupoid.compatible (contDiffGroupoid ⊤ I) - smooth_add := smooth_add I - smooth_neg := by simpa only [neg_one_mul] using @smooth_mul_left 𝕜 _ H _ E _ _ I R _ _ _ _ (-1) + compatible := StructureGroupoid.compatible (contDiffGroupoid ∞ I) + smooth_add := contMDiff_add I + smooth_neg := by simpa only [neg_one_mul] using contMDiff_mul_left (G := R) (a := -1) end SmoothRing @@ -46,7 +46,7 @@ instance (priority := 100) fieldSmoothRing {𝕜 : Type*} [NontriviallyNormedFie SmoothRing 𝓘(𝕜) 𝕜 := { normedSpaceLieAddGroup with smooth_mul := by - rw [smooth_iff] + rw [contMDiff_iff] refine ⟨continuous_mul, fun x y => ?_⟩ simp only [mfld_simps] rw [contDiffOn_univ] diff --git a/Mathlib/Geometry/Manifold/BumpFunction.lean b/Mathlib/Geometry/Manifold/BumpFunction.lean index fa6698b53773a9..0c37faf328e8a6 100644 --- a/Mathlib/Geometry/Manifold/BumpFunction.lean +++ b/Mathlib/Geometry/Manifold/BumpFunction.lean @@ -286,23 +286,28 @@ theorem nhds_basis_support {s : Set M} (hs : s ∈ 𝓝 c) : variable [SmoothManifoldWithCorners I M] /-- A smooth bump function is infinitely smooth. -/ -protected theorem smooth : Smooth I 𝓘(ℝ) f := by +protected theorem contMDiff : ContMDiff I 𝓘(ℝ) ⊤ f := by refine contMDiff_of_tsupport fun x hx => ?_ have : x ∈ (chartAt H c).source := f.tsupport_subset_chartAt_source hx refine ContMDiffAt.congr_of_eventuallyEq ?_ <| f.eqOn_source.eventuallyEq_of_mem <| (chartAt H c).open_source.mem_nhds this exact f.contDiffAt.contMDiffAt.comp _ (contMDiffAt_extChartAt' this) -protected theorem smoothAt {x} : SmoothAt I 𝓘(ℝ) f x := - f.smooth.smoothAt +@[deprecated (since := "2024-11-20")] alias smooth := SmoothBumpFunction.contMDiff + +protected theorem contMDiffAt {x} : ContMDiffAt I 𝓘(ℝ) ⊤ f x := + f.contMDiff.contMDiffAt + +@[deprecated (since := "2024-11-20")] alias smoothAt := SmoothBumpFunction.contMDiffAt protected theorem continuous : Continuous f := - f.smooth.continuous + f.contMDiff.continuous /-- If `f : SmoothBumpFunction I c` is a smooth bump function and `g : M → G` is a function smooth on the source of the chart at `c`, then `f • g` is smooth on the whole manifold. -/ -theorem smooth_smul {G} [NormedAddCommGroup G] [NormedSpace ℝ G] {g : M → G} - (hg : SmoothOn I 𝓘(ℝ, G) g (chartAt H c).source) : Smooth I 𝓘(ℝ, G) fun x => f x • g x := by +theorem contMDiff_smul {G} [NormedAddCommGroup G] [NormedSpace ℝ G] {g : M → G} + (hg : ContMDiffOn I 𝓘(ℝ, G) ⊤ g (chartAt H c).source) : + ContMDiff I 𝓘(ℝ, G) ⊤ fun x => f x • g x := by refine contMDiff_of_tsupport fun x hx => ?_ have : x ∈ (chartAt H c).source := -- Porting note: was a more readable `calc` @@ -311,6 +316,8 @@ theorem smooth_smul {G} [NormedAddCommGroup G] [NormedSpace ℝ G] {g : M → G} -- _ ⊆ tsupport f := tsupport_smul_subset_left _ _ -- _ ⊆ (chart_at _ c).source := f.tsupport_subset_chartAt_source f.tsupport_subset_chartAt_source <| tsupport_smul_subset_left _ _ hx - exact f.smoothAt.smul ((hg _ this).contMDiffAt <| (chartAt _ _).open_source.mem_nhds this) + exact f.contMDiffAt.smul ((hg _ this).contMDiffAt <| (chartAt _ _).open_source.mem_nhds this) + +@[deprecated (since := "2024-11-20")] alias smooth_smul := contMDiff_smul end SmoothBumpFunction diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean index 5f68ad7682a065..31ff5e240b2d76 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Atlas.lean @@ -13,7 +13,7 @@ and that local structomorphisms are smooth with smooth inverses. -/ open Set ChartedSpace SmoothManifoldWithCorners -open scoped Manifold +open scoped Manifold ContDiff variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] -- declare a smooth manifold `M` over the pair `(E, H)`. @@ -46,18 +46,14 @@ theorem contMDiffOn_model_symm : ContMDiffOn 𝓘(𝕜, E) I n I.symm (range I) /-- An atlas member is `C^n` for any `n`. -/ theorem contMDiffOn_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) : ContMDiffOn I I n e e.source := - ContMDiffOn.of_le - ((contDiffWithinAt_localInvariantProp ∞).liftPropOn_of_mem_maximalAtlas - contDiffWithinAtProp_id h) - le_top + ContMDiffOn.of_le ((contDiffWithinAt_localInvariantProp ⊤).liftPropOn_of_mem_maximalAtlas + contDiffWithinAtProp_id h) le_top /-- The inverse of an atlas member is `C^n` for any `n`. -/ theorem contMDiffOn_symm_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) : ContMDiffOn I I n e.symm e.target := - ContMDiffOn.of_le - ((contDiffWithinAt_localInvariantProp ∞).liftPropOn_symm_of_mem_maximalAtlas - contDiffWithinAtProp_id h) - le_top + ContMDiffOn.of_le ((contDiffWithinAt_localInvariantProp ⊤).liftPropOn_symm_of_mem_maximalAtlas + contDiffWithinAtProp_id h) le_top theorem contMDiffAt_of_mem_maximalAtlas (h : e ∈ maximalAtlas I M) (hx : x ∈ e.source) : ContMDiffAt I I n e x := @@ -112,7 +108,7 @@ theorem contMDiffWithinAt_extChartAt_symm_range /-- An element of `contDiffGroupoid ⊤ I` is `C^n` for any `n`. -/ theorem contMDiffOn_of_mem_contDiffGroupoid {e' : PartialHomeomorph H H} - (h : e' ∈ contDiffGroupoid ⊤ I) : ContMDiffOn I I n e' e'.source := + (h : e' ∈ contDiffGroupoid ∞ I) : ContMDiffOn I I n e' e'.source := (contDiffWithinAt_localInvariantProp n).liftPropOn_of_mem_groupoid contDiffWithinAtProp_id h end Atlas @@ -124,8 +120,8 @@ section IsLocalStructomorph variable [ChartedSpace H M'] [IsM' : SmoothManifoldWithCorners I M'] theorem isLocalStructomorphOn_contDiffGroupoid_iff_aux {f : PartialHomeomorph M M'} - (hf : LiftPropOn (contDiffGroupoid ⊤ I).IsLocalStructomorphWithinAt f f.source) : - SmoothOn I I f f.source := by + (hf : LiftPropOn (contDiffGroupoid ∞ I).IsLocalStructomorphWithinAt f f.source) : + ContMDiffOn I I ⊤ f f.source := by -- It suffices to show smoothness near each `x` apply contMDiffOn_of_locally_contMDiffOn intro x hx @@ -170,8 +166,8 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff_aux {f : PartialHomeomorph M is a local structomorphism for `I`, if and only if it is manifold-smooth on the domain of definition in both directions. -/ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : PartialHomeomorph M M') : - LiftPropOn (contDiffGroupoid ⊤ I).IsLocalStructomorphWithinAt f f.source ↔ - SmoothOn I I f f.source ∧ SmoothOn I I f.symm f.target := by + LiftPropOn (contDiffGroupoid ∞ I).IsLocalStructomorphWithinAt f f.source ↔ + ContMDiffOn I I ⊤ f f.source ∧ ContMDiffOn I I ⊤ f.symm f.target := by constructor · intro h refine ⟨isLocalStructomorphOn_contDiffGroupoid_iff_aux h, @@ -186,7 +182,7 @@ theorem isLocalStructomorphOn_contDiffGroupoid_iff (f : PartialHomeomorph M M') refine ⟨(f.symm.continuousAt hX).continuousWithinAt, fun h2x => ?_⟩ obtain ⟨e, he, h2e, hef, hex⟩ : ∃ e : PartialHomeomorph H H, - e ∈ contDiffGroupoid ⊤ I ∧ + e ∈ contDiffGroupoid ∞ I ∧ e.source ⊆ (c.symm ≫ₕ f ≫ₕ c').source ∧ EqOn (c' ∘ f ∘ c.symm) e e.source ∧ c x ∈ e.source := by have h1 : c' = chartAt H (f x) := by simp only [f.right_inv hX] diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean index 0b2a089aee1e61..bbe1eedcdb768f 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean @@ -82,31 +82,21 @@ theorem ContMDiffWithinAt.comp_of_eq {t : Set M'} {g : M' → M''} {x : M} {y : (st : MapsTo f s t) (hx : f x = y) : ContMDiffWithinAt I I'' n (g ∘ f) s x := by subst hx; exact hg.comp x hf st -/-- The composition of `C^∞` functions within domains at points is `C^∞`. -/ -nonrec theorem SmoothWithinAt.comp {t : Set M'} {g : M' → M''} (x : M) - (hg : SmoothWithinAt I' I'' g t (f x)) (hf : SmoothWithinAt I I' f s x) (st : MapsTo f s t) : - SmoothWithinAt I I'' (g ∘ f) s x := - hg.comp x hf st +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.comp := ContMDiffWithinAt.comp /-- The composition of `C^n` functions on domains is `C^n`. -/ theorem ContMDiffOn.comp {t : Set M'} {g : M' → M''} (hg : ContMDiffOn I' I'' n g t) (hf : ContMDiffOn I I' n f s) (st : s ⊆ f ⁻¹' t) : ContMDiffOn I I'' n (g ∘ f) s := fun x hx => (hg _ (st hx)).comp x (hf x hx) st -/-- The composition of `C^∞` functions on domains is `C^∞`. -/ -nonrec theorem SmoothOn.comp {t : Set M'} {g : M' → M''} (hg : SmoothOn I' I'' g t) - (hf : SmoothOn I I' f s) (st : s ⊆ f ⁻¹' t) : SmoothOn I I'' (g ∘ f) s := - hg.comp hf st +@[deprecated (since := "2024-11-20")] alias SmoothOn.comp := ContMDiffOn.comp /-- The composition of `C^n` functions on domains is `C^n`. -/ theorem ContMDiffOn.comp' {t : Set M'} {g : M' → M''} (hg : ContMDiffOn I' I'' n g t) (hf : ContMDiffOn I I' n f s) : ContMDiffOn I I'' n (g ∘ f) (s ∩ f ⁻¹' t) := hg.comp (hf.mono inter_subset_left) inter_subset_right -/-- The composition of `C^∞` functions is `C^∞`. -/ -nonrec theorem SmoothOn.comp' {t : Set M'} {g : M' → M''} (hg : SmoothOn I' I'' g t) - (hf : SmoothOn I I' f s) : SmoothOn I I'' (g ∘ f) (s ∩ f ⁻¹' t) := - hg.comp' hf +@[deprecated (since := "2024-11-20")] alias SmoothOn.comp' := ContMDiffOn.comp' /-- The composition of `C^n` functions is `C^n`. -/ theorem ContMDiff.comp {g : M' → M''} (hg : ContMDiff I' I'' n g) (hf : ContMDiff I I' n f) : @@ -114,10 +104,7 @@ theorem ContMDiff.comp {g : M' → M''} (hg : ContMDiff I' I'' n g) (hf : ContMD rw [← contMDiffOn_univ] at hf hg ⊢ exact hg.comp hf subset_preimage_univ -/-- The composition of `C^∞` functions is `C^∞`. -/ -nonrec theorem Smooth.comp {g : M' → M''} (hg : Smooth I' I'' g) (hf : Smooth I I' f) : - Smooth I I'' (g ∘ f) := - hg.comp hf +@[deprecated (since := "2024-11-20")] alias Smooth.comp := ContMDiff.comp /-- The composition of `C^n` functions within domains at points is `C^n`. -/ theorem ContMDiffWithinAt.comp' {t : Set M'} {g : M' → M''} (x : M) @@ -125,11 +112,7 @@ theorem ContMDiffWithinAt.comp' {t : Set M'} {g : M' → M''} (x : M) ContMDiffWithinAt I I'' n (g ∘ f) (s ∩ f ⁻¹' t) x := hg.comp x (hf.mono inter_subset_left) inter_subset_right -/-- The composition of `C^∞` functions within domains at points is `C^∞`. -/ -nonrec theorem SmoothWithinAt.comp' {t : Set M'} {g : M' → M''} (x : M) - (hg : SmoothWithinAt I' I'' g t (f x)) (hf : SmoothWithinAt I I' f s x) : - SmoothWithinAt I I'' (g ∘ f) (s ∩ f ⁻¹' t) x := - hg.comp' x hf +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.comp' := ContMDiffWithinAt.comp' /-- `g ∘ f` is `C^n` within `s` at `x` if `g` is `C^n` at `f x` and `f` is `C^n` within `s` at `x`. -/ @@ -138,11 +121,8 @@ theorem ContMDiffAt.comp_contMDiffWithinAt {g : M' → M''} (x : M) ContMDiffWithinAt I I'' n (g ∘ f) s x := hg.comp x hf (mapsTo_univ _ _) -/-- `g ∘ f` is `C^∞` within `s` at `x` if `g` is `C^∞` at `f x` and -`f` is `C^∞` within `s` at `x`. -/ -theorem SmoothAt.comp_smoothWithinAt {g : M' → M''} (x : M) (hg : SmoothAt I' I'' g (f x)) - (hf : SmoothWithinAt I I' f s x) : SmoothWithinAt I I'' (g ∘ f) s x := - hg.comp_contMDiffWithinAt x hf +@[deprecated (since := "2024-11-20")] +alias SmoothAt.comp_smoothWithinAt := ContMDiffAt.comp_contMDiffWithinAt /-- The composition of `C^n` functions at points is `C^n`. -/ nonrec theorem ContMDiffAt.comp {g : M' → M''} (x : M) (hg : ContMDiffAt I' I'' n g (f x)) @@ -154,26 +134,19 @@ theorem ContMDiffAt.comp_of_eq {g : M' → M''} {x : M} {y : M'} (hg : ContMDiff (hf : ContMDiffAt I I' n f x) (hx : f x = y) : ContMDiffAt I I'' n (g ∘ f) x := by subst hx; exact hg.comp x hf -/-- The composition of `C^∞` functions at points is `C^∞`. -/ -nonrec theorem SmoothAt.comp {g : M' → M''} (x : M) (hg : SmoothAt I' I'' g (f x)) - (hf : SmoothAt I I' f x) : SmoothAt I I'' (g ∘ f) x := - hg.comp x hf +@[deprecated (since := "2024-11-20")] alias SmoothAt.comp := ContMDiffAt.comp theorem ContMDiff.comp_contMDiffOn {f : M → M'} {g : M' → M''} {s : Set M} (hg : ContMDiff I' I'' n g) (hf : ContMDiffOn I I' n f s) : ContMDiffOn I I'' n (g ∘ f) s := hg.contMDiffOn.comp hf Set.subset_preimage_univ -theorem Smooth.comp_smoothOn {f : M → M'} {g : M' → M''} {s : Set M} (hg : Smooth I' I'' g) - (hf : SmoothOn I I' f s) : SmoothOn I I'' (g ∘ f) s := - hg.smoothOn.comp hf Set.subset_preimage_univ +@[deprecated (since := "2024-11-20")] alias Smooth.comp_smoothOn := ContMDiff.comp_contMDiffOn theorem ContMDiffOn.comp_contMDiff {t : Set M'} {g : M' → M''} (hg : ContMDiffOn I' I'' n g t) (hf : ContMDiff I I' n f) (ht : ∀ x, f x ∈ t) : ContMDiff I I'' n (g ∘ f) := contMDiffOn_univ.mp <| hg.comp hf.contMDiffOn fun x _ => ht x -theorem SmoothOn.comp_smooth {t : Set M'} {g : M' → M''} (hg : SmoothOn I' I'' g t) - (hf : Smooth I I' f) (ht : ∀ x, f x ∈ t) : Smooth I I'' (g ∘ f) := - hg.comp_contMDiff hf ht +@[deprecated (since := "2024-11-20")] alias SmoothOn.comp_smooth := ContMDiffOn.comp_contMDiff end Composition @@ -183,28 +156,24 @@ section id theorem contMDiff_id : ContMDiff I I n (id : M → M) := ContMDiff.of_le - ((contDiffWithinAt_localInvariantProp ∞).liftProp_id contDiffWithinAtProp_id) le_top + ((contDiffWithinAt_localInvariantProp ⊤).liftProp_id contDiffWithinAtProp_id) le_top -theorem smooth_id : Smooth I I (id : M → M) := - contMDiff_id +@[deprecated (since := "2024-11-20")] alias smooth_id := contMDiff_id theorem contMDiffOn_id : ContMDiffOn I I n (id : M → M) s := contMDiff_id.contMDiffOn -theorem smoothOn_id : SmoothOn I I (id : M → M) s := - contMDiffOn_id +@[deprecated (since := "2024-11-20")] alias smoothOn_id := contMDiffOn_id theorem contMDiffAt_id : ContMDiffAt I I n (id : M → M) x := contMDiff_id.contMDiffAt -theorem smoothAt_id : SmoothAt I I (id : M → M) x := - contMDiffAt_id +@[deprecated (since := "2024-11-20")] alias smoothAt_id := contMDiffAt_id theorem contMDiffWithinAt_id : ContMDiffWithinAt I I n (id : M → M) s x := contMDiffAt_id.contMDiffWithinAt -theorem smoothWithinAt_id : SmoothWithinAt I I (id : M → M) s x := - contMDiffWithinAt_id +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_id := contMDiffWithinAt_id end id @@ -223,11 +192,10 @@ theorem contMDiff_const : ContMDiff I I' n fun _ : M => c := by theorem contMDiff_one [One M'] : ContMDiff I I' n (1 : M → M') := by simp only [Pi.one_def, contMDiff_const] -theorem smooth_const : Smooth I I' fun _ : M => c := - contMDiff_const +@[deprecated (since := "2024-11-20")] alias smooth_const := contMDiff_const -@[to_additive] -theorem smooth_one [One M'] : Smooth I I' (1 : M → M') := by simp only [Pi.one_def, smooth_const] +@[deprecated (since := "2024-11-20")] alias smooth_one := contMDiff_one +@[deprecated (since := "2024-11-20")] alias smooth_zero := contMDiff_zero theorem contMDiffOn_const : ContMDiffOn I I' n (fun _ : M => c) s := contMDiff_const.contMDiffOn @@ -236,12 +204,11 @@ theorem contMDiffOn_const : ContMDiffOn I I' n (fun _ : M => c) s := theorem contMDiffOn_one [One M'] : ContMDiffOn I I' n (1 : M → M') s := contMDiff_one.contMDiffOn -theorem smoothOn_const : SmoothOn I I' (fun _ : M => c) s := - contMDiffOn_const +@[deprecated (since := "2024-11-20")] alias smoothOn_const := contMDiffOn_const + +@[deprecated (since := "2024-11-20")] alias smoothOn_one := contMDiffOn_one +@[deprecated (since := "2024-11-20")] alias smoothOn_zero := contMDiffOn_zero -@[to_additive] -theorem smoothOn_one [One M'] : SmoothOn I I' (1 : M → M') s := - contMDiffOn_one theorem contMDiffAt_const : ContMDiffAt I I' n (fun _ : M => c) x := contMDiff_const.contMDiffAt @@ -250,12 +217,10 @@ theorem contMDiffAt_const : ContMDiffAt I I' n (fun _ : M => c) x := theorem contMDiffAt_one [One M'] : ContMDiffAt I I' n (1 : M → M') x := contMDiff_one.contMDiffAt -theorem smoothAt_const : SmoothAt I I' (fun _ : M => c) x := - contMDiffAt_const +@[deprecated (since := "2024-11-20")] alias smoothAt_const := contMDiffAt_const -@[to_additive] -theorem smoothAt_one [One M'] : SmoothAt I I' (1 : M → M') x := - contMDiffAt_one +@[deprecated (since := "2024-11-20")] alias smoothAt_one := contMDiffAt_one +@[deprecated (since := "2024-11-20")] alias smoothAt_zero := contMDiffAt_zero theorem contMDiffWithinAt_const : ContMDiffWithinAt I I' n (fun _ : M => c) s x := contMDiffAt_const.contMDiffWithinAt @@ -264,12 +229,10 @@ theorem contMDiffWithinAt_const : ContMDiffWithinAt I I' n (fun _ : M => c) s x theorem contMDiffWithinAt_one [One M'] : ContMDiffWithinAt I I' n (1 : M → M') s x := contMDiffAt_const.contMDiffWithinAt -theorem smoothWithinAt_const : SmoothWithinAt I I' (fun _ : M => c) s x := - contMDiffWithinAt_const +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_const := contMDiffWithinAt_const -@[to_additive] -theorem smoothWithinAt_one [One M'] : SmoothWithinAt I I' (1 : M → M') s x := - contMDiffWithinAt_one +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_one := contMDiffWithinAt_one +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_zero := contMDiffWithinAt_zero end id @@ -305,12 +268,14 @@ section Inclusion open TopologicalSpace -theorem contMdiffAt_subtype_iff {n : ℕ∞} {U : Opens M} {f : M → M'} {x : U} : +theorem contMDiffAt_subtype_iff {n : ℕ∞} {U : Opens M} {f : M → M'} {x : U} : ContMDiffAt I I' n (fun x : U ↦ f x) x ↔ ContMDiffAt I I' n f x := ((contDiffWithinAt_localInvariantProp n).liftPropAt_iff_comp_subtype_val _ _).symm +@[deprecated (since := "2024-11-20")] alias contMdiffAt_subtype_iff := contMDiffAt_subtype_iff + theorem contMDiff_subtype_val {n : ℕ∞} {U : Opens M} : ContMDiff I I n (Subtype.val : U → M) := - fun _ ↦ contMdiffAt_subtype_iff.mpr contMDiffAt_id + fun _ ↦ contMDiffAt_subtype_iff.mpr contMDiffAt_id @[to_additive] theorem ContMDiff.extend_one [T2Space M] [One M'] {n : ℕ∞} {U : Opens M} {f : U → M'} @@ -319,7 +284,7 @@ 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] + rw [← contMDiffAt_subtype_iff] simp_rw [← comp_def] rw [extend_comp Subtype.val_injective] exact diff.contMDiffAt @@ -333,19 +298,14 @@ theorem contMDiff_inclusion {n : ℕ∞} {U V : Opens M} (h : U ≤ V) : rw [Set.univ_inter] exact contDiffWithinAt_id.congr I.rightInvOn (congr_arg I (I.left_inv y)) -theorem smooth_subtype_iff {U : Opens M} {f : M → M'} {x : U} : - SmoothAt I I' (fun x : U ↦ f x) x ↔ SmoothAt I I' f x := contMdiffAt_subtype_iff +@[deprecated (since := "2024-11-20")] alias smooth_subtype_iff := contMDiffAt_subtype_iff -theorem smooth_subtype_val {U : Opens M} : Smooth I I (Subtype.val : U → M) := contMDiff_subtype_val +@[deprecated (since := "2024-11-20")] alias smooth_subtype_val := contMDiff_subtype_val -@[to_additive] -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 +@[deprecated (since := "2024-11-20")] alias Smooth.extend_one := ContMDiff.extend_one +@[deprecated (since := "2024-11-20")] alias Smooth.extend_zero := ContMDiff.extend_zero -theorem smooth_inclusion {U V : Opens M} (h : U ≤ V) : - Smooth I I (Opens.inclusion h : U → V) := - contMDiff_inclusion h +@[deprecated (since := "2024-11-20")] alias smooth_inclusion := contMDiff_inclusion end Inclusion diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index f0917e558dc3c1..49996ee7ba8cba 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -46,7 +46,7 @@ in terms of extended charts in `contMDiffOn_iff` and `contMDiff_iff`. open Set Function Filter ChartedSpace SmoothManifoldWithCorners -open scoped Topology Manifold +open scoped Topology Manifold ContDiff /-! ### Definition of smooth functions between manifolds -/ @@ -110,7 +110,8 @@ theorem contDiffWithinAt_localInvariantProp (n : ℕ∞) : rw [this] at h have : I (e x) ∈ I.symm ⁻¹' e.target ∩ range I := by simp only [hx, mfld_simps] have := (mem_groupoid_of_pregroupoid.2 he).2.contDiffWithinAt this - convert (h.comp_inter _ (this.of_le le_top)).mono_of_mem_nhdsWithin _ using 1 + convert (h.comp_inter _ (this.of_le (mod_cast le_top))).mono_of_mem_nhdsWithin _ + using 1 · ext y; simp only [mfld_simps] refine mem_nhdsWithin.mpr ⟨I.symm ⁻¹' e.target, e.open_target.preimage I.continuous_symm, by @@ -127,7 +128,7 @@ theorem contDiffWithinAt_localInvariantProp (n : ℕ∞) : have A : (I' ∘ f ∘ I.symm) (I x) ∈ I'.symm ⁻¹' e'.source ∩ range I' := by simp only [hx, mfld_simps] have := (mem_groupoid_of_pregroupoid.2 he').1.contDiffWithinAt A - convert (this.of_le le_top).comp _ h _ + convert (this.of_le (mod_cast le_top)).comp _ h _ · ext y; simp only [mfld_simps] · intro y hy; simp only [mfld_simps] at hy; simpa only [hy, mfld_simps] using hs hy.1 @@ -155,11 +156,7 @@ read in the preferred chart at this point. -/ def ContMDiffWithinAt (n : ℕ∞) (f : M → M') (s : Set M) (x : M) := LiftPropWithinAt (ContDiffWithinAtProp I I' n) f s x -variable (I I') in -/-- Abbreviation for `ContMDiffWithinAt I I' ⊤ f s x`. See also documentation for `Smooth`. --/ -abbrev SmoothWithinAt (f : M → M') (s : Set M) (x : M) := - ContMDiffWithinAt I I' ⊤ f s x +@[deprecated (since := "024-11-21")] alias SmoothWithinAt := ContMDiffWithinAt variable (I I') in /-- A function is `n` times continuously differentiable at a point in a manifold if @@ -175,10 +172,7 @@ theorem contMDiffAt_iff {n : ℕ∞} {f : M → M'} {x : M} : (extChartAt I x x) := liftPropAt_iff.trans <| by rw [ContDiffWithinAtProp, preimage_univ, univ_inter]; rfl -variable (I I') in -/-- Abbreviation for `ContMDiffAt I I' ⊤ f x`. See also documentation for `Smooth`. -/ -abbrev SmoothAt (f : M → M') (x : M) := - ContMDiffAt I I' ⊤ f x +@[deprecated (since := "024-11-21")] alias SmoothAt := ContMDiffAt variable (I I') in /-- A function is `n` times continuously differentiable in a set of a manifold if it is continuous @@ -187,10 +181,7 @@ around these points. -/ def ContMDiffOn (n : ℕ∞) (f : M → M') (s : Set M) := ∀ x ∈ s, ContMDiffWithinAt I I' n f s x -variable (I I') in -/-- Abbreviation for `ContMDiffOn I I' ⊤ f s`. See also documentation for `Smooth`. -/ -abbrev SmoothOn (f : M → M') (s : Set M) := - ContMDiffOn I I' ⊤ f s +@[deprecated (since := "024-11-21")] alias SmoothOn := ContMDiffOn variable (I I') in /-- A function is `n` times continuously differentiable in a manifold if it is continuous @@ -199,23 +190,15 @@ around these points. -/ def ContMDiff (n : ℕ∞) (f : M → M') := ∀ x, ContMDiffAt I I' n f x -variable (I I') in -/-- Abbreviation for `ContMDiff I I' ⊤ f`. -Short note to work with these abbreviations: a lemma of the form `ContMDiffFoo.bar` will -apply fine to an assumption `SmoothFoo` using dot notation or normal notation. -If the consequence `bar` of the lemma involves `ContDiff`, it is still better to restate -the lemma replacing `ContDiff` with `Smooth` both in the assumption and in the conclusion, -to make it possible to use `Smooth` consistently. -This also applies to `SmoothAt`, `SmoothOn` and `SmoothWithinAt`. -/ -abbrev Smooth (f : M → M') := - ContMDiff I I' ⊤ f +@[deprecated (since := "024-11-21")] alias Smooth := ContMDiff + /-! ### Deducing smoothness from higher smoothness -/ theorem ContMDiffWithinAt.of_le (hf : ContMDiffWithinAt I I' n f s x) (le : m ≤ n) : ContMDiffWithinAt I I' m f s x := by simp only [ContMDiffWithinAt, LiftPropWithinAt] at hf ⊢ - exact ⟨hf.1, hf.2.of_le le⟩ + exact ⟨hf.1, hf.2.of_le (mod_cast le)⟩ theorem ContMDiffAt.of_le (hf : ContMDiffAt I I' n f x) (le : m ≤ n) : ContMDiffAt I I' m f x := ContMDiffWithinAt.of_le hf le @@ -228,49 +211,38 @@ theorem ContMDiff.of_le (hf : ContMDiff I I' n f) (le : m ≤ n) : ContMDiff I I /-! ### Basic properties of smooth functions between manifolds -/ -theorem ContMDiff.smooth (h : ContMDiff I I' ⊤ f) : Smooth I I' f := - h +@[deprecated (since := "2024-11-20")] alias ContMDiff.smooth := ContMDiff.of_le -theorem Smooth.contMDiff (h : Smooth I I' f) : ContMDiff I I' n f := - h.of_le le_top +@[deprecated (since := "2024-11-20")] alias Smooth.contMDiff := ContMDiff.of_le -theorem ContMDiffOn.smoothOn (h : ContMDiffOn I I' ⊤ f s) : SmoothOn I I' f s := - h +@[deprecated (since := "2024-11-20")] alias ContMDiffOn.smoothOn := ContMDiffOn.of_le -theorem SmoothOn.contMDiffOn (h : SmoothOn I I' f s) : ContMDiffOn I I' n f s := - h.of_le le_top +@[deprecated (since := "2024-11-20")] alias SmoothOn.contMDiffOn := ContMDiffOn.of_le -theorem ContMDiffAt.smoothAt (h : ContMDiffAt I I' ⊤ f x) : SmoothAt I I' f x := - h +@[deprecated (since := "2024-11-20")] alias ContMDiffAt.smoothAt := ContMDiffAt.of_le -theorem SmoothAt.contMDiffAt (h : SmoothAt I I' f x) : ContMDiffAt I I' n f x := - h.of_le le_top +@[deprecated (since := "2024-11-20")] alias SmoothAt.contMDiffAt := ContMDiffOn.of_le -theorem ContMDiffWithinAt.smoothWithinAt (h : ContMDiffWithinAt I I' ⊤ f s x) : - SmoothWithinAt I I' f s x := - h +@[deprecated (since := "2024-11-20")] +alias ContMDiffWithinAt.smoothWithinAt := ContMDiffWithinAt.of_le -theorem SmoothWithinAt.contMDiffWithinAt (h : SmoothWithinAt I I' f s x) : - ContMDiffWithinAt I I' n f s x := - h.of_le le_top +@[deprecated (since := "2024-11-20")] +alias SmoothWithinAt.contMDiffWithinAt := ContMDiffWithinAt.of_le theorem ContMDiff.contMDiffAt (h : ContMDiff I I' n f) : ContMDiffAt I I' n f x := h x -theorem Smooth.smoothAt (h : Smooth I I' f) : SmoothAt I I' f x := - ContMDiff.contMDiffAt h +@[deprecated (since := "2024-11-20")] alias Smooth.smoothAt := ContMDiff.contMDiffAt theorem contMDiffWithinAt_univ : ContMDiffWithinAt I I' n f univ x ↔ ContMDiffAt I I' n f x := Iff.rfl -theorem smoothWithinAt_univ : SmoothWithinAt I I' f univ x ↔ SmoothAt I I' f x := - contMDiffWithinAt_univ +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_univ := contMDiffWithinAt_univ theorem contMDiffOn_univ : ContMDiffOn I I' n f univ ↔ ContMDiff I I' n f := by simp only [ContMDiffOn, ContMDiff, contMDiffWithinAt_univ, forall_prop_of_true, mem_univ] -theorem smoothOn_univ : SmoothOn I I' f univ ↔ Smooth I I' f := - contMDiffOn_univ +@[deprecated (since := "2024-11-20")] alias smoothOn_univ := contMDiffOn_univ /-- One can reformulate smoothness within a set at a point as continuity within this set at this point, and smoothness in the corresponding extended chart. -/ @@ -315,26 +287,18 @@ theorem contMDiffWithinAt_iff_target : chartAt_self_eq, PartialHomeomorph.refl_apply, id_comp] rfl -theorem smoothWithinAt_iff : - SmoothWithinAt I I' f s x ↔ - ContinuousWithinAt f s x ∧ - ContDiffWithinAt 𝕜 ∞ (extChartAt I' (f x) ∘ f ∘ (extChartAt I x).symm) - ((extChartAt I x).symm ⁻¹' s ∩ range I) (extChartAt I x x) := - contMDiffWithinAt_iff +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_iff := contMDiffWithinAt_iff -theorem smoothWithinAt_iff_target : - SmoothWithinAt I I' f s x ↔ - ContinuousWithinAt f s x ∧ SmoothWithinAt I 𝓘(𝕜, E') (extChartAt I' (f x) ∘ f) s x := - contMDiffWithinAt_iff_target +@[deprecated (since := "2024-11-20")] +alias smoothWithinAt_iff_target := contMDiffWithinAt_iff_target theorem contMDiffAt_iff_target {x : M} : ContMDiffAt I I' n f x ↔ ContinuousAt f x ∧ ContMDiffAt I 𝓘(𝕜, E') n (extChartAt I' (f x) ∘ f) x := by rw [ContMDiffAt, ContMDiffAt, contMDiffWithinAt_iff_target, continuousWithinAt_univ] -theorem smoothAt_iff_target {x : M} : - SmoothAt I I' f x ↔ ContinuousAt f x ∧ SmoothAt I 𝓘(𝕜, E') (extChartAt I' (f x) ∘ f) x := - contMDiffAt_iff_target +@[deprecated (since := "2024-11-20")] alias smoothAt_iff_target := contMDiffAt_iff_target + section SmoothManifoldWithCorners @@ -533,20 +497,10 @@ theorem contMDiffOn_iff_target : simp · exact fun h' x y => (h' y).2 x 0 -theorem smoothOn_iff : - SmoothOn I I' f s ↔ - ContinuousOn f s ∧ - ∀ (x : M) (y : M'), - ContDiffOn 𝕜 ⊤ (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) - ((extChartAt I x).target ∩ - (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' y).source)) := - contMDiffOn_iff +@[deprecated (since := "2024-11-20")] alias smoothOn_iff := contMDiffOn_iff + +@[deprecated (since := "2024-11-20")] alias smoothOn_iff_target := contMDiffOn_iff_target -theorem smoothOn_iff_target : - SmoothOn I I' f s ↔ - ContinuousOn f s ∧ - ∀ y : M', SmoothOn I 𝓘(𝕜, E') (extChartAt I' y ∘ f) (s ∩ f ⁻¹' (extChartAt I' y).source) := - contMDiffOn_iff_target /-- One can reformulate smoothness as continuity and smoothness in any extended chart. -/ theorem contMDiff_iff : @@ -567,20 +521,9 @@ theorem contMDiff_iff_target : rw [← contMDiffOn_univ, contMDiffOn_iff_target] simp [continuous_iff_continuousOn_univ] -theorem smooth_iff : - Smooth I I' f ↔ - Continuous f ∧ - ∀ (x : M) (y : M'), - ContDiffOn 𝕜 ⊤ (extChartAt I' y ∘ f ∘ (extChartAt I x).symm) - ((extChartAt I x).target ∩ - (extChartAt I x).symm ⁻¹' (f ⁻¹' (extChartAt I' y).source)) := - contMDiff_iff +@[deprecated (since := "2024-11-20")] alias smooth_iff := contMDiff_iff -theorem smooth_iff_target : - Smooth I I' f ↔ - Continuous f ∧ - ∀ y : M', SmoothOn I 𝓘(𝕜, E') (extChartAt I' y ∘ f) (f ⁻¹' (extChartAt I' y).source) := - contMDiff_iff_target +@[deprecated (since := "2024-11-20")] alias smooth_iff_target := contMDiff_iff_target end SmoothManifoldWithCorners @@ -619,17 +562,17 @@ theorem ContMDiff.continuous (hf : ContMDiff I I' n f) : Continuous f := /-! ### `C^∞` smoothness -/ theorem contMDiffWithinAt_top : - SmoothWithinAt I I' f s x ↔ ∀ n : ℕ, ContMDiffWithinAt I I' n f s x := + ContMDiffWithinAt I I' ⊤ f s x ↔ ∀ n : ℕ, ContMDiffWithinAt I I' n f s x := ⟨fun h n => ⟨h.1, contDiffWithinAt_top.1 h.2 n⟩, fun H => ⟨(H 0).1, contDiffWithinAt_top.2 fun n => (H n).2⟩⟩ -theorem contMDiffAt_top : SmoothAt I I' f x ↔ ∀ n : ℕ, ContMDiffAt I I' n f x := +theorem contMDiffAt_top : ContMDiffAt I I' ⊤ f x ↔ ∀ n : ℕ, ContMDiffAt I I' n f x := contMDiffWithinAt_top -theorem contMDiffOn_top : SmoothOn I I' f s ↔ ∀ n : ℕ, ContMDiffOn I I' n f s := +theorem contMDiffOn_top : ContMDiffOn I I' ⊤ f s ↔ ∀ n : ℕ, ContMDiffOn I I' n f s := ⟨fun h _ => h.of_le le_top, fun h x hx => contMDiffWithinAt_top.2 fun n => h n x hx⟩ -theorem contMDiff_top : Smooth I I' f ↔ ∀ n : ℕ, ContMDiff I I' n f := +theorem contMDiff_top : ContMDiff I I' ⊤ f ↔ ∀ n : ℕ, ContMDiff I I' n f := ⟨fun h _ => h.of_le le_top, fun h x => contMDiffWithinAt_top.2 fun n => h n x⟩ theorem contMDiffWithinAt_iff_nat : @@ -691,8 +634,7 @@ protected theorem ContMDiffAt.contMDiffWithinAt (hf : ContMDiffAt I I' n f x) : ContMDiffWithinAt I I' n f s x := ContMDiffWithinAt.mono hf (subset_univ _) -protected theorem SmoothAt.smoothWithinAt (hf : SmoothAt I I' f x) : SmoothWithinAt I I' f s x := - ContMDiffAt.contMDiffWithinAt hf +@[deprecated (since := "2024-11-20")] alias SmoothAt.smoothWithinAt := ContMDiffAt.contMDiffWithinAt theorem ContMDiffOn.mono (hf : ContMDiffOn I I' n f s) (hts : t ⊆ s) : ContMDiffOn I I' n f t := fun x hx => (hf x (hts hx)).mono hts @@ -700,8 +642,7 @@ theorem ContMDiffOn.mono (hf : ContMDiffOn I I' n f s) (hts : t ⊆ s) : ContMDi protected theorem ContMDiff.contMDiffOn (hf : ContMDiff I I' n f) : ContMDiffOn I I' n f s := fun x _ => (hf x).contMDiffWithinAt -protected theorem Smooth.smoothOn (hf : Smooth I I' f) : SmoothOn I I' f s := - ContMDiff.contMDiffOn hf +@[deprecated (since := "2024-11-20")] alias Smooth.smoothOn := ContMDiff.contMDiffOn theorem contMDiffWithinAt_inter' (ht : t ∈ 𝓝[s] x) : ContMDiffWithinAt I I' n f (s ∩ t) x ↔ ContMDiffWithinAt I I' n f s x := @@ -716,16 +657,13 @@ protected theorem ContMDiffWithinAt.contMDiffAt ContMDiffAt I I' n f x := (contDiffWithinAt_localInvariantProp n).liftPropAt_of_liftPropWithinAt h ht -protected theorem SmoothWithinAt.smoothAt (h : SmoothWithinAt I I' f s x) (ht : s ∈ 𝓝 x) : - SmoothAt I I' f x := - ContMDiffWithinAt.contMDiffAt h ht +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.smoothAt := ContMDiffWithinAt.contMDiffAt protected theorem ContMDiffOn.contMDiffAt (h : ContMDiffOn I I' n f s) (hx : s ∈ 𝓝 x) : ContMDiffAt I I' n f x := (h x (mem_of_mem_nhds hx)).contMDiffAt hx -protected theorem SmoothOn.smoothAt (h : SmoothOn I I' f s) (hx : s ∈ 𝓝 x) : SmoothAt I I' f x := - h.contMDiffAt hx +@[deprecated (since := "2024-11-20")] alias SmoothOn.smoothAt := ContMDiffOn.contMDiffAt theorem contMDiffOn_iff_source_of_mem_maximalAtlas [SmoothManifoldWithCorners I M] (he : e ∈ maximalAtlas I M) (hs : s ⊆ e.source) : diff --git a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean index de822fbecd69c4..e11bb6f43fe1c2 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean @@ -105,7 +105,8 @@ theorem ContinuousLinearMap.contMDiffWithinAt (L : E →L[𝕜] F) {s x} : theorem ContinuousLinearMap.contMDiffOn (L : E →L[𝕜] F) {s} : ContMDiffOn 𝓘(𝕜, E) 𝓘(𝕜, F) n L s := L.contMDiff.contMDiffOn -theorem ContinuousLinearMap.smooth (L : E →L[𝕜] F) : Smooth 𝓘(𝕜, E) 𝓘(𝕜, F) L := L.contMDiff +@[deprecated (since := "2024-11-20")] +alias ContinuousLinearMap.smooth := ContinuousLinearMap.contMDiff theorem ContMDiffWithinAt.clm_precomp {f : M → F₁ →L[𝕜] F₂} {s : Set M} {x : M} (hf : ContMDiffWithinAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) n f s x) : @@ -261,13 +262,15 @@ theorem ContMDiff.clm_prodMap {g : M → F₁ →L[𝕜] F₃} {f : M → F₂ variable {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] /-- On any vector space, multiplication by a scalar is a smooth operation. -/ -theorem smooth_smul : Smooth (𝓘(𝕜).prod 𝓘(𝕜, V)) 𝓘(𝕜, V) fun p : 𝕜 × V => p.1 • p.2 := - smooth_iff.2 ⟨continuous_smul, fun _ _ => contDiff_smul.contDiffOn⟩ +theorem contMDiff_smul : ContMDiff (𝓘(𝕜).prod 𝓘(𝕜, V)) 𝓘(𝕜, V) ⊤ fun p : 𝕜 × V => p.1 • p.2 := + contMDiff_iff.2 ⟨continuous_smul, fun _ _ => contDiff_smul.contDiffOn⟩ + +@[deprecated (since := "2024-11-20")] alias smooth_smul := contMDiff_smul theorem ContMDiffWithinAt.smul {f : M → 𝕜} {g : M → V} (hf : ContMDiffWithinAt I 𝓘(𝕜) n f s x) (hg : ContMDiffWithinAt I 𝓘(𝕜, V) n g s x) : ContMDiffWithinAt I 𝓘(𝕜, V) n (fun p => f p • g p) s x := - (smooth_smul.of_le le_top).contMDiffAt.comp_contMDiffWithinAt x (hf.prod_mk hg) + (contMDiff_smul.of_le le_top).contMDiffAt.comp_contMDiffWithinAt x (hf.prod_mk hg) nonrec theorem ContMDiffAt.smul {f : M → 𝕜} {g : M → V} (hf : ContMDiffAt I 𝓘(𝕜) n f x) (hg : ContMDiffAt I 𝓘(𝕜, V) n g x) : ContMDiffAt I 𝓘(𝕜, V) n (fun p => f p • g p) x := @@ -281,18 +284,10 @@ theorem ContMDiff.smul {f : M → 𝕜} {g : M → V} (hf : ContMDiff I 𝓘( (hg : ContMDiff I 𝓘(𝕜, V) n g) : ContMDiff I 𝓘(𝕜, V) n fun p => f p • g p := fun x => (hf x).smul (hg x) -nonrec theorem SmoothWithinAt.smul {f : M → 𝕜} {g : M → V} (hf : SmoothWithinAt I 𝓘(𝕜) f s x) - (hg : SmoothWithinAt I 𝓘(𝕜, V) g s x) : SmoothWithinAt I 𝓘(𝕜, V) (fun p => f p • g p) s x := - hf.smul hg +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.smul := ContMDiffWithinAt.smul -nonrec theorem SmoothAt.smul {f : M → 𝕜} {g : M → V} (hf : SmoothAt I 𝓘(𝕜) f x) - (hg : SmoothAt I 𝓘(𝕜, V) g x) : SmoothAt I 𝓘(𝕜, V) (fun p => f p • g p) x := - hf.smul hg +@[deprecated (since := "2024-11-20")] alias SmoothAt.smul := ContMDiffAt.smul -nonrec theorem SmoothOn.smul {f : M → 𝕜} {g : M → V} (hf : SmoothOn I 𝓘(𝕜) f s) - (hg : SmoothOn I 𝓘(𝕜, V) g s) : SmoothOn I 𝓘(𝕜, V) (fun p => f p • g p) s := - hf.smul hg +@[deprecated (since := "2024-11-20")] alias SmoothOn.smul := ContMDiffOn.smul -nonrec theorem Smooth.smul {f : M → 𝕜} {g : M → V} (hf : Smooth I 𝓘(𝕜) f) - (hg : Smooth I 𝓘(𝕜, V) g) : Smooth I 𝓘(𝕜, V) fun p => f p • g p := - hf.smul hg +@[deprecated (since := "2024-11-20")] alias Smooth.smul := ContMDiff.smul diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean index 7e220374d46789..5562db2312500a 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean @@ -81,38 +81,22 @@ theorem ContMDiff.prod_mk_space {f : M → E'} {g : M → F'} (hf : ContMDiff I (hg : ContMDiff I 𝓘(𝕜, F') n g) : ContMDiff I 𝓘(𝕜, E' × F') n fun x => (f x, g x) := fun x => (hf x).prod_mk_space (hg x) -nonrec theorem SmoothWithinAt.prod_mk {f : M → M'} {g : M → N'} (hf : SmoothWithinAt I I' f s x) - (hg : SmoothWithinAt I J' g s x) : SmoothWithinAt I (I'.prod J') (fun x => (f x, g x)) s x := - hf.prod_mk hg +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.prod_mk := ContMDiffWithinAt.prod_mk -nonrec theorem SmoothWithinAt.prod_mk_space {f : M → E'} {g : M → F'} - (hf : SmoothWithinAt I 𝓘(𝕜, E') f s x) (hg : SmoothWithinAt I 𝓘(𝕜, F') g s x) : - SmoothWithinAt I 𝓘(𝕜, E' × F') (fun x => (f x, g x)) s x := - hf.prod_mk_space hg +@[deprecated (since := "2024-11-20")] +alias SmoothWithinAt.prod_mk_space := ContMDiffWithinAt.prod_mk_space -nonrec theorem SmoothAt.prod_mk {f : M → M'} {g : M → N'} (hf : SmoothAt I I' f x) - (hg : SmoothAt I J' g x) : SmoothAt I (I'.prod J') (fun x => (f x, g x)) x := - hf.prod_mk hg +@[deprecated (since := "2024-11-20")] alias SmoothAt.prod_mk := ContMDiffAt.prod_mk -nonrec theorem SmoothAt.prod_mk_space {f : M → E'} {g : M → F'} (hf : SmoothAt I 𝓘(𝕜, E') f x) - (hg : SmoothAt I 𝓘(𝕜, F') g x) : SmoothAt I 𝓘(𝕜, E' × F') (fun x => (f x, g x)) x := - hf.prod_mk_space hg +@[deprecated (since := "2024-11-20")] alias SmoothAt.prod_mk_space := ContMDiffAt.prod_mk_space -nonrec theorem SmoothOn.prod_mk {f : M → M'} {g : M → N'} (hf : SmoothOn I I' f s) - (hg : SmoothOn I J' g s) : SmoothOn I (I'.prod J') (fun x => (f x, g x)) s := - hf.prod_mk hg +@[deprecated (since := "2024-11-20")] alias SmoothOn.prod_mk := ContMDiffOn.prod_mk -nonrec theorem SmoothOn.prod_mk_space {f : M → E'} {g : M → F'} (hf : SmoothOn I 𝓘(𝕜, E') f s) - (hg : SmoothOn I 𝓘(𝕜, F') g s) : SmoothOn I 𝓘(𝕜, E' × F') (fun x => (f x, g x)) s := - hf.prod_mk_space hg +@[deprecated (since := "2024-11-20")] alias SmoothOn.prod_mk_space := ContMDiffOn.prod_mk_space -nonrec theorem Smooth.prod_mk {f : M → M'} {g : M → N'} (hf : Smooth I I' f) (hg : Smooth I J' g) : - Smooth I (I'.prod J') fun x => (f x, g x) := - hf.prod_mk hg +@[deprecated (since := "2024-11-20")] alias Smooth.prod_mk := ContMDiff.prod_mk -nonrec theorem Smooth.prod_mk_space {f : M → E'} {g : M → F'} (hf : Smooth I 𝓘(𝕜, E') f) - (hg : Smooth I 𝓘(𝕜, F') g) : Smooth I 𝓘(𝕜, E' × F') fun x => (f x, g x) := - hf.prod_mk_space hg +@[deprecated (since := "2024-11-20")] alias Smooth.prod_mk_space := ContMDiff.prod_mk_space end ProdMk @@ -146,18 +130,13 @@ theorem contMDiffOn_fst {s : Set (M × N)} : ContMDiffOn (I.prod J) I n Prod.fst theorem contMDiff_fst : ContMDiff (I.prod J) I n (@Prod.fst M N) := fun _ => contMDiffAt_fst -theorem smoothWithinAt_fst {s : Set (M × N)} {p : M × N} : - SmoothWithinAt (I.prod J) I Prod.fst s p := - contMDiffWithinAt_fst +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_fst := contMDiffWithinAt_fst -theorem smoothAt_fst {p : M × N} : SmoothAt (I.prod J) I Prod.fst p := - contMDiffAt_fst +@[deprecated (since := "2024-11-20")] alias smoothAt_fst := contMDiffAt_fst -theorem smoothOn_fst {s : Set (M × N)} : SmoothOn (I.prod J) I Prod.fst s := - contMDiffOn_fst +@[deprecated (since := "2024-11-20")] alias smoothOn_fst := contMDiffOn_fst -theorem smooth_fst : Smooth (I.prod J) I (@Prod.fst M N) := - contMDiff_fst +@[deprecated (since := "2024-11-20")] alias smooth_fst := contMDiff_fst theorem ContMDiffAt.fst {f : N → M × M'} {x : N} (hf : ContMDiffAt J (I.prod I') n f x) : ContMDiffAt J I n (fun x => (f x).1) x := @@ -167,12 +146,9 @@ theorem ContMDiff.fst {f : N → M × M'} (hf : ContMDiff J (I.prod I') n f) : ContMDiff J I n fun x => (f x).1 := contMDiff_fst.comp hf -theorem SmoothAt.fst {f : N → M × M'} {x : N} (hf : SmoothAt J (I.prod I') f x) : - SmoothAt J I (fun x => (f x).1) x := - smoothAt_fst.comp x hf +@[deprecated (since := "2024-11-20")] alias SmoothAt.fst := ContMDiffAt.fst -theorem Smooth.fst {f : N → M × M'} (hf : Smooth J (I.prod I') f) : Smooth J I fun x => (f x).1 := - smooth_fst.comp hf +@[deprecated (since := "2024-11-20")] alias Smooth.fst := ContMDiff.fst theorem contMDiffWithinAt_snd {s : Set (M × N)} {p : M × N} : ContMDiffWithinAt (I.prod J) J n Prod.snd s p := by @@ -202,18 +178,13 @@ theorem contMDiffOn_snd {s : Set (M × N)} : ContMDiffOn (I.prod J) J n Prod.snd theorem contMDiff_snd : ContMDiff (I.prod J) J n (@Prod.snd M N) := fun _ => contMDiffAt_snd -theorem smoothWithinAt_snd {s : Set (M × N)} {p : M × N} : - SmoothWithinAt (I.prod J) J Prod.snd s p := - contMDiffWithinAt_snd +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_snd := contMDiffWithinAt_snd -theorem smoothAt_snd {p : M × N} : SmoothAt (I.prod J) J Prod.snd p := - contMDiffAt_snd +@[deprecated (since := "2024-11-20")] alias smoothAt_snd := contMDiffAt_snd -theorem smoothOn_snd {s : Set (M × N)} : SmoothOn (I.prod J) J Prod.snd s := - contMDiffOn_snd +@[deprecated (since := "2024-11-20")] alias smoothOn_snd := contMDiffOn_snd -theorem smooth_snd : Smooth (I.prod J) J (@Prod.snd M N) := - contMDiff_snd +@[deprecated (since := "2024-11-20")] alias smooth_snd := contMDiff_snd theorem ContMDiffAt.snd {f : N → M × M'} {x : N} (hf : ContMDiffAt J (I.prod I') n f x) : ContMDiffAt J I' n (fun x => (f x).2) x := @@ -223,12 +194,9 @@ theorem ContMDiff.snd {f : N → M × M'} (hf : ContMDiff J (I.prod I') n f) : ContMDiff J I' n fun x => (f x).2 := contMDiff_snd.comp hf -theorem SmoothAt.snd {f : N → M × M'} {x : N} (hf : SmoothAt J (I.prod I') f x) : - SmoothAt J I' (fun x => (f x).2) x := - smoothAt_snd.comp x hf +@[deprecated (since := "2024-11-20")] alias SmoothAt.snd := ContMDiffAt.snd -theorem Smooth.snd {f : N → M × M'} (hf : Smooth J (I.prod I') f) : Smooth J I' fun x => (f x).2 := - smooth_snd.comp hf +@[deprecated (since := "2024-11-20")] alias Smooth.snd := ContMDiff.snd end Projections @@ -279,17 +247,16 @@ theorem contMDiff_prod_module_iff (f : M → F₁ × F₂) : rw [modelWithCornersSelf_prod, ← chartedSpaceSelf_prod] exact contMDiff_prod_iff f -theorem smoothAt_prod_iff (f : M → M' × N') {x : M} : - SmoothAt I (I'.prod J') f x ↔ SmoothAt I I' (Prod.fst ∘ f) x ∧ SmoothAt I J' (Prod.snd ∘ f) x := - contMDiffAt_prod_iff f +theorem contMDiff_prod_assoc : + ContMDiff ((I.prod I').prod J) (I.prod (I'.prod J)) n + fun x : (M × M') × N => (x.1.1, x.1.2, x.2) := + contMDiff_fst.fst.prod_mk <| contMDiff_fst.snd.prod_mk contMDiff_snd + +@[deprecated (since := "2024-11-20")] alias smoothAt_prod_iff := contMDiffAt_prod_iff -theorem smooth_prod_iff (f : M → M' × N') : - Smooth I (I'.prod J') f ↔ Smooth I I' (Prod.fst ∘ f) ∧ Smooth I J' (Prod.snd ∘ f) := - contMDiff_prod_iff f +@[deprecated (since := "2024-11-20")] alias smooth_prod_iff := contMDiff_prod_iff -theorem smooth_prod_assoc : - Smooth ((I.prod I').prod J) (I.prod (I'.prod J)) fun x : (M × M') × N => (x.1.1, x.1.2, x.2) := - smooth_fst.fst.prod_mk <| smooth_fst.snd.prod_mk smooth_snd +@[deprecated (since := "2024-11-20")] alias smooth_prod_assoc := contMDiff_prod_assoc section prodMap @@ -329,22 +296,13 @@ theorem ContMDiff.prod_map (hf : ContMDiff I I' n f) (hg : ContMDiff J J' n g) : intro p exact (hf p.1).prod_map' (hg p.2) -nonrec theorem SmoothWithinAt.prod_map (hf : SmoothWithinAt I I' f s x) - (hg : SmoothWithinAt J J' g r y) : - SmoothWithinAt (I.prod J) (I'.prod J') (Prod.map f g) (s ×ˢ r) (x, y) := - hf.prod_map hg +@[deprecated (since := "2024-11-20")] alias SmoothWithinAt.prod_map := ContMDiffWithinAt.prod_map -nonrec theorem SmoothAt.prod_map (hf : SmoothAt I I' f x) (hg : SmoothAt J J' g y) : - SmoothAt (I.prod J) (I'.prod J') (Prod.map f g) (x, y) := - hf.prod_map hg +@[deprecated (since := "2024-11-20")] alias SmoothAt.prod_map := ContMDiffAt.prod_map -nonrec theorem SmoothOn.prod_map (hf : SmoothOn I I' f s) (hg : SmoothOn J J' g r) : - SmoothOn (I.prod J) (I'.prod J') (Prod.map f g) (s ×ˢ r) := - hf.prod_map hg +@[deprecated (since := "2024-11-20")] alias SmoothOn.prod_map := ContMDiffOn.prod_map -nonrec theorem Smooth.prod_map (hf : Smooth I I' f) (hg : Smooth J J' g) : - Smooth (I.prod J) (I'.prod J') (Prod.map f g) := - hf.prod_map hg +@[deprecated (since := "2024-11-20")] alias Smooth.prod_map := ContMDiff.prod_map end prodMap @@ -380,20 +338,12 @@ theorem contMDiff_pi_space : ContMDiff I 𝓘(𝕜, ∀ i, Fi i) n φ ↔ ∀ i, ContMDiff I 𝓘(𝕜, Fi i) n fun x => φ x i := ⟨fun h i x => contMDiffAt_pi_space.1 (h x) i, fun h x => contMDiffAt_pi_space.2 fun i => h i x⟩ -theorem smoothWithinAt_pi_space : - SmoothWithinAt I 𝓘(𝕜, ∀ i, Fi i) φ s x ↔ - ∀ i, SmoothWithinAt I 𝓘(𝕜, Fi i) (fun x => φ x i) s x := - contMDiffWithinAt_pi_space +@[deprecated (since := "2024-11-20")] alias smoothWithinAt_pi_space := contMDiffWithinAt_pi_space -theorem smoothOn_pi_space : - SmoothOn I 𝓘(𝕜, ∀ i, Fi i) φ s ↔ ∀ i, SmoothOn I 𝓘(𝕜, Fi i) (fun x => φ x i) s := - contMDiffOn_pi_space +@[deprecated (since := "2024-11-20")] alias smoothAt_pi_space := contMDiffAt_pi_space -theorem smoothAt_pi_space : - SmoothAt I 𝓘(𝕜, ∀ i, Fi i) φ x ↔ ∀ i, SmoothAt I 𝓘(𝕜, Fi i) (fun x => φ x i) x := - contMDiffAt_pi_space +@[deprecated (since := "2024-11-20")] alias smoothOn_pi_space := contMDiffOn_pi_space -theorem smooth_pi_space : Smooth I 𝓘(𝕜, ∀ i, Fi i) φ ↔ ∀ i, Smooth I 𝓘(𝕜, Fi i) fun x => φ x i := - contMDiff_pi_space +@[deprecated (since := "2024-11-20")] alias smooth_pi_space := contMDiff_pi_space end PiSpace diff --git a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean index 9ab1a8b787d062..38b8fd8f39f73e 100644 --- a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean +++ b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean @@ -113,7 +113,7 @@ protected theorem ContMDiffWithinAt.mfderivWithin {x₀ : N} {f : N → M → M' rw [contMDiffWithinAt_iff] at hf' hg' simp_rw [Function.comp_def, uncurry, extChartAt_prod, PartialEquiv.prod_coe_symm, ModelWithCorners.range_prod] at hf' ⊢ - apply ContDiffWithinAt.fderivWithin _ _ _ hmn + apply ContDiffWithinAt.fderivWithin _ _ _ (show (m : WithTop ℕ∞) + 1 ≤ n from mod_cast hmn ) · simp [hx₀, t'] · apply inter_subset_left.trans rw [preimage_subset_iff] @@ -343,10 +343,7 @@ theorem ContMDiff.continuous_tangentMap (hf : ContMDiff I I' n f) (hmn : 1 ≤ n convert hf.continuousOn_tangentMapWithin hmn uniqueMDiffOn_univ rw [tangentMapWithin_univ] -/-- If a function is smooth, then its bundled derivative is smooth. -/ -theorem Smooth.tangentMap (hf : Smooth I I' f) : - Smooth I.tangent I'.tangent (tangentMap I I' f) := - ContMDiff.contMDiff_tangentMap hf le_rfl +@[deprecated (since := "2024-11-21")] alias Smooth.tangentMap := ContMDiff.contMDiff_tangentMap end tangentMap @@ -376,9 +373,9 @@ theorem tangentMap_tangentBundle_pure [Is : SmoothManifoldWithCorners I M] (p : · apply (PartialHomeomorph.open_target _).preimage I.continuous_invFun · simp only [mfld_simps] have A : MDifferentiableAt I I.tangent (fun x => @TotalSpace.mk M E (TangentSpace I) x 0) x := - haveI : Smooth I (I.prod 𝓘(𝕜, E)) (zeroSection E (TangentSpace I : M → Type _)) := - Bundle.smooth_zeroSection 𝕜 (TangentSpace I : M → Type _) - this.mdifferentiableAt + haveI : ContMDiff I (I.prod 𝓘(𝕜, E)) ⊤ (zeroSection E (TangentSpace I : M → Type _)) := + Bundle.contMDiff_zeroSection 𝕜 (TangentSpace I : M → Type _) + this.mdifferentiableAt le_top have B : fderivWithin 𝕜 (fun x' : E ↦ (x', (0 : E))) (Set.range I) (I ((chartAt H x) x)) v = (v, 0) := by rw [fderivWithin_eq_fderiv, DifferentiableAt.fderiv_prod] @@ -407,6 +404,9 @@ namespace ContMDiffMap -- (However as a consequence we import `Mathlib/Geometry/Manifold/ContMDiffMap.lean` here now.) -- They could be moved to another file (perhaps a new file) if desired. open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) protected theorem mdifferentiable' (f : C^n⟮I, M; I', M'⟯) (hn : 1 ≤ n) : MDifferentiable I I' f := f.contMDiff.mdifferentiable hn diff --git a/Mathlib/Geometry/Manifold/ContMDiffMap.lean b/Mathlib/Geometry/Manifold/ContMDiffMap.lean index 8566926007fa4e..2be46a551a7055 100644 --- a/Mathlib/Geometry/Manifold/ContMDiffMap.lean +++ b/Mathlib/Geometry/Manifold/ContMDiffMap.lean @@ -29,10 +29,7 @@ variable (I I') in def ContMDiffMap := { f : M → M' // ContMDiff I I' n f } -variable (I I') in -/-- Bundled smooth maps. -/ -abbrev SmoothMap := - ContMDiffMap I I' M M' ⊤ +@[deprecated (since := "024-11-21")] alias SmoothMap := ContMDiffMap @[inherit_doc] scoped[Manifold] notation "C^" n "⟮" I ", " M "; " I' ", " M' "⟯" => ContMDiffMap I I' M M' n @@ -42,6 +39,10 @@ scoped[Manifold] notation "C^" n "⟮" I ", " M "; " k "⟯" => ContMDiffMap I (modelWithCornersSelf k k) M k n open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) + namespace ContMDiffMap @@ -54,8 +55,7 @@ instance instFunLike : FunLike C^n⟮I, M; I', M'⟯ M M' where protected theorem contMDiff (f : C^n⟮I, M; I', M'⟯) : ContMDiff I I' n f := f.prop -protected theorem smooth (f : C^∞⟮I, M; I', M'⟯) : Smooth I I' f := - f.prop +@[deprecated (since := "2024-11-20")] alias smooth := ContMDiffMap.contMDiff -- Porting note: use generic instance instead -- instance : Coe C^n⟮I, M; I', M'⟯ C(M, M') := diff --git a/Mathlib/Geometry/Manifold/DerivationBundle.lean b/Mathlib/Geometry/Manifold/DerivationBundle.lean index ca029181286c40..fb3dbd766186af 100644 --- a/Mathlib/Geometry/Manifold/DerivationBundle.lean +++ b/Mathlib/Geometry/Manifold/DerivationBundle.lean @@ -25,6 +25,9 @@ variable (𝕜 : Type*) [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom [TopologicalSpace M] [ChartedSpace H M] (n : ℕ∞) open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) -- the following two instances prevent poorly understood type class inference timeout problems instance smoothFunctionsAlgebra : Algebra 𝕜 C^∞⟮I, M; 𝕜⟯ := by infer_instance diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 8a2f3e373a09aa..6a6dd316cf875e 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -44,7 +44,7 @@ diffeomorphism, manifold -/ -open scoped Manifold Topology +open scoped Manifold Topology ContDiff open Function Set @@ -125,7 +125,7 @@ protected theorem contMDiffWithinAt (h : M ≃ₘ^n⟮I, I'⟯ M') {s x} : ContM protected theorem contDiff (h : E ≃ₘ^n⟮𝓘(𝕜, E), 𝓘(𝕜, E')⟯ E') : ContDiff 𝕜 n h := h.contMDiff.contDiff -protected theorem smooth (h : M ≃ₘ⟮I, I'⟯ M') : Smooth I I' h := h.contMDiff +@[deprecated (since := "2024-11-21")] alias smooth := Diffeomorph.contDiff protected theorem mdifferentiable (h : M ≃ₘ^n⟮I, I'⟯ M') (hn : 1 ≤ n) : MDifferentiable I I' h := h.contMDiff.mdifferentiable hn @@ -491,7 +491,7 @@ instance smoothManifoldWithCorners_transDiffeomorph [SmoothManifoldWithCorners I SmoothManifoldWithCorners (I.transDiffeomorph e) M := by refine smoothManifoldWithCorners_of_contDiffOn (I.transDiffeomorph e) M fun e₁ e₂ h₁ h₂ => ?_ refine e.contDiff.comp_contDiffOn - (((contDiffGroupoid ⊤ I).compatible h₁ h₂).1.comp e.symm.contDiff.contDiffOn ?_) + (((contDiffGroupoid ∞ I).compatible h₁ h₂).1.comp e.symm.contDiff.contDiffOn ?_) simp only [mapsTo_iff_subset_preimage] mfld_set_tac @@ -539,9 +539,8 @@ theorem contMDiff_transDiffeomorph_right {f : M' → M} : ContMDiff I' (I.transDiffeomorph e) n f ↔ ContMDiff I' I n f := (toTransDiffeomorph I M e).contMDiff_diffeomorph_comp_iff le_top -theorem smooth_transDiffeomorph_right {f : M' → M} : - Smooth I' (I.transDiffeomorph e) f ↔ Smooth I' I f := - contMDiff_transDiffeomorph_right e +@[deprecated (since := "2024-11-21")] +alias smooth_transDiffeomorph_right := contMDiff_transDiffeomorph_right @[simp] theorem contMDiffWithinAt_transDiffeomorph_left {f : M → M'} {x s} : @@ -563,8 +562,7 @@ theorem contMDiff_transDiffeomorph_left {f : M → M'} : ContMDiff (I.transDiffeomorph e) I' n f ↔ ContMDiff I I' n f := ((toTransDiffeomorph I M e).contMDiff_comp_diffeomorph_iff le_top).symm -theorem smooth_transDiffeomorph_left {f : M → M'} : - Smooth (I.transDiffeomorph e) I' f ↔ Smooth I I' f := - e.contMDiff_transDiffeomorph_left +@[deprecated (since := "2024-11-21")] +alias smooth_transDiffeomorph_left := contMDiff_transDiffeomorph_left end Diffeomorph diff --git a/Mathlib/Geometry/Manifold/Instances/Real.lean b/Mathlib/Geometry/Manifold/Instances/Real.lean index 26caf2f7bee477..ce5fb5a376760e 100644 --- a/Mathlib/Geometry/Manifold/Instances/Real.lean +++ b/Mathlib/Geometry/Manifold/Instances/Real.lean @@ -42,7 +42,7 @@ noncomputable section open Set Function -open scoped Manifold +open scoped Manifold ContDiff /-- 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. diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index 00100a2fdd4ed9..a426774e69c589 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -69,7 +69,7 @@ noncomputable section open Metric Module Function -open scoped Manifold +open scoped Manifold ContDiff section StereographicProjection @@ -93,7 +93,7 @@ theorem stereoToFun_apply (x : E) : rfl theorem contDiffOn_stereoToFun : - ContDiffOn ℝ ⊤ (stereoToFun v) {x : E | innerSL _ v x ≠ (1 : ℝ)} := by + ContDiffOn ℝ ∞ (stereoToFun v) {x : E | innerSL _ v x ≠ (1 : ℝ)} := by refine ContDiffOn.smul ?_ (orthogonalProjection (ℝ ∙ v)ᗮ).contDiff.contDiffOn refine contDiff_const.contDiffOn.div ?_ ?_ · exact (contDiff_const.sub (innerSL ℝ v).contDiff).contDiffOn @@ -157,13 +157,13 @@ theorem hasFDerivAt_stereoInvFunAux_comp_coe (v : E) : hasFDerivAt_stereoInvFunAux v refine this.comp (0 : (ℝ ∙ v)ᗮ) (by apply ContinuousLinearMap.hasFDerivAt) -theorem contDiff_stereoInvFunAux : ContDiff ℝ ⊤ (stereoInvFunAux v) := by - have h₀ : ContDiff ℝ ⊤ fun w : E => ‖w‖ ^ 2 := contDiff_norm_sq ℝ - have h₁ : ContDiff ℝ ⊤ fun w : E => (‖w‖ ^ 2 + 4)⁻¹ := by +theorem contDiff_stereoInvFunAux : ContDiff ℝ ∞ (stereoInvFunAux v) := by + have h₀ : ContDiff ℝ ∞ fun w : E => ‖w‖ ^ 2 := contDiff_norm_sq ℝ + have h₁ : ContDiff ℝ ∞ fun w : E => (‖w‖ ^ 2 + 4)⁻¹ := by refine (h₀.add contDiff_const).inv ?_ intro x - positivity - have h₂ : ContDiff ℝ ⊤ fun w => (4 : ℝ) • w + (‖w‖ ^ 2 - 4) • v := by + nlinarith + 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 exact h₁.smul h₂ @@ -389,7 +389,7 @@ instance EuclideanSpace.instSmoothManifoldWithCornersSphere {n : ℕ} [Fact (fin -- Porting note: need to help with implicit variables again have H₂ := (contDiff_stereoInvFunAux (v := v.val)|>.comp (ℝ ∙ (v : E))ᗮ.subtypeL.contDiff).comp U.symm.contDiff - convert H₁.comp_inter (H₂.contDiffOn : ContDiffOn ℝ ⊤ _ Set.univ) using 1 + convert H₁.comp_inter (H₂.contDiffOn : ContDiffOn ℝ ∞ _ Set.univ) using 1 -- -- squeezed from `ext, simp [sphere_ext_iff, stereographic'_symm_apply, real_inner_comm]` simp only [PartialHomeomorph.trans_toPartialEquiv, PartialHomeomorph.symm_toPartialEquiv, PartialEquiv.trans_source, PartialEquiv.symm_source, stereographic'_target, @@ -407,7 +407,7 @@ instance (n : ℕ) : /-- 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 + ContMDiff (𝓡 n) 𝓘(ℝ, E) ⊤ ((↑) : sphere (0 : E) 1 → E) := by -- Porting note: trouble with filling these implicit variables in the instance have := EuclideanSpace.instSmoothManifoldWithCornersSphere (E := E) (n := n) rw [contMDiff_iff] @@ -438,7 +438,7 @@ theorem ContMDiff.codRestrict_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] {m (-- Again, partially removing type ascription... Weird that this helps! OrthonormalBasis.fromOrthogonalSpanSingleton n (ne_zero_of_mem_unit_sphere (-v))).repr - have h : ContDiffOn ℝ ⊤ _ Set.univ := U.contDiff.contDiffOn + have h : ContDiffOn ℝ ∞ _ Set.univ := U.contDiff.contDiffOn have H₁ := (h.comp_inter contDiffOn_stereoToFun).contMDiffOn have H₂ : ContMDiffOn _ _ _ _ Set.univ := hf.contMDiffOn convert (H₁.of_le le_top).comp' H₂ using 1 @@ -453,7 +453,7 @@ theorem ContMDiff.codRestrict_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] {m /-- The antipodal map is smooth. -/ theorem contMDiff_neg_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] : - ContMDiff (𝓡 n) (𝓡 n) ∞ fun x : sphere (0 : E) 1 => -x := by + ContMDiff (𝓡 n) (𝓡 n) ⊤ fun x : sphere (0 : E) 1 => -x := by -- this doesn't elaborate well in term mode apply ContMDiff.codRestrict_sphere apply contDiff_neg.contMDiff.comp _ @@ -555,7 +555,7 @@ instance : LieGroup (𝓡 1) Circle where smooth_mul := by apply ContMDiff.codRestrict_sphere let c : Circle → ℂ := (↑) - have h₂ : ContMDiff (𝓘(ℝ, ℂ).prod 𝓘(ℝ, ℂ)) 𝓘(ℝ, ℂ) ∞ fun z : ℂ × ℂ => z.fst * z.snd := by + have h₂ : ContMDiff (𝓘(ℝ, ℂ).prod 𝓘(ℝ, ℂ)) 𝓘(ℝ, ℂ) ⊤ fun z : ℂ × ℂ => z.fst * z.snd := by rw [contMDiff_iff] exact ⟨continuous_mul, fun x y => contDiff_mul.contDiffOn⟩ -- Porting note: needed to fill in first 3 arguments or could not figure out typeclasses @@ -569,7 +569,7 @@ instance : LieGroup (𝓡 1) Circle where exact Complex.conjCLE.contDiff.contMDiff.comp contMDiff_coe_sphere /-- The map `fun t ↦ exp (t * I)` from `ℝ` to the unit circle in `ℂ` is smooth. -/ -theorem contMDiff_circleExp : ContMDiff 𝓘(ℝ, ℝ) (𝓡 1) ∞ Circle.exp := +theorem contMDiff_circleExp : ContMDiff 𝓘(ℝ, ℝ) (𝓡 1) ⊤ Circle.exp := (contDiff_exp.comp (contDiff_id.smul contDiff_const)).contMDiff.codRestrict_sphere _ @[deprecated (since := "2024-07-25")] alias contMDiff_expMapCircle := contMDiff_circleExp diff --git a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean index 8ee99e793fb7c1..b66b8302d348ad 100644 --- a/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean +++ b/Mathlib/Geometry/Manifold/Instances/UnitsOfNormedAlgebra.lean @@ -27,6 +27,9 @@ example {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] [CompleteSpace V noncomputable section open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) namespace Units diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean index eecf755b43be23..9386f8ad261ec2 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean @@ -27,7 +27,7 @@ charts, differentiable, bijective noncomputable section -open scoped Manifold +open scoped Manifold ContDiff open Bundle Set Topology variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] @@ -99,7 +99,7 @@ theorem mdifferentiableAt_atlas (h : e ∈ atlas H M) {x : M} (hx : x ∈ e.sour ContDiffOn 𝕜 ∞ (I ∘ (chartAt H x).symm.trans e ∘ I.symm) (I.symm ⁻¹' ((chartAt H x).symm.trans e).source ∩ range I) := this.1 - have B := A.differentiableOn le_top (I ((chartAt H x : M → H) x)) mem + have B := A.differentiableOn (mod_cast le_top) (I ((chartAt H x : M → H) x)) mem simp only [mfld_simps] at B rw [inter_comm, differentiableWithinAt_inter] at B · simpa only [mfld_simps] @@ -120,7 +120,7 @@ theorem mdifferentiableAt_atlas_symm (h : e ∈ atlas H M) {x : H} (hx : x ∈ e ContDiffOn 𝕜 ∞ (I ∘ e.symm.trans (chartAt H (e.symm x)) ∘ I.symm) (I.symm ⁻¹' (e.symm.trans (chartAt H (e.symm x))).source ∩ range I) := this.1 - have B := A.differentiableOn le_top (I x) mem + have B := A.differentiableOn (mod_cast le_top) (I x) mem simp only [mfld_simps] at B rw [inter_comm, differentiableWithinAt_inter] at B · simpa only [mfld_simps] @@ -257,4 +257,96 @@ theorem mdifferentiableOn_extChartAt_symm : intro y hy exact (mdifferentiableWithinAt_extChartAt_symm hy).mono (extChartAt_target_subset_range x) +/-- The composition of the derivative of `extChartAt` with the derivative of the inverse of +`extChartAt` gives the identity. +Version where the basepoint belongs to `(extChartAt I x).target`. -/ +lemma mfderiv_extChartAt_comp_mfderivWithin_extChartAt_symm {x : M} + {y : E} (hy : y ∈ (extChartAt I x).target) : + (mfderiv I 𝓘(𝕜, E) (extChartAt I x) ((extChartAt I x).symm y)) ∘L + (mfderivWithin 𝓘(𝕜, E) I (extChartAt I x).symm (range I) y) = ContinuousLinearMap.id _ _ := by + have U : UniqueMDiffWithinAt 𝓘(𝕜, E) (range ↑I) y := by + apply I.uniqueMDiffOn + exact extChartAt_target_subset_range x hy + have h'y : (extChartAt I x).symm y ∈ (extChartAt I x).source := (extChartAt I x).map_target hy + have h''y : (extChartAt I x).symm y ∈ (chartAt H x).source := by + rwa [← extChartAt_source (I := I)] + rw [← mfderiv_comp_mfderivWithin]; rotate_left + · apply mdifferentiableAt_extChartAt h''y + · exact mdifferentiableWithinAt_extChartAt_symm hy + · exact U + rw [← mfderivWithin_id U] + apply Filter.EventuallyEq.mfderivWithin_eq U + · filter_upwards [extChartAt_target_mem_nhdsWithin_of_mem hy] with z hz + simp only [Function.comp_def, PartialEquiv.right_inv (extChartAt I x) hz, id_eq] + · simp only [Function.comp_def, PartialEquiv.right_inv (extChartAt I x) hy, id_eq] + +/-- The composition of the derivative of `extChartAt` with the derivative of the inverse of +`extChartAt` gives the identity. +Version where the basepoint belongs to `(extChartAt I x).source`. -/ +lemma mfderiv_extChartAt_comp_mfderivWithin_extChartAt_symm' {x : M} + {y : M} (hy : y ∈ (extChartAt I x).source) : + (mfderiv I 𝓘(𝕜, E) (extChartAt I x) y) ∘L + (mfderivWithin 𝓘(𝕜, E) I (extChartAt I x).symm (range I) (extChartAt I x y)) + = ContinuousLinearMap.id _ _ := by + have : y = (extChartAt I x).symm (extChartAt I x y) := ((extChartAt I x).left_inv hy).symm + convert mfderiv_extChartAt_comp_mfderivWithin_extChartAt_symm ((extChartAt I x).map_source hy) + +/-- The composition of the derivative of the inverse of `extChartAt` with the derivative of +`extChartAt` gives the identity. +Version where the basepoint belongs to `(extChartAt I x).target`. -/ +lemma mfderivWithin_extChartAt_symm_comp_mfderiv_extChartAt + {y : E} (hy : y ∈ (extChartAt I x).target) : + (mfderivWithin 𝓘(𝕜, E) I (extChartAt I x).symm (range I) y) ∘L + (mfderiv I 𝓘(𝕜, E) (extChartAt I x) ((extChartAt I x).symm y)) + = ContinuousLinearMap.id _ _ := by + have h'y : (extChartAt I x).symm y ∈ (extChartAt I x).source := (extChartAt I x).map_target hy + have h''y : (extChartAt I x).symm y ∈ (chartAt H x).source := by + rwa [← extChartAt_source (I := I)] + have U' : UniqueMDiffWithinAt I (extChartAt I x).source ((extChartAt I x).symm y) := + (isOpen_extChartAt_source x).uniqueMDiffWithinAt h'y + have : mfderiv I 𝓘(𝕜, E) (extChartAt I x) ((extChartAt I x).symm y) + = mfderivWithin I 𝓘(𝕜, E) (extChartAt I x) (extChartAt I x).source + ((extChartAt I x).symm y) := by + rw [mfderivWithin_eq_mfderiv U'] + exact mdifferentiableAt_extChartAt h''y + rw [this, ← mfderivWithin_comp_of_eq]; rotate_left + · exact mdifferentiableWithinAt_extChartAt_symm hy + · exact (mdifferentiableAt_extChartAt h''y).mdifferentiableWithinAt + · intro z hz + apply extChartAt_target_subset_range x + exact PartialEquiv.map_source (extChartAt I x) hz + · exact U' + · exact PartialEquiv.right_inv (extChartAt I x) hy + rw [← mfderivWithin_id U'] + apply Filter.EventuallyEq.mfderivWithin_eq U' + · filter_upwards [extChartAt_source_mem_nhdsWithin' h'y] with z hz + simp only [Function.comp_def, PartialEquiv.left_inv (extChartAt I x) hz, id_eq] + · simp only [Function.comp_def, PartialEquiv.right_inv (extChartAt I x) hy, id_eq] + +/-- The composition of the derivative of the inverse of `extChartAt` with the derivative of +`extChartAt` gives the identity. +Version where the basepoint belongs to `(extChartAt I x).source`. -/ +lemma mfderivWithin_extChartAt_symm_comp_mfderiv_extChartAt' + {y : M} (hy : y ∈ (extChartAt I x).source) : + (mfderivWithin 𝓘(𝕜, E) I (extChartAt I x).symm (range I) (extChartAt I x y)) ∘L + (mfderiv I 𝓘(𝕜, E) (extChartAt I x) y) + = ContinuousLinearMap.id _ _ := by + have : y = (extChartAt I x).symm (extChartAt I x y) := ((extChartAt I x).left_inv hy).symm + convert mfderivWithin_extChartAt_symm_comp_mfderiv_extChartAt ((extChartAt I x).map_source hy) + +lemma isInvertible_mfderivWithin_extChartAt_symm {y : E} (hy : y ∈ (extChartAt I x).target) : + (mfderivWithin 𝓘(𝕜, E) I (extChartAt I x).symm (range I) y).IsInvertible := + ContinuousLinearMap.IsInvertible.of_inverse + (mfderivWithin_extChartAt_symm_comp_mfderiv_extChartAt hy) + (mfderiv_extChartAt_comp_mfderivWithin_extChartAt_symm hy) + +lemma isInvertible_mfderiv_extChartAt {y : M} (hy : y ∈ (extChartAt I x).source) : + (mfderiv I 𝓘(𝕜, E) (extChartAt I x) y).IsInvertible := by + have h'y : extChartAt I x y ∈ (extChartAt I x).target := (extChartAt I x).map_source hy + have Z := ContinuousLinearMap.IsInvertible.of_inverse + (mfderiv_extChartAt_comp_mfderivWithin_extChartAt_symm h'y) + (mfderivWithin_extChartAt_symm_comp_mfderiv_extChartAt h'y) + have : (extChartAt I x).symm ((extChartAt I x) y) = y := (extChartAt I x).left_inv hy + rwa [this] at Z + end extChartAt diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean b/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean index 552b4986092f8d..acf6be63394ec4 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean @@ -467,7 +467,8 @@ theorem ContMDiffWithinAt.mdifferentiableWithinAt (hf : ContMDiffWithinAt I I' n apply hf.1.preimage_mem_nhdsWithin exact extChartAt_source_mem_nhds (f x) rw [mdifferentiableWithinAt_iff] - exact ⟨hf.1.mono inter_subset_left, (hf.2.differentiableWithinAt hn).mono (by mfld_set_tac)⟩ + exact ⟨hf.1.mono inter_subset_left, (hf.2.differentiableWithinAt (mod_cast hn)).mono + (by mfld_set_tac)⟩ theorem ContMDiffAt.mdifferentiableAt (hf : ContMDiffAt I I' n f x) (hn : 1 ≤ n) : MDifferentiableAt I I' f x := @@ -477,27 +478,30 @@ theorem ContMDiff.mdifferentiableAt (hf : ContMDiff I I' n f) (hn : 1 ≤ n) : MDifferentiableAt I I' f x := hf.contMDiffAt.mdifferentiableAt hn +theorem ContMDiff.mdifferentiableWithinAt (hf : ContMDiff I I' n f) (hn : 1 ≤ n) : + MDifferentiableWithinAt I I' f s x := + (hf.contMDiffAt.mdifferentiableAt hn).mdifferentiableWithinAt + theorem ContMDiffOn.mdifferentiableOn (hf : ContMDiffOn I I' n f s) (hn : 1 ≤ n) : MDifferentiableOn I I' f s := fun x hx => (hf x hx).mdifferentiableWithinAt hn -nonrec theorem SmoothWithinAt.mdifferentiableWithinAt (hf : SmoothWithinAt I I' f s x) : - MDifferentiableWithinAt I I' f s x := - hf.mdifferentiableWithinAt le_top +@[deprecated (since := "2024-11-20")] +alias SmoothWithinAt.mdifferentiableWithinAt := ContMDiffWithinAt.mdifferentiableWithinAt theorem ContMDiff.mdifferentiable (hf : ContMDiff I I' n f) (hn : 1 ≤ n) : MDifferentiable I I' f := fun x => (hf x).mdifferentiableAt hn -nonrec theorem SmoothAt.mdifferentiableAt (hf : SmoothAt I I' f x) : MDifferentiableAt I I' f x := - hf.mdifferentiableAt le_top +@[deprecated (since := "2024-11-20")] +alias SmoothAt.mdifferentiableAt := ContMDiffAt.mdifferentiableAt -nonrec theorem SmoothOn.mdifferentiableOn (hf : SmoothOn I I' f s) : MDifferentiableOn I I' f s := - hf.mdifferentiableOn le_top +@[deprecated (since := "2024-11-20")] +alias SmoothOn.mdifferentiableOn := ContMDiffOn.mdifferentiableOn -theorem Smooth.mdifferentiable (hf : Smooth I I' f) : MDifferentiable I I' f := - ContMDiff.mdifferentiable hf le_top +@[deprecated (since := "2024-11-20")] +alias Smooth.mdifferentiable := ContMDiff.mdifferentiable -theorem Smooth.mdifferentiableAt (hf : Smooth I I' f) : MDifferentiableAt I I' f x := - hf.mdifferentiable x +@[deprecated (since := "2024-11-20")] +alias Smooth.mdifferentiableAt := ContMDiff.mdifferentiableAt theorem MDifferentiableOn.continuousOn (h : MDifferentiableOn I I' f s) : ContinuousOn f s := fun x hx => (h x hx).continuousWithinAt @@ -505,8 +509,8 @@ theorem MDifferentiableOn.continuousOn (h : MDifferentiableOn I I' f s) : Contin theorem MDifferentiable.continuous (h : MDifferentiable I I' f) : Continuous f := continuous_iff_continuousAt.2 fun x => (h x).continuousAt -theorem Smooth.mdifferentiableWithinAt (hf : Smooth I I' f) : MDifferentiableWithinAt I I' f s x := - hf.mdifferentiableAt.mdifferentiableWithinAt +@[deprecated (since := "2024-11-20")] +alias Smooth.mdifferentiableWithinAt := ContMDiff.mdifferentiableWithinAt /-! ### Deriving continuity from differentiability on manifolds -/ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean index 79091c46190387..b7c3206ec39899 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean @@ -99,7 +99,7 @@ derivative, manifold noncomputable section -open scoped Topology +open scoped Topology ContDiff open Set ChartedSpace section DerivativesDefinitions @@ -147,7 +147,7 @@ theorem differentiableWithinAtProp_self_target {f : H → E'} {s : Set H} {x : H /-- Being differentiable in the model space is a local property, invariant under smooth maps. Therefore, it will lift nicely to manifolds. -/ theorem differentiableWithinAt_localInvariantProp : - (contDiffGroupoid ⊤ I).LocalInvariantProp (contDiffGroupoid ⊤ I') + (contDiffGroupoid ∞ I).LocalInvariantProp (contDiffGroupoid ∞ I') (DifferentiableWithinAtProp I I') := { is_local := by intro s x u f u_open xu @@ -167,7 +167,8 @@ theorem differentiableWithinAt_localInvariantProp : rw [this] at h have : I (e x) ∈ I.symm ⁻¹' e.target ∩ Set.range I := by simp only [hx, mfld_simps] have := (mem_groupoid_of_pregroupoid.2 he).2.contDiffWithinAt this - convert (h.comp' _ (this.differentiableWithinAt le_top)).mono_of_mem_nhdsWithin _ using 1 + convert (h.comp' _ (this.differentiableWithinAt (mod_cast le_top))).mono_of_mem_nhdsWithin _ + using 1 · ext y; simp only [mfld_simps] refine mem_nhdsWithin.mpr @@ -187,7 +188,7 @@ theorem differentiableWithinAt_localInvariantProp : have A : (I' ∘ f ∘ I.symm) (I x) ∈ I'.symm ⁻¹' e'.source ∩ Set.range I' := by simp only [hx, mfld_simps] have := (mem_groupoid_of_pregroupoid.2 he').1.contDiffWithinAt A - convert (this.differentiableWithinAt le_top).comp _ h _ + convert (this.differentiableWithinAt (mod_cast le_top)).comp _ h _ · ext y; simp only [mfld_simps] · intro y hy; simp only [mfld_simps] at hy; simpa only [hy, mfld_simps] using hs hy.1 } diff --git a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean index 2bbe312b6c383f..63e5592d2c5373 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean @@ -26,14 +26,31 @@ section SpecificFunctions /-! ### Differentiability of specific functions -/ -variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + -- declare a charted space `M` over the pair `(E, H)`. + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} - [TopologicalSpace M] [ChartedSpace H M] {E' : Type*} - [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] + [TopologicalSpace M] [ChartedSpace H M] + -- declare a charted space `M'` over the pair `(E', H')`. + {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + -- declare a charted space `M''` over the pair `(E'', H'')`. {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] {I'' : ModelWithCorners 𝕜 E'' H''} {M'' : Type*} [TopologicalSpace M''] [ChartedSpace H'' M''] + -- declare a charted space `N` over the pair `(F, G)`. + {F : Type*} + [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} [TopologicalSpace G] + {J : ModelWithCorners 𝕜 F G} {N : Type*} [TopologicalSpace N] [ChartedSpace G N] + -- declare a charted space `N'` over the pair `(F', G')`. + {F' : Type*} + [NormedAddCommGroup F'] [NormedSpace 𝕜 F'] {G' : Type*} [TopologicalSpace G'] + {J' : ModelWithCorners 𝕜 F' G'} {N' : Type*} [TopologicalSpace N'] [ChartedSpace G' N'] + -- F₁, F₂, F₃, F₄ are normed spaces + {F₁ : Type*} + [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] {F₂ : Type*} [NormedAddCommGroup F₂] + [NormedSpace 𝕜 F₂] {F₃ : Type*} [NormedAddCommGroup F₃] [NormedSpace 𝕜 F₃] {F₄ : Type*} + [NormedAddCommGroup F₄] [NormedSpace 𝕜 F₄] namespace ContinuousLinearMap @@ -301,6 +318,128 @@ theorem mfderivWithin_snd {s : Set (M × M')} {x : M × M'} ContinuousLinearMap.snd 𝕜 (TangentSpace I x.1) (TangentSpace I' x.2) := by rw [MDifferentiable.mfderivWithin mdifferentiableAt_snd hxs]; exact mfderiv_snd +theorem MDifferentiableWithinAt.fst {f : N → M × M'} {s : Set N} {x : N} + (hf : MDifferentiableWithinAt J (I.prod I') f s x) : + MDifferentiableWithinAt J I (fun x => (f x).1) s x := + mdifferentiableAt_fst.comp_mdifferentiableWithinAt x hf + +theorem MDifferentiableAt.fst {f : N → M × M'} {x : N} (hf : MDifferentiableAt J (I.prod I') f x) : + MDifferentiableAt J I (fun x => (f x).1) x := + mdifferentiableAt_fst.comp x hf + +theorem MDifferentiable.fst {f : N → M × M'} (hf : MDifferentiable J (I.prod I') f) : + MDifferentiable J I fun x => (f x).1 := + mdifferentiable_fst.comp hf + +theorem MDifferentiableWithinAt.snd {f : N → M × M'} {s : Set N} {x : N} + (hf : MDifferentiableWithinAt J (I.prod I') f s x) : + MDifferentiableWithinAt J I' (fun x => (f x).2) s x := + mdifferentiableAt_snd.comp_mdifferentiableWithinAt x hf + +theorem MDifferentiableAt.snd {f : N → M × M'} {x : N} (hf : MDifferentiableAt J (I.prod I') f x) : + MDifferentiableAt J I' (fun x => (f x).2) x := + mdifferentiableAt_snd.comp x hf + +theorem MDifferentiable.snd {f : N → M × M'} (hf : MDifferentiable J (I.prod I') f) : + MDifferentiable J I' fun x => (f x).2 := + mdifferentiable_snd.comp hf + +theorem mdifferentiableWithinAt_prod_iff (f : M → M' × N') : + MDifferentiableWithinAt I (I'.prod J') f s x ↔ + MDifferentiableWithinAt I I' (Prod.fst ∘ f) s x + ∧ MDifferentiableWithinAt I J' (Prod.snd ∘ f) s x := + ⟨fun h => ⟨h.fst, h.snd⟩, fun h => h.1.prod_mk h.2⟩ + +theorem mdifferentiableWithinAt_prod_module_iff (f : M → F₁ × F₂) : + MDifferentiableWithinAt I 𝓘(𝕜, F₁ × F₂) f s x ↔ + MDifferentiableWithinAt I 𝓘(𝕜, F₁) (Prod.fst ∘ f) s x ∧ + MDifferentiableWithinAt I 𝓘(𝕜, F₂) (Prod.snd ∘ f) s x := by + rw [modelWithCornersSelf_prod, ← chartedSpaceSelf_prod] + exact mdifferentiableWithinAt_prod_iff f + +theorem mdifferentiableAt_prod_iff (f : M → M' × N') : + MDifferentiableAt I (I'.prod J') f x ↔ + MDifferentiableAt I I' (Prod.fst ∘ f) x ∧ MDifferentiableAt I J' (Prod.snd ∘ f) x := by + simp_rw [← mdifferentiableWithinAt_univ]; exact mdifferentiableWithinAt_prod_iff f + +theorem mdifferentiableAt_prod_module_iff (f : M → F₁ × F₂) : + MDifferentiableAt I 𝓘(𝕜, F₁ × F₂) f x ↔ + MDifferentiableAt I 𝓘(𝕜, F₁) (Prod.fst ∘ f) x + ∧ MDifferentiableAt I 𝓘(𝕜, F₂) (Prod.snd ∘ f) x := by + rw [modelWithCornersSelf_prod, ← chartedSpaceSelf_prod] + exact mdifferentiableAt_prod_iff f + +theorem mdifferentiableOn_prod_iff (f : M → M' × N') : + MDifferentiableOn I (I'.prod J') f s ↔ + MDifferentiableOn I I' (Prod.fst ∘ f) s ∧ MDifferentiableOn I J' (Prod.snd ∘ f) s := + ⟨fun h ↦ ⟨fun x hx ↦ ((mdifferentiableWithinAt_prod_iff f).1 (h x hx)).1, + fun x hx ↦ ((mdifferentiableWithinAt_prod_iff f).1 (h x hx)).2⟩ , + fun h x hx ↦ (mdifferentiableWithinAt_prod_iff f).2 ⟨h.1 x hx, h.2 x hx⟩⟩ + +theorem mdifferentiableOn_prod_module_iff (f : M → F₁ × F₂) : + MDifferentiableOn I 𝓘(𝕜, F₁ × F₂) f s ↔ + MDifferentiableOn I 𝓘(𝕜, F₁) (Prod.fst ∘ f) s + ∧ MDifferentiableOn I 𝓘(𝕜, F₂) (Prod.snd ∘ f) s := by + rw [modelWithCornersSelf_prod, ← chartedSpaceSelf_prod] + exact mdifferentiableOn_prod_iff f + +theorem mdifferentiable_prod_iff (f : M → M' × N') : + MDifferentiable I (I'.prod J') f ↔ + MDifferentiable I I' (Prod.fst ∘ f) ∧ MDifferentiable I J' (Prod.snd ∘ f) := + ⟨fun h => ⟨h.fst, h.snd⟩, fun h => by convert h.1.prod_mk h.2⟩ + +theorem mdifferentiable_prod_module_iff (f : M → F₁ × F₂) : + MDifferentiable I 𝓘(𝕜, F₁ × F₂) f ↔ + MDifferentiable I 𝓘(𝕜, F₁) (Prod.fst ∘ f) ∧ MDifferentiable I 𝓘(𝕜, F₂) (Prod.snd ∘ f) := by + rw [modelWithCornersSelf_prod, ← chartedSpaceSelf_prod] + exact mdifferentiable_prod_iff f + + +section prodMap + +variable {f : M → M'} {g : N → N'} {r : Set N} {y : N} + +/-- The product map of two `C^n` functions within a set at a point is `C^n` +within the product set at the product point. -/ +theorem MDifferentiableWithinAt.prod_map' {p : M × N} (hf : MDifferentiableWithinAt I I' f s p.1) + (hg : MDifferentiableWithinAt J J' g r p.2) : + MDifferentiableWithinAt (I.prod J) (I'.prod J') (Prod.map f g) (s ×ˢ r) p := + (hf.comp p mdifferentiableWithinAt_fst (prod_subset_preimage_fst _ _)).prod_mk <| + hg.comp p mdifferentiableWithinAt_snd (prod_subset_preimage_snd _ _) + +theorem MDifferentiableWithinAt.prod_map (hf : MDifferentiableWithinAt I I' f s x) + (hg : MDifferentiableWithinAt J J' g r y) : + MDifferentiableWithinAt (I.prod J) (I'.prod J') (Prod.map f g) (s ×ˢ r) (x, y) := + MDifferentiableWithinAt.prod_map' hf hg + +theorem MDifferentiableAt.prod_map + (hf : MDifferentiableAt I I' f x) (hg : MDifferentiableAt J J' g y) : + MDifferentiableAt (I.prod J) (I'.prod J') (Prod.map f g) (x, y) := by + rw [← mdifferentiableWithinAt_univ] at * + convert hf.prod_map hg + exact univ_prod_univ.symm + +/-- Variant of `MDifferentiableAt.prod_map` in which the point in the product is given as `p` +instead of a pair `(x, y)`. -/ +theorem MDifferentiableAt.prod_map' {p : M × N} + (hf : MDifferentiableAt I I' f p.1) (hg : MDifferentiableAt J J' g p.2) : + MDifferentiableAt (I.prod J) (I'.prod J') (Prod.map f g) p := by + rcases p with ⟨⟩ + exact hf.prod_map hg + +theorem MDifferentiableOn.prod_map + (hf : MDifferentiableOn I I' f s) (hg : MDifferentiableOn J J' g r) : + MDifferentiableOn (I.prod J) (I'.prod J') (Prod.map f g) (s ×ˢ r) := + (hf.comp mdifferentiableOn_fst (prod_subset_preimage_fst _ _)).prod_mk <| + hg.comp mdifferentiableOn_snd (prod_subset_preimage_snd _ _) + +theorem MDifferentiable.prod_map (hf : MDifferentiable I I' f) (hg : MDifferentiable J J' g) : + MDifferentiable (I.prod J) (I'.prod J') (Prod.map f g) := by + intro p + exact (hf p.1).prod_map' (hg p.2) + +end prodMap + @[simp, mfld_simps] theorem tangentMap_prod_snd {p : TangentBundle (I.prod I') (M × M')} : tangentMap (I.prod I') I' Prod.snd p = ⟨p.proj.2, p.2.2⟩ := by @@ -330,22 +469,30 @@ theorem mfderiv_prod_left {x₀ : M} {y₀ : M'} : refine (mdifferentiableAt_id.mfderiv_prod mdifferentiableAt_const).trans ?_ rw [mfderiv_id, mfderiv_const, ContinuousLinearMap.inl] +theorem tangentMap_prod_left {p : TangentBundle I M} {y₀ : M'} : + tangentMap I (I.prod I') (fun x => (x, y₀)) p = ⟨(p.1, y₀), (p.2, 0)⟩ := by + simp only [tangentMap, mfderiv_prod_left, TotalSpace.mk_inj] + rfl + theorem mfderiv_prod_right {x₀ : M} {y₀ : M'} : mfderiv I' (I.prod I') (fun y => (x₀, y)) y₀ = ContinuousLinearMap.inr 𝕜 (TangentSpace I x₀) (TangentSpace I' y₀) := by refine (mdifferentiableAt_const.mfderiv_prod mdifferentiableAt_id).trans ?_ rw [mfderiv_id, mfderiv_const, ContinuousLinearMap.inr] +theorem tangentMap_prod_right {p : TangentBundle I' M'} {x₀ : M} : + tangentMap I' (I.prod I') (fun y => (x₀, y)) p = ⟨(x₀, p.1), (0, p.2)⟩ := by + simp only [tangentMap, mfderiv_prod_right, TotalSpace.mk_inj] + rfl + /-- The total derivative of a function in two variables is the sum of the partial derivatives. Note that to state this (without casts) we need to be able to see through the definition of `TangentSpace`. -/ theorem mfderiv_prod_eq_add {f : M × M' → M''} {p : M × M'} (hf : MDifferentiableAt (I.prod I') I'' f p) : mfderiv (I.prod I') I'' f p = - show E × E' →L[𝕜] E'' from mfderiv (I.prod I') I'' (fun z : M × M' => f (z.1, p.2)) p + mfderiv (I.prod I') I'' (fun z : M × M' => f (p.1, z.2)) p := by - dsimp only erw [mfderiv_comp_of_eq hf (mdifferentiableAt_fst.prod_mk mdifferentiableAt_const) rfl, mfderiv_comp_of_eq hf (mdifferentiableAt_const.prod_mk mdifferentiableAt_snd) rfl, ← ContinuousLinearMap.comp_add, @@ -356,6 +503,42 @@ theorem mfderiv_prod_eq_add {f : M × M' → M''} {p : M × M'} convert ContinuousLinearMap.comp_id <| mfderiv (.prod I I') I'' f (p.1, p.2) exact ContinuousLinearMap.coprod_inl_inr +/-- The total derivative of a function in two variables is the sum of the partial derivatives. + Note that to state this (without casts) we need to be able to see through the definition of + `TangentSpace`. Version in terms of the one-variable derivatives. -/ +theorem mfderiv_prod_eq_add_comp {f : M × M' → M''} {p : M × M'} + (hf : MDifferentiableAt (I.prod I') I'' f p) : + mfderiv (I.prod I') I'' f p = + (mfderiv I I'' (fun z : M => f (z, p.2)) p.1) ∘L (id (ContinuousLinearMap.fst 𝕜 E E') : + (TangentSpace (I.prod I') p) →L[𝕜] (TangentSpace I p.1)) + + (mfderiv I' I'' (fun z : M' => f (p.1, z)) p.2) ∘L (id (ContinuousLinearMap.snd 𝕜 E E') : + (TangentSpace (I.prod I') p) →L[𝕜] (TangentSpace I' p.2)) := by + rw [mfderiv_prod_eq_add hf] + congr + · have : (fun z : M × M' => f (z.1, p.2)) = (fun z : M => f (z, p.2)) ∘ Prod.fst := rfl + rw [this, mfderiv_comp (I' := I)] + · simp only [mfderiv_fst, id_eq] + rfl + · exact hf.comp _ (mdifferentiableAt_id.prod_mk mdifferentiableAt_const) + · exact mdifferentiableAt_fst + · have : (fun z : M × M' => f (p.1, z.2)) = (fun z : M' => f (p.1, z)) ∘ Prod.snd := rfl + rw [this, mfderiv_comp (I' := I')] + · simp only [mfderiv_snd, id_eq] + rfl + · exact hf.comp _ (mdifferentiableAt_const.prod_mk mdifferentiableAt_id) + · exact mdifferentiableAt_snd + +/-- The total derivative of a function in two variables is the sum of the partial derivatives. + Note that to state this (without casts) we need to be able to see through the definition of + `TangentSpace`. Version in terms of the one-variable derivatives. -/ +theorem mfderiv_prod_eq_add_apply {f : M × M' → M''} {p : M × M'} {v : TangentSpace (I.prod I') p} + (hf : MDifferentiableAt (I.prod I') I'' f p) : + mfderiv (I.prod I') I'' f p v = + mfderiv I I'' (fun z : M => f (z, p.2)) p.1 v.1 + + mfderiv I' I'' (fun z : M' => f (p.1, z)) p.2 v.2 := by + rw [mfderiv_prod_eq_add_comp hf] + rfl + end Prod section Arithmetic diff --git a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean index 4facc7f820910a..e090b101ab9e70 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean @@ -120,7 +120,7 @@ variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {Z : M → Type theorem Trivialization.mdifferentiable (e : Trivialization F (π F Z)) [MemTrivializationAtlas e] : e.toPartialHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := - ⟨e.smoothOn.mdifferentiableOn, e.smoothOn_symm.mdifferentiableOn⟩ + ⟨e.contMDiffOn.mdifferentiableOn le_top, e.contMDiffOn_symm.mdifferentiableOn le_top⟩ theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} (hs : UniqueMDiffWithinAt I s p.proj) : diff --git a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean index 35ffa8cfc87432..5a4131d403b71b 100644 --- a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean +++ b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean @@ -59,6 +59,9 @@ universe uι uE uH uM uF open Function Filter Module Set open scoped Topology Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) noncomputable section @@ -160,8 +163,10 @@ theorem sum_le_one (x : M) : ∑ᶠ i, f i x ≤ 1 := def toPartitionOfUnity : PartitionOfUnity ι M s := { f with toFun := fun i => f i } -theorem smooth_sum : Smooth I 𝓘(ℝ) fun x => ∑ᶠ i, f i x := - smooth_finsum (fun i => (f i).smooth) f.locallyFinite +theorem contMDiff_sum : ContMDiff I 𝓘(ℝ) ⊤ fun x => ∑ᶠ i, f i x := + contMDiff_finsum (fun i => (f i).contMDiff) f.locallyFinite + +@[deprecated (since := "2024-11-21")] alias smooth_sum := contMDiff_sum theorem le_one (i : ι) (x : M) : f i x ≤ 1 := f.toPartitionOfUnity.le_one i x @@ -178,9 +183,7 @@ theorem contMDiff_smul {g : M → F} {i} (hg : ∀ x ∈ tsupport (f i), ContMDi contMDiff_of_tsupport fun x hx => ((f i).contMDiff.contMDiffAt.of_le le_top).smul <| hg x <| tsupport_smul_subset_left _ _ hx -theorem smooth_smul {g : M → F} {i} (hg : ∀ x ∈ tsupport (f i), SmoothAt I 𝓘(ℝ, F) g x) : - Smooth I 𝓘(ℝ, F) fun x => f i x • g x := - f.contMDiff_smul hg +@[deprecated (since := "2024-11-21")] alias smooth_smul := contMDiff_smul /-- If `f` is a smooth partition of unity on a set `s : Set M` and `g : ι → M → F` is a family of functions such that `g i` is $C^n$ smooth at every point of the topological support of `f i`, then @@ -191,20 +194,14 @@ theorem contMDiff_finsum_smul {g : ι → M → F} (contMDiff_finsum fun i => f.contMDiff_smul (hg i)) <| f.locallyFinite.subset fun _ => support_smul_subset_left _ _ -/-- If `f` is a smooth partition of unity on a set `s : Set M` and `g : ι → M → F` is a family of -functions such that `g i` is smooth at every point of the topological support of `f i`, then the sum -`fun x ↦ ∑ᶠ i, f i x • g i x` is smooth on the whole manifold. -/ -theorem smooth_finsum_smul {g : ι → M → F} - (hg : ∀ (i), ∀ x ∈ tsupport (f i), SmoothAt I 𝓘(ℝ, F) (g i) x) : - Smooth I 𝓘(ℝ, F) fun x => ∑ᶠ i, f i x • g i x := - f.contMDiff_finsum_smul hg +@[deprecated (since := "2024-11-21")] alias smooth_finsum_smul := contMDiff_finsum_smul theorem contMDiffAt_finsum {x₀ : M} {g : ι → M → F} (hφ : ∀ i, x₀ ∈ tsupport (f i) → ContMDiffAt I 𝓘(ℝ, F) n (g i) x₀) : ContMDiffAt I 𝓘(ℝ, F) n (fun x ↦ ∑ᶠ i, f i x • g i x) x₀ := by refine _root_.contMDiffAt_finsum (f.locallyFinite.smul_left _) fun i ↦ ?_ by_cases hx : x₀ ∈ tsupport (f i) - · exact ContMDiffAt.smul ((f i).smooth.of_le le_top).contMDiffAt (hφ i hx) + · exact ContMDiffAt.smul ((f i).contMDiff.of_le le_top).contMDiffAt (hφ i hx) · exact contMDiffAt_of_not_mem (compl_subset_compl.mpr (tsupport_smul_subset_left (f i) (g i)) hx) n @@ -294,13 +291,8 @@ theorem IsSubordinate.contMDiff_finsum_smul {g : ι → M → F} (hf : f.IsSubor ContMDiff I 𝓘(ℝ, F) n fun x => ∑ᶠ i, f i x • g i x := f.contMDiff_finsum_smul fun i _ hx => (hg i).contMDiffAt <| (ho i).mem_nhds (hf i hx) -/-- If `f` is a smooth partition of unity on a set `s : Set M` subordinate to a family of open sets -`U : ι → Set M` and `g : ι → M → F` is a family of functions such that `g i` is smooth on `U i`, -then the sum `fun x ↦ ∑ᶠ i, f i x • g i x` is smooth on the whole manifold. -/ -theorem IsSubordinate.smooth_finsum_smul {g : ι → M → F} (hf : f.IsSubordinate U) - (ho : ∀ i, IsOpen (U i)) (hg : ∀ i, SmoothOn I 𝓘(ℝ, F) (g i) (U i)) : - Smooth I 𝓘(ℝ, F) fun x => ∑ᶠ i, f i x • g i x := - hf.contMDiff_finsum_smul ho hg +@[deprecated (since := "2024-11-21")] +alias IsSubordinate.smooth_finsum_smul := IsSubordinate.contMDiff_finsum_smul end IsSubordinate @@ -309,14 +301,17 @@ end SmoothPartitionOfUnity namespace BumpCovering -- Repeat variables to drop `[FiniteDimensional ℝ E]` and `[SmoothManifoldWithCorners I M]` -theorem smooth_toPartitionOfUnity {E : Type uE} [NormedAddCommGroup E] [NormedSpace ℝ E] +theorem contMDiff_toPartitionOfUnity {E : Type uE} [NormedAddCommGroup E] [NormedSpace ℝ E] {H : Type uH} [TopologicalSpace H] {I : ModelWithCorners ℝ E H} {M : Type uM} [TopologicalSpace M] [ChartedSpace H M] {s : Set M} (f : BumpCovering ι M s) - (hf : ∀ i, Smooth I 𝓘(ℝ) (f i)) (i : ι) : Smooth I 𝓘(ℝ) (f.toPartitionOfUnity i) := - (hf i).mul <| (smooth_finprod_cond fun j _ => smooth_const.sub (hf j)) <| by + (hf : ∀ i, ContMDiff I 𝓘(ℝ) ⊤ (f i)) (i : ι) : ContMDiff I 𝓘(ℝ) ⊤ (f.toPartitionOfUnity i) := + (hf i).mul <| (contMDiff_finprod_cond fun j _ => contMDiff_const.sub (hf j)) <| by simp only [Pi.sub_def, mulSupport_one_sub] exact f.locallyFinite +@[deprecated (since := "2024-11-21")] +alias smooth_toPartitionOfUnity := contMDiff_toPartitionOfUnity + variable {s : Set M} /-- A `BumpCovering` such that all functions in this covering are smooth generates a smooth @@ -326,24 +321,24 @@ In our formalization, not every `f : BumpCovering ι M s` with smooth functions `SmoothBumpCovering`; instead, a `SmoothBumpCovering` is a covering by supports of `SmoothBumpFunction`s. So, we define `BumpCovering.toSmoothPartitionOfUnity`, then reuse it in `SmoothBumpCovering.toSmoothPartitionOfUnity`. -/ -def toSmoothPartitionOfUnity (f : BumpCovering ι M s) (hf : ∀ i, Smooth I 𝓘(ℝ) (f i)) : +def toSmoothPartitionOfUnity (f : BumpCovering ι M s) (hf : ∀ i, ContMDiff I 𝓘(ℝ) ⊤ (f i)) : SmoothPartitionOfUnity ι I M s := { f.toPartitionOfUnity with - toFun := fun i => ⟨f.toPartitionOfUnity i, f.smooth_toPartitionOfUnity hf i⟩ } + toFun := fun i => ⟨f.toPartitionOfUnity i, f.contMDiff_toPartitionOfUnity hf i⟩ } @[simp] theorem toSmoothPartitionOfUnity_toPartitionOfUnity (f : BumpCovering ι M s) - (hf : ∀ i, Smooth I 𝓘(ℝ) (f i)) : + (hf : ∀ i, ContMDiff I 𝓘(ℝ) ⊤ (f i)) : (f.toSmoothPartitionOfUnity hf).toPartitionOfUnity = f.toPartitionOfUnity := rfl @[simp] -theorem coe_toSmoothPartitionOfUnity (f : BumpCovering ι M s) (hf : ∀ i, Smooth I 𝓘(ℝ) (f i)) +theorem coe_toSmoothPartitionOfUnity (f : BumpCovering ι M s) (hf : ∀ i, ContMDiff I 𝓘(ℝ) ⊤ (f i)) (i : ι) : ⇑(f.toSmoothPartitionOfUnity hf i) = f.toPartitionOfUnity i := rfl theorem IsSubordinate.toSmoothPartitionOfUnity {f : BumpCovering ι M s} {U : ι → Set M} - (h : f.IsSubordinate U) (hf : ∀ i, Smooth I 𝓘(ℝ) (f i)) : + (h : f.IsSubordinate U) (hf : ∀ i, ContMDiff I 𝓘(ℝ) ⊤ (f i)) : (f.toSmoothPartitionOfUnity hf).IsSubordinate U := h.toPartitionOfUnity @@ -457,7 +452,7 @@ alias ⟨_, IsSubordinate.toBumpCovering⟩ := isSubordinate_toBumpCovering /-- Every `SmoothBumpCovering` defines a smooth partition of unity. -/ def toSmoothPartitionOfUnity : SmoothPartitionOfUnity ι I M s := - fs.toBumpCovering.toSmoothPartitionOfUnity fun i => (fs i).smooth + fs.toBumpCovering.toSmoothPartitionOfUnity fun i => (fs i).contMDiff theorem toSmoothPartitionOfUnity_apply (i : ι) (x : M) : fs.toSmoothPartitionOfUnity i x = fs i x * ∏ᶠ (j) (_ : WellOrderingRel j i), (1 - fs j x) := @@ -511,7 +506,7 @@ theorem exists_smooth_zero_one_of_isClosed [T2Space M] [SigmaCompactSpace M] {s rcases SmoothBumpCovering.exists_isSubordinate I ht this with ⟨ι, f, hf⟩ set g := f.toSmoothPartitionOfUnity refine - ⟨⟨_, g.smooth_sum⟩, fun x hx => ?_, fun x => g.sum_eq_one, fun x => + ⟨⟨_, g.contMDiff_sum⟩, fun x hx => ?_, fun x => g.sum_eq_one, fun x => ⟨g.sum_nonneg x, g.sum_le_one x⟩⟩ suffices ∀ i, g i x = 0 by simp only [this, ContMDiffMap.coeFn_mk, finsum_zero, Pi.zero_apply] refine fun i => f.toSmoothPartitionOfUnity_zero_of_zero ?_ @@ -554,8 +549,9 @@ 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] + · simp only [contMDiff_one, ContinuousMap.coe_one, BumpCovering.coe_single, Pi.single_eq_same] + · simp only [contMDiff_zero, BumpCovering.coe_single, Pi.single_eq_of_ne h, + ContinuousMap.coe_zero] instance [Inhabited ι] (s : Set M) : Inhabited (SmoothPartitionOfUnity ι I M s) := ⟨single I default s⟩ @@ -570,12 +566,12 @@ theorem exists_isSubordinate {s : Set M} (hs : IsClosed s) (U : ι → Set M) (h haveI : LocallyCompactSpace M := ChartedSpace.locallyCompactSpace H M -- porting note(https://github.com/leanprover/std4/issues/116): -- split `rcases` into `have` + `rcases` - have := BumpCovering.exists_isSubordinate_of_prop (Smooth I 𝓘(ℝ)) ?_ hs U ho hU + have := BumpCovering.exists_isSubordinate_of_prop (ContMDiff I 𝓘(ℝ) ⊤) ?_ hs U ho hU · rcases this with ⟨f, hf, hfU⟩ exact ⟨f.toSmoothPartitionOfUnity hf, hfU.toSmoothPartitionOfUnity hf⟩ · intro s t hs ht hd rcases exists_smooth_zero_one_of_isClosed I hs ht hd with ⟨f, hf⟩ - exact ⟨f, f.smooth, hf⟩ + exact ⟨f, f.contMDiff, hf⟩ theorem exists_isSubordinate_chartAt_source_of_isClosed {s : Set M} (hs : IsClosed s) : ∃ f : SmoothPartitionOfUnity s I M s, @@ -618,7 +614,7 @@ Then there exists a smooth function `g : C^∞⟮I, M; 𝓘(ℝ, F), F⟯` such See also `exists_contMDiffOn_forall_mem_convex_of_local` and `exists_smooth_forall_mem_convex_of_local_const`. -/ theorem exists_smooth_forall_mem_convex_of_local (ht : ∀ x, Convex ℝ (t x)) - (Hloc : ∀ x : M, ∃ U ∈ 𝓝 x, ∃ g : M → F, SmoothOn I 𝓘(ℝ, F) g U ∧ ∀ y ∈ U, g y ∈ t y) : + (Hloc : ∀ x : M, ∃ U ∈ 𝓝 x, ∃ g : M → F, ContMDiffOn I 𝓘(ℝ, F) ⊤ g U ∧ ∀ y ∈ U, g y ∈ t y) : ∃ g : C^∞⟮I, M; 𝓘(ℝ, F), F⟯, ∀ x, g x ∈ t x := exists_contMDiffOn_forall_mem_convex_of_local I ht Hloc @@ -631,7 +627,7 @@ theorem exists_smooth_forall_mem_convex_of_local_const (ht : ∀ x, Convex ℝ ( (Hloc : ∀ x : M, ∃ c : F, ∀ᶠ y in 𝓝 x, c ∈ t y) : ∃ g : C^∞⟮I, M; 𝓘(ℝ, F), F⟯, ∀ x, g x ∈ t x := exists_smooth_forall_mem_convex_of_local I ht fun x => let ⟨c, hc⟩ := Hloc x - ⟨_, hc, fun _ => c, smoothOn_const, fun _ => id⟩ + ⟨_, hc, fun _ => c, contMDiffOn_const, fun _ => id⟩ /-- Let `M` be a smooth σ-compact manifold with extended distance. Let `K : ι → Set M` be a locally finite family of closed sets, let `U : ι → Set M` be a family of open sets such that `K i ⊆ U i` for @@ -664,7 +660,7 @@ theorem Metric.exists_smooth_forall_closedBall_subset {M} [MetricSpace M] [Chart exact hδ i x hx lemma IsOpen.exists_msmooth_support_eq_aux {s : Set H} (hs : IsOpen s) : - ∃ f : H → ℝ, f.support = s ∧ Smooth I 𝓘(ℝ) f ∧ Set.range f ⊆ Set.Icc 0 1 := by + ∃ f : H → ℝ, f.support = s ∧ ContMDiff I 𝓘(ℝ) ⊤ f ∧ Set.range f ⊆ Set.Icc 0 1 := by have h's : IsOpen (I.symm ⁻¹' s) := I.continuous_symm.isOpen_preimage _ hs rcases h's.exists_smooth_support_eq with ⟨f, f_supp, f_diff, f_range⟩ refine ⟨f ∘ I, ?_, ?_, ?_⟩ @@ -676,11 +672,11 @@ lemma IsOpen.exists_msmooth_support_eq_aux {s : Set H} (hs : IsOpen s) : /-- Given an open set in a finite-dimensional real manifold, there exists a nonnegative smooth function with support equal to `s`. -/ theorem IsOpen.exists_msmooth_support_eq {s : Set M} (hs : IsOpen s) : - ∃ f : M → ℝ, f.support = s ∧ Smooth I 𝓘(ℝ) f ∧ ∀ x, 0 ≤ f x := by + ∃ f : M → ℝ, f.support = s ∧ ContMDiff I 𝓘(ℝ) ⊤ f ∧ ∀ x, 0 ≤ f x := by rcases SmoothPartitionOfUnity.exists_isSubordinate_chartAt_source I M with ⟨f, hf⟩ have A : ∀ (c : M), ∃ g : H → ℝ, g.support = (chartAt H c).target ∩ (chartAt H c).symm ⁻¹' s ∧ - Smooth I 𝓘(ℝ) g ∧ Set.range g ⊆ Set.Icc 0 1 := by + ContMDiff I 𝓘(ℝ) ⊤ g ∧ Set.range g ⊆ Set.Icc 0 1 := by intro i apply IsOpen.exists_msmooth_support_eq_aux exact PartialHomeomorph.isOpen_inter_preimage_symm _ hs @@ -714,7 +710,7 @@ theorem IsOpen.exists_msmooth_support_eq {s : Set M} (hs : IsOpen s) : · have : x ∉ support (f c) := by contrapose! Hx; exact subset_tsupport _ Hx rw [nmem_support] at this simp [this] - · apply SmoothPartitionOfUnity.smooth_finsum_smul + · apply SmoothPartitionOfUnity.contMDiff_finsum_smul intro c x hx apply (g_diff c (chartAt H c x)).comp exact contMDiffAt_of_mem_maximalAtlas (SmoothManifoldWithCorners.chart_mem_maximalAtlas _) @@ -727,7 +723,7 @@ exists a smooth function with support equal to `s`, taking values in `[0,1]`, an exactly on `t`. -/ theorem exists_msmooth_support_eq_eq_one_iff {s t : Set M} (hs : IsOpen s) (ht : IsClosed t) (h : t ⊆ s) : - ∃ f : M → ℝ, Smooth I 𝓘(ℝ) f ∧ range f ⊆ Icc 0 1 ∧ support f = s + ∃ f : M → ℝ, ContMDiff I 𝓘(ℝ) ⊤ f ∧ range f ⊆ Icc 0 1 ∧ support f = s ∧ (∀ x, x ∈ t ↔ f x = 1) := by /- Take `f` with support equal to `s`, and `g` with support equal to `tᶜ`. Then `f / (f + g)` satisfies the conclusion of the theorem. -/ @@ -765,7 +761,7 @@ there exists an infinitely smooth function that is equal to `0` exactly on `s` a exactly on `t`. See also `exists_smooth_zero_one_of_isClosed` for a slightly weaker version. -/ theorem exists_msmooth_zero_iff_one_iff_of_isClosed {s t : Set M} (hs : IsClosed s) (ht : IsClosed t) (hd : Disjoint s t) : - ∃ f : M → ℝ, Smooth I 𝓘(ℝ) f ∧ range f ⊆ Icc 0 1 ∧ (∀ x, x ∈ s ↔ f x = 0) + ∃ f : M → ℝ, ContMDiff I 𝓘(ℝ) ⊤ f ∧ range f ⊆ Icc 0 1 ∧ (∀ x, x ∈ s ↔ f x = 0) ∧ (∀ x, x ∈ t ↔ f x = 1) := by rcases exists_msmooth_support_eq_eq_one_iff I hs.isOpen_compl ht hd.subset_compl_left with ⟨f, f_diff, f_range, fs, ft⟩ diff --git a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean index 889506e8609ea4..5c91ede6dc2594 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean @@ -31,6 +31,10 @@ smooth manifolds. noncomputable section universe u +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) + variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] {EM : Type*} [NormedAddCommGroup EM] [NormedSpace 𝕜 EM] {HM : Type*} [TopologicalSpace HM] (IM : ModelWithCorners 𝕜 EM HM) @@ -97,7 +101,7 @@ theorem smoothSheafCommRing.isUnit_stalk_iff {x : M} #adaptation_note /-- https://github.com/leanprover/lean4/pull/6024 was `exact`; somehow `convert` bypasess unification issues -/ convert ((contDiffAt_inv _ (hVf y)).contMDiffAt).comp y - (f.smooth.comp (smooth_inclusion hUV)).smoothAt + (f.contMDiff.comp (contMDiff_inclusion hUV)).contMDiffAt /-- The non-units of the stalk at `x` of the sheaf of smooth functions from `M` to `𝕜`, considered as a sheaf of commutative rings, are the functions whose values at `x` are zero. -/ diff --git a/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean b/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean index b25eee8e259506..d794651ff25d8e 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean @@ -66,6 +66,10 @@ https://github.com/leanprover-community/mathlib4/pull/5726. noncomputable section open TopologicalSpace Opposite +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) + universe u variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] @@ -126,7 +130,7 @@ def smoothSheaf.evalAt (x : TopCat.of M) (U : OpenNhds x) lemma smoothSheaf.eval_surjective (x : M) : Function.Surjective (smoothSheaf.eval IM I N x) := by apply TopCat.stalkToFiber_surjective intro n - exact ⟨⊤, fun _ ↦ n, smooth_const, rfl⟩ + exact ⟨⊤, fun _ ↦ n, contMDiff_const, rfl⟩ instance [Nontrivial N] (x : M) : Nontrivial ((smoothSheaf IM I M N).presheaf.stalk x) := (smoothSheaf.eval_surjective IM I N x).nontrivial @@ -138,11 +142,14 @@ variable {IM I N} smoothSheaf.eval IM I N (x : M) ((smoothSheaf IM I M N).presheaf.germ U x hx f) = f ⟨x, hx⟩ := TopCat.stalkToFiber_germ ((contDiffWithinAt_localInvariantProp ⊤).localPredicate M N) _ _ _ _ -lemma smoothSheaf.smooth_section {U : (Opens (TopCat.of M))ᵒᵖ} +lemma smoothSheaf.contMDiff_section {U : (Opens (TopCat.of M))ᵒᵖ} (f : (smoothSheaf IM I M N).presheaf.obj U) : - Smooth IM I f := + ContMDiff IM I ⊤ f := (contDiffWithinAt_localInvariantProp ⊤).section_spec _ _ _ _ +@[deprecated (since := "2024-11-21")] +alias smoothSheaf.smooth_section := smoothSheaf.contMDiff_section + end TypeCat section LieGroup @@ -213,7 +220,7 @@ noncomputable def smoothSheafCommGroup : TopCat.Sheaf CommGrp.{u} (TopCat.of M) @[to_additive "For a manifold `M` and a smooth homomorphism `φ` between abelian additive Lie groups `A`, `A'`, the 'left-composition-by-`φ`' morphism of sheaves from `smoothSheafAddCommGroup IM I M A` to `smoothSheafAddCommGroup IM I' M A'`."] -def smoothSheafCommGroup.compLeft (φ : A →* A') (hφ : Smooth I I' φ) : +def smoothSheafCommGroup.compLeft (φ : A →* A') (hφ : ContMDiff I I' ⊤ φ) : smoothSheafCommGroup IM I M A ⟶ smoothSheafCommGroup IM I' M A' := CategoryTheory.Sheaf.Hom.mk <| { app := fun _ ↦ CommGrp.ofHom <| SmoothMap.compLeftMonoidHom _ _ φ hφ diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index df9b1d40d1761d..1e7be0aaf95d16 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -133,10 +133,7 @@ universe u v w u' v' w' open Set Filter Function -open scoped Manifold Filter Topology - -/-- The extended natural number `∞` -/ -scoped[Manifold] notation "∞" => (⊤ : ℕ∞) +open scoped Manifold Filter Topology ContDiff /-! ### Models with corners. -/ @@ -529,9 +526,9 @@ section contDiffGroupoid /-! ### Smooth functions on models with corners -/ -variable {m n : ℕ∞} {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] - [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] {I : ModelWithCorners 𝕜 E H} {M : Type*} - [TopologicalSpace M] +variable {m n : WithTop ℕ∞} {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} + [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] + {I : ModelWithCorners 𝕜 E H} {M : Type*} [TopologicalSpace M] variable (n I) in /-- Given a model with corners `(E, H)`, we define the pregroupoid of `C^n` transformations of `H` @@ -623,8 +620,8 @@ variable {E' H' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] [Topologi /-- The product of two smooth partial homeomorphisms is smooth. -/ theorem contDiffGroupoid_prod {I : ModelWithCorners 𝕜 E H} {I' : ModelWithCorners 𝕜 E' H'} - {e : PartialHomeomorph H H} {e' : PartialHomeomorph H' H'} (he : e ∈ contDiffGroupoid ⊤ I) - (he' : e' ∈ contDiffGroupoid ⊤ I') : e.prod e' ∈ contDiffGroupoid ⊤ (I.prod I') := by + {e : PartialHomeomorph H H} {e' : PartialHomeomorph H' H'} (he : e ∈ contDiffGroupoid ∞ I) + (he' : e' ∈ contDiffGroupoid ∞ I') : e.prod e' ∈ contDiffGroupoid ∞ (I.prod I') := by cases' he with he he_symm cases' he' with he' he'_symm simp only at he he_symm he' he'_symm @@ -672,7 +669,7 @@ theorem smoothManifoldWithCorners_of_contDiffOn {𝕜 : Type*} [NontriviallyNorm {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) (M : Type*) [TopologicalSpace M] [ChartedSpace H M] (h : ∀ e e' : PartialHomeomorph M H, e ∈ atlas H M → e' ∈ atlas H M → - ContDiffOn 𝕜 ⊤ (I ∘ e.symm ≫ₕ e' ∘ I.symm) (I.symm ⁻¹' (e.symm ≫ₕ e').source ∩ range I)) : + ContDiffOn 𝕜 ∞ (I ∘ e.symm ≫ₕ e' ∘ I.symm) (I.symm ⁻¹' (e.symm ≫ₕ e').source ∩ range I)) : SmoothManifoldWithCorners I M where compatible := by haveI : HasGroupoid M (contDiffGroupoid ∞ I) := hasGroupoid_of_pregroupoid _ (h _ _) @@ -741,8 +738,8 @@ instance prod {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedA compatible := by rintro f g ⟨f1, hf1, f2, hf2, rfl⟩ ⟨g1, hg1, g2, hg2, rfl⟩ rw [PartialHomeomorph.prod_symm, PartialHomeomorph.prod_trans] - have h1 := (contDiffGroupoid ⊤ I).compatible hf1 hg1 - have h2 := (contDiffGroupoid ⊤ I').compatible hf2 hg2 + have h1 := (contDiffGroupoid ∞ I).compatible hf1 hg1 + have h2 := (contDiffGroupoid ∞ I').compatible hf2 hg2 exact contDiffGroupoid_prod h1 h2 end SmoothManifoldWithCorners @@ -1065,13 +1062,13 @@ open SmoothManifoldWithCorners theorem contDiffOn_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) : - ContDiffOn 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) ((f'.extend I).symm ≫ f.extend I).source := by + ContDiffOn 𝕜 ∞ (f.extend I ∘ (f'.extend I).symm) ((f'.extend I).symm ≫ f.extend I).source := by rw [extend_coord_change_source, I.image_eq] exact (StructureGroupoid.compatible_of_mem_maximalAtlas hf' hf).1 theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : E} (hx : x ∈ ((f'.extend I).symm ≫ f.extend I).source) : - ContDiffWithinAt 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) (range I) x := by + ContDiffWithinAt 𝕜 ∞ (f.extend I ∘ (f'.extend I).symm) (range I) x := by apply (contDiffOn_extend_coord_change hf hf' x hx).mono_of_mem_nhdsWithin rw [extend_coord_change_source] at hx ⊢ obtain ⟨z, hz, rfl⟩ := hx @@ -1079,7 +1076,7 @@ theorem contDiffWithinAt_extend_coord_change [ChartedSpace H M] (hf : f ∈ maxi theorem contDiffWithinAt_extend_coord_change' [ChartedSpace H M] (hf : f ∈ maximalAtlas I M) (hf' : f' ∈ maximalAtlas I M) {x : M} (hxf : x ∈ f.source) (hxf' : x ∈ f'.source) : - ContDiffWithinAt 𝕜 ⊤ (f.extend I ∘ (f'.extend I).symm) (range I) (f'.extend I x) := by + ContDiffWithinAt 𝕜 ∞ (f.extend I ∘ (f'.extend I).symm) (range I) (f'.extend I x) := by refine contDiffWithinAt_extend_coord_change hf hf' ?_ rw [← extend_image_source_inter] exact mem_image_of_mem _ ⟨hxf', hxf⟩ @@ -1408,15 +1405,14 @@ theorem ext_coord_change_source (x x' : M) : open SmoothManifoldWithCorners theorem contDiffOn_ext_coord_change [SmoothManifoldWithCorners I M] (x x' : M) : - ContDiffOn 𝕜 ⊤ (extChartAt I x ∘ (extChartAt I x').symm) + ContDiffOn 𝕜 ∞ (extChartAt I x ∘ (extChartAt I x').symm) ((extChartAt I x').symm ≫ extChartAt I x).source := contDiffOn_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') theorem contDiffWithinAt_ext_coord_change [SmoothManifoldWithCorners I M] (x x' : M) {y : E} (hy : y ∈ ((extChartAt I x').symm ≫ extChartAt I x).source) : - ContDiffWithinAt 𝕜 ⊤ (extChartAt I x ∘ (extChartAt I x').symm) (range I) y := - contDiffWithinAt_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') - hy + ContDiffWithinAt 𝕜 ∞ (extChartAt I x ∘ (extChartAt I x').symm) (range I) y := + contDiffWithinAt_extend_coord_change (chart_mem_maximalAtlas x) (chart_mem_maximalAtlas x') hy variable (I I') in /-- Conjugating a function to write it in the preferred charts around `x`. diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean index dab21687a47a9b..3fd4222c1dabaf 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean @@ -212,34 +212,29 @@ theorem contMDiff_proj : ContMDiff (IB.prod 𝓘(𝕜, F)) IB n (π F E) := fun rw [contMDiffAt_totalSpace] at this exact this.1 -theorem smooth_proj : Smooth (IB.prod 𝓘(𝕜, F)) IB (π F E) := - contMDiff_proj E +@[deprecated (since := "2024-11-21")] alias smooth_proj := contMDiff_proj theorem contMDiffOn_proj {s : Set (TotalSpace F E)} : ContMDiffOn (IB.prod 𝓘(𝕜, F)) IB n (π F E) s := (Bundle.contMDiff_proj E).contMDiffOn -theorem smoothOn_proj {s : Set (TotalSpace F E)} : SmoothOn (IB.prod 𝓘(𝕜, F)) IB (π F E) s := - contMDiffOn_proj E +@[deprecated (since := "2024-11-21")] alias smoothOn_proj := contMDiffOn_proj theorem contMDiffAt_proj {p : TotalSpace F E} : ContMDiffAt (IB.prod 𝓘(𝕜, F)) IB n (π F E) p := (Bundle.contMDiff_proj E).contMDiffAt -theorem smoothAt_proj {p : TotalSpace F E} : SmoothAt (IB.prod 𝓘(𝕜, F)) IB (π F E) p := - Bundle.contMDiffAt_proj E +@[deprecated (since := "2024-11-21")] alias smoothAt_proj := contMDiffAt_proj theorem contMDiffWithinAt_proj {s : Set (TotalSpace F E)} {p : TotalSpace F E} : ContMDiffWithinAt (IB.prod 𝓘(𝕜, F)) IB n (π F E) s p := (Bundle.contMDiffAt_proj E).contMDiffWithinAt -theorem smoothWithinAt_proj {s : Set (TotalSpace F E)} {p : TotalSpace F E} : - SmoothWithinAt (IB.prod 𝓘(𝕜, F)) IB (π F E) s p := - Bundle.contMDiffWithinAt_proj E +@[deprecated (since := "2024-11-21")] alias smoothWithinAt_proj := contMDiffWithinAt_proj variable (𝕜) [∀ x, AddCommMonoid (E x)] variable [∀ x, Module 𝕜 (E x)] [VectorBundle 𝕜 F E] -theorem smooth_zeroSection : Smooth IB (IB.prod 𝓘(𝕜, F)) (zeroSection F E) := fun x ↦ by +theorem contMDiff_zeroSection : ContMDiff IB (IB.prod 𝓘(𝕜, F)) ⊤ (zeroSection F E) := fun x ↦ by unfold zeroSection rw [Bundle.contMDiffAt_section] apply (contMDiffAt_const (c := 0)).congr_of_eventuallyEq @@ -247,6 +242,8 @@ theorem smooth_zeroSection : Smooth IB (IB.prod 𝓘(𝕜, F)) (zeroSection F E) (mem_baseSet_trivializationAt F E x)] with y hy using congr_arg Prod.snd <| (trivializationAt F E x).zeroSection 𝕜 hy +@[deprecated (since := "2024-11-21")] alias smooth_zeroSection := contMDiff_zeroSection + end Bundle end @@ -272,9 +269,9 @@ topological vector bundle over `B` with fibers isomorphic to `F`, then `SmoothVe registers that the bundle is smooth, in the sense of having smooth transition functions. This is a mixin, not carrying any new data. -/ class SmoothVectorBundle : Prop where - protected smoothOn_coordChangeL : + protected contMDiffOn_coordChangeL : ∀ (e e' : Trivialization F (π F E)) [MemTrivializationAtlas e] [MemTrivializationAtlas e'], - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) (e.baseSet ∩ e'.baseSet) variable [SmoothVectorBundle F E IB] @@ -284,27 +281,23 @@ section SmoothCoordChange variable {F E} variable (e e' : Trivialization F (π F E)) [MemTrivializationAtlas e] [MemTrivializationAtlas e'] -theorem smoothOn_coordChangeL : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) +theorem contMDiffOn_coordChangeL : + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) (e.baseSet ∩ e'.baseSet) := - SmoothVectorBundle.smoothOn_coordChangeL e e' + (SmoothVectorBundle.contMDiffOn_coordChangeL e e').of_le le_top -theorem smoothOn_symm_coordChangeL : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun b : B => ((e.coordChangeL 𝕜 e' b).symm : F →L[𝕜] F)) +theorem contMDiffOn_symm_coordChangeL : + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => ((e.coordChangeL 𝕜 e' b).symm : F →L[𝕜] F)) (e.baseSet ∩ e'.baseSet) := by + apply ContMDiffOn.of_le _ le_top rw [inter_comm] - refine (SmoothVectorBundle.smoothOn_coordChangeL e' e).congr fun b hb ↦ ?_ + refine (SmoothVectorBundle.contMDiffOn_coordChangeL e' e).congr fun b hb ↦ ?_ rw [e.symm_coordChangeL e' hb] -theorem contMDiffOn_coordChangeL : - ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) - (e.baseSet ∩ e'.baseSet) := - (smoothOn_coordChangeL e e').of_le le_top +@[deprecated (since := "2024-11-21")] alias smoothOn_coordChangeL := contMDiffOn_coordChangeL +@[deprecated (since := "2024-11-21")] +alias smoothOn_symm_coordChangeL := contMDiffOn_symm_coordChangeL -theorem contMDiffOn_symm_coordChangeL : - ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) n (fun b : B => ((e.coordChangeL 𝕜 e' b).symm : F →L[𝕜] F)) - (e.baseSet ∩ e'.baseSet) := - (smoothOn_symm_coordChangeL e e').of_le le_top variable {e e'} @@ -313,9 +306,7 @@ theorem contMDiffAt_coordChangeL {x : B} (h : x ∈ e.baseSet) (h' : x ∈ e'.ba (contMDiffOn_coordChangeL e e').contMDiffAt <| (e.open_baseSet.inter e'.open_baseSet).mem_nhds ⟨h, h'⟩ -theorem smoothAt_coordChangeL {x : B} (h : x ∈ e.baseSet) (h' : x ∈ e'.baseSet) : - SmoothAt IB 𝓘(𝕜, F →L[𝕜] F) (fun b : B => (e.coordChangeL 𝕜 e' b : F →L[𝕜] F)) x := - contMDiffAt_coordChangeL h h' +@[deprecated (since := "2024-11-21")] alias smoothAt_coordChangeL := contMDiffAt_coordChangeL variable {s : Set M} {f : M → B} {g : M → F} {x : M} @@ -339,25 +330,17 @@ protected theorem ContMDiff.coordChangeL ContMDiff IM 𝓘(𝕜, F →L[𝕜] F) n (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) := fun x ↦ (hf x).coordChangeL (he x) (he' x) -protected nonrec theorem SmoothWithinAt.coordChangeL - (hf : SmoothWithinAt IM IB f s x) (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : - SmoothWithinAt IM 𝓘(𝕜, F →L[𝕜] F) (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) s x := - hf.coordChangeL he he' +@[deprecated (since := "2024-11-21")] +alias SmoothWithinAt.coordChangeL := ContMDiffWithinAt.coordChangeL -protected nonrec theorem SmoothAt.coordChangeL - (hf : SmoothAt IM IB f x) (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : - SmoothAt IM 𝓘(𝕜, F →L[𝕜] F) (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) x := - hf.coordChangeL he he' +@[deprecated (since := "2024-11-21")] +alias SmoothAt.coordChangeL := ContMDiffAt.coordChangeL -protected nonrec theorem SmoothOn.coordChangeL - (hf : SmoothOn IM IB f s) (he : MapsTo f s e.baseSet) (he' : MapsTo f s e'.baseSet) : - SmoothOn IM 𝓘(𝕜, F →L[𝕜] F) (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) s := - hf.coordChangeL he he' +@[deprecated (since := "2024-11-21")] +alias SmoothOn.coordChangeL := ContMDiffOn.coordChangeL -protected nonrec theorem Smooth.coordChangeL - (hf : Smooth IM IB f) (he : ∀ x, f x ∈ e.baseSet) (he' : ∀ x, f x ∈ e'.baseSet) : - Smooth IM 𝓘(𝕜, F →L[𝕜] F) (fun y ↦ (e.coordChangeL 𝕜 e' (f y) : F →L[𝕜] F)) := - hf.coordChangeL he he' +@[deprecated (since := "2024-11-21")] +alias Smooth.coordChangeL := ContMDiff.coordChangeL protected theorem ContMDiffWithinAt.coordChange (hf : ContMDiffWithinAt IM IB n f s x) (hg : ContMDiffWithinAt IM 𝓘(𝕜, F) n g s x) @@ -386,26 +369,17 @@ protected theorem ContMDiff.coordChange (hf : ContMDiff IM IB n f) ContMDiff IM 𝓘(𝕜, F) n (fun y ↦ e.coordChange e' (f y) (g y)) := fun x ↦ (hf x).coordChange (hg x) (he x) (he' x) -protected nonrec theorem SmoothWithinAt.coordChange - (hf : SmoothWithinAt IM IB f s x) (hg : SmoothWithinAt IM 𝓘(𝕜, F) g s x) - (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : - SmoothWithinAt IM 𝓘(𝕜, F) (fun y ↦ e.coordChange e' (f y) (g y)) s x := - hf.coordChange hg he he' +@[deprecated (since := "2024-11-21")] +alias SmoothWithinAt.coordChange := ContMDiffWithinAt.coordChange -protected nonrec theorem SmoothAt.coordChange (hf : SmoothAt IM IB f x) - (hg : SmoothAt IM 𝓘(𝕜, F) g x) (he : f x ∈ e.baseSet) (he' : f x ∈ e'.baseSet) : - SmoothAt IM 𝓘(𝕜, F) (fun y ↦ e.coordChange e' (f y) (g y)) x := - hf.coordChange hg he he' +@[deprecated (since := "2024-11-21")] +alias SmoothAt.coordChange := ContMDiffAt.coordChange -protected nonrec theorem SmoothOn.coordChange (hf : SmoothOn IM IB f s) - (hg : SmoothOn IM 𝓘(𝕜, F) g s) (he : MapsTo f s e.baseSet) (he' : MapsTo f s e'.baseSet) : - SmoothOn IM 𝓘(𝕜, F) (fun y ↦ e.coordChange e' (f y) (g y)) s := - hf.coordChange hg he he' +@[deprecated (since := "2024-11-21")] +alias SmoothOn.coordChange := ContMDiffOn.coordChange -protected theorem Smooth.coordChange (hf : Smooth IM IB f) - (hg : Smooth IM 𝓘(𝕜, F) g) (he : ∀ x, f x ∈ e.baseSet) (he' : ∀ x, f x ∈ e'.baseSet) : - Smooth IM 𝓘(𝕜, F) (fun y ↦ e.coordChange e' (f y) (g y)) := fun x ↦ - (hf x).coordChange (hg x) (he x) (he' x) +@[deprecated (since := "2024-11-21")] +alias Smooth.coordChange := ContMDiff.coordChange variable (e e') @@ -458,8 +432,8 @@ instance SmoothFiberwiseLinear.hasGroupoid : haveI : MemTrivializationAtlas e := ⟨he⟩ haveI : MemTrivializationAtlas e' := ⟨he'⟩ rw [mem_smoothFiberwiseLinear_iff] - refine ⟨_, _, e.open_baseSet.inter e'.open_baseSet, smoothOn_coordChangeL e e', - smoothOn_symm_coordChangeL e e', ?_⟩ + refine ⟨_, _, e.open_baseSet.inter e'.open_baseSet, contMDiffOn_coordChangeL e e', + contMDiffOn_symm_coordChangeL e e', ?_⟩ refine PartialHomeomorph.eqOnSourceSetoid.symm ⟨?_, ?_⟩ · simp only [e.symm_trans_source_eq e', FiberwiseLinear.partialHomeomorph, trans_toPartialEquiv, symm_toPartialEquiv] @@ -478,10 +452,10 @@ instance Bundle.TotalSpace.smoothManifoldWithCorners [SmoothManifoldWithCorners refine ⟨ContMDiffOn.congr ?_ (EqOnSource.eqOn heφ), ContMDiffOn.congr ?_ (EqOnSource.eqOn (EqOnSource.symm' heφ))⟩ · rw [EqOnSource.source_eq heφ] - apply smoothOn_fst.prod_mk + apply contMDiffOn_fst.prod_mk exact (hφ.comp contMDiffOn_fst <| prod_subset_preimage_fst _ _).clm_apply contMDiffOn_snd · rw [EqOnSource.target_eq heφ] - apply smoothOn_fst.prod_mk + apply contMDiffOn_fst.prod_mk exact (h2φ.comp contMDiffOn_fst <| prod_subset_preimage_fst _ _).clm_apply contMDiffOn_snd section @@ -517,41 +491,36 @@ theorem Trivialization.contMDiff_iff {f : M → TotalSpace F E} (he : ∀ x, f x ContMDiff IM 𝓘(𝕜, F) n (fun x ↦ (e (f x)).2) := (forall_congr' fun x ↦ e.contMDiffAt_iff (he x)).trans forall_and -theorem Trivialization.smoothWithinAt_iff {f : M → TotalSpace F E} {s : Set M} {x₀ : M} - (he : f x₀ ∈ e.source) : - SmoothWithinAt IM (IB.prod 𝓘(𝕜, F)) f s x₀ ↔ - SmoothWithinAt IM IB (fun x => (f x).proj) s x₀ ∧ - SmoothWithinAt IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) s x₀ := - e.contMDiffWithinAt_iff he +@[deprecated (since := "2024-11-21")] +alias Trivialization.smoothWithinAt_iff := Trivialization.contMDiffWithinAt_iff -theorem Trivialization.smoothAt_iff {f : M → TotalSpace F E} {x₀ : M} (he : f x₀ ∈ e.source) : - SmoothAt IM (IB.prod 𝓘(𝕜, F)) f x₀ ↔ - SmoothAt IM IB (fun x => (f x).proj) x₀ ∧ SmoothAt IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) x₀ := - e.contMDiffAt_iff he +@[deprecated (since := "2024-11-21")] +alias Trivialization.smoothAt_iff := Trivialization.contMDiffAt_iff -theorem Trivialization.smoothOn_iff {f : M → TotalSpace F E} {s : Set M} - (he : MapsTo f s e.source) : - SmoothOn IM (IB.prod 𝓘(𝕜, F)) f s ↔ - SmoothOn IM IB (fun x => (f x).proj) s ∧ SmoothOn IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) s := - e.contMDiffOn_iff he - -theorem Trivialization.smooth_iff {f : M → TotalSpace F E} (he : ∀ x, f x ∈ e.source) : - Smooth IM (IB.prod 𝓘(𝕜, F)) f ↔ - Smooth IM IB (fun x => (f x).proj) ∧ Smooth IM 𝓘(𝕜, F) (fun x ↦ (e (f x)).2) := - e.contMDiff_iff he - -theorem Trivialization.smoothOn (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : - SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e e.source := by - have : SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) id e.source := smoothOn_id - rw [e.smoothOn_iff (mapsTo_id _)] at this +@[deprecated (since := "2024-11-21")] +alias Trivialization.smoothOn_iff := Trivialization.contMDiffOn_iff + +@[deprecated (since := "2024-11-21")] +alias Trivialization.smooth_iff := Trivialization.contMDiff_iff + +theorem Trivialization.contMDiffOn (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : + ContMDiffOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) ⊤ e e.source := by + have : ContMDiffOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) ⊤ id e.source := contMDiffOn_id + rw [e.contMDiffOn_iff (mapsTo_id _)] at this exact (this.1.prod_mk this.2).congr fun x hx ↦ (e.mk_proj_snd hx).symm -theorem Trivialization.smoothOn_symm (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : - SmoothOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) e.toPartialHomeomorph.symm e.target := by - rw [e.smoothOn_iff e.toPartialHomeomorph.symm_mapsTo] - refine ⟨smoothOn_fst.congr fun x hx ↦ e.proj_symm_apply hx, smoothOn_snd.congr fun x hx ↦ ?_⟩ +theorem Trivialization.contMDiffOn_symm (e : Trivialization F (π F E)) [MemTrivializationAtlas e] : + ContMDiffOn (IB.prod 𝓘(𝕜, F)) (IB.prod 𝓘(𝕜, F)) ⊤ e.toPartialHomeomorph.symm e.target := by + rw [e.contMDiffOn_iff e.toPartialHomeomorph.symm_mapsTo] + refine ⟨contMDiffOn_fst.congr fun x hx ↦ e.proj_symm_apply hx, + contMDiffOn_snd.congr fun x hx ↦ ?_⟩ rw [e.apply_symm_apply hx] +@[deprecated (since := "2024-11-21")] alias Trivialization.smoothOn := Trivialization.contMDiffOn + +@[deprecated (since := "2024-11-21")] +alias Trivialization.smoothOn_symm := Trivialization.contMDiffOn_symm + end /-! ### Core construction for smooth vector bundles -/ @@ -563,21 +532,24 @@ variable {ι : Type*} (Z : VectorBundleCore 𝕜 B F ι) /-- Mixin for a `VectorBundleCore` stating smoothness (of transition functions). -/ class IsSmooth (IB : ModelWithCorners 𝕜 EB HB) : Prop where - smoothOn_coordChange : - ∀ i j, SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (Z.coordChange i j) (Z.baseSet i ∩ Z.baseSet j) + contMDiffOn_coordChange : + ∀ i j, ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (Z.coordChange i j) (Z.baseSet i ∩ Z.baseSet j) -theorem smoothOn_coordChange (IB : ModelWithCorners 𝕜 EB HB) [h : Z.IsSmooth IB] (i j : ι) : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (Z.coordChange i j) (Z.baseSet i ∩ Z.baseSet j) := +theorem contMDiffOn_coordChange (IB : ModelWithCorners 𝕜 EB HB) [h : Z.IsSmooth IB] (i j : ι) : + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (Z.coordChange i j) (Z.baseSet i ∩ Z.baseSet j) := h.1 i j +@[deprecated (since := "2024-11-21")] +alias smoothOn_coordChange := contMDiffOn_coordChange + variable [Z.IsSmooth IB] /-- If a `VectorBundleCore` has the `IsSmooth` mixin, then the vector bundle constructed from it is a smooth vector bundle. -/ instance smoothVectorBundle : SmoothVectorBundle F Z.Fiber IB where - smoothOn_coordChangeL := by + contMDiffOn_coordChangeL := by rintro - - ⟨i, rfl⟩ ⟨i', rfl⟩ - refine (Z.smoothOn_coordChange IB i i').congr fun b hb ↦ ?_ + refine (Z.contMDiffOn_coordChange IB i i').congr fun b hb ↦ ?_ ext v exact Z.localTriv_coordChange_eq i i' hb v @@ -587,12 +559,12 @@ end VectorBundleCore /-- A trivial vector bundle over a smooth manifold is a smooth vector bundle. -/ instance Bundle.Trivial.smoothVectorBundle : SmoothVectorBundle F (Bundle.Trivial B F) IB where - smoothOn_coordChangeL := by + contMDiffOn_coordChangeL := by intro e e' he he' obtain rfl := Bundle.Trivial.eq_trivialization B F e obtain rfl := Bundle.Trivial.eq_trivialization B F e' simp_rw [Bundle.Trivial.trivialization.coordChangeL] - exact smooth_const.smoothOn + exact contMDiff_const.contMDiffOn /-! ### Direct sums of smooth vector bundles -/ @@ -613,15 +585,14 @@ variable [SmoothManifoldWithCorners IB B] /-- The direct sum of two smooth vector bundles over the same base is a smooth vector bundle. -/ instance Bundle.Prod.smoothVectorBundle : SmoothVectorBundle (F₁ × F₂) (E₁ ×ᵇ E₂) IB where - smoothOn_coordChangeL := by + contMDiffOn_coordChangeL := by rintro _ _ ⟨e₁, e₂, i₁, i₂, rfl⟩ ⟨e₁', e₂', i₁', i₂', rfl⟩ - rw [SmoothOn] refine ContMDiffOn.congr ?_ (e₁.coordChangeL_prod 𝕜 e₁' e₂ e₂') refine ContMDiffOn.clm_prodMap ?_ ?_ - · refine (smoothOn_coordChangeL e₁ e₁').mono ?_ + · refine (contMDiffOn_coordChangeL e₁ e₁').mono ?_ simp only [Trivialization.baseSet_prod, mfld_simps] mfld_set_tac - · refine (smoothOn_coordChangeL e₂ e₂').mono ?_ + · refine (contMDiffOn_coordChangeL e₂ e₂').mono ?_ simp only [Trivialization.baseSet_prod, mfld_simps] mfld_set_tac @@ -641,7 +612,7 @@ class IsSmooth (a : VectorPrebundle 𝕜 F E) : Prop where exists_smoothCoordChange : ∀ᵉ (e ∈ a.pretrivializationAtlas) (e' ∈ a.pretrivializationAtlas), ∃ f : B → F →L[𝕜] F, - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) f (e.baseSet ∩ e'.baseSet) ∧ + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ f (e.baseSet ∩ e'.baseSet) ∧ ∀ (b : B) (_ : b ∈ e.baseSet ∩ e'.baseSet) (v : F), f b v = (e' ⟨b, e.symm b v⟩).2 @@ -655,11 +626,14 @@ noncomputable def smoothCoordChange (he : e ∈ a.pretrivializationAtlas) (he' : e' ∈ a.pretrivializationAtlas) (b : B) : F →L[𝕜] F := Classical.choose (ha.exists_smoothCoordChange e he e' he') b -theorem smoothOn_smoothCoordChange (he : e ∈ a.pretrivializationAtlas) +theorem contMDiffOn_smoothCoordChange (he : e ∈ a.pretrivializationAtlas) (he' : e' ∈ a.pretrivializationAtlas) : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (a.smoothCoordChange IB he he') (e.baseSet ∩ e'.baseSet) := + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (a.smoothCoordChange IB he he') (e.baseSet ∩ e'.baseSet) := (Classical.choose_spec (ha.exists_smoothCoordChange e he e' he')).1 +@[deprecated (since := "2024-11-21")] +alias smoothOn_smoothCoordChange := contMDiffOn_smoothCoordChange + theorem smoothCoordChange_apply (he : e ∈ a.pretrivializationAtlas) (he' : e' ∈ a.pretrivializationAtlas) {b : B} (hb : b ∈ e.baseSet ∩ e'.baseSet) (v : F) : a.smoothCoordChange IB he he' b v = (e' ⟨b, e.symm b v⟩).2 := @@ -678,9 +652,9 @@ variable (IB) in theorem smoothVectorBundle : @SmoothVectorBundle _ _ F E _ _ _ _ _ _ IB _ _ _ _ _ _ a.totalSpaceTopology _ a.toFiberBundle a.toVectorBundle := letI := a.totalSpaceTopology; letI := a.toFiberBundle; letI := a.toVectorBundle - { smoothOn_coordChangeL := by + { contMDiffOn_coordChangeL := by rintro _ _ ⟨e, he, rfl⟩ ⟨e', he', rfl⟩ - refine (a.smoothOn_smoothCoordChange he he').congr ?_ + refine (a.contMDiffOn_smoothCoordChange he he').congr ?_ intro b hb ext v rw [a.smoothCoordChange_apply he he' hb v, ContinuousLinearEquiv.coe_coe, diff --git a/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean index 2a0e077c860aa0..0bc3d2285bba82 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/FiberwiseLinear.lean @@ -103,14 +103,14 @@ fiberwise linear partial homeomorphism. -/ theorem SmoothFiberwiseLinear.locality_aux₁ (e : PartialHomeomorph (B × F) (B × F)) (h : ∀ p ∈ e.source, ∃ s : Set (B × F), IsOpen s ∧ p ∈ s ∧ ∃ (φ : B → F ≃L[𝕜] F) (u : Set B) (hu : IsOpen u) - (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x : F →L[𝕜] F)) u) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => ((φ x).symm : F →L[𝕜] F)) u), + (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x : F →L[𝕜] F)) u) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => ((φ x).symm : F →L[𝕜] F)) u), (e.restr s).EqOnSource (FiberwiseLinear.partialHomeomorph φ hu hφ.continuousOn h2φ.continuousOn)) : ∃ U : Set B, e.source = U ×ˢ univ ∧ ∀ x ∈ U, ∃ (φ : B → F ≃L[𝕜] F) (u : Set B) (hu : IsOpen u) (_huU : u ⊆ U) (_hux : x ∈ u), - ∃ (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x : F →L[𝕜] F)) u) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => ((φ x).symm : F →L[𝕜] F)) u), + ∃ (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x : F →L[𝕜] F)) u) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => ((φ x).symm : F →L[𝕜] F)) u), (e.restr (u ×ˢ univ)).EqOnSource (FiberwiseLinear.partialHomeomorph φ hu hφ.continuousOn h2φ.continuousOn) := by rw [SetCoe.forall'] at h @@ -155,13 +155,13 @@ theorem SmoothFiberwiseLinear.locality_aux₂ (e : PartialHomeomorph (B × F) (B (hU : e.source = U ×ˢ univ) (h : ∀ x ∈ U, ∃ (φ : B → F ≃L[𝕜] F) (u : Set B) (hu : IsOpen u) (_hUu : u ⊆ U) (_hux : x ∈ u) - (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x : F →L[𝕜] F)) u) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => ((φ x).symm : F →L[𝕜] F)) u), + (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x : F →L[𝕜] F)) u) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => ((φ x).symm : F →L[𝕜] F)) u), (e.restr (u ×ˢ univ)).EqOnSource (FiberwiseLinear.partialHomeomorph φ hu hφ.continuousOn h2φ.continuousOn)) : ∃ (Φ : B → F ≃L[𝕜] F) (U : Set B) (hU₀ : IsOpen U) (hΦ : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (Φ x : F →L[𝕜] F)) U) (h2Φ : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => ((Φ x).symm : F →L[𝕜] F)) U), + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (Φ x : F →L[𝕜] F)) U) (h2Φ : + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => ((Φ x).symm : F →L[𝕜] F)) U), e.EqOnSource (FiberwiseLinear.partialHomeomorph Φ hU₀ hΦ.continuousOn h2Φ.continuousOn) := by classical rw [SetCoe.forall'] at h @@ -192,14 +192,14 @@ theorem SmoothFiberwiseLinear.locality_aux₂ (e : PartialHomeomorph (B × F) (B intro x y hyu refine (hΦ y (hUu x hyu)).trans ?_ exact iUnionLift_mk ⟨y, hyu⟩ _ - have hΦ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun y => (Φ y : F →L[𝕜] F)) U := by + have hΦ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun y => (Φ y : F →L[𝕜] F)) U := by apply contMDiffOn_of_locally_contMDiffOn intro x hx refine ⟨u ⟨x, hx⟩, hu ⟨x, hx⟩, hux _, ?_⟩ refine (ContMDiffOn.congr (hφ ⟨x, hx⟩) ?_).mono inter_subset_right intro y hy rw [hΦφ ⟨x, hx⟩ y hy] - have h2Φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun y => ((Φ y).symm : F →L[𝕜] F)) U := by + have h2Φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun y => ((Φ y).symm : F →L[𝕜] F)) U := by apply contMDiffOn_of_locally_contMDiffOn intro x hx refine ⟨u ⟨x, hx⟩, hu ⟨x, hx⟩, hux _, ?_⟩ @@ -221,13 +221,13 @@ variable {F B IB} in -- in `smoothFiberwiseLinear` are quite slow, even with this change) private theorem mem_aux {e : PartialHomeomorph (B × F) (B × F)} : (e ∈ ⋃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) - (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x).symm : B → F →L[𝕜] F) U), + (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => φ x : B → F →L[𝕜] F) U) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x).symm : B → F →L[𝕜] F) U), {e | e.EqOnSource (FiberwiseLinear.partialHomeomorph φ hU hφ.continuousOn h2φ.continuousOn)}) ↔ ∃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) - (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x).symm : B → F →L[𝕜] F) U), + (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => φ x : B → F →L[𝕜] F) U) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x).symm : B → F →L[𝕜] F) U), e.EqOnSource (FiberwiseLinear.partialHomeomorph φ hU hφ.continuousOn h2φ.continuousOn) := by simp only [mem_iUnion, mem_setOf_eq] @@ -239,8 +239,8 @@ to the vector bundle belong to this groupoid. -/ def smoothFiberwiseLinear : StructureGroupoid (B × F) where members := ⋃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) - (hφ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) - (h2φ : SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x).symm : B → F →L[𝕜] F) U), + (hφ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => φ x : B → F →L[𝕜] F) U) + (h2φ : ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x).symm : B → F →L[𝕜] F) U), {e | e.EqOnSource (FiberwiseLinear.partialHomeomorph φ hU hφ.continuousOn h2φ.continuousOn)} trans' := by simp only [mem_aux] @@ -248,11 +248,11 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where refine ⟨fun b => (φ b).trans (φ' b), _, hU.inter hU', ?_, ?_, Setoid.trans (PartialHomeomorph.EqOnSource.trans' heφ heφ') ⟨?_, ?_⟩⟩ · show - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x : B => (φ' x).toContinuousLinearMap ∘L (φ x).toContinuousLinearMap) (U ∩ U') exact (hφ'.mono inter_subset_right).clm_comp (hφ.mono inter_subset_left) · show - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x : B => (φ x).symm.toContinuousLinearMap ∘L (φ' x).symm.toContinuousLinearMap) (U ∩ U') exact (h2φ.mono inter_subset_left).clm_comp (h2φ'.mono inter_subset_right) @@ -267,8 +267,8 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where exact hφ id_mem' := by simp_rw [mem_aux] - refine ⟨fun _ ↦ ContinuousLinearEquiv.refl 𝕜 F, univ, isOpen_univ, smoothOn_const, - smoothOn_const, ⟨?_, fun b _hb ↦ rfl⟩⟩ + refine ⟨fun _ ↦ ContinuousLinearEquiv.refl 𝕜 F, univ, isOpen_univ, contMDiffOn_const, + contMDiffOn_const, ⟨?_, fun b _hb ↦ rfl⟩⟩ simp only [FiberwiseLinear.partialHomeomorph, PartialHomeomorph.refl_partialEquiv, PartialEquiv.refl_source, univ_prod_univ] locality' := by @@ -286,7 +286,7 @@ def smoothFiberwiseLinear : StructureGroupoid (B × F) where theorem mem_smoothFiberwiseLinear_iff (e : PartialHomeomorph (B × F) (B × F)) : e ∈ smoothFiberwiseLinear B F IB ↔ ∃ (φ : B → F ≃L[𝕜] F) (U : Set B) (hU : IsOpen U) (hφ : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => φ x : B → F →L[𝕜] F) U) (h2φ : - SmoothOn IB 𝓘(𝕜, F →L[𝕜] F) (fun x => (φ x).symm : B → F →L[𝕜] F) U), + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => φ x : B → F →L[𝕜] F) U) (h2φ : + ContMDiffOn IB 𝓘(𝕜, F →L[𝕜] F) ⊤ (fun x => (φ x).symm : B → F →L[𝕜] F) U), e.EqOnSource (FiberwiseLinear.partialHomeomorph φ hU hφ.continuousOn h2φ.continuousOn) := mem_aux diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean index f56284f714605c..d00cefedfa42bf 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Hom.lean @@ -41,16 +41,19 @@ variable {𝕜 B F₁ F₂ M : Type*} {E₁ : B → Type*} {E₂ : B → Type*} local notation "LE₁E₂" => TotalSpace (F₁ →L[𝕜] F₂) (Bundle.ContinuousLinearMap (RingHom.id 𝕜) E₁ E₂) -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11083): moved slow parts to separate lemmas -theorem smoothOn_continuousLinearMapCoordChange +theorem contMDiffOn_continuousLinearMapCoordChange [SmoothVectorBundle F₁ E₁ IB] [SmoothVectorBundle F₂ E₂ IB] [MemTrivializationAtlas e₁] [MemTrivializationAtlas e₁'] [MemTrivializationAtlas e₂] [MemTrivializationAtlas e₂'] : - SmoothOn IB 𝓘(𝕜, (F₁ →L[𝕜] F₂) →L[𝕜] F₁ →L[𝕜] F₂) + ContMDiffOn IB 𝓘(𝕜, (F₁ →L[𝕜] F₂) →L[𝕜] F₁ →L[𝕜] F₂) ⊤ (continuousLinearMapCoordChange (RingHom.id 𝕜) e₁ e₁' e₂ e₂') (e₁.baseSet ∩ e₂.baseSet ∩ (e₁'.baseSet ∩ e₂'.baseSet)) := by - have h₁ := smoothOn_coordChangeL (IB := IB) e₁' e₁ - have h₂ := smoothOn_coordChangeL (IB := IB) e₂ e₂' + have h₁ := contMDiffOn_coordChangeL (IB := IB) e₁' e₁ (n := ⊤) + have h₂ := contMDiffOn_coordChangeL (IB := IB) e₂ e₂' (n := ⊤) refine (h₁.mono ?_).cle_arrowCongr (h₂.mono ?_) <;> mfld_set_tac +@[deprecated (since := "2024-11-21")] +alias smoothOn_continuousLinearMapCoordChange := contMDiffOn_continuousLinearMapCoordChange + variable [∀ x, TopologicalAddGroup (E₂ x)] [∀ x, ContinuousSMul 𝕜 (E₂ x)] theorem hom_chart (y₀ y : LE₁E₂) : @@ -67,12 +70,8 @@ theorem contMDiffAt_hom_bundle (f : M → LE₁E₂) {x₀ : M} {n : ℕ∞} : (fun x => inCoordinates F₁ E₁ F₂ E₂ (f x₀).1 (f x).1 (f x₀).1 (f x).1 (f x).2) x₀ := contMDiffAt_totalSpace .. -theorem smoothAt_hom_bundle (f : M → LE₁E₂) {x₀ : M} : - SmoothAt IM (IB.prod 𝓘(𝕜, F₁ →L[𝕜] F₂)) f x₀ ↔ - SmoothAt IM IB (fun x => (f x).1) x₀ ∧ - SmoothAt IM 𝓘(𝕜, F₁ →L[𝕜] F₂) - (fun x => inCoordinates F₁ E₁ F₂ E₂ (f x₀).1 (f x).1 (f x₀).1 (f x).1 (f x).2) x₀ := - contMDiffAt_hom_bundle f +@[deprecated (since := "2024-11-21")] alias smoothAt_hom_bundle := contMDiffAt_hom_bundle + variable [SmoothVectorBundle F₁ E₁ IB] [SmoothVectorBundle F₂ E₂ IB] @@ -81,7 +80,7 @@ instance Bundle.ContinuousLinearMap.vectorPrebundle.isSmooth : exists_smoothCoordChange := by rintro _ ⟨e₁, e₂, he₁, he₂, rfl⟩ _ ⟨e₁', e₂', he₁', he₂', rfl⟩ exact ⟨continuousLinearMapCoordChange (RingHom.id 𝕜) e₁ e₁' e₂ e₂', - smoothOn_continuousLinearMapCoordChange, + contMDiffOn_continuousLinearMapCoordChange, continuousLinearMapCoordChange_apply (RingHom.id 𝕜) e₁ e₁' e₂ e₂'⟩ instance SmoothVectorBundle.continuousLinearMap : diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean b/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean index ef7514b05054c8..7ba8cdb7b86d38 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Pullback.lean @@ -28,14 +28,14 @@ variable [NontriviallyNormedField 𝕜] [∀ x, AddCommMonoid (E x)] [∀ x, Mod [ChartedSpace HB B] {EB' : Type*} [NormedAddCommGroup EB'] [NormedSpace 𝕜 EB'] {HB' : Type*} [TopologicalSpace HB'] (IB' : ModelWithCorners 𝕜 EB' HB') [TopologicalSpace B'] [ChartedSpace HB' B'] [FiberBundle F E] - [VectorBundle 𝕜 F E] [SmoothVectorBundle F E IB] (f : SmoothMap IB' IB B' B) + [VectorBundle 𝕜 F E] [SmoothVectorBundle F E IB] (f : ContMDiffMap IB' IB B' B ⊤) /-- For a smooth vector bundle `E` over a manifold `B` and a smooth map `f : B' → B`, the pullback vector bundle `f *ᵖ E` is a smooth vector bundle. -/ instance SmoothVectorBundle.pullback : SmoothVectorBundle F (f *ᵖ E) IB' where - smoothOn_coordChangeL := by + contMDiffOn_coordChangeL := by rintro _ _ ⟨e, he, rfl⟩ ⟨e', he', rfl⟩ - refine ((smoothOn_coordChangeL e e').comp f.smooth.smoothOn fun b hb => hb).congr ?_ + refine ((contMDiffOn_coordChangeL e e').comp f.contMDiff.contMDiffOn fun b hb => hb).congr ?_ rintro b (hb : f b ∈ e.baseSet ∩ e'.baseSet); ext v show ((e.pullback f).coordChangeL 𝕜 (e'.pullback f) b) v = (e.coordChangeL 𝕜 e' (f b)) v rw [e.coordChangeL_apply e' hb, (e.pullback f).coordChangeL_apply' _] diff --git a/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean b/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean index 198e5170ad73e4..60a27aee362865 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean @@ -19,6 +19,9 @@ sections of a smooth vector bundle over a manifold `M` and prove that it's a mod open Bundle Filter Function open scoped Bundle Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) @@ -39,9 +42,7 @@ structure ContMDiffSection where protected contMDiff_toFun : ContMDiff I (I.prod 𝓘(𝕜, F)) n fun x ↦ TotalSpace.mk' F x (toFun x) -/-- Bundled smooth sections of a vector bundle. -/ -abbrev SmoothSection := - ContMDiffSection I F ⊤ V +@[deprecated (since := "024-11-21")] alias SmoothSection := ContMDiffSection @[inherit_doc] scoped[Manifold] notation "Cₛ^" n "⟮" I "; " F ", " V "⟯" => ContMDiffSection I F n V @@ -65,9 +66,7 @@ protected theorem contMDiff (s : Cₛ^n⟮I; F, V⟯) : ContMDiff I (I.prod 𝓘(𝕜, F)) n fun x => TotalSpace.mk' F x (s x : V x) := s.contMDiff_toFun -protected theorem smooth (s : Cₛ^∞⟮I; F, V⟯) : - Smooth I (I.prod 𝓘(𝕜, F)) fun x => TotalSpace.mk' F x (s x : V x) := - s.contMDiff_toFun +@[deprecated (since := "2024-11-21")] alias smooth := ContMDiffSection.contMDiff theorem coe_inj ⦃s t : Cₛ^n⟮I; F, V⟯⦄ (h : (s : ∀ x, V x) = t) : s = t := DFunLike.ext' h @@ -114,7 +113,7 @@ theorem coe_sub (s t : Cₛ^n⟮I; F, V⟯) : ⇑(s - t) = s - t := rfl instance instZero : Zero Cₛ^n⟮I; F, V⟯ := - ⟨⟨fun _ => 0, (smooth_zeroSection 𝕜 V).of_le le_top⟩⟩ + ⟨⟨fun _ => 0, (contMDiff_zeroSection 𝕜 V).of_le le_top⟩⟩ instance inhabited : Inhabited Cₛ^n⟮I; F, V⟯ := ⟨0⟩ diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index fd5bda4a24a80e..5931fefe4f64b8 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean @@ -36,7 +36,7 @@ and a smooth manifold. open Bundle Set SmoothManifoldWithCorners PartialHomeomorph ContinuousLinearMap -open scoped Manifold Topology Bundle +open scoped Manifold Topology Bundle ContDiff noncomputable section @@ -49,7 +49,6 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCom [SmoothManifoldWithCorners I M] {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] [SmoothManifoldWithCorners I' M'] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] - /-- Auxiliary lemma for tangent spaces: the derivative of a coordinate change between two charts is smooth on its source. -/ theorem contDiffOn_fderiv_coord_change (i j : atlas H M) : @@ -58,12 +57,12 @@ 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.uniqueDiffOn le_top <| h hx).mono h + refine (ContDiffWithinAt.fderivWithin_right ?_ I.uniqueDiffOn (n := ∞) (mod_cast le_top) + <| h hx).mono h refine (PartialHomeomorph.contDiffOn_extend_coord_change (subset_maximalAtlas j.2) (subset_maximalAtlas i.2) x hx).mono_of_mem_nhdsWithin ?_ exact i.1.extend_coord_change_source_mem_nhdsWithin j.1 hx - open SmoothManifoldWithCorners variable (I M) in @@ -104,9 +103,9 @@ def tangentBundleCore : VectorBundleCore 𝕜 M E (atlas H M) where simp_rw [Function.comp_apply, (j.1.extend I).left_inv hy] · simp_rw [Function.comp_apply, i.1.extend_left_inv hxi, j.1.extend_left_inv hxj] · exact (contDiffWithinAt_extend_coord_change' (subset_maximalAtlas k.2) - (subset_maximalAtlas j.2) hxk hxj).differentiableWithinAt le_top + (subset_maximalAtlas j.2) hxk hxj).differentiableWithinAt (mod_cast le_top) · exact (contDiffWithinAt_extend_coord_change' (subset_maximalAtlas j.2) - (subset_maximalAtlas i.2) hxj hxi).differentiableWithinAt le_top + (subset_maximalAtlas i.2) hxj hxi).differentiableWithinAt (mod_cast le_top) · intro x _; exact mem_range_self _ · exact I.uniqueDiffWithinAt_image · rw [Function.comp_apply, i.1.extend_left_inv hxi] @@ -286,7 +285,7 @@ end TangentBundle instance tangentBundleCore.isSmooth : (tangentBundleCore I M).IsSmooth I := by refine ⟨fun i j => ?_⟩ - rw [SmoothOn, contMDiffOn_iff_source_of_mem_maximalAtlas (subset_maximalAtlas i.2), + rw [contMDiffOn_iff_source_of_mem_maximalAtlas (subset_maximalAtlas i.2), contMDiffOn_iff_contDiffOn] · refine ((contDiffOn_fderiv_coord_change (I := I) i j).congr fun x hx => ?_).mono ?_ · rw [PartialEquiv.trans_source'] at hx diff --git a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean index 2c5558360b39fc..a6416ab861ef1e 100644 --- a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean +++ b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean @@ -33,6 +33,9 @@ variable {ι : Type uι} {E : Type uE} [NormedAddCommGroup E] [NormedSpace ℝ E open Function Filter Module Set Topology open scoped Manifold +/- Next line is necessary while the manifold smoothness class is not extended to `ω`. +Later, replace with `open scoped ContDiff`. -/ +local notation "∞" => (⊤ : ℕ∞) noncomputable section @@ -52,7 +55,7 @@ def embeddingPiTangent : C^∞⟮I, M; 𝓘(ℝ, ι → E × ℝ), ι → E × val x i := (f i x • extChartAt I (f.c i) x, f i x) property := contMDiff_pi_space.2 fun i => - ((f i).smooth_smul contMDiffOn_extChartAt).prod_mk_space (f i).smooth + ((f i).contMDiff_smul contMDiffOn_extChartAt).prod_mk_space (f i).contMDiff @[local simp] theorem embeddingPiTangent_coe : @@ -81,7 +84,8 @@ theorem comp_embeddingPiTangent_mfderiv (x : M) (hx : x ∈ s) : set L := (ContinuousLinearMap.fst ℝ E ℝ).comp (@ContinuousLinearMap.proj ℝ _ ι (fun _ => E × ℝ) _ _ (fun _ => inferInstance) (f.ind x hx)) - have := L.hasMFDerivAt.comp x f.embeddingPiTangent.smooth.mdifferentiableAt.hasMFDerivAt + have := L.hasMFDerivAt.comp x + (f.embeddingPiTangent.contMDiff.mdifferentiableAt le_top).hasMFDerivAt convert hasMFDerivAt_unique this _ refine (hasMFDerivAt_extChartAt (f.mem_chartAt_ind_source x hx)).congr_of_eventuallyEq ?_ refine (f.eventuallyEq_one x hx).mono fun y hy => ?_ @@ -106,7 +110,7 @@ supports of bump functions, then for some `n` it can be immersed into the `n`-di Euclidean space. -/ theorem exists_immersion_euclidean {ι : Type*} [Finite ι] (f : SmoothBumpCovering ι I M) : ∃ (n : ℕ) (e : M → EuclideanSpace ℝ (Fin n)), - Smooth I (𝓡 n) e ∧ Injective e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by + ContMDiff I (𝓡 n) ⊤ e ∧ Injective e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by cases nonempty_fintype ι set F := EuclideanSpace ℝ (Fin <| finrank ℝ (ι → E × ℝ)) letI : IsNoetherian ℝ (E × ℝ) := IsNoetherian.iff_fg.2 inferInstance @@ -114,10 +118,10 @@ theorem exists_immersion_euclidean {ι : Type*} [Finite ι] (f : SmoothBumpCover set eEF : (ι → E × ℝ) ≃L[ℝ] F := ContinuousLinearEquiv.ofFinrankEq finrank_euclideanSpace_fin.symm refine ⟨_, eEF ∘ f.embeddingPiTangent, - eEF.toDiffeomorph.smooth.comp f.embeddingPiTangent.smooth, + eEF.toDiffeomorph.contMDiff.comp f.embeddingPiTangent.contMDiff, eEF.injective.comp f.embeddingPiTangent_injective, fun x => ?_⟩ rw [mfderiv_comp _ eEF.differentiableAt.mdifferentiableAt - f.embeddingPiTangent.smooth.mdifferentiableAt, + (f.embeddingPiTangent.contMDiff.mdifferentiableAt le_top), eEF.mfderiv_eq] exact eEF.injective.comp (f.embeddingPiTangent_injective_mfderiv _ trivial) @@ -128,7 +132,7 @@ supports of bump functions, then for some `n` it can be embedded into the `n`-di Euclidean space. -/ theorem exists_embedding_euclidean_of_compact [T2Space M] [CompactSpace M] : ∃ (n : ℕ) (e : M → EuclideanSpace ℝ (Fin n)), - Smooth I (𝓡 n) e ∧ IsClosedEmbedding e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by + ContMDiff I (𝓡 n) ⊤ e ∧ IsClosedEmbedding e ∧ ∀ x : M, Injective (mfderiv I (𝓡 n) e x) := by rcases SmoothBumpCovering.exists_isSubordinate I isClosed_univ fun (x : M) _ => univ_mem with ⟨ι, f, -⟩ haveI := f.fintype diff --git a/Mathlib/GroupTheory/Archimedean.lean b/Mathlib/GroupTheory/Archimedean.lean index c31b5072d4f20a..e67010ff8ade4f 100644 --- a/Mathlib/GroupTheory/Archimedean.lean +++ b/Mathlib/GroupTheory/Archimedean.lean @@ -31,6 +31,8 @@ The result is also used in `Topology.Instances.Real` as an ingredient in the cla subgroups of `ℝ`. -/ +assert_not_exists Finset + open Set variable {G : Type*} [LinearOrderedCommGroup G] [MulArchimedean G] diff --git a/Mathlib/GroupTheory/ArchimedeanDensely.lean b/Mathlib/GroupTheory/ArchimedeanDensely.lean index 0434db1da4ce64..6e65e049cb5766 100644 --- a/Mathlib/GroupTheory/ArchimedeanDensely.lean +++ b/Mathlib/GroupTheory/ArchimedeanDensely.lean @@ -3,12 +3,13 @@ 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.Data.Int.Interval -import Mathlib.GroupTheory.Archimedean import Mathlib.Algebra.Group.Equiv.TypeTags import Mathlib.Algebra.Group.Subgroup.Pointwise +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.Order.Group.TypeTags import Mathlib.Algebra.Order.Hom.Monoid +import Mathlib.Data.Int.Interval +import Mathlib.GroupTheory.Archimedean /-! # Archimedean groups are either discrete or densely ordered diff --git a/Mathlib/GroupTheory/Complement.lean b/Mathlib/GroupTheory/Complement.lean index 5884f8c7afa96b..dc8d224d031add 100644 --- a/Mathlib/GroupTheory/Complement.lean +++ b/Mathlib/GroupTheory/Complement.lean @@ -257,11 +257,11 @@ lemma exists_left_transversal (H : Subgroup G) (g : G) : ∃ S ∈ leftTransversals (H : Set G), g ∈ S := by classical refine - ⟨Set.range (Function.update Quotient.out' _ g), range_mem_leftTransversals fun q => ?_, - Quotient.mk'' g, Function.update_same (Quotient.mk'' g) g Quotient.out'⟩ + ⟨Set.range (Function.update Quotient.out _ g), range_mem_leftTransversals fun q => ?_, + Quotient.mk'' g, Function.update_same (Quotient.mk'' g) g Quotient.out⟩ by_cases hq : q = Quotient.mk'' g - · exact hq.symm ▸ congr_arg _ (Function.update_same (Quotient.mk'' g) g Quotient.out') - · refine (Function.update_noteq ?_ g Quotient.out') ▸ q.out_eq' + · exact hq.symm ▸ congr_arg _ (Function.update_same (Quotient.mk'' g) g Quotient.out) + · refine (Function.update_noteq ?_ g Quotient.out) ▸ q.out_eq' exact hq @[to_additive] @@ -269,11 +269,11 @@ lemma exists_right_transversal (H : Subgroup G) (g : G) : ∃ S ∈ rightTransversals (H : Set G), g ∈ S := by classical refine - ⟨Set.range (Function.update Quotient.out' _ g), range_mem_rightTransversals fun q => ?_, - Quotient.mk'' g, Function.update_same (Quotient.mk'' g) g Quotient.out'⟩ + ⟨Set.range (Function.update Quotient.out _ g), range_mem_rightTransversals fun q => ?_, + Quotient.mk'' g, Function.update_same (Quotient.mk'' g) g Quotient.out⟩ by_cases hq : q = Quotient.mk'' g - · exact hq.symm ▸ congr_arg _ (Function.update_same (Quotient.mk'' g) g Quotient.out') - · exact Eq.trans (congr_arg _ (Function.update_noteq hq g Quotient.out')) q.out_eq' + · exact hq.symm ▸ congr_arg _ (Function.update_same (Quotient.mk'' g) g Quotient.out) + · exact Eq.trans (congr_arg _ (Function.update_noteq hq g Quotient.out)) q.out_eq' /-- Given two subgroups `H' ⊆ H`, there exists a left transversal to `H'` inside `H`. -/ @[to_additive "Given two subgroups `H' ⊆ H`, there exists a transversal to `H'` inside `H`"] @@ -587,11 +587,11 @@ end Action @[to_additive] instance : Inhabited (leftTransversals (H : Set G)) := - ⟨⟨Set.range Quotient.out', range_mem_leftTransversals Quotient.out_eq'⟩⟩ + ⟨⟨Set.range Quotient.out, range_mem_leftTransversals Quotient.out_eq'⟩⟩ @[to_additive] instance : Inhabited (rightTransversals (H : Set G)) := - ⟨⟨Set.range Quotient.out', range_mem_rightTransversals Quotient.out_eq'⟩⟩ + ⟨⟨Set.range Quotient.out, range_mem_rightTransversals Quotient.out_eq'⟩⟩ theorem IsComplement'.isCompl (h : IsComplement' H K) : IsCompl H K := by refine @@ -666,17 +666,17 @@ variable {G : Type u} [Group G] (H : Subgroup G) (g : G) /-- Partition `G ⧸ H` into orbits of the action of `g : G`. -/ noncomputable def quotientEquivSigmaZMod : - G ⧸ H ≃ Σq : orbitRel.Quotient (zpowers g) (G ⧸ H), ZMod (minimalPeriod (g • ·) q.out') := + G ⧸ H ≃ Σq : orbitRel.Quotient (zpowers g) (G ⧸ H), ZMod (minimalPeriod (g • ·) q.out) := (selfEquivSigmaOrbits (zpowers g) (G ⧸ H)).trans - (sigmaCongrRight fun q => orbitZPowersEquiv g q.out') + (sigmaCongrRight fun q => orbitZPowersEquiv g q.out) theorem quotientEquivSigmaZMod_symm_apply (q : orbitRel.Quotient (zpowers g) (G ⧸ H)) - (k : ZMod (minimalPeriod (g • ·) q.out')) : - (quotientEquivSigmaZMod H g).symm ⟨q, k⟩ = g ^ (cast k : ℤ) • q.out' := + (k : ZMod (minimalPeriod (g • ·) q.out)) : + (quotientEquivSigmaZMod H g).symm ⟨q, k⟩ = g ^ (cast k : ℤ) • q.out := rfl theorem quotientEquivSigmaZMod_apply (q : orbitRel.Quotient (zpowers g) (G ⧸ H)) (k : ℤ) : - quotientEquivSigmaZMod H g (g ^ k • q.out') = ⟨q, k⟩ := by + quotientEquivSigmaZMod H g (g ^ k • q.out) = ⟨q, k⟩ := by rw [apply_eq_iff_eq_symm_apply, quotientEquivSigmaZMod_symm_apply, ZMod.coe_intCast, zpow_smul_mod_minimalPeriod] @@ -684,16 +684,16 @@ theorem quotientEquivSigmaZMod_apply (q : orbitRel.Quotient (zpowers g) (G ⧸ H in `G ⧸ H`, an element `g ^ k • q₀` is mapped to `g ^ k • g₀` for a fixed choice of representative `g₀` of `q₀`. -/ noncomputable def transferFunction : G ⧸ H → G := fun q => - g ^ (cast (quotientEquivSigmaZMod H g q).2 : ℤ) * (quotientEquivSigmaZMod H g q).1.out'.out' + g ^ (cast (quotientEquivSigmaZMod H g q).2 : ℤ) * (quotientEquivSigmaZMod H g q).1.out.out theorem transferFunction_apply (q : G ⧸ H) : transferFunction H g q = g ^ (cast (quotientEquivSigmaZMod H g q).2 : ℤ) * - (quotientEquivSigmaZMod H g q).1.out'.out' := + (quotientEquivSigmaZMod H g q).1.out.out := rfl theorem coe_transferFunction (q : G ⧸ H) : ↑(transferFunction H g q) = q := by - rw [transferFunction_apply, ← smul_eq_mul, Quotient.coe_smul_out', + rw [transferFunction_apply, ← smul_eq_mul, Quotient.coe_smul_out, ← quotientEquivSigmaZMod_symm_apply, Sigma.eta, symm_apply_apply] /-- The transfer transversal as a set. Contains elements of the form `g ^ k • g₀` for fixed choices @@ -714,17 +714,17 @@ theorem transferTransversal_apply (q : G ⧸ H) : toEquiv_apply (coe_transferFunction H g) q theorem transferTransversal_apply' (q : orbitRel.Quotient (zpowers g) (G ⧸ H)) - (k : ZMod (minimalPeriod (g • ·) q.out')) : - ↑(toEquiv (transferTransversal H g).2 (g ^ (cast k : ℤ) • q.out')) = - g ^ (cast k : ℤ) * q.out'.out' := by + (k : ZMod (minimalPeriod (g • ·) q.out)) : + ↑(toEquiv (transferTransversal H g).2 (g ^ (cast k : ℤ) • q.out)) = + g ^ (cast k : ℤ) * q.out.out := by rw [transferTransversal_apply, transferFunction_apply, ← quotientEquivSigmaZMod_symm_apply, apply_symm_apply] theorem transferTransversal_apply'' (q : orbitRel.Quotient (zpowers g) (G ⧸ H)) - (k : ZMod (minimalPeriod (g • ·) q.out')) : - ↑(toEquiv (g • transferTransversal H g).2 (g ^ (cast k : ℤ) • q.out')) = - if k = 0 then g ^ minimalPeriod (g • ·) q.out' * q.out'.out' - else g ^ (cast k : ℤ) * q.out'.out' := by + (k : ZMod (minimalPeriod (g • ·) q.out)) : + ↑(toEquiv (g • transferTransversal H g).2 (g ^ (cast k : ℤ) • q.out)) = + if k = 0 then g ^ minimalPeriod (g • ·) q.out * q.out.out + else g ^ (cast k : ℤ) * q.out.out := by rw [smul_apply_eq_smul_apply_inv_smul, transferTransversal_apply, transferFunction_apply, ← mul_smul, ← zpow_neg_one, ← zpow_add, quotientEquivSigmaZMod_apply, smul_eq_mul, ← mul_assoc, ← zpow_one_add, Int.cast_add, Int.cast_neg, Int.cast_one, intCast_cast, cast_id', id, ← diff --git a/Mathlib/GroupTheory/Coprod/Basic.lean b/Mathlib/GroupTheory/Coprod/Basic.lean index 084c569e85fa9f..93e15e76960150 100644 --- a/Mathlib/GroupTheory/Coprod/Basic.lean +++ b/Mathlib/GroupTheory/Coprod/Basic.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.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.PUnitInstances.Algebra import Mathlib.GroupTheory.Congruence.Basic diff --git a/Mathlib/GroupTheory/Coset/Basic.lean b/Mathlib/GroupTheory/Coset/Basic.lean index 5caed356835d7e..4f8c575b67fcf2 100644 --- a/Mathlib/GroupTheory/Coset/Basic.lean +++ b/Mathlib/GroupTheory/Coset/Basic.lean @@ -314,10 +314,19 @@ lemma orbit_mk_eq_smul (x : α) : MulAction.orbitRel.Quotient.orbit (x : α ⧸ simpa [mem_smul_set_iff_inv_smul_mem, ← leftRel_apply, Quotient.eq''] using Setoid.comm' _ @[to_additive] -lemma orbit_eq_out'_smul (x : α ⧸ s) : MulAction.orbitRel.Quotient.orbit x = x.out' • s := by +lemma orbit_eq_out_smul (x : α ⧸ s) : MulAction.orbitRel.Quotient.orbit x = x.out • s := by induction x using QuotientGroup.induction_on simp only [orbit_mk_eq_smul, ← eq_class_eq_leftCoset, Quotient.out_eq'] +@[to_additive] +alias orbit_eq_out'_smul := orbit_eq_out_smul + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated orbit_eq_out_smul (since := "2024-10-19")] orbit_eq_out'_smul +attribute [deprecated QuotientAddGroup.orbit_eq_out_vadd (since := "2024-10-19")] +QuotientAddGroup.orbit_eq_out'_vadd + end QuotientGroup namespace Subgroup @@ -344,7 +353,7 @@ def rightCosetEquivSubgroup (g : α) : (op g • s : Set α) ≃ s := noncomputable def groupEquivQuotientProdSubgroup : α ≃ (α ⧸ s) × s := calc α ≃ ΣL : α ⧸ s, { x : α // (x : α ⧸ s) = L } := (Equiv.sigmaFiberEquiv QuotientGroup.mk).symm - _ ≃ ΣL : α ⧸ s, (Quotient.out' L • s : Set α) := + _ ≃ ΣL : α ⧸ s, (Quotient.out L • s : Set α) := Equiv.sigmaCongrRight fun L => by rw [← eq_class_eq_leftCoset] show @@ -394,7 +403,7 @@ The constructive version is `quotientEquivProdOfLE'`. -/ @[to_additive (attr := simps!) "If `H ≤ K`, then `G/H ≃ G/K × K/H` nonconstructively. The constructive version is `quotientEquivProdOfLE'`."] noncomputable def quotientEquivProdOfLE (h_le : s ≤ t) : α ⧸ s ≃ (α ⧸ t) × t ⧸ s.subgroupOf t := - quotientEquivProdOfLE' h_le Quotient.out' Quotient.out_eq' + quotientEquivProdOfLE' h_le Quotient.out Quotient.out_eq' /-- If `s ≤ t`, then there is an embedding `s ⧸ H.subgroupOf s ↪ t ⧸ H.subgroupOf t`. -/ @[to_additive "If `s ≤ t`, then there is an embedding @@ -543,11 +552,11 @@ variable [Group α] noncomputable def preimageMkEquivSubgroupProdSet (s : Subgroup α) (t : Set (α ⧸ s)) : QuotientGroup.mk ⁻¹' t ≃ s × t where toFun a := - ⟨⟨((Quotient.out' (QuotientGroup.mk a)) : α)⁻¹ * a, + ⟨⟨((Quotient.out (QuotientGroup.mk a)) : α)⁻¹ * a, leftRel_apply.mp (@Quotient.exact' _ (leftRel s) _ _ <| Quotient.out_eq' _)⟩, ⟨QuotientGroup.mk a, a.2⟩⟩ invFun a := - ⟨Quotient.out' a.2.1 * a.1.1, + ⟨Quotient.out a.2.1 * a.1.1, show QuotientGroup.mk _ ∈ t by rw [mk_mul_of_mem _ a.1.2, out_eq'] exact a.2.2⟩ @@ -559,8 +568,8 @@ open MulAction in @[to_additive "An additive group is made up of a disjoint union of cosets of an additive subgroup."] lemma univ_eq_iUnion_smul (H : Subgroup α) : - (Set.univ (α := α)) = ⋃ x : α ⧸ H, x.out' • (H : Set _) := by - simp_rw [univ_eq_iUnion_orbit H.op, orbit_eq_out'_smul] + (Set.univ (α := α)) = ⋃ x : α ⧸ H, x.out • (H : Set _) := by + simp_rw [univ_eq_iUnion_orbit H.op, orbit_eq_out_smul] rfl end QuotientGroup diff --git a/Mathlib/GroupTheory/Coset/Defs.lean b/Mathlib/GroupTheory/Coset/Defs.lean index f70f9cbbba8eb2..c57164adfbaee6 100644 --- a/Mathlib/GroupTheory/Coset/Defs.lean +++ b/Mathlib/GroupTheory/Coset/Defs.lean @@ -89,6 +89,10 @@ instance leftRelDecidable [DecidablePred (· ∈ s)] : DecidableRel (leftRel s). instance instHasQuotientSubgroup : HasQuotient α (Subgroup α) := ⟨fun s => Quotient (leftRel s)⟩ +@[to_additive] +instance [DecidablePred (· ∈ s)] : DecidableEq (α ⧸ s) := + @Quotient.decidableEq _ _ (leftRelDecidable _) + /-- The equivalence relation corresponding to the partition of a group by right cosets of a subgroup. -/ @[to_additive "The equivalence relation corresponding to the partition of a group by right cosets @@ -170,7 +174,13 @@ theorem induction_on {C : α ⧸ s → Prop} (x : α ⧸ s) (H : ∀ z, C (Quoti instance : Coe α (α ⧸ s) := ⟨mk⟩ -@[to_additive (attr := deprecated (since := "2024-08-04"))] alias induction_on' := induction_on +@[to_additive] alias induction_on' := induction_on + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated induction_on (since := "2024-08-04")] induction_on' +attribute [deprecated QuotientAddGroup.induction_on (since := "2024-08-04")] +QuotientAddGroup.induction_on' @[to_additive (attr := simp)] theorem quotient_liftOn_mk {β} (f : α → β) (h) (x : α) : Quotient.liftOn' (x : α ⧸ s) f h = f x := @@ -194,20 +204,31 @@ protected theorem eq {a b : α} : (a : α ⧸ s) = b ↔ a⁻¹ * b ∈ s := _ ↔ leftRel s a b := Quotient.eq'' _ ↔ _ := by rw [leftRel_apply] -@[to_additive (attr := deprecated (since := "2024-08-04"))] alias eq' := QuotientGroup.eq +@[to_additive (attr := deprecated "No deprecation message was provided." (since := "2024-08-04"))] +alias eq' := QuotientGroup.eq @[to_additive] -theorem out_eq' (a : α ⧸ s) : mk a.out' = a := +theorem out_eq' (a : α ⧸ s) : mk a.out = a := Quotient.out_eq' a variable (s) -/- It can be useful to write `obtain ⟨h, H⟩ := mk_out'_eq_mul ...`, and then `rw [H]` or +/- 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'`. -/ + stated in terms of an arbitrary `h : s`, rather than the specific `h = g⁻¹ * (mk g).out`. -/ +@[to_additive QuotientAddGroup.mk_out_eq_mul] +theorem mk_out_eq_mul (g : α) : ∃ h : s, (mk g : α ⧸ s).out = g * h := + ⟨⟨g⁻¹ * (mk g).out, QuotientGroup.eq.mp (mk g).out_eq'.symm⟩, by rw [mul_inv_cancel_left]⟩ + @[to_additive QuotientAddGroup.mk_out'_eq_mul] -theorem mk_out'_eq_mul (g : α) : ∃ h : s, (mk g : α ⧸ s).out' = g * h := - ⟨⟨g⁻¹ * (mk g).out', QuotientGroup.eq.mp (mk g).out_eq'.symm⟩, by rw [mul_inv_cancel_left]⟩ +alias mk_out'_eq_mul := mk_out_eq_mul + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated mk_out_eq_mul (since := "2024-10-19")] mk_out'_eq_mul +attribute [deprecated QuotientAddGroup.mk_out_eq_mul (since := "2024-10-19")] +QuotientAddGroup.mk_out'_eq_mul + variable {s} {a b : α} diff --git a/Mathlib/GroupTheory/Divisible.lean b/Mathlib/GroupTheory/Divisible.lean index 99ead5b297aa7e..5543e8f8d13dfc 100644 --- a/Mathlib/GroupTheory/Divisible.lean +++ b/Mathlib/GroupTheory/Divisible.lean @@ -5,6 +5,7 @@ Authors: Jujian Zhang -/ import Mathlib.Algebra.Group.ULift import Mathlib.Algebra.Group.Subgroup.Pointwise +import Mathlib.Algebra.Module.NatInt import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.Tactic.NormNum.Eq diff --git a/Mathlib/GroupTheory/DoubleCoset.lean b/Mathlib/GroupTheory/DoubleCoset.lean index d80688cff9e27d..5efccbbe6d6e7d 100644 --- a/Mathlib/GroupTheory/DoubleCoset.lean +++ b/Mathlib/GroupTheory/DoubleCoset.lean @@ -101,7 +101,7 @@ theorem rel_bot_eq_right_group_rel (H : Subgroup G) : /-- Create a doset out of an element of `H \ G / K`-/ def quotToDoset (H K : Subgroup G) (q : Quotient (H : Set G) K) : Set G := - doset q.out' H K + doset q.out H K /-- Map from `G` to `H \ G / K`-/ abbrev mk (H K : Subgroup G) (a : G) : Quotient (H : Set G) K := @@ -115,34 +115,38 @@ theorem eq (H K : Subgroup G) (a b : G) : rw [Quotient.eq''] apply rel_iff -theorem out_eq' (H K : Subgroup G) (q : Quotient ↑H ↑K) : mk H K q.out' = q := +theorem out_eq' (H K : Subgroup G) (q : Quotient ↑H ↑K) : mk H K q.out = q := Quotient.out_eq' q -theorem mk_out'_eq_mul (H K : Subgroup G) (g : G) : - ∃ h k : G, h ∈ H ∧ k ∈ K ∧ (mk H K g : Quotient ↑H ↑K).out' = h * g * k := by - have := eq H K (mk H K g : Quotient ↑H ↑K).out' g +theorem mk_out_eq_mul (H K : Subgroup G) (g : G) : + ∃ h k : G, h ∈ H ∧ k ∈ K ∧ (mk H K g : Quotient ↑H ↑K).out = h * g * k := by + have := eq H K (mk H K g : Quotient ↑H ↑K).out g rw [out_eq'] at this obtain ⟨h, h_h, k, hk, T⟩ := this.1 rfl refine ⟨h⁻¹, k⁻¹, H.inv_mem h_h, K.inv_mem hk, eq_mul_inv_of_mul_eq (eq_inv_mul_of_mul_eq ?_)⟩ rw [← mul_assoc, ← T] +@[deprecated (since := "2024-10-19")] alias mk_out'_eq_mul := mk_out_eq_mul + theorem mk_eq_of_doset_eq {H K : Subgroup G} {a b : G} (h : doset a H K = doset b H K) : mk H K a = mk H K b := by 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 K} : - a ≠ b → Disjoint (doset a.out' H K) (doset b.out' (H : Set G) K) := by +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 simpa [out_eq'] using mk_eq_of_doset_eq (eq_of_not_disjoint h) +@[deprecated (since := "2024-10-19")] alias disjoint_out' := disjoint_out + 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] use mk H K x - obtain ⟨h, k, h3, h4, h5⟩ := mk_out'_eq_mul 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, ?_⟩ simp only [h5, Subgroup.coe_mk, ← mul_assoc, one_mul, inv_mul_cancel, mul_inv_cancel_right] diff --git a/Mathlib/GroupTheory/Exponent.lean b/Mathlib/GroupTheory/Exponent.lean index 6ee49e4b8a6ac9..ea64a5ce67e5ec 100644 --- a/Mathlib/GroupTheory/Exponent.lean +++ b/Mathlib/GroupTheory/Exponent.lean @@ -644,7 +644,8 @@ lemma inv_eq_self_of_orderOf_eq_two {x : G} (hx : orderOf x = 2) : -- TODO: delete /-- Any group of exponent two is abelian. -/ -@[to_additive (attr := reducible, deprecated (since := "2024-02-17")) +@[to_additive (attr := reducible, + deprecated "No deprecation message was provided." (since := "2024-02-17")) "Any additive group of exponent two is abelian."] def instCommGroupOfExponentTwo (hG : Monoid.exponent G = 2) : CommGroup G where mul_comm := mul_comm_of_exponent_two hG diff --git a/Mathlib/GroupTheory/FiniteAbelian/Basic.lean b/Mathlib/GroupTheory/FiniteAbelian/Basic.lean index def95dc958b3bd..38fa544799b25d 100644 --- a/Mathlib/GroupTheory/FiniteAbelian/Basic.lean +++ b/Mathlib/GroupTheory/FiniteAbelian/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Pierre-Alexandre Bazin -/ import Mathlib.Algebra.Module.PID +import Mathlib.Algebra.Group.TypeTags.Finite import Mathlib.Data.ZMod.Quotient /-! diff --git a/Mathlib/GroupTheory/FiniteAbelian/Duality.lean b/Mathlib/GroupTheory/FiniteAbelian/Duality.lean index 308c47949bf395..dafdda97bea039 100644 --- a/Mathlib/GroupTheory/FiniteAbelian/Duality.lean +++ b/Mathlib/GroupTheory/FiniteAbelian/Duality.lean @@ -42,9 +42,9 @@ lemma exists_apply_ne_one_aux (H : ∀ n : ℕ, n ∣ Monoid.exponent G → ∀ obtain ⟨i, hi⟩ : ∃ i : ι, e a i ≠ 1 := by contrapose! ha exact (MulEquiv.map_eq_one_iff e).mp <| funext ha - have hi : Multiplicative.toAdd (e a i) ≠ 0 := by + have hi : (e a i).toAdd ≠ 0 := by simp only [ne_eq, toAdd_eq_zero, hi, not_false_eq_true] - obtain ⟨φi, hφi⟩ := H (n i) (dvd_exponent e i) (Multiplicative.toAdd <| e a i) hi + obtain ⟨φi, hφi⟩ := H (n i) (dvd_exponent e i) ((e a i).toAdd) hi use (φi.comp (Pi.evalMonoidHom (fun (i : ι) ↦ Multiplicative (ZMod (n i))) i)).comp e simpa only [coe_comp, coe_coe, Function.comp_apply, Pi.evalMonoidHom_apply, ne_eq] using hφi diff --git a/Mathlib/GroupTheory/Finiteness.lean b/Mathlib/GroupTheory/Finiteness.lean index 80895c9fc92ee9..bd31d6b8743b43 100644 --- a/Mathlib/GroupTheory/Finiteness.lean +++ b/Mathlib/GroupTheory/Finiteness.lean @@ -3,8 +3,8 @@ Copyright (c) 2021 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ +import Mathlib.Algebra.Group.Pointwise.Set.Finite import Mathlib.Algebra.Group.Subgroup.Pointwise -import Mathlib.Data.Set.Pointwise.Finite import Mathlib.GroupTheory.QuotientGroup.Defs import Mathlib.SetTheory.Cardinal.Finite diff --git a/Mathlib/GroupTheory/FreeAbelianGroup.lean b/Mathlib/GroupTheory/FreeAbelianGroup.lean index 163b552783eb7f..ad652f38aa3fcf 100644 --- a/Mathlib/GroupTheory/FreeAbelianGroup.lean +++ b/Mathlib/GroupTheory/FreeAbelianGroup.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ +import Mathlib.Algebra.Module.NatInt import Mathlib.GroupTheory.Abelianization import Mathlib.GroupTheory.FreeGroup.Basic diff --git a/Mathlib/GroupTheory/FreeGroup/Basic.lean b/Mathlib/GroupTheory/FreeGroup/Basic.lean index 35f5a97da6e4ab..2c47200b1ac4d8 100644 --- a/Mathlib/GroupTheory/FreeGroup/Basic.lean +++ b/Mathlib/GroupTheory/FreeGroup/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 -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.Data.Fintype.Basic import Mathlib.Data.List.Sublists @@ -48,6 +48,7 @@ free group, Newman's diamond lemma, Church-Rosser theorem -/ open Relation +open scoped List universe u v w @@ -906,6 +907,9 @@ def reduce : (L : List (α × Bool)) -> List (α × Bool) := List.casesOn ih [hd1] fun hd2 tl2 => if hd1.1 = hd2.1 ∧ hd1.2 = not hd2.2 then tl2 else hd1 :: hd2 :: tl2 +@[to_additive (attr := simp)] lemma reduce_nil : reduce ([] : List (α × Bool)) = [] := rfl +@[to_additive] lemma reduce_singleton (s : α × Bool) : reduce [s] = [s] := rfl + @[to_additive (attr := simp)] theorem reduce.cons (x) : reduce (x :: L) = @@ -1099,11 +1103,19 @@ theorem reduce_invRev {w : List (α × Bool)} : reduce (invRev w) = invRev (redu have : Red (invRev (invRev w)) (invRev (reduce (invRev w))) := reduce.red.invRev rwa [invRev_invRev] at this -@[to_additive] -theorem toWord_inv {x : FreeGroup α} : x⁻¹.toWord = invRev x.toWord := by +@[to_additive (attr := simp)] +theorem toWord_inv (x : FreeGroup α) : x⁻¹.toWord = invRev x.toWord := by rcases x with ⟨L⟩ rw [quot_mk_eq_mk, inv_mk, toWord_mk, toWord_mk, reduce_invRev] +@[to_additive] +lemma toWord_mul_sublist (x y : FreeGroup α) : (x * y).toWord <+ x.toWord ++ y.toWord := by + refine Red.sublist ?_ + have : x * y = FreeGroup.mk (x.toWord ++ y.toWord) := by + rw [← FreeGroup.mul_mk, FreeGroup.mk_toWord, FreeGroup.mk_toWord] + rw [this] + exact FreeGroup.reduce.red + /-- **Constructive Church-Rosser theorem** (compare `church_rosser`). -/ @[to_additive "**Constructive Church-Rosser theorem** (compare `church_rosser`)."] def reduce.churchRosser (H12 : Red L₁ L₂) (H13 : Red L₁ L₃) : { L₄ // Red L₂ L₄ ∧ Red L₃ L₄ } := diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index ed5ab1ed24c4a4..ae7eaef28b78d8 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Map import Mathlib.Data.Finite.Sigma import Mathlib.Data.Set.Finite.Basic import Mathlib.Data.Set.Finite.Range diff --git a/Mathlib/GroupTheory/GroupAction/Defs.lean b/Mathlib/GroupTheory/GroupAction/Defs.lean index e2621efee5a77c..fa15f5e7d62534 100644 --- a/Mathlib/GroupTheory/GroupAction/Defs.lean +++ b/Mathlib/GroupTheory/GroupAction/Defs.lean @@ -312,9 +312,15 @@ variable {G α} theorem orbitRel_apply {a b : α} : orbitRel G α a b ↔ a ∈ orbit G b := Iff.rfl -@[to_additive (attr := deprecated (since := "2024-10-18"))] +@[to_additive] alias orbitRel_r_apply := orbitRel_apply +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated orbitRel_apply (since := "2024-10-18")] orbitRel_r_apply +attribute [deprecated AddAction.orbitRel_apply (since := "2024-10-18")] AddAction.orbitRel_r_apply + + /-- When you take a set `U` in `α`, push it down to the quotient, and pull back, you get the union of the orbit of `U` under `G`. -/ @[to_additive @@ -431,7 +437,7 @@ nonrec lemma orbitRel.Quotient.orbit_nonempty (x : orbitRel.Quotient G α) : nonrec lemma orbitRel.Quotient.mapsTo_smul_orbit (g : G) (x : orbitRel.Quotient G α) : Set.MapsTo (g • ·) x.orbit x.orbit := by rw [orbitRel.Quotient.orbit_eq_orbit_out x Quotient.out_eq'] - exact mapsTo_smul_orbit g x.out' + exact mapsTo_smul_orbit g x.out @[to_additive] instance (x : orbitRel.Quotient G α) : MulAction G x.orbit where @@ -485,12 +491,12 @@ local notation "Ω" => orbitRel.Quotient G α /-- Decomposition of a type `X` as a disjoint union of its orbits under a group action. This version is expressed in terms of `MulAction.orbitRel.Quotient.orbit` instead of -`MulAction.orbit`, to avoid mentioning `Quotient.out'`. -/ +`MulAction.orbit`, to avoid mentioning `Quotient.out`. -/ @[to_additive "Decomposition of a type `X` as a disjoint union of its orbits under an additive group action. This version is expressed in terms of `AddAction.orbitRel.Quotient.orbit` instead of - `AddAction.orbit`, to avoid mentioning `Quotient.out'`. "] + `AddAction.orbit`, to avoid mentioning `Quotient.out`. "] def selfEquivSigmaOrbits' : α ≃ Σω : Ω, ω.orbit := letI := orbitRel G α calc @@ -503,7 +509,7 @@ def selfEquivSigmaOrbits' : α ≃ Σω : Ω, ω.orbit := @[to_additive "Decomposition of a type `X` as a disjoint union of its orbits under an additive group action."] -def selfEquivSigmaOrbits : α ≃ Σω : Ω, orbit G ω.out' := +def selfEquivSigmaOrbits : α ≃ Σω : Ω, orbit G ω.out := (selfEquivSigmaOrbits' G α).trans <| Equiv.sigmaCongrRight fun _ => Equiv.Set.ofEq <| orbitRel.Quotient.orbit_eq_orbit_out _ Quotient.out_eq' diff --git a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean index f968df45e92a92..38834797ad2224 100644 --- a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean +++ b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Antoine Chambert-Loir. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Antoine Chambert-Loir -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Lattice import Mathlib.GroupTheory.GroupAction.FixedPoints /-! diff --git a/Mathlib/GroupTheory/GroupAction/Hom.lean b/Mathlib/GroupTheory/GroupAction/Hom.lean index 95bd4983abab09..2ce20e3e8812bc 100644 --- a/Mathlib/GroupTheory/GroupAction/Hom.lean +++ b/Mathlib/GroupTheory/GroupAction/Hom.lean @@ -15,6 +15,7 @@ import Mathlib.Algebra.Group.Hom.CompTypeclasses * `MulActionHom φ X Y`, the type of equivariant functions from `X` to `Y`, where `φ : M → N` is a map, `M` acting on the type `X` and `N` acting on the type of `Y`. + `AddActionHom φ X Y` is its additive version. * `DistribMulActionHom φ A B`, the type of equivariant additive monoid homomorphisms from `A` to `B`, where `φ : M → N` is a morphism of monoids, @@ -25,7 +26,8 @@ import Mathlib.Algebra.Group.Hom.CompTypeclasses The above types have corresponding classes: * `MulActionHomClass F φ X Y` states that `F` is a type of bundled `X → Y` homs - which are `φ`-equivariant + which are `φ`-equivariant; + `AddActionHomClass F φ X Y` is its additive version. * `DistribMulActionHomClass F φ A B` states that `F` is a type of bundled `A → B` homs preserving the additive monoid structure and `φ`-equivariant * `SMulSemiringHomClass F φ R S` states that `F` is a type of bundled `R → S` homs @@ -35,14 +37,19 @@ The above types have corresponding classes: We introduce the following notation to code equivariant maps (the subscript index `ₑ` is for *equivariant*) : -* `X →ₑ[φ] Y` is `MulActionHom φ X Y`. +* `X →ₑ[φ] Y` is `MulActionHom φ X Y` and `AddActionHom φ X Y` * `A →ₑ+[φ] B` is `DistribMulActionHom φ A B`. * `R →ₑ+*[φ] S` is `MulSemiringActionHom φ R S`. When `M = N` and `φ = MonoidHom.id M`, we provide the backward compatible notation : -* `X →[M] Y` is `MulActionHom (@id M) X Y` +* `X →[M] Y` is `MulActionHom (@id M) X Y` and `AddActionHom (@id M) X Y` * `A →+[M] B` is `DistribMulActionHom (MonoidHom.id M) A B` * `R →+*[M] S` is `MulSemiringActionHom (MonoidHom.id M) R S` + +The notation for `MulActionHom` and `AddActionHom` is the same, because it is unlikely +that it could lead to confusion — unless one needs types `M` and `X` with simultaneous +instances of `Mul M`, `Add M`, `SMul M X` and `VAdd M X`… + -/ assert_not_exists Submonoid @@ -56,11 +63,21 @@ variable (X : Type*) [SMul M X] [SMul M' X] variable (Y : Type*) [SMul N Y] [SMul M' Y] variable (Z : Type*) [SMul P Z] +/-- Equivariant functions : +When `φ : M → N` is a function, and types `X` and `Y` are endowed with additive actions +of `M` and `N`, a function `f : X → Y` is `φ`-equivariant if `f (m +ᵥ x) = (φ m) +ᵥ (f x)`. -/ +structure AddActionHom {M N : Type*} (φ: M → N) (X : Type*) [VAdd M X] (Y : Type*) [VAdd N Y] where + /-- The underlying function. -/ + protected toFun : X → Y + /-- The proposition that the function commutes with the additive actions. -/ + protected map_vadd' : ∀ (m : M) (x : X), toFun (m +ᵥ x) = (φ m) +ᵥ toFun x + /-- 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)`. -/ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/5171): this linter isn't ported yet. -- @[nolint has_nonempty_instance] +@[to_additive] structure MulActionHom where /-- The underlying function. -/ protected toFun : X → Y @@ -70,20 +87,40 @@ structure MulActionHom where /- Porting note: local notation given a name, conflict with Algebra.Hom.GroupAction see https://github.com/leanprover/lean4/issues/2000 -/ /-- `φ`-equivariant functions `X → Y`, -where `φ : M → N`, where `M` and `N` act on `X` and `Y` respectively -/ +where `φ : M → N`, where `M` and `N` act on `X` and `Y` respectively.-/ notation:25 (name := «MulActionHomLocal≺») X " →ₑ[" φ:25 "] " Y:0 => MulActionHom φ X Y -/-- `M`-equivariant functions `X → Y` with respect to the action of `M` - -This is the same as `X →ₑ[@id M] Y` -/ +/-- `M`-equivariant functions `X → Y` with respect to the action of `M`. +This is the same as `X →ₑ[@id M] Y`. -/ notation:25 (name := «MulActionHomIdLocal≺») X " →[" M:25 "] " Y:0 => MulActionHom (@id M) X Y +/-- `φ`-equivariant functions `X → Y`, +where `φ : M → N`, where `M` and `N` act additively on `X` and `Y` respectively +We use the same notation as for multiplicative actions, as conflicts are unlikely. -/ +notation:25 (name := «AddActionHomLocal≺») X " →ₑ[" φ:25 "] " Y:0 => AddActionHom φ X Y + +/-- `M`-equivariant functions `X → Y` with respect to the additive action of `M`. +This is the same as `X →ₑ[@id M] Y`. + +We use the same notation as for multiplicative actions, as conflicts are unlikely. -/ +notation:25 (name := «AddActionHomIdLocal≺») X " →[" M:25 "] " Y:0 => AddActionHom (@id M) X Y + +/-- `AddActionSemiHomClass F φ X Y` states that + `F` is a type of morphisms which are `φ`-equivariant. + +You should extend this class when you extend `AddActionHom`. -/ +class AddActionSemiHomClass (F : Type*) + {M N : outParam Type*} (φ : outParam (M → N)) + (X Y : outParam Type*) [VAdd M X] [VAdd N Y] [FunLike F X Y] : Prop where + /-- The proposition that the function preserves the action. -/ + map_vaddₛₗ : ∀ (f : F) (c : M) (x : X), f (c +ᵥ x) = (φ c) +ᵥ (f x) /-- `MulActionSemiHomClass F φ X Y` states that `F` is a type of morphisms which are `φ`-equivariant. You should extend this class when you extend `MulActionHom`. -/ +@[to_additive] class MulActionSemiHomClass (F : Type*) {M N : outParam Type*} (φ : outParam (M → N)) (X Y : outParam Type*) [SMul M X] [SMul N Y] [FunLike F X Y] : Prop where @@ -91,19 +128,23 @@ class MulActionSemiHomClass (F : Type*) map_smulₛₗ : ∀ (f : F) (c : M) (x : X), f (c • x) = (φ c) • (f x) export MulActionSemiHomClass (map_smulₛₗ) +export AddActionSemiHomClass (map_vaddₛₗ) /-- `MulActionHomClass F M X Y` states that `F` is a type of morphisms which are equivariant with respect to actions of `M` This is an abbreviation of `MulActionSemiHomClass`. -/ +@[to_additive "`MulActionHomClass F M X Y` states that `F` is a type of +morphisms which are equivariant with respect to actions of `M` +This is an abbreviation of `MulActionSemiHomClass`."] abbrev MulActionHomClass (F : Type*) (M : outParam Type*) (X Y : outParam Type*) [SMul M X] [SMul M Y] [FunLike F X Y] := MulActionSemiHomClass F (@id M) X Y -instance : FunLike (MulActionHom φ X Y) X Y where +@[to_additive] instance : FunLike (MulActionHom φ X Y) X Y where coe := MulActionHom.toFun coe_injective' f g h := by cases f; cases g; congr -@[simp] +@[to_additive (attr := simp)] theorem map_smul {F M X Y : Type*} [SMul M X] [SMul M Y] [FunLike F X Y] [MulActionHomClass F M X Y] (f : F) (c : M) (x : X) : f (c • x) = c • f x := @@ -113,10 +154,12 @@ theorem map_smul {F M X Y : Type*} [SMul M X] [SMul M Y] -- Porting note: removed has_coe_to_fun instance, coercions handled differently now +@[to_additive] instance : MulActionSemiHomClass (X →ₑ[φ] Y) φ X Y where map_smulₛₗ := MulActionHom.map_smul' initialize_simps_projections MulActionHom (toFun → apply) +initialize_simps_projections AddActionHom (toFun → apply) namespace MulActionHom @@ -128,7 +171,10 @@ see also Algebra.Hom.Group -/ /-- Turn an element of a type `F` satisfying `MulActionSemiHomClass F φ X Y` into an actual `MulActionHom`. This is declared as the default coercion from `F` to `MulActionSemiHom φ X Y`. -/ -@[coe] +@[to_additive (attr := coe) + "Turn an element of a type `F` satisfying `AddActionSemiHomClass F φ X Y` + into an actual `AddActionHom`. + This is declared as the default coercion from `F` to `AddActionSemiHom φ X Y`."] def _root_.MulActionSemiHomClass.toMulActionHom [MulActionSemiHomClass F φ X Y] (f : F) : X →ₑ[φ] Y where toFun := DFunLike.coe f @@ -136,39 +182,44 @@ def _root_.MulActionSemiHomClass.toMulActionHom [MulActionSemiHomClass F φ X Y] /-- Any type satisfying `MulActionSemiHomClass` can be cast into `MulActionHom` via `MulActionHomSemiClass.toMulActionHom`. -/ +@[to_additive] instance [MulActionSemiHomClass F φ X Y] : CoeTC F (X →ₑ[φ] Y) := ⟨MulActionSemiHomClass.toMulActionHom⟩ variable (M' X Y F) in /-- If Y/X/M forms a scalar tower, any map X → Y preserving X-action also preserves M-action. -/ +@[to_additive] theorem _root_.IsScalarTower.smulHomClass [MulOneClass X] [SMul X Y] [IsScalarTower M' X Y] [MulActionHomClass F X X Y] : MulActionHomClass F M' X Y where map_smulₛₗ f m x := by rw [← mul_one (m • x), ← smul_eq_mul, map_smul, smul_assoc, ← map_smul, smul_eq_mul, mul_one, id_eq] +@[to_additive] protected theorem map_smul (f : X →[M'] Y) (m : M') (x : X) : f (m • x) = m • f x := map_smul f m x -@[ext] +@[to_additive (attr := ext)] theorem ext {f g : X →ₑ[φ] Y} : (∀ x, f x = g x) → f = g := DFunLike.ext f g +@[to_additive] protected theorem congr_fun {f g : X →ₑ[φ] Y} (h : f = g) (x : X) : f x = g x := DFunLike.congr_fun h _ /-- Two equal maps on scalars give rise to an equivariant map for identity -/ +@[to_additive "Two equal maps on scalars give rise to an equivariant map for identity"] def ofEq {φ' : M → N} (h : φ = φ') (f : X →ₑ[φ] Y) : X →ₑ[φ'] Y where toFun := f.toFun map_smul' m a := h ▸ f.map_smul' m a -@[simp] +@[to_additive (attr := simp)] theorem ofEq_coe {φ' : M → N} (h : φ = φ') (f : X →ₑ[φ] Y) : (f.ofEq h).toFun = f.toFun := rfl -@[simp] +@[to_additive (attr := simp)] theorem ofEq_apply {φ' : M → N} (h : φ = φ') (f : X →ₑ[φ] Y) (a : X) : (f.ofEq h) a = f a := rfl @@ -177,12 +228,13 @@ theorem ofEq_apply {φ' : M → N} (h : φ = φ') (f : X →ₑ[φ] Y) (a : X) : variable {ψ χ} (M N) /-- The identity map as an equivariant map. -/ +@[to_additive "The identity map as an equivariant map."] protected def id : X →[M] X := ⟨id, fun _ _ => rfl⟩ variable {M N Z} -@[simp] +@[to_additive (attr := simp)] theorem id_apply (x : X) : MulActionHom.id M x = x := rfl @@ -197,6 +249,7 @@ variable {φ ψ χ X Y Z} -- attribute [instance] CompTriple.id_comp CompTriple.comp_id /-- Composition of two equivariant maps. -/ +@[to_additive "Composition of two equivariant maps."] def comp (g : Y →ₑ[ψ] Z) (f : X →ₑ[φ] Y) [κ : CompTriple φ ψ χ] : X →ₑ[χ] Z := ⟨g ∘ f, fun m x => @@ -206,22 +259,22 @@ def comp (g : Y →ₑ[ψ] Z) (f : X →ₑ[φ] Y) [κ : CompTriple φ ψ χ] : _ = (ψ ∘ φ) m • g (f x) := rfl _ = χ m • g (f x) := by rw [κ.comp_eq] ⟩ -@[simp] +@[to_additive (attr := simp)] theorem comp_apply (g : Y →ₑ[ψ] Z) (f : X →ₑ[φ] Y) [CompTriple φ ψ χ] (x : X) : g.comp f x = g (f x) := rfl -@[simp] +@[to_additive (attr := simp)] theorem id_comp (f : X →ₑ[φ] Y) : (MulActionHom.id N).comp f = f := ext fun x => by rw [comp_apply, id_apply] -@[simp] +@[to_additive (attr := simp)] theorem comp_id (f : X →ₑ[φ] Y) : f.comp (MulActionHom.id M) = f := ext fun x => by rw [comp_apply, id_apply] -@[simp] +@[to_additive (attr := simp)] theorem comp_assoc {Q T : Type*} [SMul Q T] {η : P → Q} {θ : M → Q} {ζ : N → Q} (h : Z →ₑ[η] T) (g : Y →ₑ[ψ] Z) (f : X →ₑ[φ] Y) @@ -232,8 +285,9 @@ theorem comp_assoc {Q T : Type*} [SMul Q T] variable {φ' : N → M} variable {Y₁ : Type*} [SMul M Y₁] + /-- The inverse of a bijective equivariant map is equivariant. -/ -@[simps] +@[to_additive (attr := simps) "The inverse of a bijective equivariant map is equivariant."] def inverse (f : X →[M] Y₁) (g : Y₁ → X) (h₁ : Function.LeftInverse g f) (h₂ : Function.RightInverse g f) : Y₁ →[M] X where toFun := g @@ -245,7 +299,7 @@ def inverse (f : X →[M] Y₁) (g : Y₁ → X) /-- The inverse of a bijective equivariant map is equivariant. -/ -@[simps] +@[to_additive (attr := simps) "The inverse of a bijective equivariant map is equivariant."] def inverse' (f : X →ₑ[φ] Y) (g : Y → X) (k : Function.RightInverse φ' φ) (h₁ : Function.LeftInverse g f) (h₂ : Function.RightInverse g f) : Y →ₑ[φ'] X where @@ -257,11 +311,13 @@ def inverse' (f : X →ₑ[φ] Y) (g : Y → X) (k : Function.RightInverse φ' _ = g (f (φ' m • g x)) := by rw [map_smulₛₗ] _ = φ' m • g x := by rw [h₁] +@[to_additive] lemma inverse_eq_inverse' (f : X →[M] Y₁) (g : Y₁ → X) (h₁ : Function.LeftInverse g f) (h₂ : Function.RightInverse g f) : inverse f g h₁ h₂ = inverse' f g (congrFun rfl) h₁ h₂ := by rfl +@[to_additive] theorem inverse'_inverse' {f : X →ₑ[φ] Y} {g : Y → X} {k₁ : Function.LeftInverse φ' φ} {k₂ : Function.RightInverse φ' φ} @@ -269,6 +325,7 @@ theorem inverse'_inverse' inverse' (inverse' f g k₂ h₁ h₂) f k₁ h₂ h₁ = f := ext fun _ => rfl +@[to_additive] theorem comp_inverse' {f : X →ₑ[φ] Y} {g : Y → X} {k₁ : Function.LeftInverse φ' φ} {k₂ : Function.RightInverse φ' φ} {h₁ : Function.LeftInverse g f} {h₂ : Function.RightInverse g f} : @@ -279,6 +336,7 @@ theorem comp_inverse' {f : X →ₑ[φ] Y} {g : Y → X} simp only [comp_apply, inverse_apply, id_apply] exact h₁ x +@[to_additive] theorem inverse'_comp {f : X →ₑ[φ] Y} {g : Y → X} {k₂ : Function.RightInverse φ' φ} {h₁ : Function.LeftInverse g f} {h₂ : Function.RightInverse g f} : @@ -290,7 +348,8 @@ theorem inverse'_comp {f : X →ₑ[φ] Y} {g : Y → X} /-- If actions of `M` and `N` on `α` commute, then for `c : M`, `(c • · : α → α)` is an `N`-action homomorphism. -/ -@[simps] +@[to_additive (attr := simps) "If additive actions of `M` and `N` on `α` commute, + then for `c : M`, `(c • · : α → α)` is an `N`-additive action homomorphism."] def _root_.SMulCommClass.toMulActionHom {M} (N α : Type*) [SMul M α] [SMul N α] [SMulCommClass M N α] (c : M) : α →[N] α where diff --git a/Mathlib/GroupTheory/GroupAction/Quotient.lean b/Mathlib/GroupTheory/GroupAction/Quotient.lean index af70bfbcd8453b..778fb1159400a2 100644 --- a/Mathlib/GroupTheory/GroupAction/Quotient.lean +++ b/Mathlib/GroupTheory/GroupAction/Quotient.lean @@ -90,19 +90,43 @@ theorem Quotient.smul_coe [QuotientAction β H] (b : β) (a : α) : rfl @[to_additive (attr := simp)] -theorem Quotient.mk_smul_out' [QuotientAction β H] (b : β) (q : α ⧸ H) : - QuotientGroup.mk (b • q.out') = b • q := by rw [← Quotient.smul_mk, QuotientGroup.out_eq'] +theorem Quotient.mk_smul_out [QuotientAction β H] (b : β) (q : α ⧸ H) : + QuotientGroup.mk (b • q.out) = b • q := by rw [← Quotient.smul_mk, QuotientGroup.out_eq'] -- Porting note: removed simp attribute, simp can prove this @[to_additive] -theorem Quotient.coe_smul_out' [QuotientAction β H] (b : β) (q : α ⧸ H) : ↑(b • q.out') = b • q := - Quotient.mk_smul_out' H b q +theorem Quotient.coe_smul_out [QuotientAction β H] (b : β) (q : α ⧸ H) : ↑(b • q.out) = b • q := + Quotient.mk_smul_out H b q -theorem _root_.QuotientGroup.out'_conj_pow_minimalPeriod_mem (a : α) (q : α ⧸ H) : - q.out'⁻¹ * a ^ Function.minimalPeriod (a • ·) q * q.out' ∈ H := by - rw [mul_assoc, ← QuotientGroup.eq, QuotientGroup.out_eq', ← smul_eq_mul, Quotient.mk_smul_out', +theorem _root_.QuotientGroup.out_conj_pow_minimalPeriod_mem (a : α) (q : α ⧸ H) : + q.out⁻¹ * a ^ Function.minimalPeriod (a • ·) q * q.out ∈ H := by + rw [mul_assoc, ← QuotientGroup.eq, QuotientGroup.out_eq', ← smul_eq_mul, Quotient.mk_smul_out, eq_comm, pow_smul_eq_iff_minimalPeriod_dvd] +@[to_additive] +alias Quotient.mk_smul_out' := Quotient.mk_smul_out + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated Quotient.mk_smul_out (since := "2024-10-19")] Quotient.mk_smul_out' +attribute [deprecated AddAction.Quotient.mk_vadd_out (since := "2024-10-19")] +AddAction.Quotient.mk_vadd_out' + +-- Porting note: removed simp attribute, simp can prove this +@[to_additive] +alias Quotient.coe_smul_out' := Quotient.coe_smul_out + +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated Quotient.coe_smul_out (since := "2024-10-19")] Quotient.coe_smul_out' +attribute [deprecated AddAction.Quotient.coe_vadd_out (since := "2024-10-19")] +AddAction.Quotient.coe_vadd_out' + + +@[deprecated (since := "2024-10-19")] +alias _root_.QuotientGroup.out'_conj_pow_minimalPeriod_mem := + QuotientGroup.out_conj_pow_minimalPeriod_mem + end QuotientAction open QuotientGroup @@ -192,14 +216,14 @@ local notation "Ω" => Quotient <| orbitRel α β /-- **Class formula** : given `G` a group acting on `X` and `φ` a function mapping each orbit of `X` under this action (that is, each element of the quotient of `X` by the relation `orbitRel G X`) to an element in this orbit, this gives a (noncomputable) bijection between `X` and the disjoint union -of `G/Stab(φ(ω))` over all orbits `ω`. In most cases you'll want `φ` to be `Quotient.out'`, so we +of `G/Stab(φ(ω))` over all orbits `ω`. In most cases you'll want `φ` to be `Quotient.out`, so we provide `MulAction.selfEquivSigmaOrbitsQuotientStabilizer'` as a special case. -/ @[to_additive "**Class formula** : given `G` an additive group acting on `X` and `φ` a function mapping each orbit of `X` under this action (that is, each element of the quotient of `X` by the relation `orbit_rel G X`) to an element in this orbit, this gives a (noncomputable) bijection between `X` and the disjoint union of `G/Stab(φ(ω))` over all orbits `ω`. In most - cases you'll want `φ` to be `Quotient.out'`, so we provide + cases you'll want `φ` to be `Quotient.out`, so we provide `AddAction.selfEquivSigmaOrbitsQuotientStabilizer'` as a special case. "] noncomputable def selfEquivSigmaOrbitsQuotientStabilizer' {φ : Ω → β} (hφ : LeftInverse Quotient.mk'' φ) : β ≃ Σω : Ω, α ⧸ stabilizer α (φ ω) := @@ -212,11 +236,11 @@ noncomputable def selfEquivSigmaOrbitsQuotientStabilizer' {φ : Ω → β} /-- **Class formula** for a finite group acting on a finite type. See `MulAction.card_eq_sum_card_group_div_card_stabilizer` for a specialized version using -`Quotient.out'`. -/ +`Quotient.out`. -/ @[to_additive "**Class formula** for a finite group acting on a finite type. See `AddAction.card_eq_sum_card_addGroup_div_card_stabilizer` for a specialized version using - `Quotient.out'`."] + `Quotient.out`."] theorem card_eq_sum_card_group_div_card_stabilizer' [Fintype α] [Fintype β] [Fintype Ω] [∀ b : β, Fintype <| stabilizer α b] {φ : Ω → β} (hφ : LeftInverse Quotient.mk'' φ) : Fintype.card β = ∑ ω : Ω, Fintype.card α / Fintype.card (stabilizer α (φ ω)) := by @@ -231,18 +255,18 @@ theorem card_eq_sum_card_group_div_card_stabilizer' [Fintype α] [Fintype β] [F Fintype.card_congr (selfEquivSigmaOrbitsQuotientStabilizer' α β hφ)] /-- **Class formula**. This is a special case of -`MulAction.self_equiv_sigma_orbits_quotient_stabilizer'` with `φ = Quotient.out'`. -/ +`MulAction.self_equiv_sigma_orbits_quotient_stabilizer'` with `φ = Quotient.out`. -/ @[to_additive "**Class formula**. This is a special case of - `AddAction.self_equiv_sigma_orbits_quotient_stabilizer'` with `φ = Quotient.out'`. "] -noncomputable def selfEquivSigmaOrbitsQuotientStabilizer : β ≃ Σω : Ω, α ⧸ stabilizer α ω.out' := + `AddAction.self_equiv_sigma_orbits_quotient_stabilizer'` with `φ = Quotient.out`. "] +noncomputable def selfEquivSigmaOrbitsQuotientStabilizer : β ≃ Σω : Ω, α ⧸ stabilizer α ω.out := selfEquivSigmaOrbitsQuotientStabilizer' α β Quotient.out_eq' /-- **Class formula** for a finite group acting on a finite type. -/ @[to_additive "**Class formula** for a finite group acting on a finite type."] theorem card_eq_sum_card_group_div_card_stabilizer [Fintype α] [Fintype β] [Fintype Ω] [∀ b : β, Fintype <| stabilizer α b] : - Fintype.card β = ∑ ω : Ω, Fintype.card α / Fintype.card (stabilizer α ω.out') := + Fintype.card β = ∑ ω : Ω, Fintype.card α / Fintype.card (stabilizer α ω.out) := card_eq_sum_card_group_div_card_stabilizer' α β Quotient.out_eq' /-- **Burnside's lemma** : a (noncomputable) bijection between the disjoint union of all @@ -259,16 +283,16 @@ noncomputable def sigmaFixedByEquivOrbitsProdGroup : (Σa : α, fixedBy β a) _ ≃ { ba : β × α // ba.2 • ba.1 = ba.1 } := (Equiv.prodComm α β).subtypeEquiv fun _ => Iff.rfl _ ≃ Σb : β, stabilizer α b := Equiv.subtypeProdEquivSigmaSubtype fun (b : β) a => a ∈ stabilizer α b - _ ≃ Σωb : Σω : Ω, orbit α ω.out', stabilizer α (ωb.2 : β) := + _ ≃ Σωb : Σω : Ω, orbit α ω.out, stabilizer α (ωb.2 : β) := (selfEquivSigmaOrbits α β).sigmaCongrLeft' - _ ≃ Σω : Ω, Σb : orbit α ω.out', stabilizer α (b : β) := - Equiv.sigmaAssoc fun (ω : Ω) (b : orbit α ω.out') => stabilizer α (b : β) - _ ≃ Σω : Ω, Σ _ : orbit α ω.out', stabilizer α ω.out' := + _ ≃ Σω : Ω, Σb : orbit α ω.out, stabilizer α (b : β) := + Equiv.sigmaAssoc fun (ω : Ω) (b : orbit α ω.out) => stabilizer α (b : β) + _ ≃ Σω : Ω, Σ _ : orbit α ω.out, stabilizer α ω.out := Equiv.sigmaCongrRight fun _ => Equiv.sigmaCongrRight fun ⟨_, hb⟩ => (stabilizerEquivStabilizerOfOrbitRel hb).toEquiv - _ ≃ Σω : Ω, orbit α ω.out' × stabilizer α ω.out' := + _ ≃ Σω : Ω, orbit α ω.out × stabilizer α ω.out := Equiv.sigmaCongrRight fun _ => Equiv.sigmaEquivProd _ _ - _ ≃ Σ _ : Ω, α := Equiv.sigmaCongrRight fun ω => orbitProdStabilizerEquivGroup α ω.out' + _ ≃ Σ _ : Ω, α := Equiv.sigmaCongrRight fun ω => orbitProdStabilizerEquivGroup α ω.out _ ≃ Ω × α := Equiv.sigmaEquivProd Ω α /-- **Burnside's lemma** : given a finite group `G` acting on a set `X`, the average number of diff --git a/Mathlib/GroupTheory/Index.lean b/Mathlib/GroupTheory/Index.lean index 8357feb56afc92..c31a41f62822f5 100644 --- a/Mathlib/GroupTheory/Index.lean +++ b/Mathlib/GroupTheory/Index.lean @@ -554,6 +554,17 @@ variable {H K} theorem finiteIndex_of_le [FiniteIndex H] (h : H ≤ K) : FiniteIndex K := ⟨ne_zero_of_dvd_ne_zero FiniteIndex.finiteIndex (index_dvd_of_le h)⟩ +@[to_additive (attr := gcongr)] +lemma index_antitone (h : H ≤ K) [H.FiniteIndex] : K.index ≤ H.index := + Nat.le_of_dvd (Nat.zero_lt_of_ne_zero FiniteIndex.finiteIndex) (index_dvd_of_le h) + +@[to_additive (attr := gcongr)] +lemma index_strictAnti (h : H < K) [H.FiniteIndex] : K.index < H.index := by + have h0 : K.index ≠ 0 := (finiteIndex_of_le h.le).finiteIndex + apply lt_of_le_of_ne (index_antitone h.le) + rw [← relindex_mul_index h.le, Ne, eq_comm, mul_eq_right₀ h0, relindex_eq_one] + exact h.not_le + variable (H K) @[to_additive] diff --git a/Mathlib/GroupTheory/NoncommPiCoprod.lean b/Mathlib/GroupTheory/NoncommPiCoprod.lean index 3e22ae8416ac7f..e5b14b7d091184 100644 --- a/Mathlib/GroupTheory/NoncommPiCoprod.lean +++ b/Mathlib/GroupTheory/NoncommPiCoprod.lean @@ -30,7 +30,7 @@ images of different morphisms commute, we obtain a canonical morphism * `MonoidHom.noncommPiCoprod_range`: The range of `MonoidHom.noncommPiCoprod` is `⨆ (i : ι), (ϕ i).range` * `Subgroup.noncommPiCoprod_range`: The range of `Subgroup.noncommPiCoprod` is `⨆ (i : ι), H i`. -* `MonoidHom.injective_noncommPiCoprod_of_independent`: in the case of groups, `pi_hom.hom` is +* `MonoidHom.injective_noncommPiCoprod_of_iSupIndep`: in the case of groups, `pi_hom.hom` is injective if the `ϕ` are injective and the ranges of the `ϕ` are independent. * `MonoidHom.independent_range_of_coprime_order`: If the `N i` have coprime orders, then the ranges of the `ϕ` are independent. @@ -48,8 +48,8 @@ variable {G : Type*} [Group G] generalizes (one direction of) `Subgroup.disjoint_iff_mul_eq_one`. -/ @[to_additive "`Finset.noncommSum` is “injective” in `f` if `f` maps into independent subgroups. This generalizes (one direction of) `AddSubgroup.disjoint_iff_add_eq_zero`. "] -theorem eq_one_of_noncommProd_eq_one_of_independent {ι : Type*} (s : Finset ι) (f : ι → G) (comm) - (K : ι → Subgroup G) (hind : CompleteLattice.Independent K) (hmem : ∀ x ∈ s, f x ∈ K x) +theorem eq_one_of_noncommProd_eq_one_of_iSupIndep {ι : Type*} (s : Finset ι) (f : ι → G) (comm) + (K : ι → Subgroup G) (hind : iSupIndep K) (hmem : ∀ x ∈ s, f x ∈ K x) (heq1 : s.noncommProd f comm = 1) : ∀ i ∈ s, f i = 1 := by classical revert heq1 @@ -73,6 +73,9 @@ theorem eq_one_of_noncommProd_eq_one_of_independent {ι : Type*} (s : Finset ι) · exact heq1i · refine ih hcomm hmem.2 heq1S _ h +@[deprecated (since := "2024-11-24")] +alias eq_one_of_noncommProd_eq_one_of_independent := eq_one_of_noncommProd_eq_one_of_iSupIndep + end Subgroup section FamilyOfMonoids @@ -200,27 +203,30 @@ theorem noncommPiCoprod_range [Fintype ι] exact ⟨Pi.mulSingle i y, noncommPiCoprod_mulSingle _ _ _⟩ @[to_additive] -theorem injective_noncommPiCoprod_of_independent [Fintype ι] +theorem injective_noncommPiCoprod_of_iSupIndep [Fintype ι] {hcomm : Pairwise fun i j : ι => ∀ (x : H i) (y : H j), Commute (ϕ i x) (ϕ j y)} - (hind : CompleteLattice.Independent fun i => (ϕ i).range) + (hind : iSupIndep fun i => (ϕ i).range) (hinj : ∀ i, Function.Injective (ϕ i)) : Function.Injective (noncommPiCoprod ϕ hcomm) := by classical apply (MonoidHom.ker_eq_bot_iff _).mp rw [eq_bot_iff] intro f heq1 have : ∀ i, i ∈ Finset.univ → ϕ i (f i) = 1 := - Subgroup.eq_one_of_noncommProd_eq_one_of_independent _ _ (fun _ _ _ _ h => hcomm h _ _) + Subgroup.eq_one_of_noncommProd_eq_one_of_iSupIndep _ _ (fun _ _ _ _ h => hcomm h _ _) _ hind (by simp) heq1 ext i apply hinj simp [this i (Finset.mem_univ i)] +@[deprecated (since := "2024-11-24")] +alias injective_noncommPiCoprod_of_independent := injective_noncommPiCoprod_of_iSupIndep + @[to_additive] theorem independent_range_of_coprime_order (hcomm : Pairwise fun i j : ι => ∀ (x : H i) (y : H j), Commute (ϕ i x) (ϕ j y)) [Finite ι] [∀ i, Fintype (H i)] (hcoprime : Pairwise fun i j => Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : - CompleteLattice.Independent fun i => (ϕ i).range := by + iSupIndep fun i => (ϕ i).range := by cases nonempty_fintype ι letI := Classical.decEq ι rintro i @@ -279,7 +285,7 @@ theorem independent_of_coprime_order (hcomm : Pairwise fun i j : ι => ∀ x y : G, x ∈ H i → y ∈ H j → Commute x y) [Finite ι] [∀ i, Fintype (H i)] (hcoprime : Pairwise fun i j => Nat.Coprime (Fintype.card (H i)) (Fintype.card (H j))) : - CompleteLattice.Independent H := by + iSupIndep H := by simpa using MonoidHom.independent_range_of_coprime_order (fun i => (H i).subtype) (commute_subtype_of_commute hcomm) hcoprime @@ -306,11 +312,11 @@ theorem noncommPiCoprod_range simp [noncommPiCoprod, MonoidHom.noncommPiCoprod_range] @[to_additive] -theorem injective_noncommPiCoprod_of_independent +theorem injective_noncommPiCoprod_of_iSupIndep {hcomm : Pairwise fun i j : ι => ∀ x y : G, x ∈ H i → y ∈ H j → Commute x y} - (hind : CompleteLattice.Independent H) : + (hind : iSupIndep H) : Function.Injective (noncommPiCoprod hcomm) := by - apply MonoidHom.injective_noncommPiCoprod_of_independent + apply MonoidHom.injective_noncommPiCoprod_of_iSupIndep · simpa using hind · intro i exact Subtype.coe_injective diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 8142e71f6f6538..b18e30f62e7814 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -5,7 +5,9 @@ Authors: Johannes Hölzl, Julian Kuelshammer -/ import Mathlib.Algebra.CharP.Defs import Mathlib.Algebra.Group.Subgroup.Finite +import Mathlib.Algebra.Module.NatInt import Mathlib.Algebra.Order.Group.Action +import Mathlib.Algebra.Order.Ring.Abs import Mathlib.GroupTheory.Index import Mathlib.Order.Interval.Set.Infinite @@ -86,9 +88,14 @@ theorem not_isOfFinOrder_of_injective_pow {x : G} (h : Injective fun n : ℕ => theorem IsOfFinOrder.one : IsOfFinOrder (1 : G) := isOfFinOrder_iff_pow_eq_one.mpr ⟨1, Nat.one_pos, one_pow 1⟩ -@[to_additive (attr := deprecated (since := "2024-10-11"))] +@[to_additive] alias isOfFinOrder_one := IsOfFinOrder.one +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated IsOfFinOrder.one (since := "2024-10-11")] isOfFinOrder_one +attribute [deprecated IsOfFinAddOrder.zero (since := "2024-10-11")] isOfFinAddOrder_zero + @[to_additive] lemma IsOfFinOrder.pow {n : ℕ} : IsOfFinOrder a → IsOfFinOrder (a ^ n) := by simp_rw [isOfFinOrder_iff_pow_eq_one] diff --git a/Mathlib/GroupTheory/PGroup.lean b/Mathlib/GroupTheory/PGroup.lean index 9b119d28f05df6..071291b214ad55 100644 --- a/Mathlib/GroupTheory/PGroup.lean +++ b/Mathlib/GroupTheory/PGroup.lean @@ -189,7 +189,7 @@ theorem card_modEq_card_fixedPoints : Nat.card α ≡ Nat.card (fixedPoints G α theorem nonempty_fixed_point_of_prime_not_dvd_card (α) [MulAction G α] (hpα : ¬p ∣ Nat.card α) : (fixedPoints G α).Nonempty := have : Finite α := Nat.finite_of_card_ne_zero (fun h ↦ (h ▸ hpα) (dvd_zero p)) - @Set.nonempty_of_nonempty_subtype _ _ + @Set.Nonempty.of_subtype _ _ (by rw [← Finite.card_pos_iff, pos_iff_ne_zero] contrapose! hpα diff --git a/Mathlib/GroupTheory/Perm/ClosureSwap.lean b/Mathlib/GroupTheory/Perm/ClosureSwap.lean index b00b89f6c6ce77..2256c8a2e0210f 100644 --- a/Mathlib/GroupTheory/Perm/ClosureSwap.lean +++ b/Mathlib/GroupTheory/Perm/ClosureSwap.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Thomas Browning, Junyan Xu. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning, Junyan Xu -/ +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.FixedPoints import Mathlib.GroupTheory.Perm.Support diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index d09dd86518f644..bfb55453b7c78a 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -3,14 +3,15 @@ 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.Subgroup.Basic +import Mathlib.Algebra.Group.Conj +import Mathlib.Algebra.Group.Subgroup.Lattice import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Ring.Int.Units import Mathlib.Data.Finset.Fin import Mathlib.Data.Finset.Sort +import Mathlib.Data.Fintype.Prod import Mathlib.Data.Fintype.Sum import Mathlib.Data.Int.Order.Units -import Mathlib.Data.Fintype.Prod import Mathlib.GroupTheory.Perm.Support import Mathlib.Logic.Equiv.Fin import Mathlib.Tactic.NormNum.Ineq diff --git a/Mathlib/GroupTheory/PresentedGroup.lean b/Mathlib/GroupTheory/PresentedGroup.lean index ddfb60a247e999..dccb34fb884fd7 100644 --- a/Mathlib/GroupTheory/PresentedGroup.lean +++ b/Mathlib/GroupTheory/PresentedGroup.lean @@ -3,6 +3,7 @@ Copyright (c) 2019 Michael Howes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Howes, Newell Jensen -/ +import Mathlib.Algebra.Group.Subgroup.Basic import Mathlib.GroupTheory.FreeGroup.Basic import Mathlib.GroupTheory.QuotientGroup.Defs diff --git a/Mathlib/GroupTheory/QuotientGroup/Basic.lean b/Mathlib/GroupTheory/QuotientGroup/Basic.lean index 4495ebe68b0785..3c1822db6828da 100644 --- a/Mathlib/GroupTheory/QuotientGroup/Basic.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Basic.lean @@ -6,6 +6,7 @@ Authors: Kevin Buzzard, Patrick Massot -- This file is to a certain extent based on `quotient_module.lean` by Johannes Hölzl. import Mathlib.Algebra.Group.Subgroup.Pointwise +import Mathlib.Data.Int.Cast.Lemmas import Mathlib.GroupTheory.Congruence.Hom import Mathlib.GroupTheory.Coset.Basic import Mathlib.GroupTheory.QuotientGroup.Defs diff --git a/Mathlib/GroupTheory/QuotientGroup/Defs.lean b/Mathlib/GroupTheory/QuotientGroup/Defs.lean index f193d7652942f3..d33a94cc017c64 100644 --- a/Mathlib/GroupTheory/QuotientGroup/Defs.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Defs.lean @@ -5,7 +5,7 @@ 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.Basic +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.GroupTheory.Congruence.Hom import Mathlib.GroupTheory.Coset.Defs diff --git a/Mathlib/GroupTheory/SemidirectProduct.lean b/Mathlib/GroupTheory/SemidirectProduct.lean index f3ac71a7ce4c70..f89efaef708f7f 100644 --- a/Mathlib/GroupTheory/SemidirectProduct.lean +++ b/Mathlib/GroupTheory/SemidirectProduct.lean @@ -3,7 +3,8 @@ Copyright (c) 2020 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Aut +import Mathlib.Algebra.Group.Subgroup.Ker /-! # Semidirect product diff --git a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean index 982ee49d373ef2..8b0f82d484a0d0 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean @@ -78,7 +78,6 @@ theorem IsThreeCycle.mem_alternatingGroup {f : Perm α} (h : IsThreeCycle f) : f ∈ alternatingGroup α := Perm.mem_alternatingGroup.mpr h.sign -set_option linter.deprecated false in theorem finRotate_bit1_mem_alternatingGroup {n : ℕ} : finRotate (2 * n + 1) ∈ alternatingGroup (Fin (2 * n + 1)) := by rw [mem_alternatingGroup, sign_finRotate, pow_mul, pow_two, Int.units_mul_self, one_pow] diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index ca2a56cc761c72..d13254a943cc7b 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -327,10 +327,17 @@ lemma isCyclic_iff_exists_ofOrder_eq_natCard [Finite α] : refine isCyclic_of_orderOf_eq_card g ?_ simp [hg] -@[to_additive (attr := deprecated (since := "2024-04-20"))] +@[to_additive] protected alias IsCyclic.iff_exists_ofOrder_eq_natCard_of_Fintype := isCyclic_iff_exists_ofOrder_eq_natCard +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated isCyclic_iff_exists_ofOrder_eq_natCard (since := "2024-04-20")] +IsCyclic.iff_exists_ofOrder_eq_natCard_of_Fintype +attribute [deprecated isAddCyclic_iff_exists_ofOrder_eq_natCard (since := "2024-04-20")] +IsAddCyclic.iff_exists_ofOrder_eq_natCard_of_Fintype + section variable [Fintype α] @@ -551,7 +558,7 @@ instance (priority := 100) isCyclic : IsCyclic α := by theorem prime_card [Finite α] : (Nat.card α).Prime := by have h0 : 0 < Nat.card α := Nat.card_pos obtain ⟨g, hg⟩ := IsCyclic.exists_generator (α := α) - rw [Nat.prime_def_lt''] + rw [Nat.prime_def] refine ⟨Finite.one_lt_card_iff_nontrivial.2 inferInstance, fun n hn => ?_⟩ refine (IsSimpleOrder.eq_bot_or_eq_top (Subgroup.zpowers (g ^ n))).symm.imp ?_ ?_ · intro h diff --git a/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean b/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean index 3ce9f9ecba4d98..318e8a450260d8 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Julian Kuelshammer -/ import Mathlib.Data.ZMod.Basic -import Mathlib.Algebra.Group.Nat import Mathlib.Tactic.IntervalCases import Mathlib.GroupTheory.SpecificGroups.Dihedral import Mathlib.GroupTheory.SpecificGroups.Cyclic diff --git a/Mathlib/GroupTheory/Subgroup/Saturated.lean b/Mathlib/GroupTheory/Subgroup/Saturated.lean index 6cbc7b2c45d712..e68e30ed0f3039 100644 --- a/Mathlib/GroupTheory/Subgroup/Saturated.lean +++ b/Mathlib/GroupTheory/Subgroup/Saturated.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.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Subgroup.Ker import Mathlib.Algebra.NoZeroSMulDivisors.Defs /-! diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index 55217195596227..fdfa524a631b97 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -806,7 +806,7 @@ noncomputable def directProductOfNormal [Finite G] apply MulEquiv.ofBijective (Subgroup.noncommPiCoprod hcomm) apply (Fintype.bijective_iff_injective_and_card _).mpr constructor - · apply Subgroup.injective_noncommPiCoprod_of_independent + · apply Subgroup.injective_noncommPiCoprod_of_iSupIndep apply independent_of_coprime_order hcomm rintro ⟨p₁, hp₁⟩ ⟨p₂, hp₂⟩ hne haveI hp₁' := Fact.mk (Nat.prime_of_mem_primeFactors hp₁) diff --git a/Mathlib/GroupTheory/Transfer.lean b/Mathlib/GroupTheory/Transfer.lean index ce1d169cd838eb..8b40c9d992fa95 100644 --- a/Mathlib/GroupTheory/Transfer.lean +++ b/Mathlib/GroupTheory/Transfer.lean @@ -103,8 +103,8 @@ theorem transfer_eq_prod_quotient_orbitRel_zpowers_quot [FiniteIndex H] (g : G) transfer ϕ g = ∏ q : Quotient (orbitRel (zpowers g) (G ⧸ H)), ϕ - ⟨q.out'.out'⁻¹ * g ^ Function.minimalPeriod (g • ·) q.out' * q.out'.out', - QuotientGroup.out'_conj_pow_minimalPeriod_mem H g q.out'⟩ := by + ⟨q.out.out⁻¹ * g ^ Function.minimalPeriod (g • ·) q.out * q.out.out, + QuotientGroup.out_conj_pow_minimalPeriod_mem H g q.out⟩ := by classical letI := H.fintypeQuotientOfFiniteIndex calc @@ -115,7 +115,7 @@ theorem transfer_eq_prod_quotient_orbitRel_zpowers_quot [FiniteIndex H] (g : G) refine Fintype.prod_congr _ _ (fun q => ?_) simp only [quotientEquivSigmaZMod_symm_apply, transferTransversal_apply', transferTransversal_apply''] - rw [Fintype.prod_eq_single (0 : ZMod (Function.minimalPeriod (g • ·) q.out')) _] + rw [Fintype.prod_eq_single (0 : ZMod (Function.minimalPeriod (g • ·) q.out)) _] · simp only [if_pos, ZMod.cast_zero, zpow_zero, one_mul, mul_assoc] · intro k hk simp only [if_neg hk, inv_mul_cancel] @@ -133,11 +133,11 @@ theorem transfer_eq_pow_aux (g : G) replace key : ∀ (k : ℕ) (g₀ : G), g₀⁻¹ * g ^ k * g₀ ∈ H → g ^ k ∈ H := fun k g₀ hk => (congr_arg (· ∈ H) (key k g₀ hk)).mp hk replace key : ∀ q : G ⧸ H, g ^ Function.minimalPeriod (g • ·) q ∈ H := fun q => - key (Function.minimalPeriod (g • ·) q) q.out' - (QuotientGroup.out'_conj_pow_minimalPeriod_mem H g q) + key (Function.minimalPeriod (g • ·) q) q.out + (QuotientGroup.out_conj_pow_minimalPeriod_mem H g q) let f : Quotient (orbitRel (zpowers g) (G ⧸ H)) → zpowers g := fun q => - (⟨g, mem_zpowers g⟩ : zpowers g) ^ Function.minimalPeriod (g • ·) q.out' - have hf : ∀ q, f q ∈ H.subgroupOf (zpowers g) := fun q => key q.out' + (⟨g, mem_zpowers g⟩ : zpowers g) ^ Function.minimalPeriod (g • ·) q.out + have hf : ∀ q, f q ∈ H.subgroupOf (zpowers g) := fun q => key q.out replace key := Subgroup.prod_mem (H.subgroupOf (zpowers g)) fun q (_ : q ∈ Finset.univ) => hf q simpa only [f, minimalPeriod_eq_card, Finset.prod_pow_eq_pow_sum, Fintype.card_sigma, diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean index 20adcbf5832397..75e11673b7d742 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean @@ -422,7 +422,7 @@ theorem constVAdd_symm (v : V₁) : (constVAdd k P₁ v).symm = constVAdd k P₁ /-- A more bundled version of `AffineEquiv.constVAdd`. -/ @[simps] def constVAddHom : Multiplicative V₁ →* P₁ ≃ᵃ[k] P₁ where - toFun v := constVAdd k P₁ (Multiplicative.toAdd v) + toFun v := constVAdd k P₁ v.toAdd map_one' := constVAdd_zero _ _ map_mul' := constVAdd_add _ P₁ @@ -486,22 +486,26 @@ theorem pointReflection_self (x : P₁) : pointReflection k x x = x := theorem pointReflection_involutive (x : P₁) : Involutive (pointReflection k x : P₁ → P₁) := Equiv.pointReflection_involutive x -set_option linter.deprecated false in /-- `x` is the only fixed point of `pointReflection x`. This lemma requires `x + x = y + y ↔ x = y`. There is no typeclass to use here, so we add it as an explicit argument. -/ -theorem pointReflection_fixed_iff_of_injective_bit0 {x y : P₁} (h : Injective (2 • · : V₁ → V₁)) : - pointReflection k x y = y ↔ y = x := - Equiv.pointReflection_fixed_iff_of_injective_bit0 h +theorem pointReflection_fixed_iff_of_injective_two_nsmul {x y : P₁} + (h : Injective (2 • · : V₁ → V₁)) : pointReflection k x y = y ↔ y = x := + Equiv.pointReflection_fixed_iff_of_injective_two_nsmul h + +@[deprecated (since := "2024-11-18")] alias pointReflection_fixed_iff_of_injective_bit0 := +pointReflection_fixed_iff_of_injective_two_nsmul -set_option linter.deprecated false in -theorem injective_pointReflection_left_of_injective_bit0 +theorem injective_pointReflection_left_of_injective_two_nsmul (h : Injective (2 • · : V₁ → V₁)) (y : P₁) : Injective fun x : P₁ => pointReflection k x y := - Equiv.injective_pointReflection_left_of_injective_bit0 h y + Equiv.injective_pointReflection_left_of_injective_two_nsmul h y + +@[deprecated (since := "2024-11-18")] alias injective_pointReflection_left_of_injective_bit0 := +injective_pointReflection_left_of_injective_two_nsmul theorem injective_pointReflection_left_of_module [Invertible (2 : k)] : ∀ y, Injective fun x : P₁ => pointReflection k x y := - injective_pointReflection_left_of_injective_bit0 k fun x y h => by + injective_pointReflection_left_of_injective_two_nsmul k fun x y h => by dsimp at h rwa [two_nsmul, two_nsmul, ← two_smul k x, ← two_smul k y, (isUnit_of_invertible (2 : k)).smul_left_cancel] at h diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean index 71f99e5c85dde4..259da107ba0114 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean @@ -3,7 +3,7 @@ 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.Data.Set.Pointwise.Interval +import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.LinearAlgebra.AffineSpace.Basic import Mathlib.LinearAlgebra.BilinearMap import Mathlib.LinearAlgebra.Pi diff --git a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean index 9476da73472ed3..308268392107ce 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean @@ -618,7 +618,7 @@ theorem affineIndependent_of_ne {p₁ p₂ : P} (h : p₁ ≠ p₂) : AffineInde ext fin_cases i · simp at hi - · simp only [Fin.val_one] + · simp haveI : Unique { x // x ≠ (0 : Fin 2) } := ⟨⟨i₁⟩, he'⟩ apply linearIndependent_unique rw [he' default] diff --git a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean index 0768933dedc463..da171b8d6bfaa6 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Basic.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Basic.lean @@ -58,7 +58,7 @@ namespace LinearMap namespace BilinForm -@[deprecated (since := "2024-04-14")] +@[deprecated "No deprecation message was provided." (since := "2024-04-14")] theorem coeFn_congr : ∀ {x x' y y' : M}, x = x' → y = y' → B x y = B x' y' | _, _, _, _, rfl, rfl => rfl @@ -101,7 +101,7 @@ theorem ext (H : ∀ x y : M, B x y = D x y) : B = D := ext₂ H theorem congr_fun (h : B = D) (x y : M) : B x y = D x y := congr_fun₂ h _ _ -@[deprecated (since := "2024-04-14")] +@[deprecated "No deprecation message was provided." (since := "2024-04-14")] theorem coe_zero : ⇑(0 : BilinForm R M) = 0 := rfl @@ -111,7 +111,7 @@ theorem zero_apply (x y : M) : (0 : BilinForm R M) x y = 0 := variable (B D B₁ D₁) -@[deprecated (since := "2024-04-14")] +@[deprecated "No deprecation message was provided." (since := "2024-04-14")] theorem coe_add : ⇑(B + D) = B + D := rfl @@ -119,7 +119,7 @@ theorem coe_add : ⇑(B + D) = B + D := theorem add_apply (x y : M) : (B + D) x y = B x y + D x y := rfl -@[deprecated (since := "2024-04-14")] +@[deprecated "No deprecation message was provided." (since := "2024-04-14")] theorem coe_neg : ⇑(-B₁) = -B₁ := rfl @@ -127,7 +127,7 @@ theorem coe_neg : ⇑(-B₁) = -B₁ := theorem neg_apply (x y : M₁) : (-B₁) x y = -B₁ x y := rfl -@[deprecated (since := "2024-04-14")] +@[deprecated "No deprecation message was provided." (since := "2024-04-14")] theorem coe_sub : ⇑(B₁ - D₁) = B₁ - D₁ := rfl diff --git a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean index 9c011c36ed52b8..c1b171f04d13ec 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean @@ -58,16 +58,16 @@ section ToLin' def toLinHomAux₁ (A : BilinForm R M) (x : M) : M →ₗ[R] R := A x /-- Auxiliary definition to define `toLinHom`; see below. -/ -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] def toLinHomAux₂ (A : BilinForm R M) : M →ₗ[R] M →ₗ[R] R := A /-- The linear map obtained from a `BilinForm` by fixing the left co-ordinate and evaluating in the right. -/ -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] def toLinHom : BilinForm R M →ₗ[R] M →ₗ[R] M →ₗ[R] R := LinearMap.id set_option linter.deprecated false in -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem toLin'_apply (A : BilinForm R M) (x : M) : toLinHom (M := M) A x = A x := rfl @@ -112,7 +112,7 @@ def LinearMap.toBilinAux (f : M →ₗ[R] M →ₗ[R] R) : BilinForm R M := f set_option linter.deprecated false in /-- Bilinear forms are linearly equivalent to maps with two arguments that are linear in both. -/ -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] def LinearMap.BilinForm.toLin : BilinForm R M ≃ₗ[R] M →ₗ[R] M →ₗ[R] R := { BilinForm.toLinHom with invFun := LinearMap.toBilinAux @@ -121,35 +121,35 @@ def LinearMap.BilinForm.toLin : BilinForm R M ≃ₗ[R] M →ₗ[R] M →ₗ[R] set_option linter.deprecated false in /-- A map with two arguments that is linear in both is linearly equivalent to bilinear form. -/ -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] def LinearMap.toBilin : (M →ₗ[R] M →ₗ[R] R) ≃ₗ[R] BilinForm R M := BilinForm.toLin.symm -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem LinearMap.toBilinAux_eq (f : M →ₗ[R] M →ₗ[R] R) : LinearMap.toBilinAux f = f := rfl set_option linter.deprecated false in -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem LinearMap.toBilin_symm : (LinearMap.toBilin.symm : BilinForm R M ≃ₗ[R] _) = BilinForm.toLin := rfl set_option linter.deprecated false in -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem BilinForm.toLin_symm : (BilinForm.toLin.symm : _ ≃ₗ[R] BilinForm R M) = LinearMap.toBilin := LinearMap.toBilin.symm_symm set_option linter.deprecated false in -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem LinearMap.toBilin_apply (f : M →ₗ[R] M →ₗ[R] R) (x y : M) : toBilin f x y = f x y := rfl set_option linter.deprecated false in -@[deprecated (since := "2024-04-26")] +@[deprecated "No deprecation message was provided." (since := "2024-04-26")] theorem BilinForm.toLin_apply (x : M) : BilinForm.toLin B x = B x := rfl diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/CategoryTheory.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/CategoryTheory.lean index 2311b81349cc47..0b5239188f1206 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/CategoryTheory.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/CategoryTheory.lean @@ -25,7 +25,7 @@ variable {R : Type u} [CommRing R] This is `CliffordAlgebra.map` through the lens of category theory. -/ @[simps] def QuadraticModuleCat.cliffordAlgebra : QuadraticModuleCat.{u} R ⥤ AlgebraCat.{u} R where - obj M := { carrier := CliffordAlgebra M.form } - map {_M _N} f := CliffordAlgebra.map f.toIsometry - map_id _M := CliffordAlgebra.map_id _ - map_comp {_M _N _P} f g := (CliffordAlgebra.map_comp_map g.toIsometry f.toIsometry).symm + obj M := AlgebraCat.of R (CliffordAlgebra M.form) + map {_M _N} f := AlgebraCat.ofHom <| CliffordAlgebra.map f.toIsometry + map_id _M := by simp + map_comp {_M _N _P} f g := by ext; simp diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean index 39224b85617fe1..d88ad526801836 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean @@ -75,7 +75,6 @@ nonrec theorem GradedAlgebra.ι_sq_scalar (m : M) : rw [GradedAlgebra.ι_apply Q, DirectSum.of_mul_of, DirectSum.algebraMap_apply] exact DirectSum.of_eq_of_gradedMonoid_eq (Sigma.subtype_ext rfl <| ι_sq_scalar _ _) -set_option linter.deprecated false in theorem GradedAlgebra.lift_ι_eq (i' : ZMod 2) (x' : evenOdd Q i') : -- Porting note: added a second `by apply` lift Q ⟨by apply GradedAlgebra.ι Q, by apply GradedAlgebra.ι_sq_scalar Q⟩ x' = @@ -85,29 +84,27 @@ theorem GradedAlgebra.lift_ι_eq (i' : ZMod 2) (x' : evenOdd Q i') : induction hx' using Submodule.iSup_induction' with | mem i x hx => obtain ⟨i, rfl⟩ := i - -- Porting note: `dsimp only [Subtype.coe_mk] at hx` doesn't work, use `change` instead - change x ∈ LinearMap.range (ι Q) ^ i at hx + dsimp only [Subtype.coe_mk] at hx induction hx using Submodule.pow_induction_on_left' with | algebraMap r => rw [AlgHom.commutes, DirectSum.algebraMap_apply]; rfl | add x y i hx hy ihx ihy => - -- Note: in https://github.com/leanprover-community/mathlib4/pull/8386 `map_add` had to be specialized to avoid a timeout - -- (the definition was already very slow) - rw [AlgHom.map_add, ihx, ihy, ← AddMonoidHom.map_add] + rw [map_add, ihx, ihy, ← AddMonoidHom.map_add] rfl | mem_mul m hm i x hx ih => obtain ⟨_, rfl⟩ := hm - rw [AlgHom.map_mul, ih, lift_ι_apply, GradedAlgebra.ι_apply Q, DirectSum.of_mul_of] + rw [map_mul, ih, lift_ι_apply, GradedAlgebra.ι_apply Q, DirectSum.of_mul_of] refine DirectSum.of_eq_of_gradedMonoid_eq (Sigma.subtype_ext ?_ ?_) <;> dsimp only [GradedMonoid.mk, Subtype.coe_mk] · rw [Nat.succ_eq_add_one, add_comm, Nat.cast_add, Nat.cast_one] rfl | zero => + set_option linter.deprecated false in rw [AlgHom.map_zero] apply Eq.symm apply DFinsupp.single_eq_zero.mpr; rfl | add x y hx hy ihx ihy => - rw [AlgHom.map_add, ihx, ihy, ← AddMonoidHom.map_add]; rfl + rw [map_add, ihx, ihy, ← AddMonoidHom.map_add]; rfl /-- The clifford algebra is graded by the even and odd parts. -/ instance gradedAlgebra : GradedAlgebra (evenOdd Q) := diff --git a/Mathlib/LinearAlgebra/CrossProduct.lean b/Mathlib/LinearAlgebra/CrossProduct.lean index 8fb6567b4ec219..3093c7a58ad504 100644 --- a/Mathlib/LinearAlgebra/CrossProduct.lean +++ b/Mathlib/LinearAlgebra/CrossProduct.lean @@ -36,8 +36,6 @@ crossproduct -/ -open Matrix - open Matrix variable {R : Type*} [CommRing R] diff --git a/Mathlib/LinearAlgebra/DFinsupp.lean b/Mathlib/LinearAlgebra/DFinsupp.lean index 406aa08a4c0327..f411c6bc0c1b57 100644 --- a/Mathlib/LinearAlgebra/DFinsupp.lean +++ b/Mathlib/LinearAlgebra/DFinsupp.lean @@ -390,8 +390,6 @@ theorem mem_iSup_finset_iff_exists_sum {s : Finset ι} (p : ι → Submodule R N end Submodule -namespace CompleteLattice - open DFinsupp section Semiring @@ -401,23 +399,26 @@ variable [DecidableEq ι] [Semiring R] [AddCommMonoid N] [Module R N] /-- Independence of a family of submodules can be expressed as a quantifier over `DFinsupp`s. This is an intermediate result used to prove -`CompleteLattice.independent_of_dfinsupp_lsum_injective` and -`CompleteLattice.Independent.dfinsupp_lsum_injective`. -/ -theorem independent_iff_forall_dfinsupp (p : ι → Submodule R N) : - Independent p ↔ +`iSupIndep_of_dfinsupp_lsum_injective` and +`iSupIndep.dfinsupp_lsum_injective`. -/ +theorem iSupIndep_iff_forall_dfinsupp (p : ι → Submodule R N) : + iSupIndep p ↔ ∀ (i) (x : p i) (v : Π₀ i : ι, ↥(p i)), lsum ℕ (M := fun i ↦ ↥(p i)) (fun i => (p i).subtype) (erase i v) = x → x = 0 := by - simp_rw [CompleteLattice.independent_def, Submodule.disjoint_def, + simp_rw [iSupIndep_def, Submodule.disjoint_def, Submodule.mem_biSup_iff_exists_dfinsupp, exists_imp, filter_ne_eq_erase] refine forall_congr' fun i => Subtype.forall'.trans ?_ simp_rw [Submodule.coe_eq_zero] +@[deprecated (since := "2024-11-24")] +alias independent_iff_forall_dfinsupp := iSupIndep_iff_forall_dfinsupp + /- If `DFinsupp.lsum` applied with `Submodule.subtype` is injective then the submodules are -independent. -/ -theorem independent_of_dfinsupp_lsum_injective (p : ι → Submodule R N) +iSupIndep. -/ +theorem iSupIndep_of_dfinsupp_lsum_injective (p : ι → Submodule R N) (h : Function.Injective (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype)) : - Independent p := by - rw [independent_iff_forall_dfinsupp] + iSupIndep p := by + rw [iSupIndep_iff_forall_dfinsupp] intro i x v hv replace hv : lsum ℕ (M := fun i ↦ ↥(p i)) (fun i => (p i).subtype) (erase i v) = lsum ℕ (M := fun i ↦ ↥(p i)) (fun i => (p i).subtype) (single i x) := by @@ -425,12 +426,18 @@ theorem independent_of_dfinsupp_lsum_injective (p : ι → Submodule R N) have := DFunLike.ext_iff.mp (h hv) i simpa [eq_comm] using this +@[deprecated (since := "2024-11-24")] +alias independent_of_dfinsupp_lsum_injective := iSupIndep_of_dfinsupp_lsum_injective + /- If `DFinsupp.sumAddHom` applied with `AddSubmonoid.subtype` is injective then the additive submonoids are independent. -/ -theorem independent_of_dfinsupp_sumAddHom_injective (p : ι → AddSubmonoid N) - (h : Function.Injective (sumAddHom fun i => (p i).subtype)) : Independent p := by - rw [← independent_map_orderIso_iff (AddSubmonoid.toNatSubmodule : AddSubmonoid N ≃o _)] - exact independent_of_dfinsupp_lsum_injective _ h +theorem iSupIndep_of_dfinsupp_sumAddHom_injective (p : ι → AddSubmonoid N) + (h : Function.Injective (sumAddHom fun i => (p i).subtype)) : iSupIndep p := by + rw [← iSupIndep_map_orderIso_iff (AddSubmonoid.toNatSubmodule : AddSubmonoid N ≃o _)] + exact iSupIndep_of_dfinsupp_lsum_injective _ h + +@[deprecated (since := "2024-11-24")] +alias independent_of_dfinsupp_sumAddHom_injective := iSupIndep_of_dfinsupp_sumAddHom_injective /-- Combining `DFinsupp.lsum` with `LinearMap.toSpanSingleton` is the same as `Finsupp.linearCombination` -/ @@ -450,24 +457,27 @@ section Ring variable [DecidableEq ι] [Ring R] [AddCommGroup N] [Module R N] -/- If `DFinsupp.sumAddHom` applied with `AddSubmonoid.subtype` is injective then the additive +/-- If `DFinsupp.sumAddHom` applied with `AddSubmonoid.subtype` is injective then the additive subgroups are independent. -/ -theorem independent_of_dfinsupp_sumAddHom_injective' (p : ι → AddSubgroup N) - (h : Function.Injective (sumAddHom fun i => (p i).subtype)) : Independent p := by - rw [← independent_map_orderIso_iff (AddSubgroup.toIntSubmodule : AddSubgroup N ≃o _)] - exact independent_of_dfinsupp_lsum_injective _ h +theorem iSupIndep_of_dfinsupp_sumAddHom_injective' (p : ι → AddSubgroup N) + (h : Function.Injective (sumAddHom fun i => (p i).subtype)) : iSupIndep p := by + rw [← iSupIndep_map_orderIso_iff (AddSubgroup.toIntSubmodule : AddSubgroup N ≃o _)] + exact iSupIndep_of_dfinsupp_lsum_injective _ h + +@[deprecated (since := "2024-11-24")] +alias independent_of_dfinsupp_sumAddHom_injective' := iSupIndep_of_dfinsupp_sumAddHom_injective' /-- The canonical map out of a direct sum of a family of submodules is injective when the submodules -are `CompleteLattice.Independent`. +are `iSupIndep`. Note that this is not generally true for `[Semiring R]`, for instance when `A` is the `ℕ`-submodules of the positive and negative integers. See `Counterexamples/DirectSumIsInternal.lean` for a proof of this fact. -/ -theorem Independent.dfinsupp_lsum_injective {p : ι → Submodule R N} (h : Independent p) : +theorem iSupIndep.dfinsupp_lsum_injective {p : ι → Submodule R N} (h : iSupIndep p) : Function.Injective (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype) := by -- simplify everything down to binders over equalities in `N` - rw [independent_iff_forall_dfinsupp] at h + rw [iSupIndep_iff_forall_dfinsupp] at h suffices LinearMap.ker (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype) = ⊥ by -- Lean can't find this without our help letI thisI : AddCommGroup (Π₀ i, p i) := inferInstance @@ -482,34 +492,46 @@ theorem Independent.dfinsupp_lsum_injective {p : ι → Submodule R N} (h : Inde rwa [← erase_add_single i m, LinearMap.map_add, lsum_single, Submodule.subtype_apply, add_eq_zero_iff_eq_neg, ← Submodule.coe_neg] at hm +@[deprecated (since := "2024-11-24")] +alias Independent.dfinsupp_lsum_injective := iSupIndep.dfinsupp_lsum_injective + /-- The canonical map out of a direct sum of a family of additive subgroups is injective when the -additive subgroups are `CompleteLattice.Independent`. -/ -theorem Independent.dfinsupp_sumAddHom_injective {p : ι → AddSubgroup N} (h : Independent p) : +additive subgroups are `iSupIndep`. -/ +theorem iSupIndep.dfinsupp_sumAddHom_injective {p : ι → AddSubgroup N} (h : iSupIndep p) : Function.Injective (sumAddHom fun i => (p i).subtype) := by - rw [← independent_map_orderIso_iff (AddSubgroup.toIntSubmodule : AddSubgroup N ≃o _)] at h + rw [← iSupIndep_map_orderIso_iff (AddSubgroup.toIntSubmodule : AddSubgroup N ≃o _)] at h exact h.dfinsupp_lsum_injective +@[deprecated (since := "2024-11-24")] +alias Independent.dfinsupp_sumAddHom_injective := iSupIndep.dfinsupp_sumAddHom_injective + /-- A family of submodules over an additive group are independent if and only iff `DFinsupp.lsum` applied with `Submodule.subtype` is injective. Note that this is not generally true for `[Semiring R]`; see -`CompleteLattice.Independent.dfinsupp_lsum_injective` for details. -/ -theorem independent_iff_dfinsupp_lsum_injective (p : ι → Submodule R N) : - Independent p ↔ Function.Injective (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype) := - ⟨Independent.dfinsupp_lsum_injective, independent_of_dfinsupp_lsum_injective p⟩ +`iSupIndep.dfinsupp_lsum_injective` for details. -/ +theorem iSupIndep_iff_dfinsupp_lsum_injective (p : ι → Submodule R N) : + iSupIndep p ↔ Function.Injective (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype) := + ⟨iSupIndep.dfinsupp_lsum_injective, iSupIndep_of_dfinsupp_lsum_injective p⟩ + +@[deprecated (since := "2024-11-24")] +alias independent_iff_dfinsupp_lsum_injective := iSupIndep_iff_dfinsupp_lsum_injective /-- A family of additive subgroups over an additive group are independent if and only if `DFinsupp.sumAddHom` applied with `AddSubgroup.subtype` is injective. -/ -theorem independent_iff_dfinsupp_sumAddHom_injective (p : ι → AddSubgroup N) : - Independent p ↔ Function.Injective (sumAddHom fun i => (p i).subtype) := - ⟨Independent.dfinsupp_sumAddHom_injective, independent_of_dfinsupp_sumAddHom_injective' p⟩ +theorem iSupIndep_iff_dfinsupp_sumAddHom_injective (p : ι → AddSubgroup N) : + iSupIndep p ↔ Function.Injective (sumAddHom fun i => (p i).subtype) := + ⟨iSupIndep.dfinsupp_sumAddHom_injective, iSupIndep_of_dfinsupp_sumAddHom_injective' p⟩ + +@[deprecated (since := "2024-11-24")] +alias independent_iff_dfinsupp_sumAddHom_injective := iSupIndep_iff_dfinsupp_sumAddHom_injective -/-- If a family of submodules is `Independent`, then a choice of nonzero vector from each submodule +/-- If a family of submodules is independent, then a choice of nonzero vector from each submodule forms a linearly independent family. -See also `CompleteLattice.Independent.linearIndependent'`. -/ -theorem Independent.linearIndependent [NoZeroSMulDivisors R N] {ι} (p : ι → Submodule R N) - (hp : Independent p) {v : ι → N} (hv : ∀ i, v i ∈ p i) (hv' : ∀ i, v i ≠ 0) : +See also `iSupIndep.linearIndependent'`. -/ +theorem iSupIndep.linearIndependent [NoZeroSMulDivisors R N] {ι} (p : ι → Submodule R N) + (hp : iSupIndep p) {v : ι → N} (hv : ∀ i, v i ∈ p i) (hv' : ∀ i, v i ≠ 0) : LinearIndependent R v := by let _ := Classical.decEq ι let _ := Classical.decEq R @@ -527,15 +549,19 @@ theorem Independent.linearIndependent [NoZeroSMulDivisors R N] {ι} (p : ι → simp only [coe_zero, Pi.zero_apply, ZeroMemClass.coe_zero, smul_eq_zero, ha] at this simpa -theorem independent_iff_linearIndependent_of_ne_zero [NoZeroSMulDivisors R N] {ι} {v : ι → N} - (h_ne_zero : ∀ i, v i ≠ 0) : (Independent fun i => R ∙ v i) ↔ LinearIndependent R v := +@[deprecated (since := "2024-11-24")] +alias Independent.linearIndependent := iSupIndep.linearIndependent + +theorem iSupIndep_iff_linearIndependent_of_ne_zero [NoZeroSMulDivisors R N] {ι} {v : ι → N} + (h_ne_zero : ∀ i, v i ≠ 0) : (iSupIndep fun i => R ∙ v i) ↔ LinearIndependent R v := let _ := Classical.decEq ι ⟨fun hv => hv.linearIndependent _ (fun i => Submodule.mem_span_singleton_self <| v i) h_ne_zero, - fun hv => hv.independent_span_singleton⟩ + fun hv => hv.iSupIndep_span_singleton⟩ -end Ring +@[deprecated (since := "2024-11-24")] +alias independent_iff_linearIndependent_of_ne_zero := iSupIndep_iff_linearIndependent_of_ne_zero -end CompleteLattice +end Ring namespace LinearMap diff --git a/Mathlib/LinearAlgebra/Dimension/Basic.lean b/Mathlib/LinearAlgebra/Dimension/Basic.lean index 76b2ee39e5e516..16bbd326c31120 100644 --- a/Mathlib/LinearAlgebra/Dimension/Basic.lean +++ b/Mathlib/LinearAlgebra/Dimension/Basic.lean @@ -353,6 +353,16 @@ theorem rank_subsingleton [Subsingleton R] : Module.rank R M = 1 := by subsingleton · exact hw.trans_eq (Cardinal.mk_singleton _).symm +lemma rank_le_of_isSMulRegular {S : Type*} [CommSemiring S] [Algebra S R] [Module S M] + [IsScalarTower S R M] (L L' : Submodule R M) {s : S} (hr : IsSMulRegular M s) + (h : ∀ x ∈ L, s • x ∈ L') : + Module.rank R L ≤ Module.rank R L' := + ((Algebra.lsmul S R M s).restrict h).rank_le_of_injective <| + fun _ _ h ↦ by simpa using hr (Subtype.ext_iff.mp h) + +@[deprecated (since := "2024-11-21")] +alias rank_le_of_smul_regular := rank_le_of_isSMulRegular + end end Module diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean index 49fba6493d2d15..6c000a000aaf90 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finite.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean @@ -249,8 +249,8 @@ theorem Module.Finite.not_linearIndependent_of_infinite {ι : Type*} [Infinite section variable [NoZeroSMulDivisors R M] -theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [Nontrivial R] - {V : ι → Submodule R M} (hV : CompleteLattice.Independent V) : +theorem iSupIndep.subtype_ne_bot_le_rank [Nontrivial R] + {V : ι → Submodule R M} (hV : iSupIndep V) : Cardinal.lift.{v} #{ i : ι // V i ≠ ⊥ } ≤ Cardinal.lift.{w} (Module.rank R M) := by set I := { i : ι // V i ≠ ⊥ } have hI : ∀ i : I, ∃ v ∈ V i, v ≠ (0 : M) := by @@ -261,10 +261,13 @@ theorem CompleteLattice.Independent.subtype_ne_bot_le_rank [Nontrivial R] have : LinearIndependent R v := (hV.comp Subtype.coe_injective).linearIndependent _ hvV hv exact this.cardinal_lift_le_rank +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.subtype_ne_bot_le_rank := iSupIndep.subtype_ne_bot_le_rank + variable [Module.Finite R M] [StrongRankCondition R] -theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux - {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) : +theorem iSupIndep.subtype_ne_bot_le_finrank_aux + {p : ι → Submodule R M} (hp : iSupIndep p) : #{ i // p i ≠ ⊥ } ≤ (finrank R M : Cardinal.{w}) := by suffices Cardinal.lift.{v} #{ i // p i ≠ ⊥ } ≤ Cardinal.lift.{v} (finrank R M : Cardinal.{w}) by rwa [Cardinal.lift_le] at this @@ -276,8 +279,8 @@ theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank_aux /-- If `p` is an independent family of submodules of a `R`-finite module `M`, then the number of nontrivial subspaces in the family `p` is finite. -/ -noncomputable def CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional - {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) : +noncomputable def iSupIndep.fintypeNeBotOfFiniteDimensional + {p : ι → Submodule R M} (hp : iSupIndep p) : Fintype { i : ι // p i ≠ ⊥ } := by suffices #{ i // p i ≠ ⊥ } < (ℵ₀ : Cardinal.{w}) by rw [Cardinal.lt_aleph0_iff_fintype] at this @@ -289,9 +292,9 @@ noncomputable def CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional number of nontrivial subspaces in the family `p` is bounded above by the dimension of `M`. Note that the `Fintype` hypothesis required here can be provided by -`CompleteLattice.Independent.fintypeNeBotOfFiniteDimensional`. -/ -theorem CompleteLattice.Independent.subtype_ne_bot_le_finrank - {p : ι → Submodule R M} (hp : CompleteLattice.Independent p) [Fintype { i // p i ≠ ⊥ }] : +`iSupIndep.fintypeNeBotOfFiniteDimensional`. -/ +theorem iSupIndep.subtype_ne_bot_le_finrank + {p : ι → Submodule R M} (hp : iSupIndep p) [Fintype { i // p i ≠ ⊥ }] : Fintype.card { i // p i ≠ ⊥ } ≤ finrank R M := by simpa using hp.subtype_ne_bot_le_finrank_aux end diff --git a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean index 79f9779cf62711..cf3c16a79daa0f 100644 --- a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean +++ b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean @@ -203,13 +203,23 @@ lemma Submodule.finrank_quotient_add_finrank [Module.Finite R M] (N : Submodule Submodule.finrank_eq_rank] exact HasRankNullity.rank_quotient_add_rank _ - /-- Rank-nullity theorem using `finrank` and subtraction. -/ lemma Submodule.finrank_quotient [Module.Finite R M] {S : Type*} [Ring S] [SMul R S] [Module S M] [IsScalarTower R S M] (N : Submodule S M) : finrank R (M ⧸ N) = finrank R M - finrank R N := by rw [← (N.restrictScalars R).finrank_quotient_add_finrank] exact Nat.eq_sub_of_add_eq rfl +lemma Submodule.disjoint_ker_of_finrank_eq [NoZeroSMulDivisors R M] {N : Type*} [AddCommGroup N] + [Module R N] {L : Submodule R M} [Module.Finite R L] (f : M →ₗ[R] N) + (h : finrank R (L.map f) = finrank R L) : + Disjoint L (LinearMap.ker f) := by + refine disjoint_iff.mpr <| LinearMap.injective_domRestrict_iff.mp <| LinearMap.ker_eq_bot.mp <| + Submodule.rank_eq_zero.mp ?_ + rw [← Submodule.finrank_eq_rank, Nat.cast_eq_zero] + rw [← LinearMap.range_domRestrict] at h + have := (LinearMap.ker (f.domRestrict L)).finrank_quotient_add_finrank + rwa [LinearEquiv.finrank_eq (f.domRestrict L).quotKerEquivRange, h, Nat.add_eq_left] at this + end Finrank section diff --git a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean index cd51f9aec9d87e..71be346b20eaaa 100644 --- a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean +++ b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean @@ -465,4 +465,15 @@ theorem LinearMap.finrank_range_le [Module.Finite R M] (f : M →ₗ[R] M') : finrank R (LinearMap.range f) ≤ finrank R M := finrank_le_finrank_of_rank_le_rank (lift_rank_range_le f) (rank_lt_aleph0 _ _) +theorem LinearMap.finrank_le_of_isSMulRegular {S : Type*} [CommSemiring S] [Algebra S R] + [Module S M] [IsScalarTower S R M] (L L' : Submodule R M) [Module.Finite R L'] {s : S} + (hr : IsSMulRegular M s) (h : ∀ x ∈ L, s • x ∈ L') : + Module.finrank R L ≤ Module.finrank R L' := by + refine finrank_le_finrank_of_rank_le_rank (lift_le.mpr <| rank_le_of_isSMulRegular L L' hr h) ?_ + rw [← Module.finrank_eq_rank R L'] + exact nat_lt_aleph0 (finrank R ↥L') + +@[deprecated (since := "2024-11-21")] +alias LinearMap.finrank_le_of_smul_regular := LinearMap.finrank_le_of_isSMulRegular + end StrongRankCondition diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index c41abe513c0a79..a203905b0a8a22 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -339,11 +339,11 @@ theorem toDual_injective : Injective b.toDual := fun x y h ↦ b.ext_elem_iff.mp theorem toDual_inj (m : M) (a : b.toDual m = 0) : m = 0 := b.toDual_injective (by rwa [_root_.map_zero]) --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker theorem toDual_ker : LinearMap.ker b.toDual = ⊥ := ker_eq_bot'.mpr b.toDual_inj --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range 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) @@ -447,7 +447,7 @@ theorem eval_ker {ι : Type*} (b : Basis ι R M) : simp_rw [LinearMap.ext_iff, Dual.eval_apply, zero_apply] at hm exact (Basis.forall_coord_eq_zero_iff _).mp fun i => hm (b.coord i) --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range theorem eval_range {ι : Type*} [Finite ι] (b : Basis ι R M) : LinearMap.range (Dual.eval R M) = ⊤ := by classical @@ -501,7 +501,7 @@ section variable (K) (V) --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker theorem eval_ker : LinearMap.ker (eval K V) = ⊥ := have ⟨s, hs⟩ := Module.projective_def'.mp ‹Projective K V› ker_eq_bot.mpr <| .of_comp (f := s.dualMap.dualMap) <| (ker_eq_bot.mp <| @@ -595,7 +595,7 @@ instance (priority := 900) IsReflexive.of_finite_of_free [Module.Finite R M] [Fr variable [IsReflexive R M] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range theorem erange_coe : LinearMap.range (eval R M) = ⊤ := range_eq_top.mpr (bijective_dual_eval _ _).2 @@ -715,6 +715,17 @@ instance instFiniteDimensionalOfIsReflexive (K V : Type*) rw [lift_id'] exact lt_trans h₁ h₂ +instance [IsDomain R] : NoZeroSMulDivisors R M := by + refine (noZeroSMulDivisors_iff R M).mpr ?_ + intro r m hrm + rw [or_iff_not_imp_left] + intro hr + suffices Dual.eval R M m = Dual.eval R M 0 from (bijective_dual_eval R M).injective this + ext n + simp only [Dual.eval_apply, map_zero, LinearMap.zero_apply] + suffices r • n m = 0 from eq_zero_of_ne_zero_of_mul_left_eq_zero hr this + rw [← LinearMap.map_smul_of_tower, hrm, LinearMap.map_zero] + end IsReflexive end Module @@ -932,7 +943,7 @@ theorem dualRestrict_apply (W : Submodule R M) (φ : Module.Dual R M) (x : W) : that `φ w = 0` for all `w ∈ W`. -/ def dualAnnihilator {R : Type u} {M : Type v} [CommSemiring R] [AddCommMonoid M] [Module R M] (W : Submodule R M) : Submodule R <| Module.Dual R M := --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker LinearMap.ker W.dualRestrict @[simp] @@ -944,7 +955,7 @@ theorem mem_dualAnnihilator (φ : Module.Dual R M) : φ ∈ W.dualAnnihilator /-- That $\operatorname{ker}(\iota^* : V^* \to W^*) = \operatorname{ann}(W)$. This is the definition of the dual annihilator of the submodule $W$. -/ theorem dualRestrict_ker_eq_dualAnnihilator (W : Submodule R M) : - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker LinearMap.ker W.dualRestrict = W.dualAnnihilator := rfl @@ -1178,7 +1189,7 @@ theorem quotAnnihilatorEquiv_apply (W : Subspace K V) (φ : Module.Dual K V) : rfl /-- The natural isomorphism from the dual of a subspace `W` to `W.dualLift.range`. -/ --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range noncomputable def dualEquivDual (W : Subspace K V) : Module.Dual K W ≃ₗ[K] LinearMap.range W.dualLift := LinearEquiv.ofInjective _ dualLift_injective @@ -1217,7 +1228,7 @@ theorem dualAnnihilator_dualAnnihilator_eq (W : Subspace K V) : rwa [← OrderIso.symm_apply_eq] /-- The quotient by the dual is isomorphic to its dual annihilator. -/ --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range noncomputable def quotDualEquivAnnihilator (W : Subspace K V) : (Module.Dual K V ⧸ LinearMap.range W.dualLift) ≃ₗ[K] W.dualAnnihilator := LinearEquiv.quotEquivOfQuotEquiv <| LinearEquiv.trans W.quotAnnihilatorEquiv W.dualEquivDual @@ -1263,7 +1274,7 @@ variable {R : Type uR} [CommSemiring R] {M₁ : Type uM₁} {M₂ : Type uM₂} variable [AddCommMonoid M₁] [Module R M₁] [AddCommMonoid M₂] [Module R M₂] variable (f : M₁ →ₗ[R] M₂) --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker theorem ker_dualMap_eq_dualAnnihilator_range : LinearMap.ker f.dualMap = f.range.dualAnnihilator := by ext @@ -1271,7 +1282,7 @@ theorem ker_dualMap_eq_dualAnnihilator_range : ← SetLike.mem_coe, range_coe, Set.forall_mem_range] rfl --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range theorem range_dualMap_le_dualAnnihilator_ker : LinearMap.range f.dualMap ≤ f.ker.dualAnnihilator := by rintro _ ⟨ψ, rfl⟩ @@ -1327,7 +1338,7 @@ theorem dualPairing_apply {W : Submodule R M} (φ : Module.Dual R M) (x : W) : W.dualPairing (Quotient.mk φ) x = φ x := rfl --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range /-- That $\operatorname{im}(q^* : (V/W)^* \to V^*) = \operatorname{ann}(W)$. -/ theorem range_dualMap_mkQ_eq (W : Submodule R M) : LinearMap.range W.mkQ.dualMap = W.dualAnnihilator := by @@ -1349,7 +1360,7 @@ def dualQuotEquivDualAnnihilator (W : Submodule R M) : Module.Dual R (M ⧸ W) ≃ₗ[R] W.dualAnnihilator := LinearEquiv.ofLinear (W.mkQ.dualMap.codRestrict W.dualAnnihilator fun φ => --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.mem_range_self +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.mem_range_self W.range_dualMap_mkQ_eq ▸ LinearMap.mem_range_self W.mkQ.dualMap φ) W.dualCopairing (by ext; rfl) (by ext; rfl) @@ -1404,7 +1415,7 @@ namespace LinearMap open Submodule --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range theorem range_dualMap_eq_dualAnnihilator_ker_of_surjective (f : M →ₗ[R] M') (hf : Function.Surjective f) : LinearMap.range f.dualMap = f.ker.dualAnnihilator := ((f.quotKerEquivOfSurjective hf).dualMap.range_comp _).trans f.ker.range_dualMap_mkQ_eq @@ -1418,7 +1429,7 @@ theorem range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective (f : M rw [← range_eq_top, range_rangeRestrict] have := range_dualMap_eq_dualAnnihilator_ker_of_surjective f.rangeRestrict rr_surj convert this using 1 - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 · calc _ = range ((range f).subtype.comp f.rangeRestrict).dualMap := by simp _ = _ := ?_ @@ -1514,7 +1525,7 @@ theorem dualMap_surjective_of_injective {f : V₁ →ₗ[K] V₂} (hf : Function have ⟨f', hf'⟩ := f.exists_leftInverse_of_injective (ker_eq_bot.mpr hf) ⟨φ.comp f', ext fun x ↦ congr(φ <| $hf' x)⟩ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.range + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.range theorem range_dualMap_eq_dualAnnihilator_ker (f : V₁ →ₗ[K] V₂) : LinearMap.range f.dualMap = f.ker.dualAnnihilator := range_dualMap_eq_dualAnnihilator_ker_of_subtype_range_surjective f <| @@ -1565,7 +1576,7 @@ theorem dualAnnihilator_inf_eq (W W' : Subspace K V₁) : (W ⊓ W').dualAnnihilator = W.dualAnnihilator ⊔ W'.dualAnnihilator := by refine le_antisymm ?_ (sup_dualAnnihilator_le_inf W W') let F : V₁ →ₗ[K] (V₁ ⧸ W) × V₁ ⧸ W' := (Submodule.mkQ W).prod (Submodule.mkQ W') - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 LinearMap.ker + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 LinearMap.ker have : LinearMap.ker F = W ⊓ W' := by simp only [F, LinearMap.ker_prod, ker_mkQ] rw [← this, ← LinearMap.range_dualMap_eq_dualAnnihilator_ker] intro φ @@ -1621,7 +1632,7 @@ namespace LinearMap @[simp] theorem finrank_range_dualMap_eq_finrank_range (f : V₁ →ₗ[K] V₂) : - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1910 + -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11036): broken dot notation https://github.com/leanprover/lean4/issues/1629 finrank K (LinearMap.range f.dualMap) = finrank K (LinearMap.range f) := by rw [congr_arg dualMap (show f = (range f).subtype.comp f.rangeRestrict by rfl), ← dualMap_comp_dualMap, range_comp, diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index 05c1324d366e96..3003ced8d18b7f 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -664,11 +664,11 @@ lemma injOn_iSup_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : apply injOn_maxGenEigenspace theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) (k : ℕ∞) : - CompleteLattice.Independent (f.genEigenspace · k) := by + iSupIndep (f.genEigenspace · k) := by classical suffices ∀ μ₁ (s : Finset R), μ₁ ∉ s → Disjoint (f.genEigenspace μ₁ k) (s.sup fun μ ↦ f.genEigenspace μ k) by - simp_rw [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_genEigenspace f k), + simp_rw [iSupIndep_iff_supIndep_of_injOn (injOn_genEigenspace f k), Finset.supIndep_iff_disjoint_erase] exact fun s μ _ ↦ this _ _ (s.not_mem_erase μ) intro μ₁ s @@ -703,27 +703,29 @@ theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) (k : rwa [ih.eq_bot, Submodule.mem_bot] at hyz theorem independent_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent f.maxGenEigenspace := by + iSupIndep f.maxGenEigenspace := by apply independent_genEigenspace @[deprecated independent_genEigenspace (since := "2024-10-23")] theorem independent_iSup_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent (fun μ ↦ ⨆ k : ℕ, f.genEigenspace μ k) := by + iSupIndep (fun μ ↦ ⨆ k : ℕ, f.genEigenspace μ k) := by simp_rw [iSup_genEigenspace_eq] apply independent_maxGenEigenspace /-- The eigenspaces of a linear operator form an independent family of subspaces of `M`. That is, any eigenspace has trivial intersection with the span of all the other eigenspaces. -/ -theorem eigenspaces_independent [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent f.eigenspace := +theorem eigenspaces_iSupIndep [NoZeroSMulDivisors R M] (f : End R M) : + iSupIndep f.eigenspace := (f.independent_genEigenspace 1).mono fun _ ↦ le_rfl +@[deprecated (since := "2024-11-24")] alias eigenspaces_independent := eigenspaces_iSupIndep + /-- Eigenvectors corresponding to distinct eigenvalues of a linear operator are linearly independent. -/ 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 _ + f.eigenspaces_iSupIndep.comp hμ |>.linearIndependent _ (fun i ↦ h_eigenvec i |>.left) (fun i ↦ h_eigenvec i |>.right) /-- Eigenvectors corresponding to distinct eigenvalues of a linear operator are linearly diff --git a/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean b/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean index 7ae63cc2e199b5..0b327ae0fd03de 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean @@ -55,7 +55,7 @@ lemma hasEigenvalue_toLin_diagonal_iff (d : n → R) {μ : R} [NoZeroSMulDivisor rw [mem_eigenspace_iff] exact (hasEigenvector_toLin_diagonal d i b).apply_eq_smul have hμ_not_mem : μ ∉ Set.range d := by simpa using fun i ↦ (hμ i) - have := eigenspaces_independent (toLin b b (diagonal d)) |>.disjoint_biSup hμ_not_mem + have := eigenspaces_iSupIndep (toLin b b (diagonal d)) |>.disjoint_biSup hμ_not_mem rw [h_iSup, disjoint_top] at this exact h_eig this · rintro ⟨i, rfl⟩ diff --git a/Mathlib/LinearAlgebra/Eigenspace/Pi.lean b/Mathlib/LinearAlgebra/Eigenspace/Pi.lean index 9f089022d24ad7..ddb8f9f9ea5acc 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Pi.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Pi.lean @@ -85,7 +85,7 @@ lemma injOn_iInf_maxGenEigenspace : lemma independent_iInf_maxGenEigenspace_of_forall_mapsTo (h : ∀ i j φ, MapsTo (f i) ((f j).maxGenEigenspace φ) ((f j).maxGenEigenspace φ)) : - CompleteLattice.Independent fun χ : ι → R ↦ ⨅ i, (f i).maxGenEigenspace (χ i) := by + iSupIndep fun χ : ι → R ↦ ⨅ i, (f i).maxGenEigenspace (χ i) := by replace h (l : ι) (χ : ι → R) : MapsTo (f l) (⨅ i, (f i).maxGenEigenspace (χ i)) (⨅ i, (f i).maxGenEigenspace (χ i)) := by intro x hx @@ -95,7 +95,7 @@ lemma independent_iInf_maxGenEigenspace_of_forall_mapsTo suffices ∀ χ (s : Finset (ι → R)) (_ : χ ∉ s), Disjoint (⨅ i, (f i).maxGenEigenspace (χ i)) (s.sup fun (χ : ι → R) ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) by - simpa only [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_iInf_maxGenEigenspace f), + simpa only [iSupIndep_iff_supIndep_of_injOn (injOn_iInf_maxGenEigenspace f), Finset.supIndep_iff_disjoint_erase] using fun s χ _ ↦ this _ _ (s.not_mem_erase χ) intro χ₁ s induction s using Finset.induction_on with diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean index 81a29f15438173..d39a95c8a5d29d 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Grading.lean @@ -54,22 +54,16 @@ def GradedAlgebra.liftι : ExteriorAlgebra R M →ₐ[R] ⨁ i : ℕ, ⋀[R]^i M := lift R ⟨by apply GradedAlgebra.ι R M, GradedAlgebra.ι_sq_zero R M⟩ -set_option linter.deprecated false in theorem GradedAlgebra.liftι_eq (i : ℕ) (x : ⋀[R]^i M) : GradedAlgebra.liftι R M x = DirectSum.of (fun i => ⋀[R]^i M) i x := by cases' x with x hx dsimp only [Subtype.coe_mk, DirectSum.lof_eq_of] - -- Porting note: original statement was - -- refine Submodule.pow_induction_on_left' _ (fun r => ?_) (fun x y i hx hy ihx ihy => ?_) - -- (fun m hm i x hx ih => ?_) hx - -- but it created invalid goals induction hx using Submodule.pow_induction_on_left' with | algebraMap => simp_rw [AlgHom.commutes, DirectSum.algebraMap_apply]; rfl - -- FIXME: specialized `map_add` to avoid a (whole-declaration) timeout - | add _ _ _ _ _ ihx ihy => simp_rw [AlgHom.map_add, ihx, ihy, ← AddMonoidHom.map_add]; rfl + | add _ _ _ _ _ ihx ihy => simp_rw [map_add, ihx, ihy, ← AddMonoidHom.map_add]; rfl | mem_mul _ hm _ _ _ ih => obtain ⟨_, rfl⟩ := hm - simp_rw [AlgHom.map_mul, ih, GradedAlgebra.liftι, lift_ι_apply, GradedAlgebra.ι_apply R M, + simp_rw [map_mul, ih, GradedAlgebra.liftι, lift_ι_apply, GradedAlgebra.ι_apply R M, DirectSum.of_mul_of] exact DirectSum.of_eq_of_gradedMonoid_eq (Sigma.subtype_ext (add_comm _ _) rfl) diff --git a/Mathlib/LinearAlgebra/FreeAlgebra.lean b/Mathlib/LinearAlgebra/FreeAlgebra.lean index 02bbf0606d7640..727a91d91de6a3 100644 --- a/Mathlib/LinearAlgebra/FreeAlgebra.lean +++ b/Mathlib/LinearAlgebra/FreeAlgebra.lean @@ -45,3 +45,15 @@ theorem rank_eq [CommRing R] [Nontrivial R] : Cardinal.lift_umax.{v, u}, FreeMonoid] end FreeAlgebra + +open Cardinal + +theorem Algebra.rank_adjoin_le {R : Type u} {S : Type v} [CommRing R] [Ring S] [Algebra R S] + (s : Set S) : Module.rank R (adjoin R s) ≤ max #s ℵ₀ := by + rw [adjoin_eq_range_freeAlgebra_lift] + cases subsingleton_or_nontrivial R + · rw [rank_subsingleton]; exact one_le_aleph0.trans (le_max_right _ _) + rw [← lift_le.{max u v}] + refine (lift_rank_range_le (FreeAlgebra.lift R ((↑) : s → S)).toLinearMap).trans ?_ + rw [FreeAlgebra.rank_eq, lift_id'.{v,u}, lift_umax.{v,u}, lift_le, max_comm] + exact mk_list_le_max _ diff --git a/Mathlib/LinearAlgebra/FreeModule/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Basic.lean index a53c69bdf4ff3f..99e69913af94bd 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Basic.lean @@ -118,6 +118,27 @@ theorem of_equiv' {P : Type v} [AddCommMonoid P] [Module R P] (_ : Module.Free R (e : P ≃ₗ[R] N) : Module.Free R N := of_equiv e +attribute [local instance] RingHomInvPair.of_ringEquiv in +lemma of_ringEquiv {R R' M M'} [Semiring R] [AddCommMonoid M] [Module R M] + [Semiring R'] [AddCommMonoid M'] [Module R' M'] + (e₁ : R ≃+* R') (e₂ : M ≃ₛₗ[RingHomClass.toRingHom e₁] M') [Module.Free R M] : + Module.Free R' M' := by + let I := Module.Free.ChooseBasisIndex R M + obtain ⟨e₃ : M ≃ₗ[R] I →₀ R⟩ := Module.Free.chooseBasis R M + let e : M' ≃+ (I →₀ R') := + (e₂.symm.trans e₃).toAddEquiv.trans (Finsupp.mapRange.addEquiv (α := I) e₁.toAddEquiv) + have he (x) : e x = Finsupp.mapRange.addEquiv (α := I) e₁.toAddEquiv (e₃ (e₂.symm x)) := rfl + let e' : M' ≃ₗ[R'] (I →₀ R') := + { __ := e, map_smul' := fun m x ↦ Finsupp.ext fun i ↦ by simp [he, map_smulₛₗ] } + exact of_basis (.ofRepr e') + +attribute [local instance] RingHomInvPair.of_ringEquiv in +lemma iff_of_ringEquiv {R R' M M'} [Semiring R] [AddCommMonoid M] [Module R M] + [Semiring R'] [AddCommMonoid M'] [Module R' M'] + (e₁ : R ≃+* R') (e₂ : M ≃ₛₗ[RingHomClass.toRingHom e₁] M') : + Module.Free R M ↔ Module.Free R' M' := + ⟨fun _ ↦ of_ringEquiv e₁ e₂, fun _ ↦ of_ringEquiv e₁.symm e₂.symm⟩ + variable (R M N) /-- The module structure provided by `Semiring.toModule` is free. -/ diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index 39d2c59e032321..eedfde103f8a00 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -913,10 +913,10 @@ theorem linearIndependent_iff_not_smul_mem_span : simp [hij] · simp [hl]⟩ -/-- See also `CompleteLattice.independent_iff_linearIndependent_of_ne_zero`. -/ -theorem LinearIndependent.independent_span_singleton (hv : LinearIndependent R v) : - CompleteLattice.Independent fun i => R ∙ v i := by - refine CompleteLattice.independent_def.mp fun i => ?_ +/-- See also `iSupIndep_iff_linearIndependent_of_ne_zero`. -/ +theorem LinearIndependent.iSupIndep_span_singleton (hv : LinearIndependent R v) : + iSupIndep fun i => R ∙ v i := by + refine iSupIndep_def.mp fun i => ?_ rw [disjoint_iff_inf_le] intro m hm simp only [mem_inf, mem_span_singleton, iSup_subtype'] at hm @@ -928,6 +928,9 @@ theorem LinearIndependent.independent_span_singleton (hv : LinearIndependent R v ext simp +@[deprecated (since := "2024-11-24")] +alias LinearIndependent.independent_span_singleton := LinearIndependent.iSupIndep_span_singleton + variable (R) theorem exists_maximal_independent' (s : ι → M) : diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Minpoly.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Minpoly.lean index 7f0eb6a40db51a..e2a73551493a8f 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Minpoly.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Minpoly.lean @@ -28,8 +28,6 @@ open Finset namespace Matrix -open Matrix - variable (M : Matrix n n R) @[simp] diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean index dafa3eb44607d8..bd291498d65eb5 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean @@ -42,8 +42,6 @@ open Equiv Equiv.Perm Finset Function namespace Matrix -open Matrix - variable {m n : Type*} [DecidableEq n] [Fintype n] [DecidableEq m] [Fintype m] variable {R : Type v} [CommRing R] @@ -211,7 +209,7 @@ theorem det_permute' (σ : Perm n) (M : Matrix n n R) : (M.submatrix id σ).det = Perm.sign σ * M.det := by rw [← det_transpose, transpose_submatrix, det_permute, det_transpose] -/-- Permuting rows and columns with the same equivalence has no effect. -/ +/-- Permuting rows and columns with the same equivalence does not change the determinant. -/ @[simp] theorem det_submatrix_equiv_self (e : n ≃ m) (A : Matrix m m R) : det (A.submatrix e e) = det A := by @@ -224,6 +222,17 @@ theorem det_submatrix_equiv_self (e : n ≃ m) (A : Matrix m m R) : intro i rw [Equiv.permCongr_apply, Equiv.symm_apply_apply, submatrix_apply] +/-- Permuting rows and columns with two equivalences does not change the absolute value of the +determinant. -/ +@[simp] +theorem abs_det_submatrix_equiv_equiv {R : Type*} [LinearOrderedCommRing R] + (e₁ e₂ : n ≃ m) (A : Matrix m m R) : + |(A.submatrix e₁ e₂).det| = |A.det| := by + have hee : e₂ = e₁.trans (e₁.symm.trans e₂) := by ext; simp + rw [hee] + show |((A.submatrix id (e₁.symm.trans e₂)).submatrix e₁ e₁).det| = |A.det| + rw [Matrix.det_submatrix_equiv_self, Matrix.det_permute', abs_mul, abs_unit_intCast, one_mul] + /-- Reindexing both indices along the same equivalence preserves the determinant. For the `simp` version of this lemma, see `det_submatrix_equiv_self`; this one is unsuitable because diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean index 1c03274799f139..03da13b5d17575 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean @@ -5,6 +5,7 @@ Authors: Martin Dvorak, Vladimir Kolmogorov, Ivan Sergeev -/ import Mathlib.LinearAlgebra.Matrix.Determinant.Basic import Mathlib.Data.Matrix.ColumnRowPartitioned +import Mathlib.Data.Sign /-! # Totally unimodular matrices @@ -28,24 +29,21 @@ namespace Matrix variable {m n R : Type*} [CommRing R] -/-- Is the matrix `A` totally unimodular? -/ +/-- `A.IsTotallyUnimodular` means that every square submatrix of `A` (not necessarily contiguous) +has determinant `0` or `1` or `-1`; that is, the determinant is in the range of `SignType.cast`. -/ def IsTotallyUnimodular (A : Matrix m n R) : Prop := ∀ k : ℕ, ∀ f : Fin k → m, ∀ g : Fin k → n, f.Injective → g.Injective → - (A.submatrix f g).det = 0 ∨ - (A.submatrix f g).det = 1 ∨ - (A.submatrix f g).det = -1 + (A.submatrix f g).det ∈ Set.range SignType.cast lemma isTotallyUnimodular_iff (A : Matrix m n R) : A.IsTotallyUnimodular ↔ ∀ k : ℕ, ∀ f : Fin k → m, ∀ g : Fin k → n, - (A.submatrix f g).det = 0 ∨ - (A.submatrix f g).det = 1 ∨ - (A.submatrix f g).det = -1 := by + (A.submatrix f g).det ∈ Set.range SignType.cast := by constructor <;> intro hA · intro k f g - if h : f.Injective ∧ g.Injective then - exact hA k f g h.1 h.2 - else - left + by_cases h : f.Injective ∧ g.Injective + · exact hA k f g h.1 h.2 + · refine ⟨0, ?_⟩ + rw [SignType.coe_zero, eq_comm] simp_rw [not_and_or, Function.not_injective_iff] at h obtain ⟨i, j, hfij, hij⟩ | ⟨i, j, hgij, hij⟩ := h · rw [← det_transpose, transpose_submatrix] @@ -56,12 +54,24 @@ lemma isTotallyUnimodular_iff (A : Matrix m n R) : A.IsTotallyUnimodular ↔ · intro _ _ _ _ _ apply hA +lemma isTotallyUnimodular_iff_fintype.{w} (A : Matrix m n R) : A.IsTotallyUnimodular ↔ + ∀ (ι : Type w) [Fintype ι] [DecidableEq ι], ∀ f : ι → m, ∀ g : ι → n, + (A.submatrix f g).det ∈ Set.range SignType.cast := by + rw [isTotallyUnimodular_iff] + constructor + · intro hA ι _ _ f g + specialize hA (Fintype.card ι) (f ∘ (Fintype.equivFin ι).symm) (g ∘ (Fintype.equivFin ι).symm) + rwa [←submatrix_submatrix, det_submatrix_equiv_self] at hA + · intro hA k f g + specialize hA (ULift (Fin k)) (f ∘ Equiv.ulift) (g ∘ Equiv.ulift) + rwa [←submatrix_submatrix, det_submatrix_equiv_self] at hA + lemma IsTotallyUnimodular.apply {A : Matrix m n R} (hA : A.IsTotallyUnimodular) (i : m) (j : n) : - A i j = 0 ∨ A i j = 1 ∨ A i j = -1 := by + A i j ∈ Set.range SignType.cast := by let f : Fin 1 → m := (fun _ => i) let g : Fin 1 → n := (fun _ => j) - convert hA 1 f g (Function.injective_of_subsingleton f) (Function.injective_of_subsingleton g) <;> + convert hA 1 f g (Function.injective_of_subsingleton f) (Function.injective_of_subsingleton g) exact (det_fin_one (A.submatrix f g)).symm lemma IsTotallyUnimodular.submatrix {A : Matrix m n R} (hA : A.IsTotallyUnimodular) {k : ℕ} @@ -95,7 +105,8 @@ lemma fromRows_row0_isTotallyUnimodular_iff (A : Matrix m n R) {m' : Type*} : · exact hA k (Sum.inl ∘ f) g · if zerow : ∃ i, ∃ x', f i = Sum.inr x' then obtain ⟨i, _, _⟩ := zerow - left + use 0 + rw [eq_comm] apply det_eq_zero_of_row_eq_zero i intro simp_all diff --git a/Mathlib/LinearAlgebra/Matrix/Symmetric.lean b/Mathlib/LinearAlgebra/Matrix/Symmetric.lean index 83d9a2f3dccbab..498e22fb3bacc9 100644 --- a/Mathlib/LinearAlgebra/Matrix/Symmetric.lean +++ b/Mathlib/LinearAlgebra/Matrix/Symmetric.lean @@ -25,8 +25,6 @@ variable {α β n m R : Type*} namespace Matrix -open Matrix - /-- A matrix `A : Matrix n n α` is "symmetric" if `Aᵀ = A`. -/ def IsSymm (A : Matrix n n α) : Prop := Aᵀ = A diff --git a/Mathlib/LinearAlgebra/Matrix/Transvection.lean b/Mathlib/LinearAlgebra/Matrix/Transvection.lean index 1580376e82cc2b..1c777ee3fb514d 100644 --- a/Mathlib/LinearAlgebra/Matrix/Transvection.lean +++ b/Mathlib/LinearAlgebra/Matrix/Transvection.lean @@ -63,8 +63,6 @@ universe u₁ u₂ namespace Matrix -open Matrix - variable (n p : Type*) (R : Type u₂) {𝕜 : Type*} [Field 𝕜] variable [DecidableEq n] [DecidableEq p] variable [CommRing R] diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean index bef753458eb59e..d12337d2b24a34 100644 --- a/Mathlib/LinearAlgebra/Multilinear/Basic.lean +++ b/Mathlib/LinearAlgebra/Multilinear/Basic.lean @@ -285,7 +285,6 @@ def constOfIsEmpty [IsEmpty ι] (m : M₂) : MultilinearMap R M₁ M₂ where end --- Porting note: Included `DFunLike.coe` to avoid strange CoeFun instance for Equiv /-- Given a multilinear map `f` on `n` variables (parameterized by `Fin n`) and a subset `s` of `k` of these variables, one gets a new multilinear map on `Fin k` by varying these variables, and fixing the other ones equal to a given value `z`. It is denoted by `f.restr s hk z`, where `hk` is a @@ -293,7 +292,7 @@ proof that the cardinality of `s` is `k`. The implicit identification between `F we use is the canonical (increasing) bijection. -/ def restr {k n : ℕ} (f : MultilinearMap R (fun _ : Fin n => M') M₂) (s : Finset (Fin n)) (hk : #s = k) (z : M') : MultilinearMap R (fun _ : Fin k => M') M₂ where - toFun v := f fun j => if h : j ∈ s then v ((DFunLike.coe (s.orderIsoOfFin hk).symm) ⟨j, h⟩) else z + toFun v := f fun j => if h : j ∈ s then v ((s.orderIsoOfFin hk).symm ⟨j, h⟩) else z /- Porting note: The proofs of the following two lemmas used to only use `erw` followed by `simp`, but it seems `erw` no longer unfolds or unifies well enough to work without more help. -/ map_update_add' v i x y := by @@ -1719,7 +1718,6 @@ theorem curryFinFinset_symm_apply {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = m <| finSumEquivOfFinset hk hl (Sum.inr i) := rfl --- @[simp] -- Porting note: simpNF linter, lhs simplifies, added aux version below theorem curryFinFinset_symm_apply_piecewise_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) @@ -1734,18 +1732,6 @@ theorem curryFinFinset_symm_apply_piecewise_const {k l n : ℕ} {s : Finset (Fin rw [finSumEquivOfFinset_inr, Finset.piecewise_eq_of_not_mem] exact Finset.mem_compl.1 (Finset.orderEmbOfFin_mem _ _ _) -@[simp] -theorem curryFinFinset_symm_apply_piecewise_const_aux {k l n : ℕ} {s : Finset (Fin n)} - (hk : #s = k) (hl : #sᶜ = l) - (f : MultilinearMap R (fun _ : Fin k => M') (MultilinearMap R (fun _ : Fin l => M') M₂)) - (x y : M') : - ((⇑f fun _ => x) (fun i => (Finset.piecewise s (fun _ => x) (fun _ => y) - ((sᶜ.orderEmbOfFin hl) i))) = f (fun _ => x) fun _ => y) := by - have := curryFinFinset_symm_apply_piecewise_const hk hl f x y - simp only [curryFinFinset_symm_apply, finSumEquivOfFinset_inl, Finset.orderEmbOfFin_mem, - Finset.piecewise_eq_of_mem, finSumEquivOfFinset_inr] at this - exact this - @[simp] theorem curryFinFinset_symm_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) @@ -1753,23 +1739,14 @@ theorem curryFinFinset_symm_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : (x : M') : ((curryFinFinset R M₂ M' hk hl).symm f fun _ => x) = f (fun _ => x) fun _ => x := rfl --- @[simp] -- Porting note: simpNF, lhs simplifies, added aux version below theorem curryFinFinset_apply_const {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : (curryFinFinset R M₂ M' hk hl f (fun _ => x) fun _ => y) = f (s.piecewise (fun _ => x) fun _ => y) := by + -- Porting note: `rw` fails refine (curryFinFinset_symm_apply_piecewise_const hk hl _ _ _).symm.trans ?_ - -- `rw` fails rw [LinearEquiv.symm_apply_apply] -@[simp] -theorem curryFinFinset_apply_const_aux {k l n : ℕ} {s : Finset (Fin n)} (hk : #s = k) - (hl : #sᶜ = l) (f : MultilinearMap R (fun _ : Fin n => M') M₂) (x y : M') : - (f fun i => Sum.elim (fun _ => x) (fun _ => y) ((⇑ (Equiv.symm (finSumEquivOfFinset hk hl))) i)) - = f (s.piecewise (fun _ => x) fun _ => y) := by - rw [← curryFinFinset_apply] - apply curryFinFinset_apply_const - end MultilinearMap end Currying diff --git a/Mathlib/LinearAlgebra/Prod.lean b/Mathlib/LinearAlgebra/Prod.lean index 4a19736a68ba4e..23732c0a352844 100644 --- a/Mathlib/LinearAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/Prod.lean @@ -4,6 +4,7 @@ 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.Algebra.Prod +import Mathlib.Algebra.Group.Graph import Mathlib.LinearAlgebra.Span.Basic import Mathlib.Order.PartialSups @@ -834,17 +835,17 @@ set_option linter.deprecated false /-- An auxiliary construction for `tunnel`. The composition of `f`, followed by the isomorphism back to `K`, followed by the inclusion of this submodule back into `M`. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tunnelAux (f : M × N →ₗ[R] M) (Kφ : ΣK : Submodule R M, K ≃ₗ[R] M) : M × N →ₗ[R] M := (Kφ.1.subtype.comp Kφ.2.symm.toLinearMap).comp f -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tunnelAux_injective (f : M × N →ₗ[R] M) (i : Injective f) (Kφ : ΣK : Submodule R M, K ≃ₗ[R] M) : Injective (tunnelAux f Kφ) := (Subtype.val_injective.comp Kφ.2.symm.injective).comp i /-- Auxiliary definition for `tunnel`. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tunnel' (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → ΣK : Submodule R M, K ≃ₗ[R] M | 0 => ⟨⊤, LinearEquiv.ofTop ⊤ rfl⟩ | n + 1 => @@ -855,7 +856,7 @@ def tunnel' (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → ΣK : Submodule /-- Give an injective map `f : M × N →ₗ[R] M` we can find a nested sequence of submodules all isomorphic to `M`. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tunnel (f : M × N →ₗ[R] M) (i : Injective f) : ℕ →o (Submodule R M)ᵒᵈ := -- Note: the hint `(α := _)` had to be added in https://github.com/leanprover-community/mathlib4/pull/8386 ⟨fun n => OrderDual.toDual (α := Submodule R M) (tunnel' f i n).1, @@ -867,24 +868,24 @@ def tunnel (f : M × N →ₗ[R] M) (i : Injective f) : ℕ →o (Submodule R M) /-- Give an injective map `f : M × N →ₗ[R] M` we can find a sequence of submodules all isomorphic to `N`. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tailing (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Submodule R M := (Submodule.snd R M N).map (tunnelAux f (tunnel' f i n)) /-- Each `tailing f i n` is a copy of `N`. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tailingLinearEquiv (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ≃ₗ[R] N := ((Submodule.snd R M N).equivMapOfInjective _ (tunnelAux_injective f i (tunnel' f i n))).symm.trans (Submodule.sndEquiv R M N) -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ≤ OrderDual.ofDual (α := Submodule R M) (tunnel f i n) := by dsimp [tailing, tunnelAux] rw [Submodule.map_comp, Submodule.map_comp] apply Submodule.map_subtype_le -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailing f i n) (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) := by rw [disjoint_iff] @@ -893,7 +894,7 @@ theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) Submodule.comap_map_eq_of_injective (tunnelAux_injective _ i _), inf_comm, Submodule.fst_inf_snd, Submodule.map_bot] -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ⊔ (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) ≤ (OrderDual.ofDual (α := Submodule R M) <| tunnel f i n) := by @@ -902,19 +903,19 @@ theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injectiv apply Submodule.map_subtype_le /-- The supremum of all the copies of `N` found inside the tunnel. -/ -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tailings (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → Submodule R M := partialSups (tailing f i) -@[simp, deprecated (since := "2024-06-05")] +@[simp, deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_zero (f : M × N →ₗ[R] M) (i : Injective f) : tailings f i 0 = tailing f i 0 := by simp [tailings] -@[simp, deprecated (since := "2024-06-05")] +@[simp, deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailings f i (n + 1) = tailings f i n ⊔ tailing f i (n + 1) := by simp [tailings] -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailings f i n) (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) := by induction' n with n ih @@ -926,7 +927,7 @@ theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : · apply Disjoint.mono_right _ ih apply tailing_sup_tunnel_succ_le_tunnel -@[deprecated (since := "2024-06-05")] +@[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_disjoint_tailing (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailings f i n) (tailing f i (n + 1)) := Disjoint.mono_right (tailing_le_tunnel f i _) (tailings_disjoint_tunnel f i _) @@ -965,3 +966,84 @@ theorem graph_eq_range_prod : f.graph = range (LinearMap.id.prod f) := by end Graph end LinearMap + +section LineTest + +open Set Function + +variable {R S G H I : Type*} + [Semiring R] [Semiring S] {σ : R →+* S} [RingHomSurjective σ] + [AddCommMonoid G] [Module R G] + [AddCommMonoid H] [Module S H] + [AddCommMonoid I] [Module S I] + +/-- **Vertical line test** for module homomorphisms. + +Let `f : G → H × I` be a linear (or semilinear) map to a product. Assume that `f` is surjective on +the first factor and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` at +most once. Then the image of `f` is the graph of some linear map `f' : H → I`. -/ +lemma LinearMap.exists_range_eq_graph {f : G →ₛₗ[σ] H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 → (f g₁).2 = (f g₂).2) : + ∃ f' : H →ₗ[S] I, LinearMap.range f = LinearMap.graph f' := by + obtain ⟨f', hf'⟩ := AddMonoidHom.exists_mrange_eq_mgraph (I := I) (f := f) hf₁ hf + simp only [SetLike.ext_iff, AddMonoidHom.mem_mrange, AddMonoidHom.coe_coe, + AddMonoidHom.mem_mgraph] at hf' + use + { toFun := f'.toFun + map_add' := f'.map_add' + map_smul' := by + intro s h + simp only [ZeroHom.toFun_eq_coe, AddMonoidHom.toZeroHom_coe, RingHom.id_apply] + refine (hf' (s • h, _)).mp ?_ + rw [← Prod.smul_mk, ← LinearMap.mem_range] + apply Submodule.smul_mem + rw [LinearMap.mem_range, hf'] } + ext x + simpa only [mem_range, Eq.comm, ZeroHom.toFun_eq_coe, AddMonoidHom.toZeroHom_coe, mem_graph_iff, + coe_mk, AddHom.coe_mk, AddMonoidHom.coe_coe, Set.mem_range] using hf' x + +/-- **Vertical line test** for module homomorphisms. + +Let `G ≤ H × I` be a submodule of a product of modules. Assume that `G` maps bijectively to the +first factor. Then `G` is the graph of some module homomorphism `f : H →ₗ[R] I`. -/ +lemma Submodule.exists_eq_graph {G : Submodule S (H × I)} (hf₁ : Bijective (Prod.fst ∘ G.subtype)) : + ∃ f : H →ₗ[S] I, G = LinearMap.graph f := by + simpa only [range_subtype] using LinearMap.exists_range_eq_graph hf₁.surjective + (fun a b h ↦ congr_arg (Prod.snd ∘ G.subtype) (hf₁.injective h)) + +/-- **Line test** for module isomorphisms. + +Let `f : G → H × I` be a homomorphism to a product of modules. Assume that `f` is surjective onto +both factors and that the image of `f` intersects every "vertical line" `{(h, i) | i : I}` and every +"horizontal line" `{(h, i) | h : H}` at most once. Then the image of `f` is the graph of some +module isomorphism `f' : H ≃ I`. -/ +lemma LinearMap.exists_linearEquiv_eq_graph {f : G →ₛₗ[σ] H × I} (hf₁ : Surjective (Prod.fst ∘ f)) + (hf₂ : Surjective (Prod.snd ∘ f)) (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 ↔ (f g₁).2 = (f g₂).2) : + ∃ e : H ≃ₗ[S] I, range f = e.toLinearMap.graph := by + obtain ⟨e₁, he₁⟩ := f.exists_range_eq_graph hf₁ fun _ _ ↦ (hf _ _).1 + obtain ⟨e₂, he₂⟩ := ((LinearEquiv.prodComm _ _ _).toLinearMap.comp f).exists_range_eq_graph + (by simpa) <| by simp [hf] + have he₁₂ h i : e₁ h = i ↔ e₂ i = h := by + simp only [SetLike.ext_iff, LinearMap.mem_graph_iff] at he₁ he₂ + rw [Eq.comm, ← he₁ (h, i), Eq.comm, ← he₂ (i, h)] + simp only [mem_range, coe_comp, LinearEquiv.coe_coe, Function.comp_apply, + LinearEquiv.prodComm_apply, Prod.swap_eq_iff_eq_swap, Prod.swap_prod_mk] + exact ⟨ + { toFun := e₁ + map_smul' := e₁.map_smul' + map_add' := e₁.map_add' + invFun := e₂ + left_inv := fun h ↦ by rw [← he₁₂] + right_inv := fun i ↦ by rw [he₁₂] }, he₁⟩ + +/-- **Goursat's lemma** for module isomorphisms. + +Let `G ≤ H × I` be a submodule of a product of modules. Assume that the natural maps from `G` to +both factors are bijective. Then `G` is the graph of some module isomorphism `f : H ≃ I`. -/ +lemma Submodule.exists_equiv_eq_graph {G : Submodule S (H × I)} + (hG₁ : Bijective (Prod.fst ∘ G.subtype)) (hG₂ : Bijective (Prod.snd ∘ G.subtype)) : + ∃ e : H ≃ₗ[S] I, G = e.toLinearMap.graph := by + simpa only [range_subtype] using LinearMap.exists_linearEquiv_eq_graph + hG₁.surjective hG₂.surjective fun _ _ ↦ hG₁.injective.eq_iff.trans hG₂.injective.eq_iff.symm + +end LineTest diff --git a/Mathlib/LinearAlgebra/Projectivization/Basic.lean b/Mathlib/LinearAlgebra/Projectivization/Basic.lean index 9a12ad4ccb6576..38496cfef13f4d 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Basic.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Basic.lean @@ -84,10 +84,10 @@ protected lemma lift_mk {α : Type*} (f : { v : V // v ≠ 0 } → α) /-- Choose a representative of `v : Projectivization K V` in `V`. -/ protected noncomputable def rep (v : ℙ K V) : V := - v.out' + v.out theorem rep_nonzero (v : ℙ K V) : v.rep ≠ 0 := - v.out'.2 + v.out.2 @[simp] theorem mk_rep (v : ℙ K V) : mk K v.rep v.rep_nonzero = v := Quotient.out_eq' _ diff --git a/Mathlib/LinearAlgebra/Projectivization/Independence.lean b/Mathlib/LinearAlgebra/Projectivization/Independence.lean index e9a6bf429c7e2a..403138f8a84d98 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Independence.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Independence.lean @@ -56,17 +56,19 @@ theorem independent_iff : Independent f ↔ LinearIndependent K (Projectivizatio /-- A family of points in projective space is independent if and only if the family of submodules which the points determine is independent in the lattice-theoretic sense. -/ -theorem independent_iff_completeLattice_independent : - Independent f ↔ CompleteLattice.Independent fun i => (f i).submodule := by +theorem independent_iff_iSupIndep : Independent f ↔ iSupIndep fun i => (f i).submodule := by refine ⟨?_, fun h => ?_⟩ · rintro ⟨f, hf, hi⟩ simp only [submodule_mk] - exact (CompleteLattice.independent_iff_linearIndependent_of_ne_zero (R := K) hf).mpr hi + exact (iSupIndep_iff_linearIndependent_of_ne_zero (R := K) hf).mpr hi · rw [independent_iff] refine h.linearIndependent (Projectivization.submodule ∘ f) (fun i => ?_) fun i => ?_ · simpa only [Function.comp_apply, submodule_eq] using Submodule.mem_span_singleton_self _ · exact rep_nonzero (f i) +@[deprecated (since := "2024-11-24")] +alias independent_iff_completeLattice_independent := independent_iff_iSupIndep + /-- A linearly dependent family of nonzero vectors gives a dependent family of points in projective space. -/ inductive Dependent : (ι → ℙ K V) → Prop diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean index bec420998fa643..9778e86170c131 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean @@ -526,8 +526,8 @@ variable [CommSemiring R] [CommSemiring S] [AddCommMonoid M] [Module R M] [AddCo [Module R N] [Module S M] [Module S N] [Algebra S R] variable [IsScalarTower S R M] [IsScalarTower S R N] -/-- If `B : M → N → Pₗ` is `R`-`S` bilinear and `R'` and `S'` are compatible scalar multiplications, -then the restriction of scalars is a `R'`-`S'` bilinear map. -/ +/-- If `Q : M → N` is a quadratic map of `R`-modules and `R` is an `S`-algebra, +then the restriction of scalars is a quadratic map of `S`-modules. -/ @[simps!] def restrictScalars (Q : QuadraticMap R M N) : QuadraticMap S M N where toFun x := Q x @@ -597,12 +597,13 @@ theorem _root_.LinearEquiv.congrQuadraticMap_symm (e : N ≃ₗ[R] P) : (LinearEquiv.congrQuadraticMap e (M := M)).symm = e.symm.congrQuadraticMap := rfl end Comp + section NonUnitalNonAssocSemiring variable [CommSemiring R] [NonUnitalNonAssocSemiring A] [AddCommMonoid M] [Module R M] variable [Module R A] [SMulCommClass R A A] [IsScalarTower R A A] -/-- The product of linear forms is a quadratic form. -/ +/-- The product of linear maps into an `R`-algebra is a quadratic map. -/ def linMulLin (f g : M →ₗ[R] A) : QuadraticMap R M A where toFun := f * g toFun_smul a x := by @@ -635,12 +636,12 @@ theorem linMulLin_comp (f g : M →ₗ[R] A) (h : N' →ₗ[R] M) : variable {n : Type*} -/-- `sq` is the quadratic form mapping the vector `x : A` to `x * x` -/ +/-- `sq` is the quadratic map sending the vector `x : A` to `x * x` -/ @[simps!] def sq : QuadraticMap R A A := linMulLin LinearMap.id LinearMap.id -/-- `proj i j` is the quadratic form mapping the vector `x : n → R` to `x i * x j` -/ +/-- `proj i j` is the quadratic map sending the vector `x : n → R` to `x i * x j` -/ def proj (i j : n) : QuadraticMap R (n → A) A := linMulLin (@LinearMap.proj _ _ _ (fun _ => A) _ _ i) (@LinearMap.proj _ _ _ (fun _ => A) _ _ j) @@ -655,10 +656,16 @@ end QuadraticMap /-! ### Associated bilinear maps -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 `QuadraticMap.associated` -quadratic map. +If multiplication by 2 is invertible on the target module `N` of +`QuadraticMap R M N`, then there is a linear bijection `QuadraticMap.associated` +between quadratic maps `Q` over `R` from `M` to `N` and symmetric bilinear maps +`B : M →ₗ[R] M →ₗ[R] → N` such that `BilinMap.toQuadraticMap B = Q` +(see `QuadraticMap.associated_rightInverse`). The associated bilinear map is half +`Q.polarBilin` (see `QuadraticMap.two_nsmul_associated`); this is where the invertibility condition +comes from. We spell the condition as `[Invertible (2 : Module.End R N)]`. + +Note that this makes the bijection available in more cases than the simpler condition +`Invertible (2 : R)`, e.g., when `R = ℤ` and `N = ℝ`. -/ namespace LinearMap @@ -711,14 +718,14 @@ section variable (S R M) -/-- `LinearMap.BilinForm.toQuadraticMap` as an additive homomorphism -/ +/-- `LinearMap.BilinMap.toQuadraticMap` as an additive homomorphism -/ @[simps] def toQuadraticMapAddMonoidHom : (BilinMap R M N) →+ QuadraticMap R M N where toFun := toQuadraticMap map_zero' := toQuadraticMap_zero _ _ map_add' := toQuadraticMap_add -/-- `LinearMap.BilinForm.toQuadraticMap` as a linear map -/ +/-- `LinearMap.BilinMap.toQuadraticMap` as a linear map -/ @[simps!] def toQuadraticMapLinearMap [Semiring S] [Module S N] [SMulCommClass S R N] [SMulCommClass R S N] : (BilinMap R M N) →ₗ[S] QuadraticMap R M N where @@ -818,43 +825,87 @@ namespace QuadraticMap open LinearMap (BilinMap) +section + +variable [Semiring R] [AddCommMonoid M] [Module R M] + +instance : SMulCommClass R (Submonoid.center R) M where + smul_comm r r' m := by + simp_rw [Submonoid.smul_def, smul_smul, (Set.mem_center_iff.1 r'.prop).1] + +/-- If `2` is invertible in `R`, then it is also invertible in `End R M`. -/ +instance [Invertible (2 : R)] : Invertible (2 : Module.End R M) where + invOf := (⟨⅟2, Set.invOf_mem_center (Set.ofNat_mem_center _ _)⟩ : Submonoid.center R) • + (1 : Module.End R M) + invOf_mul_self := by + ext m + dsimp [Submonoid.smul_def] + rw [← ofNat_smul_eq_nsmul R, invOf_smul_smul (2 : R) m] + mul_invOf_self := by + ext m + dsimp [Submonoid.smul_def] + rw [← ofNat_smul_eq_nsmul R, smul_invOf_smul (2 : R) m] + +/-- If `2` is invertible in `R`, then applying the inverse of `2` in `End R M` to an element +of `M` is the same as multiplying by the inverse of `2` in `R`. -/ +@[simp] +lemma half_moduleEnd_apply_eq_half_smul [Invertible (2 : R)] (x : M) : + ⅟ (2 : Module.End R M) x = ⅟ (2 : R) • x := + rfl + +end + section AssociatedHom -variable [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] -variable (S) [CommSemiring S] [Algebra S R] -variable [Module S N] [IsScalarTower S R N] -variable [Invertible (2 : R)] {B₁ : BilinMap R M R} +variable [CommRing R] [AddCommGroup M] [Module R M] +variable [AddCommGroup N] [Module R N] +variable (S) [CommSemiring S] [Algebra S R] [Module S N] [IsScalarTower S R N] + +-- the requirement that multiplication by `2` is invertible on the target module `N` +variable [Invertible (2 : Module.End R N)] /-- `associatedHom` is the map that sends a quadratic map on a module `M` over `R` to its associated symmetric bilinear map. As provided here, this has the structure of an `S`-linear map -where `S` is a commutative subring of `R`. +where `S` is a commutative ring and `R` is an `S`-algebra. Over a commutative ring, use `QuadraticMap.associated`, which gives an `R`-linear map. Over a general ring with no nontrivial distinguished commutative subring, use `QuadraticMap.associated'`, which gives an additive homomorphism (or more precisely a `ℤ`-linear map.) -/ -def associatedHom : QuadraticMap R M N →ₗ[S] (BilinMap R M N) := - -- TODO: this `center` stuff is vertigial from an incorrect non-commutative version, but we leave - -- it behind to make a future refactor to a *correct* non-commutative version easier in future. - (⟨⅟2, Set.invOf_mem_center (Set.ofNat_mem_center _ _)⟩ : Submonoid.center R) • - { toFun := polarBilin - map_add' := fun _x _y => LinearMap.ext₂ <| polar_add _ _ - map_smul' := fun _c _x => LinearMap.ext₂ <| polar_smul _ _ } +def associatedHom : QuadraticMap R M N →ₗ[S] (BilinMap R M N) where + toFun Q := ⅟ (2 : Module.End R N) • polarBilin Q + map_add' _ _ := + LinearMap.ext₂ fun _ _ ↦ by + simp only [LinearMap.smul_apply, polarBilin_apply_apply, coeFn_add, polar_add, + LinearMap.smul_def, LinearMap.map_add, LinearMap.add_apply] + map_smul' _ _ := + LinearMap.ext₂ fun _ _ ↦ by + simp only [LinearMap.smul_apply, polarBilin_apply_apply, coeFn_smul, polar_smul, + LinearMap.smul_def, LinearMap.map_smul_of_tower, RingHom.id_apply] variable (Q : QuadraticMap R M N) @[simp] -theorem associated_apply (x y : M) : associatedHom S Q x y = ⅟ (2 : R) • (Q (x + y) - Q x - Q y) := +theorem associated_apply (x y : M) : + associatedHom S Q x y = ⅟ (2 : Module.End R N) • (Q (x + y) - Q x - Q y) := rfl +/-- Twice the associated bilinear map of `Q` is the same as the polar of `Q`. -/ @[simp] theorem two_nsmul_associated : 2 • associatedHom S Q = Q.polarBilin := by ext dsimp - rw [← smul_assoc, two_nsmul, invOf_two_add_invOf_two, one_smul, polar] + rw [← LinearMap.smul_apply, nsmul_eq_mul, Nat.cast_ofNat, mul_invOf_self', LinearMap.one_apply, + polar] -theorem associated_isSymm (Q : QuadraticMap R M R) : (associatedHom S Q).IsSymm := fun x y => by - simp only [associated_apply, sub_eq_add_neg, add_assoc, map_mul, RingHom.id_apply, map_add, - _root_.map_neg, add_comm, add_left_comm] +theorem associated_isSymm (Q : QuadraticForm R M) [Invertible (2 : R)] : + (associatedHom S Q).IsSymm := fun x y ↦ by + simp only [associated_apply, sub_eq_add_neg, add_assoc, RingHom.id_apply, add_comm, add_left_comm] +/-- A version of `QuadraticMap.associated_isSymm` for general targets +(using `flip` because `IsSymm` does not apply here). -/ +lemma associated_flip : (associatedHom S Q).flip = associatedHom S Q := by + ext + simp only [LinearMap.flip_apply, associated_apply, add_comm, sub_eq_add_neg, add_left_comm, + add_assoc] @[simp] theorem associated_comp {N' : Type*} [AddCommGroup N'] [Module R N'] (f : N' →ₗ[R] M) : @@ -862,23 +913,29 @@ theorem associated_comp {N' : Type*} [AddCommGroup N'] [Module R N'] (f : N' → ext simp only [associated_apply, comp_apply, map_add, LinearMap.compl₁₂_apply] -theorem associated_toQuadraticMap (B : BilinMap R M R) (x y : M) : - associatedHom S B.toQuadraticMap x y = ⅟ (2 : R) • (B x y + B y x) := by - simp only [associated_apply, LinearMap.BilinMap.toQuadraticMap_apply, map_add, - LinearMap.add_apply, smul_eq_mul] +theorem associated_toQuadraticMap (B : BilinMap R M N) (x y : M) : + associatedHom S B.toQuadraticMap x y = ⅟ (2 : Module.End R N) • (B x y + B y x) := by + simp only [associated_apply, BilinMap.toQuadraticMap_apply, map_add, LinearMap.add_apply, + LinearMap.smul_def, _root_.map_sub] abel_nf -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] - match_scalars - linear_combination invOf_mul_self' (2:R) +theorem associated_left_inverse [Invertible (2 : R)] {B₁ : BilinMap R M R} (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_eq_mul, + invOf_smul_eq_iff, two_smul, two_smul] + +/-- A version of `QuadraticMap.associated_left_inverse` for general targets. -/ +lemma associated_left_inverse' {B₁ : BilinMap R M N} (hB₁ : B₁.flip = B₁) : + associatedHom S B₁.toQuadraticMap = B₁ := by + ext _ y + rw [associated_toQuadraticMap, ← LinearMap.flip_apply _ y, hB₁, invOf_smul_eq_iff, two_smul] -- 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] - match_scalars - linear_combination invOf_mul_self' (2:R) + 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, + invOf_smul_eq_iff, two_smul, two_smul] theorem toQuadraticMap_associated : (associatedHom S Q).toQuadraticMap = Q := QuadraticMap.ext <| associated_eq_self_apply S Q @@ -887,7 +944,7 @@ theorem toQuadraticMap_associated : (associatedHom S Q).toQuadraticMap = Q := -- with historical naming in this file. theorem associated_rightInverse : Function.RightInverse (associatedHom S) (BilinMap.toQuadraticMap : _ → QuadraticMap R M N) := - fun Q => toQuadraticMap_associated S Q + toQuadraticMap_associated S /-- `associated'` is the `ℤ`-linear map that sends a quadratic form on a module `M` over `R` to its associated symmetric bilinear form. -/ @@ -895,10 +952,15 @@ abbrev associated' : QuadraticMap R M N →ₗ[ℤ] BilinMap R M N := associatedHom ℤ /-- Symmetric bilinear forms can be lifted to quadratic forms -/ -instance canLift : +instance canLift [Invertible (2 : R)] : CanLift (BilinMap R M R) (QuadraticForm R M) (associatedHom ℕ) LinearMap.IsSymm where prf B hB := ⟨B.toQuadraticMap, associated_left_inverse _ hB⟩ +/-- Symmetric bilinear maps can be lifted to quadratic maps -/ +instance canLift' : + CanLift (BilinMap R M N) (QuadraticMap R M N) (associatedHom ℕ) fun B ↦ B.flip = B where + prf B hB := ⟨B.toQuadraticMap, associated_left_inverse' _ hB⟩ + /-- There exists a non-null vector with respect to any quadratic form `Q` whose associated bilinear form is non-zero, i.e. there exists `x` such that `Q x ≠ 0`. -/ theorem exists_quadraticMap_ne_zero {Q : QuadraticMap R M N} @@ -919,10 +981,11 @@ section Associated variable [CommSemiring S] [CommRing R] [AddCommGroup M] [Algebra S R] [Module R M] variable [AddCommGroup N] [Module R N] [Module S N] [IsScalarTower S R N] -variable [Invertible (2 : R)] +variable [Invertible (2 : Module.End R N)] -- Note: When possible, rather than writing lemmas about `associated`, write a lemma applying to -- the more general `associatedHom` and place it in the previous section. + /-- `associated` is the linear map that sends a quadratic map over a commutative ring to its associated symmetric bilinear map. -/ abbrev associated : QuadraticMap R M N →ₗ[R] BilinMap R M N := @@ -935,17 +998,19 @@ theorem coe_associatedHom : open LinearMap in @[simp] -theorem associated_linMulLin (f g : M →ₗ[R] R) : - associated (R := R) (linMulLin f g) = +theorem associated_linMulLin [Invertible (2 : R)] (f g : M →ₗ[R] R) : + associated (R := R) (N := R) (linMulLin f g) = ⅟ (2 : R) • ((mul R R).compl₁₂ f g + (mul R R).compl₁₂ g f) := by ext simp only [associated_apply, linMulLin_apply, map_add, smul_add, LinearMap.add_apply, - LinearMap.smul_apply, compl₁₂_apply, mul_apply', smul_eq_mul] + LinearMap.smul_apply, compl₁₂_apply, mul_apply', smul_eq_mul, invOf_smul_eq_iff] + simp only [smul_add, LinearMap.smul_def, Module.End.ofNat_apply, nsmul_eq_mul, Nat.cast_ofNat, + mul_invOf_cancel_left'] ring_nf open LinearMap in @[simp] -lemma associated_sq : associated (R := R) sq = mul R R := +lemma associated_sq [Invertible (2 : R)] : associated (R := R) sq = mul R R := (associated_linMulLin (id) (id)).trans <| by simp only [smul_add, invOf_two_smul_add_invOf_two_smul]; rfl @@ -1296,7 +1361,7 @@ theorem weightedSumSquares_apply [Monoid S] [DistribMulAction S R] [SMulCommClas /-- On an orthogonal basis, the basis representation of `Q` is just a sum of squares. -/ theorem basisRepr_eq_of_iIsOrtho {R M} [CommRing R] [AddCommGroup M] [Module R M] - [Invertible (2 : R)] (Q : QuadraticMap R M R) (v : Basis ι R M) + [Invertible (2 : R)] (Q : QuadraticForm R M) (v : Basis ι R M) (hv₂ : (associated (R := R) Q).IsOrthoᵢ v) : Q.basisRepr v = weightedSumSquares _ fun i => Q (v i) := by ext w @@ -1304,7 +1369,7 @@ theorem basisRepr_eq_of_iIsOrtho {R M} [CommRing R] [AddCommGroup M] [Module R M refine sum_congr rfl fun j hj => ?_ rw [← @associated_eq_self_apply R, LinearMap.map_sum₂, sum_eq_single_of_mem j hj] · rw [LinearMap.map_smul, LinearMap.map_smul₂, smul_eq_mul, associated_apply, smul_eq_mul, - smul_eq_mul, smul_eq_mul] + smul_eq_mul, LinearMap.smul_def, half_moduleEnd_apply_eq_half_smul] ring_nf · intro i _ hij rw [LinearMap.map_smul, LinearMap.map_smul₂, hv₂ hij] diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean b/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean index 48db5f20ea5c2b..803a8340d71e36 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Dual.lean @@ -141,8 +141,11 @@ def toDualProd (Q : QuadraticForm R M) [Invertible (2 : R)] : LinearMap.coe_toAddHom, LinearMap.prod_apply, Pi.prod, LinearMap.add_apply, LinearMap.coe_comp, Function.comp_apply, LinearMap.fst_apply, LinearMap.snd_apply, LinearMap.sub_apply, dualProd_apply, polarBilin_apply_apply, prod_apply, neg_apply] - simp [polar_comm _ x.1 x.2, ← sub_add, mul_sub, sub_mul, smul_sub, Submonoid.smul_def, ← - sub_eq_add_neg (Q x.1) (Q x.2)] + simp only [polar_sub_right, polar_self, nsmul_eq_mul, Nat.cast_ofNat, polar_comm _ x.1 x.2, + smul_sub, LinearMap.smul_def, sub_add_sub_cancel, ← sub_eq_add_neg (Q x.1) (Q x.2)] + rw [← LinearMap.map_sub (⅟ 2 : Module.End R R), ← mul_sub, ← LinearMap.smul_def] + simp only [LinearMap.smul_def, half_moduleEnd_apply_eq_half_smul, smul_eq_mul, + invOf_mul_cancel_left'] /-! TODO: show that `QuadraticForm.toDualProd` is an `QuadraticForm.IsometryEquiv` diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean index 328b2319e0765e..c9ef8e47cf38d1 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Prod.lean @@ -37,8 +37,6 @@ variable {ι : Type*} {R : Type*} {M₁ M₂ N₁ N₂ P : Type*} {Mᵢ Nᵢ : namespace QuadraticMap -open QuadraticMap - section Prod section Semiring diff --git a/Mathlib/LinearAlgebra/Ray.lean b/Mathlib/LinearAlgebra/Ray.lean index 7890952886f09a..d569b5c080c98f 100644 --- a/Mathlib/LinearAlgebra/Ray.lean +++ b/Mathlib/LinearAlgebra/Ray.lean @@ -6,7 +6,7 @@ Authors: Joseph Myers import Mathlib.Algebra.Order.Module.Algebra import Mathlib.LinearAlgebra.LinearIndependent import Mathlib.Algebra.Ring.Subring.Units -import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Positivity.Basic /-! # Rays in modules diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean index 420de4b340130d..d9ab0eb932455c 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean @@ -374,6 +374,12 @@ 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 linear span of roots. -/ +abbrev rootSpan := span R (range P.root) + +/-- The linear span of coroots. -/ +abbrev corootSpan := span R (range P.coroot) + /-- The `Weyl group` of a root pairing is the group of automorphisms of the weight space generated by reflections in roots. -/ def weylGroup : Subgroup (M ≃ₗ[R] M) := diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean index d495f1b08bbcc5..1f7676b71d4ad5 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean @@ -3,8 +3,9 @@ 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.Order.BigOperators.Ring.Finset import Mathlib.Algebra.Ring.SumsOfSquares +import Mathlib.LinearAlgebra.RootSystem.Defs /-! # The canonical bilinear form on a finite root pairing @@ -22,27 +23,28 @@ Weyl group. * `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. + * `rootForm_self_non_neg`: `RootForm` is positive semidefinite. + +## References: + * [N. Bourbaki, *Lie groups and {L}ie algebras. {C}hapters 4--6*][bourbaki1968] + * [M. Demazure, *SGA III, Expos\'{e} XXI, Don\'{e}es Radicielles*][demazure1970] ## 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 Set Function open Module hiding reflection +open Submodule (span) noncomputable section @@ -132,6 +134,54 @@ 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] +theorem range_polarization_domRestrict_le_span_coroot : + LinearMap.range (P.Polarization.domRestrict P.rootSpan) ≤ P.corootSpan := by + intro y hy + obtain ⟨x, hx⟩ := hy + rw [← hx, LinearMap.domRestrict_apply, Polarization_apply] + refine (mem_span_range_iff_exists_fun R).mpr ?_ + use fun i => (P.toPerfectPairing x) (P.coroot i) + simp + end CommRing +section LinearOrderedCommRing + +variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] + [Module R N] (P : RootPairing ι R M N) + +theorem rootForm_self_non_neg (x : M) : 0 ≤ P.RootForm x x := + IsSumSq.nonneg (P.rootForm_self_sum_of_squares x) + +theorem rootForm_self_zero_iff (x : M) : + P.RootForm x x = 0 ↔ ∀ i, P.coroot' i x = 0 := by + simp only [rootForm_apply_apply, PerfectPairing.toLin_apply, LinearMap.coe_comp, comp_apply, + Polarization_apply, map_sum, map_smul, smul_eq_mul] + convert Finset.sum_mul_self_eq_zero_iff Finset.univ fun i => P.coroot' i x + simp + +lemma rootForm_root_self_pos (j : ι) : + 0 < P.RootForm (P.root j) (P.root j) := by + simp only [LinearMap.coe_mk, AddHom.coe_mk, LinearMap.coe_comp, comp_apply, + rootForm_apply_apply, toLin_toPerfectPairing] + refine Finset.sum_pos' (fun i _ => (sq (P.pairing j i)) ▸ sq_nonneg (P.pairing j i)) ?_ + use j + simp + +lemma prod_rootForm_root_self_pos : + 0 < ∏ i, P.RootForm (P.root i) (P.root i) := + Finset.prod_pos fun i _ => rootForm_root_self_pos P i + +lemma prod_rootForm_smul_coroot_mem_range_domRestrict (i : ι) : + (∏ a : ι, P.RootForm (P.root a) (P.root a)) • P.coroot i ∈ + LinearMap.range (P.Polarization.domRestrict (P.rootSpan)) := by + obtain ⟨c, hc⟩ := Finset.dvd_prod_of_mem (fun a ↦ P.RootForm (P.root a) (P.root a)) + (Finset.mem_univ i) + rw [hc, mul_comm, mul_smul, rootForm_self_smul_coroot] + refine LinearMap.mem_range.mpr ?_ + use ⟨(c • 2 • P.root i), by aesop⟩ + simp + +end LinearOrderedCommRing + end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean new file mode 100644 index 00000000000000..1efe86c29f24f5 --- /dev/null +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean @@ -0,0 +1,128 @@ +/- +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.BilinearForm.Basic +import Mathlib.LinearAlgebra.Dimension.Localization +import Mathlib.LinearAlgebra.QuadraticForm.Basic +import Mathlib.LinearAlgebra.RootSystem.Finite.CanonicalBilinear +import Mathlib.LinearAlgebra.RootSystem.RootPositive + +/-! +# Nondegeneracy of the polarization on a finite root pairing + +We show that if the base ring of a finite root pairing is linearly ordered, then the canonical +bilinear form is root-positive 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 root pairing are restricted to the +interval `[-4, 4]`. Furthermore, a linearly independent pair of roots cannot have Coxeter weight 4. +For the case of crystallographic root pairings, we are thus reduced to a finite set of possible +options for each pair. +Another application is to the faithfulness of the Weyl group action on roots, and finiteness of the +Weyl group. + +## Main results: + * `RootPairing.rootForm_rootPositive`: `RootForm` is root-positive. + * `RootPairing.polarization_domRestrict_injective`: The polarization restricted to the span of + roots is injective. + * `RootPairing.rootForm_pos_of_nonzero`: `RootForm` is strictly positive on non-zero linear + combinations of roots. This gives us a convenient way to eliminate certain Dynkin diagrams from + the classification, since it suffices to produce a nonzero linear combination of simple roots with + non-positive norm. + +## References: + * [N. Bourbaki, *Lie groups and {L}ie algebras. {C}hapters 4--6*][bourbaki1968] + * [M. Demazure, *SGA III, Expos\'{e} XXI, Don\'{e}es Radicielles*][demazure1970] + +## Todo + * Weyl-invariance of `RootForm` and `CorootForm` + * Faithfulness of Weyl group perm action, and finiteness of Weyl group, over ordered rings. + * Relation to Coxeter weight. In particular, positivity constraints for finite root pairings mean + we restrict to weights between 0 and 4. +-/ + +noncomputable section + +open Set Function +open Module hiding reflection +open Submodule (span) + +namespace RootPairing + +variable {ι R M N : Type*} + +variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] +[Module R N] (P : RootPairing ι R M N) + +lemma rootForm_rootPositive : IsRootPositive P P.RootForm where + zero_lt_apply_root i := P.rootForm_root_self_pos i + symm := P.rootForm_symmetric + apply_reflection_eq := P.rootForm_reflection_reflection_apply + +instance : Module.Finite R P.rootSpan := Finite.span_of_finite R <| finite_range P.root + +instance : Module.Finite R P.corootSpan := Finite.span_of_finite R <| finite_range P.coroot + +@[simp] +lemma finrank_rootSpan_map_polarization_eq_finrank_corootSpan : + finrank R (P.rootSpan.map P.Polarization) = finrank R P.corootSpan := by + rw [← LinearMap.range_domRestrict] + apply (Submodule.finrank_mono P.range_polarization_domRestrict_le_span_coroot).antisymm + have : IsReflexive R N := PerfectPairing.reflexive_right P.toPerfectPairing + refine LinearMap.finrank_le_of_isSMulRegular P.corootSpan + (LinearMap.range (P.Polarization.domRestrict P.rootSpan)) + (smul_right_injective N (Ne.symm (ne_of_lt P.prod_rootForm_root_self_pos))) + fun _ hx => ?_ + obtain ⟨c, hc⟩ := (mem_span_range_iff_exists_fun R).mp hx + rw [← hc, Finset.smul_sum] + simp_rw [smul_smul, mul_comm, ← smul_smul] + exact Submodule.sum_smul_mem (LinearMap.range (P.Polarization.domRestrict P.rootSpan)) c + (fun c _ ↦ prod_rootForm_smul_coroot_mem_range_domRestrict P c) + +/-- An auxiliary lemma en route to `RootPairing.finrank_corootSpan_eq`. -/ +private lemma finrank_corootSpan_le : + finrank R P.corootSpan ≤ finrank R P.rootSpan := by + rw [← finrank_rootSpan_map_polarization_eq_finrank_corootSpan] + exact Submodule.finrank_map_le P.Polarization P.rootSpan + +lemma finrank_corootSpan_eq : + finrank R P.corootSpan = finrank R P.rootSpan := + le_antisymm P.finrank_corootSpan_le P.flip.finrank_corootSpan_le + +lemma disjoint_rootSpan_ker_polarization : + Disjoint P.rootSpan (LinearMap.ker P.Polarization) := by + have : IsReflexive R M := PerfectPairing.reflexive_left P.toPerfectPairing + refine Submodule.disjoint_ker_of_finrank_eq (L := P.rootSpan) P.Polarization ?_ + rw [finrank_rootSpan_map_polarization_eq_finrank_corootSpan, finrank_corootSpan_eq] + +lemma mem_ker_polarization_of_rootForm_self_eq_zero {x : M} (hx : P.RootForm x x = 0) : + x ∈ LinearMap.ker P.Polarization := by + rw [LinearMap.mem_ker, Polarization_apply] + rw [rootForm_self_zero_iff] at hx + exact Fintype.sum_eq_zero _ fun i ↦ by simp [hx i] + +lemma eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero {x : M} + (hx : x ∈ P.rootSpan) (hx' : P.RootForm x x = 0) : + x = 0 := by + rw [← Submodule.mem_bot (R := R), ← P.disjoint_rootSpan_ker_polarization.eq_bot] + exact ⟨hx, P.mem_ker_polarization_of_rootForm_self_eq_zero hx'⟩ + +lemma _root_.RootSystem.rootForm_anisotropic (P : RootSystem ι R M N) : + P.RootForm.toQuadraticMap.Anisotropic := + fun x ↦ P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero <| by + simpa only [rootSpan, P.span_eq_top] using Submodule.mem_top + +lemma rootForm_pos_of_nonzero {x : M} (hx : x ∈ P.rootSpan) (h : x ≠ 0) : + 0 < P.RootForm x x := by + apply (P.rootForm_self_non_neg x).lt_of_ne + contrapose! h + exact eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero P hx h.symm + +lemma rootForm_restrict_nondegenerate : + (P.RootForm.restrict P.rootSpan).Nondegenerate := + LinearMap.IsRefl.nondegenerate_of_separatingLeft (LinearMap.IsSymm.isRefl fun x y => by + simp [rootForm_apply_apply, mul_comm]) fun x h => SetLike.coe_eq_coe.mp + (P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero (Submodule.coe_mem x) (h x)) + +end RootPairing diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean index 7a0eb1ff4d84f4..89c3a8fe8a2f1d 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -725,20 +725,21 @@ alias by_contradiction := byContradiction -- TODO: remove? rename in core? alias prop_complete := propComplete -- TODO: remove? rename in core? -@[elab_as_elim, deprecated (since := "2024-07-27")] theorem cases_true_false (p : Prop → Prop) +@[elab_as_elim, deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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 diff --git a/Mathlib/Logic/Denumerable.lean b/Mathlib/Logic/Denumerable.lean index f96dccd8f839c8..d6160e1858ab6e 100644 --- a/Mathlib/Logic/Denumerable.lean +++ b/Mathlib/Logic/Denumerable.lean @@ -121,7 +121,6 @@ instance option : Denumerable (Option α) := · rw [decode_option_succ, decode_eq_ofNat, Option.map_some', Option.mem_def] rw [encode_some, encode_ofNat]⟩ -set_option linter.deprecated false in /-- If `α` and `β` are denumerable, then so is their sum. -/ instance sum : Denumerable (α ⊕ β) := ⟨fun n => by diff --git a/Mathlib/Logic/Equiv/Nat.lean b/Mathlib/Logic/Equiv/Nat.lean index 0bc17024d26091..69466efcdac2da 100644 --- a/Mathlib/Logic/Equiv/Nat.lean +++ b/Mathlib/Logic/Equiv/Nat.lean @@ -36,7 +36,6 @@ def boolProdNatEquivNat : Bool × ℕ ≃ ℕ where def natSumNatEquivNat : ℕ ⊕ ℕ ≃ ℕ := (boolProdEquivSum ℕ).symm.trans boolProdNatEquivNat -set_option linter.deprecated false in @[simp] theorem natSumNatEquivNat_apply : ⇑natSumNatEquivNat = Sum.elim (2 * ·) (2 * · + 1) := by ext (x | x) <;> rfl diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index de06be836259b2..23adc61b8b596e 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -330,7 +330,7 @@ instance (priority := 100) OpensMeasurableSpace.separatesPoints [T0Space α] : rw [separatesPoints_iff] intro x y hxy apply Inseparable.eq - rw [inseparable_iff_forall_open] + rw [inseparable_iff_forall_isOpen] exact fun s hs => hxy _ hs.measurableSet theorem borel_eq_top_of_countable {α : Type*} [TopologicalSpace α] [T0Space α] [Countable α] : diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index aafd0f1b3c5eff..670e4e5bf03472 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -80,7 +80,7 @@ theorem isPiSystem_pi [∀ i, MeasurableSpace (α i)] : section Finite -variable [Finite ι] [Finite ι'] +variable [Finite ι] /-- Boxes of countably spanning sets are countably spanning. -/ theorem IsCountablySpanning.pi {C : ∀ i, Set (Set (α i))} (hC : ∀ i, IsCountablySpanning (C i)) : diff --git a/Mathlib/MeasureTheory/Function/AEEqFun.lean b/Mathlib/MeasureTheory/Function/AEEqFun.lean index 86720959dec253..38c86bd0a94b38 100644 --- a/Mathlib/MeasureTheory/Function/AEEqFun.lean +++ b/Mathlib/MeasureTheory/Function/AEEqFun.lean @@ -124,7 +124,7 @@ then we choose that one. -/ def cast (f : α →ₘ[μ] β) : α → β := if h : ∃ (b : β), f = mk (const α b) aestronglyMeasurable_const then const α <| Classical.choose h else - AEStronglyMeasurable.mk _ (Quotient.out' f : { f : α → β // AEStronglyMeasurable f μ }).2 + AEStronglyMeasurable.mk _ (Quotient.out f : { f : α → β // AEStronglyMeasurable f μ }).2 /-- A measurable representative of an `AEEqFun` [f] -/ instance instCoeFun : CoeFun (α →ₘ[μ] β) fun _ => α → β := ⟨cast⟩ diff --git a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean index ce393e78fea5c6..10f195e4aacff1 100644 --- a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean +++ b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean @@ -193,12 +193,12 @@ theorem ae_le_of_forall_setLIntegral_le_of_sigmaFinite₀ [SigmaFinite μ] have : Tendsto (fun n => g x + u n) atTop (𝓝 (g x + (0 : ℝ≥0))) := tendsto_const_nhds.add (ENNReal.tendsto_coe.2 u_lim) simp only [ENNReal.coe_zero, add_zero] at this - exact eventually_le_of_tendsto_lt hx this + exact this.eventually_le_const hx have L2 : ∀ᶠ n : ℕ in (atTop : Filter ℕ), g x ≤ (n : ℝ≥0) := - haveI : Tendsto (fun n : ℕ => ((n : ℝ≥0) : ℝ≥0∞)) atTop (𝓝 ∞) := by + have : Tendsto (fun n : ℕ => ((n : ℝ≥0) : ℝ≥0∞)) atTop (𝓝 ∞) := by simp only [ENNReal.coe_natCast] exact ENNReal.tendsto_nat_nhds_top - eventually_ge_of_tendsto_gt (hx.trans_le le_top) this + this.eventually_const_le (hx.trans_le le_top) apply Set.mem_iUnion.2 exact ((L1.and L2).and (eventually_mem_spanningSets μ x)).exists refine le_antisymm ?_ bot_le diff --git a/Mathlib/MeasureTheory/Function/L1Space.lean b/Mathlib/MeasureTheory/Function/L1Space.lean index 25e17db9f409b5..b003cc9a9db030 100644 --- a/Mathlib/MeasureTheory/Function/L1Space.lean +++ b/Mathlib/MeasureTheory/Function/L1Space.lean @@ -443,7 +443,7 @@ lemma Integrable.of_finite [Finite α] [MeasurableSingletonClass α] [IsFiniteMe /-- This lemma is a special case of `Integrable.of_finite`. -/ -- Eternal deprecation for discoverability, don't remove -@[deprecated Integrable.of_finite, nolint deprecatedNoSince] +@[deprecated Integrable.of_finite (since := "2024-10-05"), nolint deprecatedNoSince] lemma Integrable.of_isEmpty [IsEmpty α] {f : α → β} : Integrable f μ := .of_finite @[deprecated (since := "2024-02-05")] alias integrable_of_fintype := Integrable.of_finite diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index 01ccd428154705..582ddfc879f14a 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -673,8 +673,7 @@ theorem exists_eLpNorm_indicator_le (hp : p ≠ ∞) (c : E) {ε : ℝ≥0∞} ( convert (NNReal.continuousAt_rpow_const (Or.inr hp₀')).tendsto.const_mul _ simp [hp₀''.ne'] have hε' : 0 < ε := hε.bot_lt - obtain ⟨δ, hδ, hδε'⟩ := - NNReal.nhds_zero_basis.eventually_iff.mp (eventually_le_of_tendsto_lt hε' this) + obtain ⟨δ, hδ, hδε'⟩ := NNReal.nhds_zero_basis.eventually_iff.mp (this.eventually_le_const hε') obtain ⟨η, hη, hηδ⟩ := exists_between hδ refine ⟨η, hη, ?_⟩ rw [← ENNReal.coe_rpow_of_nonneg _ hp₀', ← ENNReal.coe_mul] @@ -1193,7 +1192,7 @@ def compLpₗ (L : E →L[𝕜] F) : Lp E p μ →ₗ[𝕜] Lp F p μ where ext1 filter_upwards [Lp.coeFn_smul c f, coeFn_compLp L (c • f), Lp.coeFn_smul c (L.compLp f), coeFn_compLp L f] with _ ha1 ha2 ha3 ha4 - simp only [ha1, ha2, ha3, ha4, map_smul, Pi.smul_apply] + simp only [ha1, ha2, ha3, ha4, _root_.map_smul, Pi.smul_apply] /-- Composing `f : Lp E p μ` with `L : E →L[𝕜] F`, seen as a continuous `𝕜`-linear map on `Lp E p μ`. See also the similar diff --git a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean index 7ab91eabbf17be..b2da38021c0f91 100644 --- a/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean +++ b/Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean @@ -512,8 +512,6 @@ variable [MeasurableSpace α] [TopologicalSpace β] open Filter -open Filter - @[aesop safe 20 (rule_sets := [Measurable])] protected theorem sup [Max β] [ContinuousSup β] (hf : StronglyMeasurable f) (hg : StronglyMeasurable g) : StronglyMeasurable (f ⊔ g) := diff --git a/Mathlib/MeasureTheory/Group/Action.lean b/Mathlib/MeasureTheory/Group/Action.lean index 04f432bce67b90..cad802e003d1ff 100644 --- a/Mathlib/MeasureTheory/Group/Action.lean +++ b/Mathlib/MeasureTheory/Group/Action.lean @@ -28,7 +28,7 @@ namespace MeasureTheory universe u v w -variable {G : Type u} {M : Type v} {α : Type w} {s : Set α} +variable {G : Type u} {M : Type v} {α : Type w} namespace SMulInvariantMeasure @@ -198,7 +198,7 @@ instance smulInvariantMeasure_map_smul [SMul M α] [SMul N α] [SMulCommClass N end SMulHomClass -variable (G) {m : MeasurableSpace α} [Group G] [MulAction G α] (c : G) (μ : Measure α) +variable (G) {m : MeasurableSpace α} [Group G] [MulAction G α] (μ : Measure α) variable [MeasurableSpace G] [MeasurableSMul G α] in /-- Equivalent definitions of a measure invariant under a multiplicative action of a group. @@ -307,7 +307,7 @@ variable [Measure.Regular μ] @[to_additive] theorem measure_isOpen_pos_of_smulInvariant_of_ne_zero (hμ : μ ≠ 0) (hU : IsOpen U) (hne : U.Nonempty) : 0 < μ U := - let ⟨_K, hK, hμK⟩ := Regular.exists_compact_not_null.mpr hμ + let ⟨_K, hK, hμK⟩ := Regular.exists_isCompact_not_null.mpr hμ measure_isOpen_pos_of_smulInvariant_of_compact_ne_zero G hK hμK hU hne @[to_additive] diff --git a/Mathlib/MeasureTheory/Group/LIntegral.lean b/Mathlib/MeasureTheory/Group/LIntegral.lean index e0344acdeed93f..74c8453b516af9 100644 --- a/Mathlib/MeasureTheory/Group/LIntegral.lean +++ b/Mathlib/MeasureTheory/Group/LIntegral.lean @@ -20,7 +20,7 @@ open Measure TopologicalSpace open scoped ENNReal -variable {G : Type*} [MeasurableSpace G] {μ : Measure G} {g : G} +variable {G : Type*} [MeasurableSpace G] {μ : Measure G} section MeasurableMul diff --git a/Mathlib/MeasureTheory/Group/Measure.lean b/Mathlib/MeasureTheory/Group/Measure.lean index 05604e5fa4945c..8662ff3b7f53c1 100644 --- a/Mathlib/MeasureTheory/Group/Measure.lean +++ b/Mathlib/MeasureTheory/Group/Measure.lean @@ -502,7 +502,7 @@ theorem isOpenPosMeasure_of_mulLeftInvariant_of_compact (K : Set G) (hK : IsComp @[to_additive "A nonzero left-invariant regular measure gives positive mass to any open set."] instance (priority := 80) isOpenPosMeasure_of_mulLeftInvariant_of_regular [Regular μ] [NeZero μ] : IsOpenPosMeasure μ := - let ⟨K, hK, h2K⟩ := Regular.exists_compact_not_null.mpr (NeZero.ne μ) + let ⟨K, hK, h2K⟩ := Regular.exists_isCompact_not_null.mpr (NeZero.ne μ) isOpenPosMeasure_of_mulLeftInvariant_of_compact K hK h2K /-- A nonzero left-invariant inner regular measure gives positive mass to any open set. -/ @@ -510,7 +510,7 @@ instance (priority := 80) isOpenPosMeasure_of_mulLeftInvariant_of_regular [Regul instance (priority := 80) isOpenPosMeasure_of_mulLeftInvariant_of_innerRegular [InnerRegular μ] [NeZero μ] : IsOpenPosMeasure μ := - let ⟨K, hK, h2K⟩ := InnerRegular.exists_compact_not_null.mpr (NeZero.ne μ) + let ⟨K, hK, h2K⟩ := InnerRegular.exists_isCompact_not_null.mpr (NeZero.ne μ) isOpenPosMeasure_of_mulLeftInvariant_of_compact K hK h2K @[to_additive] diff --git a/Mathlib/MeasureTheory/Integral/Bochner.lean b/Mathlib/MeasureTheory/Integral/Bochner.lean index c85ae9df03c295..2cf72496737ad5 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner.lean @@ -638,7 +638,7 @@ theorem integral_sub (f g : α →₁[μ] E) : integral (f - g) = integral f - i theorem integral_smul (c : 𝕜) (f : α →₁[μ] E) : integral (c • f) = c • integral f := by simp only [integral] show (integralCLM' (E := E) 𝕜) (c • f) = c • (integralCLM' (E := E) 𝕜) f - exact map_smul (integralCLM' (E := E) 𝕜) c f + exact _root_.map_smul (integralCLM' (E := E) 𝕜) c f local notation "Integral" => @integralCLM α E _ _ μ _ _ diff --git a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean index f9d75e6cfea42e..d23df43813b602 100644 --- a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean +++ b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean @@ -489,7 +489,7 @@ lemma IntegrableAtFilter.eq_zero_of_tendsto (h : IntegrableAtFilter f l μ) (h' : ∀ s ∈ l, μ s = ∞) {a : E} (hf : Tendsto f l (𝓝 a)) : a = 0 := by by_contra H - obtain ⟨ε, εpos, hε⟩ : ∃ (ε : ℝ), 0 < ε ∧ ε < ‖a‖ := exists_between (norm_pos_iff'.mpr H) + obtain ⟨ε, εpos, hε⟩ : ∃ (ε : ℝ), 0 < ε ∧ ε < ‖a‖ := exists_between (norm_pos_iff.mpr H) rcases h with ⟨u, ul, hu⟩ let v := u ∩ {b | ε < ‖f b‖} have hv : IntegrableOn f v μ := hu.mono_set inter_subset_left diff --git a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean index e2ec1a0114d795..9678b171ff3fc7 100644 --- a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean +++ b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean @@ -388,9 +388,7 @@ theorem AECover.iSup_lintegral_eq_of_countably_generated [Nonempty ι] [l.NeBot] have := hφ.lintegral_tendsto_of_countably_generated hfm refine ciSup_eq_of_forall_le_of_forall_lt_exists_gt (fun i => lintegral_mono' Measure.restrict_le_self le_rfl) fun w hw => ?_ - rcases exists_between hw with ⟨m, hm₁, hm₂⟩ - rcases (eventually_ge_of_tendsto_gt hm₂ this).exists with ⟨i, hi⟩ - exact ⟨i, lt_of_lt_of_le hm₁ hi⟩ + exact (this.eventually_const_lt hw).exists end Lintegral diff --git a/Mathlib/MeasureTheory/Integral/Marginal.lean b/Mathlib/MeasureTheory/Integral/Marginal.lean index 76fcaa682df92b..4e19390aa37fb8 100644 --- a/Mathlib/MeasureTheory/Integral/Marginal.lean +++ b/Mathlib/MeasureTheory/Integral/Marginal.lean @@ -66,7 +66,7 @@ section LMarginal variable {δ δ' : Type*} {π : δ → Type*} [∀ x, MeasurableSpace (π x)] variable {μ : ∀ i, Measure (π i)} [DecidableEq δ] -variable {s t : Finset δ} {f g : (∀ i, π i) → ℝ≥0∞} {x y : ∀ i, π i} {i : δ} +variable {s t : Finset δ} {f : (∀ i, π i) → ℝ≥0∞} {x : ∀ i, π i} /-- Integrate `f(x₁,…,xₙ)` over all variables `xᵢ` where `i ∈ s`. Return a function in the remaining variables (it will be constant in the `xᵢ` for `i ∈ s`). diff --git a/Mathlib/MeasureTheory/Integral/PeakFunction.lean b/Mathlib/MeasureTheory/Integral/PeakFunction.lean index 7d17886a1c7d23..9c33e5b4134925 100644 --- a/Mathlib/MeasureTheory/Integral/PeakFunction.lean +++ b/Mathlib/MeasureTheory/Integral/PeakFunction.lean @@ -321,11 +321,11 @@ theorem tendsto_setIntegral_pow_smul_of_unique_maximum_of_isCompact_of_measure_n _ ≤ ∫ y in s, c y ^ n ∂μ := 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) _ - · apply mul_pos (pow_pos (t_pos.trans_lt tt') _) (ENNReal.toReal_pos (hμ v v_open x₀_v).ne' _) - have : μ (v ∩ s) ≤ μ s := measure_mono inter_subset_right - exact ne_of_lt (lt_of_le_of_lt this hs.measure_lt_top) + have := ENNReal.toReal_pos (hμ v v_open x₀_v).ne' + ((measure_mono inter_subset_right).trans_lt hs.measure_lt_top).ne + gcongr + · exact hnc _ hx.1 + · exact ht x hx have N : Tendsto (fun n => (μ (v ∩ s)).toReal⁻¹ * (t / t') ^ n) atTop (𝓝 ((μ (v ∩ s)).toReal⁻¹ * 0)) := by diff --git a/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean b/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean index 2aa0a2e287af94..2365cd675affac 100644 --- a/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean +++ b/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean @@ -527,7 +527,7 @@ theorem exists_upperSemicontinuous_lt_integral_gt [SigmaFinite μ] (f : α → rcases exists_lt_lowerSemicontinuous_integral_lt (fun x => -f x) hf.neg εpos with ⟨g, g_lt_f, gcont, g_integrable, g_lt_top, gint⟩ refine ⟨fun x => -g x, ?_, ?_, ?_, ?_, ?_⟩ - · exact fun x => EReal.neg_lt_iff_neg_lt.1 (by simpa only [EReal.coe_neg] using g_lt_f x) + · exact fun x => EReal.neg_lt_comm.1 (by simpa only [EReal.coe_neg] using g_lt_f x) · exact continuous_neg.comp_lowerSemicontinuous_antitone gcont fun x y hxy => EReal.neg_le_neg_iff.2 hxy diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index 4d2eb7fd31ab1b..678a6983571d01 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -55,7 +55,7 @@ open Set Encodable Function Equiv Filter MeasureTheory universe uι -variable {α β γ δ δ' : Type*} {ι : Sort uι} {s t u : Set α} +variable {α β γ δ δ' : Type*} {ι : Sort uι} {s : Set α} namespace MeasurableSpace @@ -225,7 +225,7 @@ variable {f g : α → β} section TypeclassMeasurableSpace -variable [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] +variable [MeasurableSpace α] [MeasurableSpace β] @[nontriviality, measurability] theorem Subsingleton.measurable [Subsingleton α] : Measurable f := fun _ _ => diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean b/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean index e9f2db14bfc25c..9dec6c3e39e9bc 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Prod.lean @@ -18,7 +18,7 @@ noncomputable section open Set MeasurableSpace -variable {α β γ : Type*} [MeasurableSpace α] [MeasurableSpace β] [MeasurableSpace γ] +variable {α β : Type*} [MeasurableSpace α] [MeasurableSpace β] /-- The product of generated σ-algebras is the one generated by rectangles, if both generating sets are countably spanning. -/ diff --git a/Mathlib/MeasureTheory/Measure/Count.lean b/Mathlib/MeasureTheory/Measure/Count.lean index b91e37e621e4a0..6d5d487517d6d4 100644 --- a/Mathlib/MeasureTheory/Measure/Count.lean +++ b/Mathlib/MeasureTheory/Measure/Count.lean @@ -98,33 +98,21 @@ theorem count_apply_lt_top [MeasurableSingletonClass α] : count s < ∞ ↔ s.F _ ↔ ¬s.Infinite := not_congr count_apply_eq_top _ ↔ s.Finite := Classical.not_not -theorem empty_of_count_eq_zero' (s_mble : MeasurableSet s) (hsc : count s = 0) : s = ∅ := by - have hs : s.Finite := by - rw [← count_apply_lt_top' s_mble, hsc] - exact WithTop.top_pos - simpa [count_apply_finite' hs s_mble] using hsc - -theorem empty_of_count_eq_zero [MeasurableSingletonClass α] (hsc : count s = 0) : s = ∅ := by - have hs : s.Finite := by - rw [← count_apply_lt_top, hsc] - exact WithTop.top_pos - simpa [count_apply_finite _ hs] using hsc - @[simp] -theorem count_eq_zero_iff' (s_mble : MeasurableSet s) : count s = 0 ↔ s = ∅ := - ⟨empty_of_count_eq_zero' s_mble, fun h => h.symm ▸ count_empty⟩ +theorem count_eq_zero_iff : count s = 0 ↔ s = ∅ where + mp h := eq_empty_of_forall_not_mem fun x hx ↦ by + simpa [hx] using ((ENNReal.le_tsum x).trans <| le_sum_apply _ _).trans_eq h + mpr := by rintro rfl; exact count_empty -@[simp] -theorem count_eq_zero_iff [MeasurableSingletonClass α] : count s = 0 ↔ s = ∅ := - ⟨empty_of_count_eq_zero, fun h => h.symm ▸ count_empty⟩ +lemma count_ne_zero_iff : count s ≠ 0 ↔ s.Nonempty := + count_eq_zero_iff.not.trans nonempty_iff_ne_empty.symm -theorem count_ne_zero' (hs' : s.Nonempty) (s_mble : MeasurableSet s) : count s ≠ 0 := by - rw [Ne, count_eq_zero_iff' s_mble] - exact hs'.ne_empty +alias ⟨_, count_ne_zero⟩ := count_ne_zero_iff -theorem count_ne_zero [MeasurableSingletonClass α] (hs' : s.Nonempty) : count s ≠ 0 := by - rw [Ne, count_eq_zero_iff] - exact hs'.ne_empty +@[deprecated (since := "2024-11-20")] alias ⟨empty_of_count_eq_zero, _⟩ := count_eq_zero_iff +@[deprecated (since := "2024-11-20")] alias empty_of_count_eq_zero' := empty_of_count_eq_zero +@[deprecated (since := "2024-11-20")] alias count_eq_zero_iff' := count_eq_zero_iff +@[deprecated (since := "2024-11-20")] alias count_ne_zero' := count_ne_zero @[simp] theorem count_singleton' {a : α} (ha : MeasurableSet ({a} : Set α)) : count ({a} : Set α) = 1 := by diff --git a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean index c09a1445000144..546c35be2dda7b 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean @@ -280,7 +280,7 @@ theorem prehaar_pos (K₀ : PositiveCompacts G) {U : Set G} (hU : (interior U).N theorem prehaar_mono {K₀ : PositiveCompacts G} {U : Set G} (hU : (interior U).Nonempty) {K₁ K₂ : Compacts G} (h : (K₁ : Set G) ⊆ K₂.1) : prehaar (K₀ : Set G) U K₁ ≤ prehaar (K₀ : Set G) U K₂ := by - simp only [prehaar]; rw [div_le_div_right] + simp only [prehaar]; rw [div_le_div_iff_of_pos_right] · exact mod_cast index_mono K₂.2 h hU · exact mod_cast index_pos K₀ hU @@ -293,7 +293,7 @@ theorem prehaar_self {K₀ : PositiveCompacts G} {U : Set G} (hU : (interior U). theorem prehaar_sup_le {K₀ : PositiveCompacts G} {U : Set G} (K₁ K₂ : Compacts G) (hU : (interior U).Nonempty) : prehaar (K₀ : Set G) U (K₁ ⊔ K₂) ≤ prehaar (K₀ : Set G) U K₁ + prehaar (K₀ : Set G) U K₂ := by - simp only [prehaar]; rw [div_add_div_same, div_le_div_right] + simp only [prehaar]; rw [div_add_div_same, div_le_div_iff_of_pos_right] · exact mod_cast index_union_le K₁ K₂ hU · exact mod_cast index_pos K₀ hU diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean index 7f76b5cbe8048c..a0db8d8e207b9d 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean @@ -116,7 +116,7 @@ theorem parallelepiped_orthonormalBasis_one_dim (b : OrthonormalBasis ι ℝ ℝ · right simp_rw [H, parallelepiped, Algebra.id.smul_eq_mul, A] simp only [F, Finset.univ_unique, Fin.default_eq_zero, mul_neg, mul_one, Finset.sum_neg_distrib, - Finset.sum_singleton, ← image_comp, Function.comp, image_neg, preimage_neg_Icc, neg_zero] + Finset.sum_singleton, ← image_comp, Function.comp, image_neg, neg_Icc, neg_zero] theorem parallelepiped_eq_sum_segment (v : ι → E) : parallelepiped v = ∑ i, segment ℝ 0 (v i) := by ext diff --git a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean index e552fa14c32864..a782f7e429aeba 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean @@ -134,7 +134,7 @@ lemma MeasureTheory.QuotientMeasureEqMeasurePreimage.mulInvariantMeasure_quotien obtain ⟨x₁, h⟩ := @Quotient.exists_rep _ (QuotientGroup.leftRel Γ) x convert measure_preimage_smul μ x₁ A using 1 · rw [← h, Measure.map_apply (measurable_const_mul _) hA] - simp [← MulAction.Quotient.coe_smul_out', ← Quotient.mk''_eq_mk] + simp [← MulAction.Quotient.coe_smul_out, ← Quotient.mk''_eq_mk] exact smulInvariantMeasure_quotient ν variable [Countable Γ] [IsMulRightInvariant ν] [SigmaFinite ν] diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean index e4968335130b1f..e72be147a0f257 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean @@ -83,7 +83,7 @@ theorem integral_comp_neg_Iic {E : Type*} [NormedAddCommGroup E] [NormedSpace (Homeomorph.neg ℝ).isClosedEmbedding.measurableEmbedding have := MeasurableEmbedding.setIntegral_map (μ := volume) A f (Ici (-c)) rw [Measure.map_neg_eq_self (volume : Measure ℝ)] at this - simp_rw [← integral_Ici_eq_integral_Ioi, this, neg_preimage, preimage_neg_Ici, neg_neg] + simp_rw [← integral_Ici_eq_integral_Ioi, this, neg_preimage, neg_Ici, neg_neg] /- @[simp] Porting note: Linter complains it does not apply to itself. Although it does apply to itself, it does not apply when `f` is more complicated -/ @@ -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_def, abs_neg, neg_preimage, preimage_neg_Iic, neg_zero] + simp_rw [Function.comp_def, abs_neg, neg_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/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 8cf14fc5dc9a61..3d62ba51018604 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -748,6 +748,11 @@ theorem coe_zero {_m : MeasurableSpace α} : ⇑(0 : Measure α) = 0 := ext s hs simp [hs] +@[simp] lemma _root_.MeasureTheory.OuterMeasure.toMeasure_eq_zero {ms : MeasurableSpace α} + {μ : OuterMeasure α} (h : ms ≤ μ.caratheodory) : μ.toMeasure h = 0 ↔ μ = 0 where + mp hμ := by ext s; exact le_bot_iff.1 <| (le_toMeasure_apply _ _ _).trans_eq congr($hμ s) + mpr := by rintro rfl; simp + @[nontriviality] lemma apply_eq_zero_of_isEmpty [IsEmpty α] {_ : MeasurableSpace α} (μ : Measure α) (s : Set α) : μ s = 0 := by @@ -1274,10 +1279,11 @@ theorem sum_apply₀ (f : ι → Measure α) {s : Set α} (hs : NullMeasurableSe /-! For the next theorem, the countability assumption is necessary. For a counterexample, consider an uncountable space, with a distinguished point `x₀`, and the sigma-algebra made of countable sets not containing `x₀`, and their complements. All points but `x₀` are measurable. -Consider the sum of the Dirac masses at points different from `x₀`, and `s = x₀`. For any Dirac mass -`δ_x`, we have `δ_x (x₀) = 0`, so `∑' x, δ_x (x₀) = 0`. On the other hand, the measure `sum δ_x` -gives mass one to each point different from `x₀`, so it gives infinite mass to any measurable set -containing `x₀` (as such a set is uncountable), and by outer regularity one get `sum δ_x {x₀} = ∞`. +Consider the sum of the Dirac masses at points different from `x₀`, and `s = {x₀}`. For any Dirac +mass `δ_x`, we have `δ_x (x₀) = 0`, so `∑' x, δ_x (x₀) = 0`. On the other hand, the measure +`sum δ_x` gives mass one to each point different from `x₀`, so it gives infinite mass to any +measurable set containing `x₀` (as such a set is uncountable), and by outer regularity one gets +`sum δ_x {x₀} = ∞`. -/ theorem sum_apply_of_countable [Countable ι] (f : ι → Measure α) (s : Set α) : sum f s = ∑' i, f i s := by diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean index 8eb64f43a20e20..11481cc61993f4 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean @@ -82,9 +82,9 @@ instance Measure.instFunLike [MeasurableSpace α] : FunLike (Measure α) (Set α coe μ := μ.toOuterMeasure coe_injective' | ⟨_, _, _⟩, ⟨_, _, _⟩, h => toOuterMeasure_injective <| DFunLike.coe_injective h -set_option linter.deprecated false in -- Not immediately obvious how to use `measure_empty` here. + instance Measure.instOuterMeasureClass [MeasurableSpace α] : OuterMeasureClass (Measure α) α where - measure_empty m := m.empty' + measure_empty m := measure_empty (μ := m.toOuterMeasure) measure_iUnion_nat_le m := m.iUnion_nat measure_mono m := m.mono diff --git a/Mathlib/MeasureTheory/Measure/Portmanteau.lean b/Mathlib/MeasureTheory/Measure/Portmanteau.lean index 4d82e897d17714..72fe3305828bec 100644 --- a/Mathlib/MeasureTheory/Measure/Portmanteau.lean +++ b/Mathlib/MeasureTheory/Measure/Portmanteau.lean @@ -278,14 +278,14 @@ theorem FiniteMeasure.limsup_measure_closed_le_of_tendsto {Ω ι : Type*} {L : F HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed (μ : Measure Ω) 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₁ + obtain ⟨M, hM⟩ := eventually_atTop.mp <| key₁.eventually_lt_const room₁ 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 := 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 + have ev_near := key₂.eventually_le_const room₂ + have ev_near' := ev_near.mono (fun n ↦ le_trans (HasOuterApproxClosed.measure_le_lintegral F_closed (μs n) M)) apply (Filter.limsup_le_limsup ev_near').trans rw [limsup_const] diff --git a/Mathlib/MeasureTheory/Measure/Regular.lean b/Mathlib/MeasureTheory/Measure/Regular.lean index 00bbeafec255eb..91b924e0a4f30a 100644 --- a/Mathlib/MeasureTheory/Measure/Regular.lean +++ b/Mathlib/MeasureTheory/Measure/Regular.lean @@ -446,7 +446,7 @@ protected theorem FiniteSpanningSetsIn.outerRegular namespace InnerRegularWRT -variable {p q : Set α → Prop} {U s : Set α} {ε r : ℝ≥0∞} +variable {p : Set α → Prop} /-- If the restrictions of a measure to a monotone sequence of sets covering the space are inner regular for some property `p` and all measurable sets, then the measure itself is @@ -637,7 +637,7 @@ end InnerRegularWRT namespace InnerRegular -variable {U : Set α} {ε : ℝ≥0∞} [TopologicalSpace α] +variable [TopologicalSpace α] /-- The measure of a measurable set is the supremum of the measures of compact sets it contains. -/ theorem _root_.MeasurableSet.measure_eq_iSup_isCompact ⦃U : Set α⦄ (hU : MeasurableSet U) @@ -663,9 +663,10 @@ lemma innerRegularWRT_isClosed_isOpen [R1Space α] [OpensMeasurableSpace α] [h exact ⟨closure K, K_comp.closure_subset_of_isOpen hU KU, isClosed_closure, hK.trans_le (measure_mono subset_closure)⟩ -theorem exists_compact_not_null [InnerRegular μ] : (∃ K, IsCompact K ∧ μ K ≠ 0) ↔ μ ≠ 0 := by +theorem exists_isCompact_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] +@[deprecated (since := "2024-11-19")] alias exists_compact_not_null := exists_isCompact_not_null /-- 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`. -/ @@ -986,9 +987,10 @@ theorem _root_.IsOpen.measure_eq_iSup_isCompact ⦃U : Set α⦄ (hU : IsOpen U) [Regular μ] : μ U = ⨆ (K : Set α) (_ : K ⊆ U) (_ : IsCompact K), μ K := Regular.innerRegular.measure_eq_iSup hU -theorem exists_compact_not_null [Regular μ] : (∃ K, IsCompact K ∧ μ K ≠ 0) ↔ μ ≠ 0 := by +theorem exists_isCompact_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] +@[deprecated (since := "2024-11-19")] alias exists_compact_not_null := exists_isCompact_not_null /-- 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 diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses.lean b/Mathlib/MeasureTheory/Measure/Typeclasses.lean index 7ab48f42229144..f8d833559d3e93 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean @@ -567,7 +567,7 @@ instance isFiniteMeasure_sfiniteSeq [h : SFinite μ] (n : ℕ) : IsFiniteMeasure h.1.choose_spec.1 n set_option linter.deprecated false in -@[deprecated (since := "2024-10-11")] +@[deprecated "No deprecation message was provided." (since := "2024-10-11")] instance isFiniteMeasure_sFiniteSeq [SFinite μ] (n : ℕ) : IsFiniteMeasure (sFiniteSeq μ n) := isFiniteMeasure_sfiniteSeq n @@ -800,7 +800,7 @@ theorem countable_meas_pos_of_disjoint_of_meas_iUnion_ne_top₀ {ι : Type*} {_ simp only [fairmeas] rfl simpa only [fairmeas_eq, posmeas_def, ← preimage_iUnion, - iUnion_Ici_eq_Ioi_of_lt_of_tendsto (0 : ℝ≥0∞) (fun n => (as_mem n).1) as_lim] + iUnion_Ici_eq_Ioi_of_lt_of_tendsto (fun n => (as_mem n).1) as_lim] rw [countable_union] refine countable_iUnion fun n => Finite.countable ?_ exact finite_const_le_meas_of_disjoint_iUnion₀ μ (as_mem n).1 As_mble As_disj Union_As_finite diff --git a/Mathlib/MeasureTheory/Measure/WithDensity.lean b/Mathlib/MeasureTheory/Measure/WithDensity.lean index d343307b3e3fc1..f8c9285e8bbbf6 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensity.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensity.lean @@ -669,7 +669,7 @@ lemma IsLocallyFiniteMeasure.withDensity_coe {f : α → ℝ≥0} (hf : Continuo IsLocallyFiniteMeasure (μ.withDensity fun x ↦ f x) := by refine ⟨fun x ↦ ?_⟩ rcases (μ.finiteAt_nhds x).exists_mem_basis ((nhds_basis_opens' x).restrict_subset - (eventually_le_of_tendsto_lt (lt_add_one _) (hf.tendsto x))) with ⟨U, ⟨⟨hUx, hUo⟩, hUf⟩, hμU⟩ + ((hf.tendsto x).eventually_le_const (lt_add_one _))) with ⟨U, ⟨⟨hUx, hUo⟩, hUf⟩, hμU⟩ refine ⟨U, hUx, ?_⟩ rw [withDensity_apply _ hUo.measurableSet] exact setLIntegral_lt_top_of_bddAbove hμU.ne ⟨f x + 1, forall_mem_image.2 hUf⟩ diff --git a/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean b/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean index 21abd06cd6ceea..40b56846328c75 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean @@ -117,7 +117,7 @@ noncomputable def Measure.densityToFinite (μ : Measure α) [SFinite μ] (a : α μ.rnDeriv μ.toFinite a set_option linter.deprecated false in -@[deprecated (since := "2024-10-04")] +@[deprecated "No deprecation message was provided." (since := "2024-10-04")] lemma densityToFinite_def (μ : Measure α) [SFinite μ] : μ.densityToFinite = μ.rnDeriv μ.toFinite := rfl diff --git a/Mathlib/ModelTheory/Encoding.lean b/Mathlib/ModelTheory/Encoding.lean index 5395d5324a5a68..180cb86b870edc 100644 --- a/Mathlib/ModelTheory/Encoding.lean +++ b/Mathlib/ModelTheory/Encoding.lean @@ -181,13 +181,6 @@ or returns `default` if not possible. -/ def sigmaImp : (Σn, L.BoundedFormula α n) → (Σn, L.BoundedFormula α n) → Σn, L.BoundedFormula α n | ⟨m, φ⟩, ⟨n, ψ⟩ => if h : m = n then ⟨m, φ.imp (Eq.mp (by rw [h]) ψ)⟩ else default -#adaptation_note -/-- -`List.drop_sizeOf_le` is deprecated. -See https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Why.20is.20.60Mathlib.2EModelTheory.2EEncoding.60.20using.20.60SizeOf.2EsizeOf.60.3F -for discussion about adapting this code. --/ -set_option linter.deprecated false in /-- Decodes a list of symbols as a list of formulas. -/ @[simp] lemma sigmaImp_apply {n} {φ ψ : L.BoundedFormula α n} : diff --git a/Mathlib/NumberTheory/ArithmeticFunction.lean b/Mathlib/NumberTheory/ArithmeticFunction.lean index d6a37afa99adb0..8b8038b188ab06 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -299,7 +299,7 @@ theorem one_smul' (b : ArithmeticFunction M) : (1 : ArithmeticFunction R) • b intro y ymem ynmem have y1ne : y.fst ≠ 1 := by intro con - simp only [Con, mem_divisorsAntidiagonal, one_mul, Ne] at ymem + simp only [mem_divisorsAntidiagonal, one_mul, Ne] at ymem simp only [mem_singleton, Prod.ext_iff] at ynmem -- Porting note: `tauto` worked from here. cases y @@ -331,7 +331,7 @@ instance instMonoid : Monoid (ArithmeticFunction R) := have y2ne : y.snd ≠ 1 := by intro con cases y; subst con -- Porting note: added - simp only [Con, mem_divisorsAntidiagonal, mul_one, Ne] at ymem + simp only [mem_divisorsAntidiagonal, mul_one, Ne] at ymem simp only [mem_singleton, Prod.ext_iff] at ynmem tauto simp [y2ne] @@ -1291,7 +1291,8 @@ theorem _root_.Nat.card_divisors {n : ℕ} (hn : n ≠ 0) : exact Finset.prod_congr n.support_factorization fun _ h => sigma_zero_apply_prime_pow <| Nat.prime_of_mem_primeFactors h -@[deprecated (since := "2024-06-09")] theorem card_divisors (n : ℕ) (hn : n ≠ 0) : +@[deprecated "No deprecation message was provided." (since := "2024-06-09")] +theorem card_divisors (n : ℕ) (hn : n ≠ 0) : #n.divisors = n.primeFactors.prod (n.factorization · + 1) := Nat.card_divisors hn theorem _root_.Nat.sum_divisors {n : ℕ} (hn : n ≠ 0) : diff --git a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean index fabb26655f44bc..6d1c1c2f19d9b6 100644 --- a/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean +++ b/Mathlib/NumberTheory/ClassNumber/AdmissibleCardPowDegree.lean @@ -23,8 +23,6 @@ use to show the class number of the ring of integers of a function field is fini namespace Polynomial -open Polynomial - open AbsoluteValue Real variable {Fq : Type*} [Fintype Fq] diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index 604980a89620e2..cdccd001950cb8 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -408,7 +408,7 @@ private theorem aux₁ : 0 < fract ξ := by have H : (2 * v - 1 : ℝ) < 1 := by 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₀] + rw [h', abs_div, abs_of_pos hv₀, ← one_div, div_le_div_iff_of_pos_right hv₀] norm_cast rw [← zero_add (1 : ℤ), add_one_le_iff, abs_pos, sub_ne_zero] rintro rfl diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index e2bfeafb8e2171..5d34808cc47195 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -391,7 +391,7 @@ theorem Prime.prod_divisors {α : Type*} [CommMonoid α] {p : ℕ} {f : ℕ → theorem properDivisors_eq_singleton_one_iff_prime : n.properDivisors = {1} ↔ n.Prime := by refine ⟨?_, ?_⟩ · intro h - refine Nat.prime_def_lt''.mpr ⟨?_, fun m hdvd => ?_⟩ + refine Nat.prime_def.mpr ⟨?_, fun m hdvd => ?_⟩ · match n with | 0 => contradiction | 1 => contradiction diff --git a/Mathlib/NumberTheory/FLT/Basic.lean b/Mathlib/NumberTheory/FLT/Basic.lean index 3630dbe1368d92..c6ebe0078285bf 100644 --- a/Mathlib/NumberTheory/FLT/Basic.lean +++ b/Mathlib/NumberTheory/FLT/Basic.lean @@ -6,6 +6,7 @@ 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.Order.Ring.Abs import Mathlib.RingTheory.PrincipalIdealDomain /-! diff --git a/Mathlib/NumberTheory/FLT/Four.lean b/Mathlib/NumberTheory/FLT/Four.lean index e6da8e8d4814fe..b6802f986775d1 100644 --- a/Mathlib/NumberTheory/FLT/Four.lean +++ b/Mathlib/NumberTheory/FLT/Four.lean @@ -3,6 +3,7 @@ Copyright (c) 2020 Paul van Wamelen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Paul van Wamelen -/ +import Mathlib.Data.Nat.Factors import Mathlib.NumberTheory.FLT.Basic import Mathlib.NumberTheory.PythagoreanTriples import Mathlib.RingTheory.Coprime.Lemmas diff --git a/Mathlib/NumberTheory/Fermat.lean b/Mathlib/NumberTheory/Fermat.lean index 18c9ed47758f27..bdb8dd1117803b 100644 --- a/Mathlib/NumberTheory/Fermat.lean +++ b/Mathlib/NumberTheory/Fermat.lean @@ -196,7 +196,7 @@ theorem prime_of_pow_sub_one_prime {a n : ℕ} (hn1 : n ≠ 1) (hP : (a ^ n - 1) rw [one_pow, hP.dvd_iff_eq (mt (Nat.sub_eq_iff_eq_add ha1.le).mp hn1), eq_comm] at h exact (pow_eq_self_iff ha1).mp (Nat.sub_one_cancel ha0 (pow_pos ha0 n) h).symm subst ha2 - refine ⟨rfl, Nat.prime_def_lt''.mpr ⟨(two_le_iff n).mpr ⟨hn0, hn1⟩, fun d hdn ↦ ?_⟩⟩ + refine ⟨rfl, Nat.prime_def.mpr ⟨(two_le_iff n).mpr ⟨hn0, hn1⟩, fun d hdn ↦ ?_⟩⟩ have hinj : ∀ x y, 2 ^ x - 1 = 2 ^ y - 1 → x = y := fun x y h ↦ Nat.pow_right_injective le_rfl (sub_one_cancel (pow_pos ha0 x) (pow_pos ha0 y) h) let h := nat_sub_dvd_pow_sub_pow (2 ^ d) 1 (n / d) diff --git a/Mathlib/NumberTheory/FermatPsp.lean b/Mathlib/NumberTheory/FermatPsp.lean index 9fc7ee08221355..31cdde409beb6f 100644 --- a/Mathlib/NumberTheory/FermatPsp.lean +++ b/Mathlib/NumberTheory/FermatPsp.lean @@ -197,10 +197,8 @@ private theorem psp_from_prime_psp {b : ℕ} (b_ge_two : 2 ≤ b) {p : ℕ} (p_p have hi_p : 1 ≤ p := Nat.one_le_of_lt p_gt_two have hi_bsquared : 0 < b ^ 2 - 1 := by -- Porting note: was `by nlinarith [Nat.one_le_pow 2 b hi_b]` - have h0 := mul_le_mul b_ge_two b_ge_two zero_le_two hi_b.le - have h1 : 1 < 2 * 2 := by omega - have := tsub_pos_of_lt (h1.trans_le h0) - rwa [pow_two] + have := Nat.pow_le_pow_left b_ge_two 2 + omega have hi_bpowtwop : 1 ≤ b ^ (2 * p) := Nat.one_le_pow (2 * p) b hi_b have hi_bpowpsubone : 1 ≤ b ^ (p - 1) := Nat.one_le_pow (p - 1) b hi_b -- Other useful facts @@ -306,7 +304,7 @@ private theorem psp_from_prime_gt_p {b : ℕ} (b_ge_two : 2 ≤ b) {p : ℕ} (p_ suffices h : p * b ^ 2 < (b ^ 2) ^ (p - 1) * b ^ 2 by apply gt_of_ge_of_gt · exact tsub_le_tsub_left (one_le_of_lt p_gt_two) ((b ^ 2) ^ (p - 1) * b ^ 2) - · have : p ≤ p * b ^ 2 := Nat.le_mul_of_pos_right _ (show 0 < b ^ 2 by nlinarith) + · have : p ≤ p * b ^ 2 := Nat.le_mul_of_pos_right _ (show 0 < b ^ 2 by positivity) exact tsub_lt_tsub_right_of_le this h suffices h : p < (b ^ 2) ^ (p - 1) by have : 4 ≤ b ^ 2 := by nlinarith diff --git a/Mathlib/NumberTheory/Harmonic/Defs.lean b/Mathlib/NumberTheory/Harmonic/Defs.lean index effef54ba3920c..29d3f5fa6bbe53 100644 --- a/Mathlib/NumberTheory/Harmonic/Defs.lean +++ b/Mathlib/NumberTheory/Harmonic/Defs.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Koundinya Vajjha, Thomas Browning -/ import Mathlib.Algebra.BigOperators.Intervals -import Mathlib.Tactic.Positivity.Finset +import Mathlib.Algebra.Order.Field.Basic +import Mathlib.Tactic.Positivity /-! diff --git a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean index 93d06720ea1b36..ae321a0cce2eb8 100644 --- a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean +++ b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean @@ -274,7 +274,7 @@ lemma continuousOn_term_tsum : ContinuousOn term_tsum (Ici 1) := by refine setIntegral_mono_on ?_ ?_ measurableSet_Ioc (fun x hx ↦ ?_) · exact (term_welldef n.succ_pos (zero_lt_one.trans_le hs)).1 · exact (term_welldef n.succ_pos zero_lt_one).1 - · rw [div_le_div_left] -- leave side-goals to end and kill them all together + · rw [div_le_div_iff_of_pos_left] -- leave side-goals to end and kill them all together · apply rpow_le_rpow_of_exponent_le · exact (lt_of_le_of_lt (by simp) hx.1).le · linarith [mem_Ici.mp hs] diff --git a/Mathlib/NumberTheory/LSeries/Convergence.lean b/Mathlib/NumberTheory/LSeries/Convergence.lean index c5a161fa9aae97..5310dc93a15ed9 100644 --- a/Mathlib/NumberTheory/LSeries/Convergence.lean +++ b/Mathlib/NumberTheory/LSeries/Convergence.lean @@ -119,3 +119,21 @@ lemma LSeries.abscissaOfAbsConv_le_one_of_isBigO_one {f : ℕ → ℂ} (h : f =O convert abscissaOfAbsConv_le_of_isBigO_rpow (x := 0) ?_ · simp only [EReal.coe_zero, zero_add] · simpa only [Real.rpow_zero] using h + +/-- If `f` is real-valued and `x` is strictly greater than the abscissa of absolute convergence +of `f`, then the real series `∑' n, f n / n ^ x` converges. -/ +lemma LSeries.summable_real_of_abscissaOfAbsConv_lt {f : ℕ → ℝ} {x : ℝ} + (h : abscissaOfAbsConv (f ·) < x) : + Summable fun n : ℕ ↦ f n / (n : ℝ) ^ x := by + have h' : abscissaOfAbsConv (f ·) < (x : ℂ).re := by simpa only [ofReal_re] using h + have := LSeriesSummable_of_abscissaOfAbsConv_lt_re h' + rw [LSeriesSummable, show term _ _ = fun n ↦ _ from rfl] at this + conv at this => + enter [1, n] + rw [term_def, show (n : ℂ) = (n : ℝ) from rfl, ← ofReal_cpow n.cast_nonneg, ← ofReal_div, + show (0 : ℂ) = (0 : ℝ) from rfl, ← apply_ite] + rw [summable_ofReal] at this + refine this.congr_cofinite ?_ + filter_upwards [Set.Finite.compl_mem_cofinite <| Set.finite_singleton 0] with n hn + simp only [Set.mem_compl_iff, Set.mem_singleton_iff] at hn + exact if_neg hn diff --git a/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean index e4b323edd1d75c..033ad5dde6fc60 100644 --- a/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean +++ b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean @@ -84,11 +84,13 @@ lemma deriv_LFunction_eq_deriv_LSeries (χ : DirichletCharacter ℂ N) {s : ℂ} The L-function of a Dirichlet character is differentiable, except at `s = 1` if the character is trivial. -/ +@[fun_prop] 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. -/ +@[fun_prop] lemma differentiable_LFunction {χ : DirichletCharacter ℂ N} (hχ : χ ≠ 1) : Differentiable ℂ (LFunction χ) := (differentiableAt_LFunction _ · <| Or.inr hχ) @@ -113,7 +115,7 @@ lemma Even.LFunction_neg_two_mul_nat {χ : DirichletCharacter ℂ N} (hχ : Even ZMod.LFunction_neg_two_mul_nat_sub_one hχ.to_fun n /-! -## Results on changing levels +### Results on changing levels -/ private lemma LFunction_changeLevel_aux {M N : ℕ} [NeZero M] [NeZero N] (hMN : M ∣ N) @@ -156,7 +158,7 @@ lemma LFunction_changeLevel {M N : ℕ} [NeZero M] [NeZero N] (hMN : M ∣ N) · exact LFunction_changeLevel_aux hMN χ h /-! -## The `L`-function of the trivial character mod `N` +### The `L`-function of the trivial character mod `N` -/ /-- The `L`-function of the trivial character mod `N`. -/ @@ -189,7 +191,7 @@ lemma LFunctionTrivChar_residue_one : fun_prop /-! -## Completed L-functions and the functional equation +### Completed L-functions and the functional equation -/ section gammaFactor @@ -307,3 +309,86 @@ theorem completedLFunction_one_sub {χ : DirichletCharacter ℂ N} (hχ : IsPrim end IsPrimitive end DirichletCharacter + +/-! +### The logarithmic derivative of the L-function of a Dirichlet character + +We show that `s ↦ -(L' χ s) / L χ s + 1 / (s - 1)` is continuous outside the zeros of `L χ` +when `χ` is a trivial Dirichlet character and that `-L' χ / L χ` is continuous outside +the zeros of `L χ` when `χ` is nontrivial. +-/ + +namespace DirichletCharacter + +open Complex + +section trivial + +variable (n : ℕ) [NeZero n] + +/-- The function obtained by "multiplying away" the pole of `L χ` for a trivial Dirichlet +character `χ`. Its (negative) logarithmic derivative is used to prove Dirichlet's Theorem +on primes in arithmetic progression. -/ +noncomputable abbrev LFunctionTrivChar₁ : ℂ → ℂ := + Function.update (fun s ↦ (s - 1) * LFunctionTrivChar n s) 1 + (∏ p ∈ n.primeFactors, (1 - (p : ℂ)⁻¹)) + +lemma LFunctionTrivChar₁_apply_one_ne_zero : LFunctionTrivChar₁ n 1 ≠ 0 := by + simp only [Function.update_same] + refine Finset.prod_ne_zero_iff.mpr fun p hp ↦ ?_ + simpa only [ne_eq, sub_ne_zero, one_eq_inv, Nat.cast_eq_one] + using (Nat.prime_of_mem_primeFactors hp).ne_one + +/-- `s ↦ (s - 1) * L χ s` is an entire function when `χ` is a trivial Dirichlet character. -/ +lemma differentiable_LFunctionTrivChar₁ : Differentiable ℂ (LFunctionTrivChar₁ n) := by + rw [← differentiableOn_univ, + ← differentiableOn_compl_singleton_and_continuousAt_iff (c := 1) Filter.univ_mem] + refine ⟨DifferentiableOn.congr (f := fun s ↦ (s - 1) * LFunctionTrivChar n s) + (fun _ hs ↦ DifferentiableAt.differentiableWithinAt <| by fun_prop (disch := simp_all [hs])) + fun _ hs ↦ Function.update_noteq (Set.mem_diff_singleton.mp hs).2 .., + continuousWithinAt_compl_self.mp ?_⟩ + simpa only [continuousWithinAt_compl_self, continuousAt_update_same] + using LFunctionTrivChar_residue_one + +lemma deriv_LFunctionTrivChar₁_apply_of_ne_one {s : ℂ} (hs : s ≠ 1) : + deriv (LFunctionTrivChar₁ n) s = + (s - 1) * deriv (LFunctionTrivChar n) s + LFunctionTrivChar n s := by + have H : deriv (LFunctionTrivChar₁ n) s = + deriv (fun w ↦ (w - 1) * LFunctionTrivChar n w) s := by + refine eventuallyEq_iff_exists_mem.mpr ?_ |>.deriv_eq + exact ⟨_, isOpen_ne.mem_nhds hs, fun _ hw ↦ Function.update_noteq (Set.mem_setOf.mp hw) ..⟩ + rw [H, deriv_mul (by fun_prop) (differentiableAt_LFunction _ s (.inl hs)), deriv_sub_const, + deriv_id'', one_mul, add_comm] + +/-- The negative logarithmtic derivative of `s ↦ (s - 1) * L χ s` for a trivial +Dirichlet character `χ` is continuous away from the zeros of `L χ` (including at `s = 1`). -/ +lemma continuousOn_neg_logDeriv_LFunctionTrivChar₁ : + ContinuousOn (fun s ↦ -deriv (LFunctionTrivChar₁ n) s / LFunctionTrivChar₁ n s) + {s | s = 1 ∨ LFunctionTrivChar n s ≠ 0} := by + simp_rw [neg_div] + have h := differentiable_LFunctionTrivChar₁ n + refine ((h.contDiff.continuous_deriv le_rfl).continuousOn.div + h.continuous.continuousOn fun w hw ↦ ?_).neg + rcases eq_or_ne w 1 with rfl | hw' + · exact LFunctionTrivChar₁_apply_one_ne_zero _ + · rw [LFunctionTrivChar₁, Function.update_noteq hw', mul_ne_zero_iff] + exact ⟨sub_ne_zero_of_ne hw', (Set.mem_setOf.mp hw).resolve_left hw'⟩ + +end trivial + +section nontrivial + +variable {n : ℕ} [NeZero n] {χ : DirichletCharacter ℂ n} + +/-- The negative logarithmic derivative of the L-function of a nontrivial Dirichlet character +is continuous away from the zeros of the L-function. -/ +lemma continuousOn_neg_logDeriv_LFunction_of_nontriv (hχ : χ ≠ 1) : + ContinuousOn (fun s ↦ -deriv (LFunction χ) s / LFunction χ s) {s | LFunction χ s ≠ 0} := by + simp only [neg_div] + have h := differentiable_LFunction hχ + exact ((h.contDiff.continuous_deriv le_rfl).continuousOn.div + h.continuous.continuousOn fun _ hw ↦ hw).neg + +end nontrivial + +end DirichletCharacter diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean index 5407eebea6353e..81dee4c2c5ae9d 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean @@ -519,7 +519,7 @@ lemma hasSum_int_completedCosZeta (a : ℝ) {s : ℂ} (hs : 1 < re s) : rw [mellin_div_const, completedCosZeta] congr 1 refine ((hurwitzEvenFEPair a).symm.hasMellin (?_ : 1 / 2 < (s / 2).re)).2.symm - rwa [div_ofNat_re, div_lt_div_right two_pos]] + rwa [div_ofNat_re, div_lt_div_iff_of_pos_right two_pos]] refine (hasSum_mellin_pi_mul_sq (zero_lt_one.trans hs) hF ?_).congr_fun fun n ↦ ?_ · apply (((summable_one_div_int_add_rpow 0 s.re).mpr hs).div_const 2).of_norm_bounded intro i @@ -560,7 +560,7 @@ lemma hasSum_int_completedHurwitzZetaEven (a : ℝ) {s : ℂ} (hs : 1 < re s) : ↑(if (a : UnitAddCircle) = 0 then 1 else 0 : ℝ)) / 2) (s / 2) by simp_rw [mellin_div_const, apply_ite ofReal, ofReal_one, ofReal_zero] refine congr_arg (· / 2) ((hurwitzEvenFEPair a).hasMellin (?_ : 1 / 2 < (s / 2).re)).2.symm - rwa [div_ofNat_re, div_lt_div_right two_pos]] + rwa [div_ofNat_re, div_lt_div_iff_of_pos_right two_pos]] refine (hasSum_mellin_pi_mul_sq (zero_lt_one.trans hs) hF ?_).congr_fun fun n ↦ ?_ · simp_rw [← mul_one_div ‖_‖] apply Summable.mul_left diff --git a/Mathlib/NumberTheory/LSeries/PrimesInAP.lean b/Mathlib/NumberTheory/LSeries/PrimesInAP.lean new file mode 100644 index 00000000000000..3cd0c083dd5d63 --- /dev/null +++ b/Mathlib/NumberTheory/LSeries/PrimesInAP.lean @@ -0,0 +1,492 @@ +/- +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.DirichletCharacter.Orthogonality +import Mathlib.NumberTheory.LSeries.Linearity +import Mathlib.NumberTheory.LSeries.Nonvanishing +import Mathlib.RingTheory.RootsOfUnity.AlgebraicallyClosed + +/-! +# Dirichlet's Theorem on primes in arithmetic progression + +The goal of this file is to prove **Dirichlet's Theorem**: If `q` is a positive natural number +and `a : ZMod q` is invertible, then there are infinitely many prime numbers `p` such that +`(p : ZMod q) = a`. + +The main steps of the proof are as follows. +1. Define `ArithmeticFunction.vonMangoldt.residueClass a` for `a : ZMod q`, which is + a function `ℕ → ℝ` taking the value zero when `(n : ℤMod q) ≠ a` and `Λ n` else + (where `Λ` is the von Mangoldt function `ArithmeticFunction.vonMangoldt`; we have + `Λ (p^k) = log p` for prime powers and `Λ n = 0` otherwise.) +2. Show that this function can be written as a linear combination of functions + of the form `χ * Λ` (pointwise product) with Dirichlet characters `χ` mod `q`. + See `ArithmeticFunction.vonMangoldt.residueClass_eq`. +3. This implies that the L-series of `ArithmeticFunction.vonMangoldt.residueClass a` + agrees (on `re s > 1`) with the corresponding linear combination of negative logarithmic + derivatives of Dirichlet L-functions. + See `ArithmeticFunction.vonMangoldt.LSeries_residueClass_eq`. +4. Define an auxiliary function `ArithmeticFunction.vonMangoldt.LfunctionResidueClassAux a` that is + this linear combination of negative logarithmic derivatives of L-functions minus + `(q.totient)⁻¹/(s-1)`, which cancels the pole at `s = 1`. + See `ArithmeticFunction.vonMangoldt.eqOn_LfunctionResidueClassAux` for the statement + that the auxiliary function agrees with the L-series of + `ArithmeticFunction.vonMangoldt.residueClass` up to the term `(q.totient)⁻¹/(s-1)`. +5. Show that the auxiliary function is continuous on `re s ≥ 1`; + see `ArithmeticFunction.vonMangoldt.continuousOn_LfunctionResidueClassAux`. + This relies heavily on the non-vanishing of Dirichlet L-functions on the *closed* + half-plane `re s ≥ 1` (`DirichletCharacter.LFunction_ne_zero_of_one_le_re`), which + in turn can only be stated since we know that the L-series of a Dirichlet character + extends to an entire function (unless the character is trivial; then there is a + simple pole at `s = 1`); see `DirichletCharacter.LFunction_eq_LSeries` + (contributed by David Loeffler). +6. Show that the sum of `Λ n / n` over any residue class, but *excluding* the primes, converges. + See `ArithmeticFunction.vonMangoldt.summable_residueClass_non_primes_div`. +7. Combining these ingredients, we can deduce that the sum of `Λ n / n` over + the *primes* in a residue class must diverge. + See `ArithmeticFunction.vonMangoldt.not_summable_residueClass_prime_div`. +8. This finally easily implies that there must be infinitely many primes in the residue class. + +## Definitions + +* `ArithmeticFunction.vonMangoldt.residueClass a` (see above). +* `ArithmeticFunction.vonMangoldt.continuousOn_LfunctionResidueClassAux` (see above). + +## Main Result + +We give two versions of **Dirichlet's Theorem**: +* `Nat.setOf_prime_and_eq_mod_infinite` states that the set of primes `p` + such that `(p : ZMod q) = a` is infinite (when `a` is invertible in `ZMod q`). +* `Nat.forall_exists_prime_gt_and_eq_mod` states that for any natural number `n` + there is a prime `p > n` such that `(p : ZMod q) = a`. + +## Tags + +prime number, arithmetic progression, residue class, Dirichlet's Theorem +-/ + +/-! +### Auxiliary statements + +An infinite product or sum over a function supported in prime powers can be written +as an iterated product or sum over primes and natural numbers. +-/ + +section auxiliary + +variable {α β γ : Type*} [CommGroup α] [UniformSpace α] [UniformGroup α] [CompleteSpace α] + [T0Space α] + +open Nat.Primes in +@[to_additive tsum_eq_tsum_primes_of_support_subset_prime_powers] +lemma tprod_eq_tprod_primes_of_mulSupport_subset_prime_powers {f : ℕ → α} + (hfm : Multipliable f) (hf : Function.mulSupport f ⊆ {n | IsPrimePow n}) : + ∏' n : ℕ, f n = ∏' (p : Nat.Primes) (k : ℕ), f (p ^ (k + 1)) := by + have hfm' : Multipliable fun pk : Nat.Primes × ℕ ↦ f (pk.fst ^ (pk.snd + 1)) := + prodNatEquiv.symm.multipliable_iff.mp <| by + simpa only [← coe_prodNatEquiv_apply, Prod.eta, Function.comp_def, Equiv.apply_symm_apply] + using hfm.subtype _ + simp only [← tprod_subtype_eq_of_mulSupport_subset hf, Set.coe_setOf, ← prodNatEquiv.tprod_eq, + ← tprod_prod hfm'] + refine tprod_congr fun (p, k) ↦ congrArg f <| coe_prodNatEquiv_apply .. + +@[to_additive tsum_eq_tsum_primes_add_tsum_primes_of_support_subset_prime_powers] +lemma tprod_eq_tprod_primes_mul_tprod_primes_of_mulSupport_subset_prime_powers {f : ℕ → α} + (hfm : Multipliable f) (hf : Function.mulSupport f ⊆ {n | IsPrimePow n}) : + ∏' n : ℕ, f n = (∏' p : Nat.Primes, f p) * ∏' (p : Nat.Primes) (k : ℕ), f (p ^ (k + 2)) := by + rw [tprod_eq_tprod_primes_of_mulSupport_subset_prime_powers hfm hf] + have hfs' (p : Nat.Primes) : Multipliable fun k : ℕ ↦ f (p ^ (k + 1)) := + hfm.comp_injective <| (strictMono_nat_of_lt_succ + fun k ↦ pow_lt_pow_right₀ p.prop.one_lt <| lt_add_one (k + 1)).injective + conv_lhs => + enter [1, p]; rw [tprod_eq_zero_mul (hfs' p), zero_add, pow_one] + enter [2, 1, k]; rw [add_assoc, one_add_one_eq_two] + exact tprod_mul (Multipliable.subtype hfm _) <| + Multipliable.prod (f := fun (pk : Nat.Primes × ℕ) ↦ f (pk.1 ^ (pk.2 + 2))) <| + hfm.comp_injective <| Subtype.val_injective |>.comp + Nat.Primes.prodNatEquiv.injective |>.comp <| + Function.Injective.prodMap (fun ⦃_ _⦄ a ↦ a) <| add_left_injective 1 + +end auxiliary + +/-! +### The L-series of the von Mangoldt function restricted to a residue class +-/ + +section arith_prog + +namespace ArithmeticFunction.vonMangoldt + +open Complex LSeries DirichletCharacter + +open scoped LSeries.notation + +variable {q : ℕ} (a : ZMod q) + +/-- The von Mangoldt function restricted to the residue class `a` mod `q`. -/ +noncomputable abbrev residueClass : ℕ → ℝ := + {n : ℕ | (n : ZMod q) = a}.indicator (vonMangoldt ·) + +lemma residueClass_nonneg (n : ℕ) : 0 ≤ residueClass a n := + Set.indicator_apply_nonneg fun _ ↦ vonMangoldt_nonneg + +lemma residueClass_le (n : ℕ) : residueClass a n ≤ vonMangoldt n := + Set.indicator_apply_le' (fun _ ↦ le_rfl) (fun _ ↦ vonMangoldt_nonneg) + +@[simp] +lemma residueClass_apply_zero : residueClass a 0 = 0 := by + simp only [Set.indicator_apply_eq_zero, Set.mem_setOf_eq, Nat.cast_zero, map_zero, ofReal_zero, + implies_true] + +lemma abscissaOfAbsConv_residueClass_le_one : + abscissaOfAbsConv ↗(residueClass a) ≤ 1 := by + refine abscissaOfAbsConv_le_of_forall_lt_LSeriesSummable fun y hy ↦ ?_ + unfold LSeriesSummable + have := LSeriesSummable_vonMangoldt <| show 1 < (y : ℂ).re by simp only [ofReal_re, hy] + convert this.indicator {n : ℕ | (n : ZMod q) = a} + ext1 n + by_cases hn : (n : ZMod q) = a + · simp +contextual only [term, Set.indicator, Set.mem_setOf_eq, hn, ↓reduceIte, apply_ite, + ite_self] + · simp +contextual only [term, Set.mem_setOf_eq, hn, not_false_eq_true, Set.indicator_of_not_mem, + ofReal_zero, zero_div, ite_self] + +/-- The set we are interested in (prime numbers in the residue class `a`) is the same as the support +of `ArithmeticFunction.vonMangoldt.residueClass` restricted to primes (and divided by `n`; +this is how this result is used later). -/ +lemma support_residueClass_prime_div : + Function.support (fun n : ℕ ↦ (if n.Prime then residueClass a n else 0) / n) = + {p : ℕ | p.Prime ∧ (p : ZMod q) = a} := by + simp only [Function.support, ne_eq, div_eq_zero_iff, ite_eq_right_iff, + Set.indicator_apply_eq_zero, Set.mem_setOf_eq, Nat.cast_eq_zero, not_or, Classical.not_imp] + ext1 p + simp only [Set.mem_setOf_eq] + exact ⟨fun H ↦ ⟨H.1.1, H.1.2.1⟩, + fun H ↦ ⟨⟨H.1, H.2, vonMangoldt_ne_zero_iff.mpr H.1.isPrimePow⟩, H.1.ne_zero⟩⟩ + +private noncomputable def F₀ (n : ℕ) : ℝ := (if n.Prime then 0 else vonMangoldt n) / n + +private noncomputable def F' (pk : Nat.Primes × ℕ) : ℝ := F₀ (pk.1 ^ (pk.2 + 1)) + +private noncomputable def F'' : Nat.Primes × ℕ → ℝ := F' ∘ (Prod.map _root_.id (· + 1)) + +private lemma F''_le (p : Nat.Primes) (k : ℕ) : F'' (p, k) ≤ 2 * (p : ℝ)⁻¹ ^ (k + 3 / 2 : ℝ) := + calc _ + _ = Real.log p * (p : ℝ)⁻¹ ^ (k + 2) := by + simp only [F'', Function.comp_apply, F', F₀, Prod.map_apply, id_eq, le_add_iff_nonneg_left, + zero_le, Nat.Prime.not_prime_pow, ↓reduceIte, vonMangoldt_apply_prime p.prop, + vonMangoldt_apply_pow (Nat.zero_ne_add_one _).symm, Nat.cast_pow, div_eq_mul_inv, + inv_pow (p : ℝ) (k + 2)] + _ ≤ (p: ℝ) ^ (1 / 2 : ℝ) / (1 / 2) * (p : ℝ)⁻¹ ^ (k + 2) := + mul_le_mul_of_nonneg_right (Real.log_le_rpow_div p.val.cast_nonneg one_half_pos) + (pow_nonneg (inv_nonneg_of_nonneg (Nat.cast_nonneg ↑p)) (k + 2)) + _ = 2 * (p : ℝ)⁻¹ ^ (-1 / 2 : ℝ) * (p : ℝ)⁻¹ ^ (k + 2) := by + simp only [← div_mul, div_one, mul_comm, neg_div, Real.inv_rpow p.val.cast_nonneg, + ← Real.rpow_neg p.val.cast_nonneg, neg_neg] + _ = _ := by + rw [mul_assoc, ← Real.rpow_natCast, + ← Real.rpow_add <| by have := p.prop.pos; positivity, Nat.cast_add, Nat.cast_two, + add_comm, add_assoc] + norm_num + +open Nat.Primes + +private lemma summable_F'' : Summable F'' := by + have hp₀ (p : Nat.Primes) : 0 < (p : ℝ)⁻¹ := inv_pos_of_pos (Nat.cast_pos.mpr p.prop.pos) + have hp₁ (p : Nat.Primes) : (p : ℝ)⁻¹ < 1 := + (inv_lt_one₀ <| mod_cast p.prop.pos).mpr <| Nat.one_lt_cast.mpr <| p.prop.one_lt + suffices Summable fun (pk : Nat.Primes × ℕ) ↦ (pk.1 : ℝ)⁻¹ ^ (pk.2 + 3 / 2 : ℝ) by + refine (Summable.mul_left 2 this).of_nonneg_of_le (fun pk ↦ ?_) (fun pk ↦ F''_le pk.1 pk.2) + simp only [F'', Function.comp_apply, F', F₀, Prod.map_fst, id_eq, Prod.map_snd, Nat.cast_pow] + have := vonMangoldt_nonneg (n := (pk.1 : ℕ) ^ (pk.2 + 2)) + positivity + conv => enter [1, pk]; rw [Real.rpow_add <| hp₀ pk.1, Real.rpow_natCast] + refine (summable_prod_of_nonneg (fun _ ↦ by positivity)).mpr ⟨(fun p ↦ ?_), ?_⟩ + · dsimp only -- otherwise the `exact` below times out + exact Summable.mul_right _ <| summable_geometric_of_lt_one (hp₀ p).le (hp₁ p) + · dsimp only + conv => enter [1, p]; rw [tsum_mul_right, tsum_geometric_of_lt_one (hp₀ p).le (hp₁ p)] + refine (summable_rpow.mpr (by norm_num : -(3 / 2 : ℝ) < -1)).mul_left 2 + |>.of_nonneg_of_le (fun p ↦ ?_) (fun p ↦ ?_) + · have := sub_pos.mpr (hp₁ p) + positivity + · rw [Real.inv_rpow p.val.cast_nonneg, Real.rpow_neg p.val.cast_nonneg] + gcongr + rw [inv_le_comm₀ (sub_pos.mpr (hp₁ p)) zero_lt_two, le_sub_comm, + show (1 : ℝ) - 2⁻¹ = 2⁻¹ by norm_num, inv_le_inv₀ (mod_cast p.prop.pos) zero_lt_two] + exact Nat.ofNat_le_cast.mpr p.prop.two_le + +/-- The function `n ↦ Λ n / n`, restriced to non-primes in a residue class, is summable. +This is used to convert results on `ArithmeticFunction.vonMangoldt.residueClass` to results +on primes in an arithmetic progression. -/ +lemma summable_residueClass_non_primes_div : + Summable fun n : ℕ ↦ (if n.Prime then 0 else residueClass a n) / n := by + have h₀ (n : ℕ) : 0 ≤ (if n.Prime then 0 else residueClass a n) / n := by + have := residueClass_nonneg a n + positivity + have hleF₀ (n : ℕ) : (if n.Prime then 0 else residueClass a n) / n ≤ F₀ n := by + refine div_le_div_of_nonneg_right ?_ n.cast_nonneg + split_ifs; exacts [le_rfl, residueClass_le a n] + refine Summable.of_nonneg_of_le h₀ hleF₀ ?_ + have hF₀ (p : Nat.Primes) : F₀ p.val = 0 := by + simp only [p.prop, ↓reduceIte, zero_div, F₀] + refine (summable_subtype_iff_indicator (s := {n | IsPrimePow n}).mp ?_).congr + fun n ↦ Set.indicator_apply_eq_self.mpr fun (hn : ¬ IsPrimePow n) ↦ ?_ + swap + · simp +contextual only [div_eq_zero_iff, ite_eq_left_iff, vonMangoldt_eq_zero_iff, hn, + not_false_eq_true, implies_true, Nat.cast_eq_zero, true_or, F₀] + have hFF' : + F₀ ∘ Subtype.val (p := fun n ↦ n ∈ {n | IsPrimePow n}) = F' ∘ ⇑prodNatEquiv.symm := by + refine (Equiv.eq_comp_symm prodNatEquiv (F₀ ∘ Subtype.val) F').mpr ?_ + ext1 n + simp only [Function.comp_apply, F'] + congr + rw [hFF'] + refine (Nat.Primes.prodNatEquiv.symm.summable_iff (f := F')).mpr ?_ + have hF'₀ (p : Nat.Primes) : F' (p, 0) = 0 := by simp only [zero_add, pow_one, hF₀, F'] + have hF'₁ : F'' = F' ∘ (Prod.map _root_.id (· + 1)) := by + ext1 + simp only [Function.comp_apply, Prod.map_fst, id_eq, Prod.map_snd, F'', F'] + refine (Function.Injective.summable_iff ?_ fun u hu ↦ ?_).mp <| hF'₁ ▸ summable_F'' + · exact Function.Injective.prodMap (fun ⦃a₁ a₂⦄ a ↦ a) <| add_left_injective 1 + · simp only [Set.range_prod_map, Set.range_id, Set.mem_prod, Set.mem_univ, Set.mem_range, + Nat.exists_add_one_eq, true_and, not_lt, nonpos_iff_eq_zero] at hu + rw [← hF'₀ u.1, ← hu] + +variable [NeZero q] {a} + +/-- We can express `ArithmeticFunction.vonMangoldt.residueClass` as a linear combination +of twists of the von Mangoldt function by Dirichlet charaters. -/ +lemma residueClass_apply (ha : IsUnit a) (n : ℕ) : + residueClass a n = + (q.totient : ℂ)⁻¹ * ∑ χ : DirichletCharacter ℂ q, χ a⁻¹ * χ n * vonMangoldt n := by + rw [eq_inv_mul_iff_mul_eq₀ <| mod_cast (Nat.totient_pos.mpr q.pos_of_neZero).ne'] + simp +contextual only [residueClass, Set.indicator_apply, Set.mem_setOf_eq, apply_ite, + ofReal_zero, mul_zero, ← Finset.sum_mul, sum_char_inv_mul_char_eq ℂ ha n, eq_comm (a := a), + ite_mul, zero_mul, ↓reduceIte, ite_self] + +/-- We can express `ArithmeticFunction.vonMangoldt.residueClass` as a linear combination +of twists of the von Mangoldt function by Dirichlet charaters. -/ +lemma residueClass_eq (ha : IsUnit a) : + ↗(residueClass a) = (q.totient : ℂ)⁻¹ • + ∑ χ : DirichletCharacter ℂ q, χ a⁻¹ • (fun n : ℕ ↦ χ n * vonMangoldt n) := by + ext1 n + simpa only [Pi.smul_apply, Finset.sum_apply, smul_eq_mul, ← mul_assoc] + using residueClass_apply ha n + +/-- The L-series of the von Mangoldt function restricted to the residue class `a` mod `q` +with `a` invertible in `ZMod q` is a linear combination of logarithmic derivatives of +L-functions of the Dirichlet characters mod `q` (on `re s > 1`). -/ +lemma LSeries_residueClass_eq (ha : IsUnit a) {s : ℂ} (hs : 1 < s.re) : + LSeries ↗(residueClass a) s = + -(q.totient : ℂ)⁻¹ * ∑ χ : DirichletCharacter ℂ q, χ a⁻¹ * + (deriv (LFunction χ) s / LFunction χ s) := by + simp only [deriv_LFunction_eq_deriv_LSeries _ hs, LFunction_eq_LSeries _ hs, neg_mul, ← mul_neg, + ← Finset.sum_neg_distrib, ← neg_div, ← LSeries_twist_vonMangoldt_eq _ hs] + rw [eq_inv_mul_iff_mul_eq₀ <| mod_cast (Nat.totient_pos.mpr q.pos_of_neZero).ne'] + simp_rw [← LSeries_smul, + ← LSeries_sum <| fun χ _ ↦ (LSeriesSummable_twist_vonMangoldt χ hs).smul _] + refine LSeries_congr s fun {n} _ ↦ ?_ + simp only [Pi.smul_apply, residueClass_apply ha, smul_eq_mul, ← mul_assoc, + mul_inv_cancel_of_invertible, one_mul, Finset.sum_apply, Pi.mul_apply] + +variable (a) + +open Classical in +/-- The auxiliary function used, e.g., with the Wiener-Ikehara Theorem to prove +Dirichlet's Theorem. On `re s > 1`, it agrees with the L-series of the von Mangoldt +function restricted to the residue class `a : ZMod q` minus the principal part +`(q.totient)⁻¹/(s-1)` of the pole at `s = 1`; +see `ArithmeticFunction.vonMangoldt.eqOn_LfunctionResidueClassAux`. -/ +noncomputable +abbrev LfunctionResidueClassAux (s : ℂ) : ℂ := + (q.totient : ℂ)⁻¹ * (-deriv (LFunctionTrivChar₁ q) s / LFunctionTrivChar₁ q s - + ∑ χ ∈ ({1}ᶜ : Finset (DirichletCharacter ℂ q)), χ a⁻¹ * deriv (LFunction χ) s / LFunction χ s) + +/-- The auxiliary function is continuous away from the zeros of the L-functions of the Dirichlet +characters mod `q` (including at `s = 1`). -/ +lemma continuousOn_LfunctionResidueClassAux' : + ContinuousOn (LfunctionResidueClassAux a) + {s | s = 1 ∨ ∀ χ : DirichletCharacter ℂ q, LFunction χ s ≠ 0} := by + rw [show LfunctionResidueClassAux a = fun s ↦ _ from rfl] + simp only [LfunctionResidueClassAux, sub_eq_add_neg] + refine continuousOn_const.mul <| ContinuousOn.add ?_ ?_ + · refine (continuousOn_neg_logDeriv_LFunctionTrivChar₁ q).mono fun s hs ↦ ?_ + have := LFunction_ne_zero_of_one_le_re (1 : DirichletCharacter ℂ q) (s := s) + simp only [ne_eq, Set.mem_setOf_eq] at hs + tauto + · simp only [← Finset.sum_neg_distrib, mul_div_assoc, ← mul_neg, ← neg_div] + refine continuousOn_finset_sum _ fun χ hχ ↦ continuousOn_const.mul ?_ + replace hχ : χ ≠ 1 := by simpa only [ne_eq, Finset.mem_compl, Finset.mem_singleton] using hχ + refine (continuousOn_neg_logDeriv_LFunction_of_nontriv hχ).mono fun s hs ↦ ?_ + simp only [ne_eq, Set.mem_setOf_eq] at hs + rcases hs with rfl | hs + · simp only [ne_eq, Set.mem_setOf_eq, one_re, le_refl, + LFunction_ne_zero_of_one_le_re χ (.inl hχ), not_false_eq_true] + · exact hs χ + +/-- The L-series of the von Mangoldt function restricted to the prime residue class `a` mod `q` +is continuous on `re s ≥ 1` except for a simple pole at `s = 1` with residue `(q.totient)⁻¹`. +The statement as given here in terms of `ArithmeticFunction.vonMangoldt.LfunctionResidueClassAux` +is equivalent. -/ +lemma continuousOn_LfunctionResidueClassAux : + ContinuousOn (LfunctionResidueClassAux a) {s | 1 ≤ s.re} := by + refine (continuousOn_LfunctionResidueClassAux' a).mono fun s hs ↦ ?_ + rcases eq_or_ne s 1 with rfl | hs₁ + · simp only [ne_eq, Set.mem_setOf_eq, true_or] + · simp only [ne_eq, Set.mem_setOf_eq, hs₁, false_or] + exact fun χ ↦ LFunction_ne_zero_of_one_le_re χ (.inr hs₁) <| Set.mem_setOf.mp hs + +variable {a} + +open scoped LSeries.notation + +/-- The auxiliary function agrees on `re s > 1` with the L-series of the von Mangoldt function +restricted to the residue class `a : ZMod q` minus the principal part `(q.totient)⁻¹/(s-1)` +of its pole at `s = 1`. -/ +lemma eqOn_LfunctionResidueClassAux (ha : IsUnit a) : + Set.EqOn (LfunctionResidueClassAux a) + (fun s ↦ L ↗(residueClass a) s - (q.totient : ℂ)⁻¹ / (s - 1)) + {s | 1 < s.re} := by + intro s hs + replace hs := Set.mem_setOf.mp hs + simp only [LSeries_residueClass_eq ha hs, LfunctionResidueClassAux] + rw [neg_div, ← neg_add', mul_neg, ← neg_mul, div_eq_mul_one_div (q.totient : ℂ)⁻¹, + sub_eq_add_neg, ← neg_mul, ← mul_add] + congrm (_ * ?_) + -- this should be easier, but `IsUnit.inv ha` does not work here + have ha' : IsUnit a⁻¹ := isUnit_of_dvd_one ⟨a, (ZMod.inv_mul_of_unit a ha).symm⟩ + classical -- for `Fintype.sum_eq_add_sum_compl` + rw [Fintype.sum_eq_add_sum_compl 1, MulChar.one_apply ha', one_mul, add_right_comm] + simp only [mul_div_assoc] + congrm (?_ + _) + have hs₁ : s ≠ 1 := fun h ↦ ((h ▸ hs).trans_eq one_re).false + rw [deriv_LFunctionTrivChar₁_apply_of_ne_one _ hs₁, LFunctionTrivChar₁, + Function.update_noteq hs₁, LFunctionTrivChar, add_div, + mul_div_mul_left _ _ (sub_ne_zero_of_ne hs₁)] + conv_lhs => enter [2, 1]; rw [← mul_one (LFunction ..)] + rw [mul_comm _ 1, mul_div_mul_right _ _ <| LFunction_ne_zero_of_one_le_re 1 (.inr hs₁) hs.le] + +/-- The auxiliary function takes real values for real arguments `x > 1`. -/ +lemma LfunctionResidueClassAux_real (ha : IsUnit a) {x : ℝ} (hx : 1 < x) : + LfunctionResidueClassAux a x = (LfunctionResidueClassAux a x).re := by + rw [eqOn_LfunctionResidueClassAux ha hx] + simp only [sub_re, ofReal_sub] + congr 1 + · rw [LSeries, re_tsum <| LSeriesSummable_of_abscissaOfAbsConv_lt_re <| + (abscissaOfAbsConv_residueClass_le_one a).trans_lt <| by norm_cast] + push_cast + refine tsum_congr fun n ↦ ?_ + rcases eq_or_ne n 0 with rfl | hn + · simp only [term_zero, zero_re, ofReal_zero] + · simp only [term_of_ne_zero hn, ← ofReal_natCast n, ← ofReal_cpow n.cast_nonneg, ← ofReal_div, + ofReal_re] + · rw [show (q.totient : ℂ) = (q.totient : ℝ) from rfl, ← ofReal_one, ← ofReal_sub, ← ofReal_inv, + ← ofReal_div, ofReal_re] + +variable {q : ℕ} [NeZero q] {a : ZMod q} + +/-- As `x` approaches `1` from the right along the real axis, the L-series of +`ArithmeticFunction.vonMangoldt.residueClass` is bounded below by `(q.totient)⁻¹/(x-1) - C`. -/ +lemma LSeries_residueClass_lower_bound (ha : IsUnit a) : + ∃ C : ℝ, ∀ {x : ℝ} (_ : x ∈ Set.Ioc 1 2), + (q.totient : ℝ)⁻¹ / (x - 1) - C ≤ ∑' n, residueClass a n / (n : ℝ) ^ x := by + have H {x : ℝ} (hx : 1 < x) : + ∑' n, residueClass a n / (n : ℝ) ^ x = + (LfunctionResidueClassAux a x).re + (q.totient : ℝ)⁻¹ / (x - 1) := by + refine ofReal_injective ?_ + simp only [ofReal_tsum, ofReal_div, ofReal_cpow (Nat.cast_nonneg _), ofReal_natCast, + ofReal_add, ofReal_inv, ofReal_sub, ofReal_one] + simp_rw [← LfunctionResidueClassAux_real ha hx, + eqOn_LfunctionResidueClassAux ha <| Set.mem_setOf.mpr (ofReal_re x ▸ hx), sub_add_cancel, + LSeries, term] + refine tsum_congr fun n ↦ ?_ + split_ifs with hn + · simp only [hn, residueClass_apply_zero, ofReal_zero, zero_div] + · rfl + have : ContinuousOn (fun x : ℝ ↦ (LfunctionResidueClassAux a x).re) (Set.Icc 1 2) := + continuous_re.continuousOn.comp (t := Set.univ) (continuousOn_LfunctionResidueClassAux a) + (fun ⦃x⦄ a ↦ trivial) |>.comp continuous_ofReal.continuousOn fun x hx ↦ by + simpa only [Set.mem_setOf_eq, ofReal_re] using hx.1 + obtain ⟨C, hC⟩ := bddBelow_def.mp <| IsCompact.bddBelow_image isCompact_Icc this + replace hC {x : ℝ} (hx : x ∈ Set.Icc 1 2) : C ≤ (LfunctionResidueClassAux a x).re := + hC (LfunctionResidueClassAux a x).re <| + Set.mem_image_of_mem (fun x : ℝ ↦ (LfunctionResidueClassAux a x).re) hx + refine ⟨-C, fun {x} hx ↦ ?_⟩ + rw [H hx.1, add_comm, sub_neg_eq_add, add_le_add_iff_left] + exact hC <| Set.mem_Icc_of_Ioc hx + +open vonMangoldt Filter Topology in +/-- The function `n ↦ Λ n / n` restricted to primes in an invertible residue class +is not summable. This then implies that there must be infinitely many such primes. -/ +lemma not_summable_residueClass_prime_div (ha : IsUnit a) : + ¬ Summable fun n : ℕ ↦ (if n.Prime then residueClass a n else 0) / n := by + intro H + have key : Summable fun n : ℕ ↦ residueClass a n / n := by + convert (summable_residueClass_non_primes_div a).add H using 2 with n + simp only [← add_div, ite_add_ite, zero_add, add_zero, ite_self] + let C := ∑' n, residueClass a n / n + have H₁ {x : ℝ} (hx : 1 < x) : ∑' n, residueClass a n / (n : ℝ) ^ x ≤ C := by + refine tsum_le_tsum (fun n ↦ ?_) ?_ key + · rcases n.eq_zero_or_pos with rfl | hn + · simp only [Nat.cast_zero, Real.zero_rpow (zero_lt_one.trans hx).ne', div_zero, le_refl] + · refine div_le_div_of_nonneg_left (residueClass_nonneg a _) (mod_cast hn) ?_ + conv_lhs => rw [← Real.rpow_one n] + exact Real.rpow_le_rpow_of_exponent_le (by norm_cast) hx.le + · exact summable_real_of_abscissaOfAbsConv_lt <| + (abscissaOfAbsConv_residueClass_le_one a).trans_lt <| mod_cast hx + obtain ⟨C', hC'⟩ := LSeries_residueClass_lower_bound ha + have H₁ {x} (hx : x ∈ Set.Ioc 1 2) : (q.totient : ℝ)⁻¹ ≤ (C + C') * (x - 1) := + (div_le_iff₀ <| sub_pos.mpr hx.1).mp <| + sub_le_iff_le_add.mp <| (hC' hx).trans (H₁ hx.1) + have hq : 0 < (q.totient : ℝ)⁻¹ := inv_pos.mpr (mod_cast q.totient.pos_of_neZero) + rcases le_or_lt (C + C') 0 with h₀ | h₀ + · have := hq.trans_le (H₁ (Set.right_mem_Ioc.mpr one_lt_two)) + rw [show (2 : ℝ) - 1 = 1 by norm_num, mul_one] at this + exact (this.trans_le h₀).false + · obtain ⟨ξ, hξ₁, hξ₂⟩ : ∃ ξ ∈ Set.Ioc 1 2, (C + C') * (ξ - 1) < (q.totient : ℝ)⁻¹ := by + refine ⟨min (1 + (q.totient : ℝ)⁻¹ / (C + C') / 2) 2, ⟨?_, min_le_right ..⟩, ?_⟩ + · simpa only [lt_inf_iff, lt_add_iff_pos_right, Nat.ofNat_pos, div_pos_iff_of_pos_right, + Nat.one_lt_ofNat, and_true] using div_pos hq h₀ + · rw [← min_sub_sub_right, add_sub_cancel_left, ← lt_div_iff₀' h₀] + exact (min_le_left ..).trans_lt <| div_lt_self (div_pos hq h₀) one_lt_two + exact ((H₁ hξ₁).trans_lt hξ₂).false + +end ArithmeticFunction.vonMangoldt + +end arith_prog + +/-! +### Dirichlet's Theorem +-/ + +section DirichletsTheorem + +namespace Nat + +open ArithmeticFunction vonMangoldt + +variable {q : ℕ} [NeZero q] {a : ZMod q} + +/-- **Dirichlet's Theorem** on primes in arithmetic progression: if `q` is a positive +integer and `a : ZMod q` is a unit, then there are infintely many prime numbers `p` +such that `(p : ZMod q) = a`. -/ +theorem setOf_prime_and_eq_mod_infinite (ha : IsUnit a) : + {p : ℕ | p.Prime ∧ (p : ZMod q) = a}.Infinite := by + by_contra H + rw [Set.not_infinite] at H + exact not_summable_residueClass_prime_div ha <| + summable_of_finite_support <| support_residueClass_prime_div a ▸ H + +/-- **Dirichlet's Theorem** on primes in arithmetic progression: if `q` is a positive +integer and `a : ZMod q` is a unit, then there are infintely many prime numbers `p` +such that `(p : ZMod q) = a`. -/ +theorem forall_exists_prime_gt_and_eq_mod (ha : IsUnit a) (n : ℕ) : + ∃ p > n, p.Prime ∧ (p : ZMod q) = a := by + obtain ⟨p, hp₁, hp₂⟩ := Set.infinite_iff_exists_gt.mp (setOf_prime_and_eq_mod_infinite ha) n + exact ⟨p, hp₂.gt, Set.mem_setOf.mp hp₁⟩ + +end Nat + +end DirichletsTheorem diff --git a/Mathlib/NumberTheory/Modular.lean b/Mathlib/NumberTheory/Modular.lean index 6426b4dac0aada..59b083317b35bc 100644 --- a/Mathlib/NumberTheory/Modular.lean +++ b/Mathlib/NumberTheory/Modular.lean @@ -180,9 +180,6 @@ def lcRow0Extend {cd : Fin 2 → ℤ} (hcd : IsCoprime (cd 0) (cd 1)) : rw [neg_sq] exact hcd.sq_add_sq_ne_zero, LinearEquiv.refl ℝ (Fin 2 → ℝ)] --- `simpNF` times out, but only in CI where all of `Mathlib` is imported -attribute [nolint simpNF] lcRow0Extend_apply lcRow0Extend_symm_apply - /-- The map `lcRow0` is proper, that is, preimages of cocompact sets are finite in `[[* , *], [c, d]]`. -/ theorem tendsto_lcRow0 {cd : Fin 2 → ℤ} (hcd : IsCoprime (cd 0) (cd 1)) : @@ -210,17 +207,19 @@ theorem tendsto_lcRow0 {cd : Fin 2 → ℤ} (hcd : IsCoprime (cd 0) (cd 1)) : ext ⟨g, rfl⟩ i j : 3 fin_cases i <;> [fin_cases j; skip] -- the following are proved by `simp`, but it is replaced by `simp only` to avoid timeouts. - · simp only [mB, mulVec, dotProduct, Fin.sum_univ_two, coe_matrix_coe, - Int.coe_castRingHom, lcRow0_apply, Function.comp_apply, cons_val_zero, lcRow0Extend_apply, + · simp only [Fin.isValue, Int.cast_one, map_apply_coe, RingHom.mapMatrix_apply, + Int.coe_castRingHom, lcRow0_apply, map_apply, Fin.zero_eta, id_eq, Function.comp_apply, + of_apply, cons_val', cons_val_zero, empty_val', cons_val_fin_one, lcRow0Extend_apply, LinearMap.GeneralLinearGroup.coeFn_generalLinearEquiv, GeneralLinearGroup.coe_toLinear, - val_planeConformalMatrix, neg_neg, mulVecLin_apply, cons_val_one, head_cons, of_apply, - Fin.mk_zero, Fin.mk_one] + val_planeConformalMatrix, neg_neg, mulVecLin_apply, mulVec, dotProduct, Fin.sum_univ_two, + cons_val_one, head_cons, mB, f₁] · convert congr_arg (fun n : ℤ => (-n : ℝ)) g.det_coe.symm using 1 - simp only [f₁, mulVec, dotProduct, Fin.sum_univ_two, Matrix.det_fin_two, Function.comp_apply, - Subtype.coe_mk, lcRow0Extend_apply, cons_val_zero, + simp only [Fin.zero_eta, id_eq, Function.comp_apply, lcRow0Extend_apply, cons_val_zero, LinearMap.GeneralLinearGroup.coeFn_generalLinearEquiv, GeneralLinearGroup.coe_toLinear, - val_planeConformalMatrix, mulVecLin_apply, cons_val_one, head_cons, map_apply, neg_mul, - Int.cast_sub, Int.cast_mul, neg_sub, of_apply, Fin.mk_zero, Fin.mk_one] + mulVecLin_apply, mulVec, dotProduct, det_fin_two, f₁] + simp only [Fin.isValue, Fin.mk_one, val_planeConformalMatrix, neg_neg, of_apply, cons_val', + empty_val', cons_val_fin_one, cons_val_one, head_fin_const, map_apply, Fin.sum_univ_two, + cons_val_zero, neg_mul, head_cons, Int.cast_sub, Int.cast_mul, neg_sub] ring · rfl @@ -239,7 +238,7 @@ theorem smul_eq_lcRow0_add {p : Fin 2 → ℤ} (hp : IsCoprime (p 0) (p 1)) (hg (p 1 : ℂ) * z - p 0 = (p 1 * z - p 0) * ↑(Matrix.det (↑g : Matrix (Fin 2) (Fin 2) ℤ)))] rw [← hg, det_fin_two] simp only [Int.coe_castRingHom, coe_matrix_coe, Int.cast_mul, ofReal_intCast, map_apply, denom, - Int.cast_sub, coe_GLPos_coe_GL_coe_matrix, coe'_apply_complex] + Int.cast_sub, coe_GLPos_coe_GL_coe_matrix, coe_apply_complex] ring theorem tendsto_abs_re_smul {p : Fin 2 → ℤ} (hp : IsCoprime (p 0) (p 1)) : @@ -279,7 +278,7 @@ theorem exists_max_im : ∃ g : SL(2, ℤ), ∀ g' : SL(2, ℤ), (g' • z).im obtain ⟨g, -, hg⟩ := bottom_row_surj hp_coprime refine ⟨g, fun g' => ?_⟩ rw [ModularGroup.im_smul_eq_div_normSq, ModularGroup.im_smul_eq_div_normSq, - div_le_div_left] + div_le_div_iff_of_pos_left] · simpa [← hg] using hp (g' 1) (bottom_row_coprime g') · exact z.im_pos · exact normSq_denom_pos g' z @@ -384,6 +383,11 @@ theorem three_lt_four_mul_im_sq_of_mem_fdo (h : z ∈ 𝒟ᵒ) : 3 < 4 * z.im ^ have := h.2 cases abs_cases z.re <;> nlinarith +/-- non-strict variant of `ModularGroup.three_le_four_mul_im_sq_of_mem_fdo` -/ +theorem three_le_four_mul_im_sq_of_mem_fd {τ : ℍ} (h : τ ∈ 𝒟) : 3 ≤ 4 * τ.im ^ 2 := by + have : 1 ≤ τ.re * τ.re + τ.im * τ.im := by simpa [Complex.normSq_apply] using h.1 + cases abs_cases τ.re <;> nlinarith [h.2] + /-- If `z ∈ 𝒟ᵒ`, and `n : ℤ`, then `|z + n| > 1`. -/ theorem one_lt_normSq_T_zpow_smul (hz : z ∈ 𝒟ᵒ) (n : ℤ) : 1 < normSq (T ^ n • z : ℍ) := by have hz₁ : 1 < z.re * z.re + z.im * z.im := hz.1 @@ -453,22 +457,17 @@ theorem abs_c_le_one (hz : z ∈ 𝒟ᵒ) (hg : g • z ∈ 𝒟ᵒ) : |g 1 0| specialize this hc linarith intro hc - replace hc : 0 < c ^ 4 := by - change 0 < c ^ (2 * 2); rw [pow_mul]; apply sq_pos_of_pos (sq_pos_of_ne_zero hc) - have h₁ := - mul_lt_mul_of_pos_right - (mul_lt_mul'' (three_lt_four_mul_im_sq_of_mem_fdo hg) (three_lt_four_mul_im_sq_of_mem_fdo hz) - (by linarith) (by linarith)) - hc + have h₁ : 3 * 3 * c ^ 4 < 4 * (g • z).im ^ 2 * (4 * z.im ^ 2) * c ^ 4 := by + gcongr <;> apply three_lt_four_mul_im_sq_of_mem_fdo <;> assumption have h₂ : (c * z.im) ^ 4 / normSq (denom (↑g) z) ^ 2 ≤ 1 := div_le_one_of_le₀ - (pow_four_le_pow_two_of_pow_two_le (UpperHalfPlane.c_mul_im_sq_le_normSq_denom z g)) + (pow_four_le_pow_two_of_pow_two_le (z.c_mul_im_sq_le_normSq_denom g)) (sq_nonneg _) let nsq := normSq (denom g z) calc 9 * c ^ 4 < c ^ 4 * z.im ^ 2 * (g • z).im ^ 2 * 16 := by linarith _ = c ^ 4 * z.im ^ 4 / nsq ^ 2 * 16 := by - rw [ModularGroup.im_smul_eq_div_normSq, div_pow] + rw [im_smul_eq_div_normSq, div_pow] ring _ ≤ 16 := by rw [← mul_pow]; linarith @@ -504,4 +503,21 @@ end UniqueRepresentative end FundamentalDomain +lemma exists_one_half_le_im_smul (τ : ℍ) : ∃ γ : SL(2, ℤ), 1 / 2 ≤ im (γ • τ) := by + obtain ⟨γ, hγ⟩ := exists_smul_mem_fd τ + use γ + nlinarith [three_le_four_mul_im_sq_of_mem_fd hγ, im_pos (γ • τ)] + +/-- For every `τ : ℍ` there is some `γ ∈ SL(2, ℤ)` that sends it to an element whose +imaginary part is at least `1/2` and such that `denom γ τ` has norm at most 1. -/ +lemma exists_one_half_le_im_smul_and_norm_denom_le (τ : ℍ) : + ∃ γ : SL(2, ℤ), 1 / 2 ≤ im (γ • τ) ∧ ‖denom γ τ‖ ≤ 1 := by + rcases le_total (1 / 2) τ.im with h | h + · exact ⟨1, (one_smul SL(2, ℤ) τ).symm ▸ h, by simp only [coe_one, denom_one, norm_one, le_refl]⟩ + · refine (exists_one_half_le_im_smul τ).imp (fun γ hγ ↦ ⟨hγ, ?_⟩) + have h1 : τ.im ≤ (γ • τ).im := h.trans hγ + rw [im_smul_eq_div_normSq, le_div_iff₀ (normSq_denom_pos (↑γ) τ), normSq_eq_norm_sq] at h1 + simpa only [norm_eq_abs, sq_le_one_iff_abs_le_one, Complex.abs_abs] using + (mul_le_iff_le_one_right τ.2).mp h1 + end ModularGroup diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index d82d0134a4d492..2a7ff22c6f8989 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -227,10 +227,7 @@ def mul {k_1 k_2 : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : ModularForm Γ k_1) (g : toSlashInvariantForm := f.1.mul g.1 holo' := f.holo'.mul g.holo' bdd_at_infty' A := by - -- Porting note: was `by simpa using ...` - -- `mul_slash_SL2` is no longer a `simp` and `simpa only [mul_slash_SL2] using ...` failed - rw [SlashInvariantForm.coe_mul, mul_slash_SL2] - exact (f.bdd_at_infty' A).mul (g.bdd_at_infty' A) + simpa only [coe_mul, mul_slash_SL2] using (f.bdd_at_infty' A).mul (g.bdd_at_infty' A) @[simp] theorem mul_coe {k_1 k_2 : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : ModularForm Γ k_1) diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean index 533e632c675958..890e52757badd0 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean @@ -109,10 +109,10 @@ def _root_.eisensteinSeries (k : ℤ) (z : ℍ) : ℂ := ∑' x : gammaSet N a, lemma eisensteinSeries_slash_apply (k : ℤ) (γ : SL(2, ℤ)) : eisensteinSeries a k ∣[k] γ = eisensteinSeries (a ᵥ* γ) k := by ext1 z - simp_rw [SL_slash, slash_def, slash, ModularGroup.det_coe', ofReal_one, one_zpow, mul_one, + simp_rw [SL_slash, slash_def, slash, ModularGroup.det_coe, ofReal_one, one_zpow, mul_one, zpow_neg, mul_inv_eq_iff_eq_mul₀ (zpow_ne_zero _ <| z.denom_ne_zero _), mul_comm, eisensteinSeries, ← ModularGroup.sl_moeb, eisSummand_SL2_apply, tsum_mul_left] - erw [(gammaSetEquiv a γ).tsum_eq (eisSummand k · z)] + exact congr_arg (_ * ·) <| (gammaSetEquiv a γ).tsum_eq (eisSummand k · z) /-- The SlashInvariantForm defined by an Eisenstein series of weight `k : ℤ`, level `Γ(N)`, and congruence condition given by `a : Fin 2 → ZMod N`. -/ diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/IsBoundedAtImInfty.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/IsBoundedAtImInfty.lean index d5fe5f9673fc05..eb74346576451c 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/IsBoundedAtImInfty.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/IsBoundedAtImInfty.lean @@ -52,7 +52,7 @@ lemma abs_le_tsum_abs (N : ℕ) (a : Fin 2 → ZMod N) (k : ℤ) (hk : 3 ≤ k) /-- Eisenstein series are bounded at infinity. -/ theorem isBoundedAtImInfty_eisensteinSeries_SIF {N : ℕ+} (a : Fin 2 → ZMod N) {k : ℤ} (hk : 3 ≤ k) (A : SL(2, ℤ)) : IsBoundedAtImInfty ((eisensteinSeries_SIF a k).toFun ∣[k] A) := by - simp_rw [UpperHalfPlane.bounded_mem, eisensteinSeries_SIF] at * + simp_rw [UpperHalfPlane.isBoundedAtImInfty_iff, eisensteinSeries_SIF] at * refine ⟨∑'(x : Fin 2 → ℤ), r ⟨⟨N, 2⟩, Nat.ofNat_pos⟩ ^ (-k) * ‖x‖ ^ (-k), 2, ?_⟩ intro z hz obtain ⟨n, hn⟩ := (ModularGroup_T_zpow_mem_verticalStrip z N.2) diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean new file mode 100644 index 00000000000000..20ba662c6cc3b2 --- /dev/null +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2024 Chris Birkbeck. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Birkbeck +-/ +import Mathlib.NumberTheory.Modular +import Mathlib.NumberTheory.ModularForms.SlashInvariantForms +/-! +# Level one modular forms + +This file contains results specific to modular forms of level one, ie. modular forms for `SL(2, ℤ)`. + +TODO: Add finite-dimensionality of these spaces of modular forms. + +-/ + +open UpperHalfPlane ModularGroup SlashInvariantForm ModularForm Complex MatrixGroups + +lemma SlashInvariantForm.exists_one_half_le_im_and_norm_le {k : ℤ} (hk : k ≤ 0) {F : Type*} + [FunLike F ℍ ℂ] [SlashInvariantFormClass F ⊤ k] (f : F) (τ : ℍ) : + ∃ ξ : ℍ, 1/2 ≤ ξ.im ∧ ‖f τ‖ ≤ ‖f ξ‖ := + let ⟨γ, hγ, hdenom⟩ := exists_one_half_le_im_smul_and_norm_denom_le τ + ⟨γ • τ, hγ, by simpa only [slash_action_eqn'' _ (show γ ∈ ⊤ by tauto), norm_mul, norm_zpow] + using le_mul_of_one_le_left (norm_nonneg _) <| + one_le_zpow_of_nonpos₀ (norm_pos_iff.2 (denom_ne_zero _ _)) hdenom hk⟩ + +/-- If a constant function is modular of weight `k`, then either `k = 0`, or the constant is `0`. -/ +lemma SlashInvariantForm.wt_eq_zero_of_eq_const + {F : Type*} [FunLike F ℍ ℂ] (k : ℤ) [SlashInvariantFormClass F ⊤ k] + {f : F} {c : ℂ} (hf : ∀ τ, f τ = c) : k = 0 ∨ c = 0 := by + have hI := slash_action_eqn'' f (by tauto : ModularGroup.S ∈ ⊤) I + have h2I2 := slash_action_eqn'' f (by tauto : ModularGroup.S ∈ ⊤) ⟨2 * Complex.I, by simp⟩ + simp only [sl_moeb, hf, denom_S, coe_mk_subtype] at hI h2I2 + nth_rw 1 [h2I2] at hI + simp only [mul_zpow, coe_I, mul_eq_mul_right_iff, mul_left_eq_self₀] at hI + refine hI.imp_left (Or.casesOn · (fun H ↦ ?_) (False.elim ∘ zpow_ne_zero k I_ne_zero)) + rwa [← Complex.ofReal_ofNat, ← ofReal_zpow, ← ofReal_one, ofReal_inj, + zpow_eq_one_iff_right₀ (by norm_num) (by norm_num)] at H diff --git a/Mathlib/NumberTheory/ModularForms/SlashActions.lean b/Mathlib/NumberTheory/ModularForms/SlashActions.lean index 4b39fc4a7a847d..ef9d1a0bcb1468 100644 --- a/Mathlib/NumberTheory/ModularForms/SlashActions.lean +++ b/Mathlib/NumberTheory/ModularForms/SlashActions.lean @@ -139,14 +139,18 @@ theorem SL_slash (γ : SL(2, ℤ)) : f ∣[k] γ = f ∣[k] (γ : GL(2, ℝ)⁺) theorem is_invariant_const (A : SL(2, ℤ)) (x : ℂ) : Function.const ℍ x ∣[(0 : ℤ)] A = Function.const ℍ x := by funext - simp only [SL_slash, slash_def, slash, Function.const_apply, det_coe', ofReal_one, zero_sub, + simp only [SL_slash, slash_def, slash, Function.const_apply, det_coe, ofReal_one, zero_sub, zpow_neg, zpow_one, inv_one, mul_one, neg_zero, zpow_zero] /-- The constant function 1 is invariant under any element of `SL(2, ℤ)`. -/ --- @[simp] -- Porting note: simpNF says LHS simplifies to something more complex theorem is_invariant_one (A : SL(2, ℤ)) : (1 : ℍ → ℂ) ∣[(0 : ℤ)] A = (1 : ℍ → ℂ) := is_invariant_const _ _ +/-- Variant of `is_invariant_one` with the left hand side in simp normal form. -/ +@[simp] +theorem is_invariant_one' (A : SL(2, ℤ)) : (1 : ℍ → ℂ) ∣[(0 : ℤ)] (A : GL(2, ℝ)⁺) = 1 := by + simpa using is_invariant_one A + /-- A function `f : ℍ → ℂ` is slash-invariant, of weight `k ∈ ℤ` and level `Γ`, if for every matrix `γ ∈ Γ` we have `f(γ • z)= (c*z+d)^k f(z)` where `γ= ![![a, b], ![c, d]]`, and it acts on `ℍ` via Möbius transformations. -/ @@ -155,7 +159,7 @@ theorem slash_action_eq'_iff (k : ℤ) (f : ℍ → ℂ) (γ : SL(2, ℤ)) (z : simp only [SL_slash, slash_def, ModularForm.slash] convert inv_mul_eq_iff_eq_mul₀ (G₀ := ℂ) _ using 2 · rw [mul_comm] - simp only [denom, zpow_neg, det_coe', ofReal_one, one_zpow, mul_one, + simp only [denom, zpow_neg, det_coe, ofReal_one, one_zpow, mul_one, sl_moeb] rfl · convert zpow_ne_zero k (denom_ne_zero γ z) @@ -184,7 +188,7 @@ theorem mul_slash_SL2 (k1 k2 : ℤ) (A : SL(2, ℤ)) (f g : ℍ → ℂ) : (f * g) ∣[k1 + k2] (A : GL(2, ℝ)⁺) = ((↑ₘA).det : ℝ) • f ∣[k1] A * g ∣[k2] A := by apply mul_slash - _ = (1 : ℝ) • f ∣[k1] A * g ∣[k2] A := by rw [det_coe'] + _ = (1 : ℝ) • f ∣[k1] A * g ∣[k2] A := by rw [det_coe] _ = f ∣[k1] A * g ∣[k2] A := by rw [one_smul] end diff --git a/Mathlib/NumberTheory/MulChar/Basic.lean b/Mathlib/NumberTheory/MulChar/Basic.lean index 2df970973c59d4..7ddd95b920b4e2 100644 --- a/Mathlib/NumberTheory/MulChar/Basic.lean +++ b/Mathlib/NumberTheory/MulChar/Basic.lean @@ -391,13 +391,13 @@ lemma ne_one_iff {χ : MulChar R R'} : χ ≠ 1 ↔ ∃ a : Rˣ, χ a ≠ 1 := b simp only [Ne, eq_one_iff, not_forall] /-- A multiplicative character is *nontrivial* if it takes a value `≠ 1` on a unit. -/ -@[deprecated (since := "2024-06-16")] +@[deprecated "No deprecation message was provided." (since := "2024-06-16")] def IsNontrivial (χ : MulChar R R') : Prop := ∃ a : Rˣ, χ a ≠ 1 set_option linter.deprecated false in /-- A multiplicative character is nontrivial iff it is not the trivial character. -/ -@[deprecated (since := "2024-06-16")] +@[deprecated "No deprecation message was provided." (since := "2024-06-16")] theorem isNontrivial_iff (χ : MulChar R R') : χ.IsNontrivial ↔ χ ≠ 1 := by simp only [IsNontrivial, Ne, MulChar.ext_iff, not_forall, one_apply_coe] @@ -573,7 +573,7 @@ theorem sum_eq_zero_of_ne_one [IsDomain R'] {χ : MulChar R R'} (hχ : χ ≠ 1) simpa only [Finset.mul_sum, ← map_mul] using b.mulLeft_bijective.sum_comp _ set_option linter.deprecated false in -@[deprecated (since := "2024-06-16")] +@[deprecated "No deprecation message was provided." (since := "2024-06-16")] lemma IsNontrivial.sum_eq_zero [IsDomain R'] {χ : MulChar R R'} (hχ : χ.IsNontrivial) : ∑ a, χ a = 0 := sum_eq_zero_of_ne_one ((isNontrivial_iff _).mp hχ) diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean index 3cfe928f41764c..3b10a1368dea73 100644 --- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean @@ -367,8 +367,8 @@ theorem forall_normAtPlace_eq_zero_iff {x : mixedSpace K} : (∀ w, normAtPlace w x = 0) ↔ x = 0 := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · ext w - · exact norm_eq_zero'.mp (normAtPlace_apply_isReal w.prop _ ▸ h w.1) - · exact norm_eq_zero'.mp (normAtPlace_apply_isComplex w.prop _ ▸ h w.1) + · exact norm_eq_zero.mp (normAtPlace_apply_isReal w.prop _ ▸ h w.1) + · 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 @@ -585,17 +585,17 @@ theorem stdBasis_repr_eq_matrixToStdBasis_mul (x : (K →+* ℂ) → ℂ) | inr c => rcases c with ⟨w, j⟩ fin_cases j - · simp_rw [Fin.mk_zero, stdBasis_apply_ofIsComplex_fst, fromBlocks_apply₂₁, - fromBlocks_apply₂₂, Matrix.zero_apply, submatrix_apply, - blockDiagonal_apply, Prod.swap_prod_mk, ite_mul, zero_mul, sum_const_zero, zero_add, - sum_add_distrib, sum_ite_eq, mem_univ, ite_true, of_apply, cons_val', cons_val_zero, - cons_val_one, head_cons, ← hx (embedding w), re_eq_add_conj] + · simp only [Fin.zero_eta, Fin.isValue, id_eq, stdBasis_apply_ofIsComplex_fst, re_eq_add_conj, + mul_neg, fromBlocks_apply₂₁, zero_apply, zero_mul, sum_const_zero, fromBlocks_apply₂₂, + submatrix_apply, Prod.swap_prod_mk, blockDiagonal_apply, of_apply, cons_val', cons_val_zero, + empty_val', cons_val_fin_one, ite_mul, cons_val_one, head_cons, sum_add_distrib, sum_ite_eq, + mem_univ, ↓reduceIte, ← hx (embedding w), zero_add] field_simp - · simp_rw [Fin.mk_one, stdBasis_apply_ofIsComplex_snd, fromBlocks_apply₂₁, - fromBlocks_apply₂₂, Matrix.zero_apply, submatrix_apply, blockDiagonal_apply, - Prod.swap_prod_mk, ite_mul, zero_mul, sum_const_zero, zero_add, sum_add_distrib, sum_ite_eq, - mem_univ, ite_true, of_apply, cons_val', cons_val_zero, cons_val_one, head_cons, - ← hx (embedding w), im_eq_sub_conj] + · simp only [Fin.mk_one, Fin.isValue, id_eq, stdBasis_apply_ofIsComplex_snd, im_eq_sub_conj, + mul_neg, fromBlocks_apply₂₁, zero_apply, zero_mul, sum_const_zero, fromBlocks_apply₂₂, + submatrix_apply, Prod.swap_prod_mk, blockDiagonal_apply, of_apply, cons_val', cons_val_zero, + empty_val', cons_val_fin_one, cons_val_one, head_fin_const, ite_mul, neg_mul, head_cons, + sum_add_distrib, sum_ite_eq, mem_univ, ↓reduceIte, ← hx (embedding w), zero_add] ring_nf; field_simp end stdBasis diff --git a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean index c735c105489002..4fbfe52301fe90 100644 --- a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean +++ b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean @@ -75,7 +75,7 @@ variable (K) /-- The logarithmic embedding of the units (seen as an `Additive` group). -/ def _root_.NumberField.Units.logEmbedding : Additive ((𝓞 K)ˣ) →+ ({w : InfinitePlace K // w ≠ w₀} → ℝ) := -{ toFun := fun x w => mult w.val * Real.log (w.val ↑(Additive.toMul x)) +{ toFun := fun x w => mult w.val * Real.log (w.val ↑x.toMul) map_zero' := by simp; rfl map_add' := fun _ _ => by simp [Real.log_mul, mul_add]; rfl } @@ -465,7 +465,7 @@ def basisUnitLattice : Basis (Fin (rank K)) ℤ (unitLattice K) := units in `basisModTorsion`. -/ def fundSystem : Fin (rank K) → (𝓞 K)ˣ := -- `:)` prevents the `⧸` decaying to a quotient by `leftRel` when we unfold this later - fun i => Quotient.out' (Additive.toMul (basisModTorsion K i):) + fun i => Quotient.out ((basisModTorsion K i).toMul:) theorem fundSystem_mk (i : Fin (rank K)) : Additive.ofMul (QuotientGroup.mk (fundSystem K i)) = (basisModTorsion K i) := by diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index e45dc9dad9d428..74e302eb5dbe25 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -267,7 +267,7 @@ private theorem newton_seq_succ_dist (n : ℕ) : newton_seq_norm_eq hnorm _ _ = ‖F.eval (newton_seq n)‖ / ‖F.derivative.eval a‖ := by rw [newton_seq_deriv_norm] _ ≤ ‖F.derivative.eval a‖ ^ 2 * T ^ 2 ^ n / ‖F.derivative.eval a‖ := - ((div_le_div_right (deriv_norm_pos hnorm)).2 (newton_seq_norm_le hnorm _)) + ((div_le_div_iff_of_pos_right (deriv_norm_pos hnorm)).2 (newton_seq_norm_le hnorm _)) _ = ‖F.derivative.eval a‖ * T ^ 2 ^ n := div_sq_cancel _ _ private theorem newton_seq_dist_aux (n : ℕ) : diff --git a/Mathlib/NumberTheory/Padics/MahlerBasis.lean b/Mathlib/NumberTheory/Padics/MahlerBasis.lean index 543eaf0533d7d0..a6be858db53356 100644 --- a/Mathlib/NumberTheory/Padics/MahlerBasis.lean +++ b/Mathlib/NumberTheory/Padics/MahlerBasis.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: Giulio Caflisch, David Loeffler -/ +import Mathlib.Algebra.Group.ForwardDiff import Mathlib.Analysis.Normed.Group.Ultra import Mathlib.NumberTheory.Padics.ProperSpace import Mathlib.RingTheory.Binomial @@ -15,15 +16,26 @@ import Mathlib.Topology.ContinuousMap.Compact In this file we introduce the Mahler basis function `mahler k`, for `k : ℕ`, which is the unique continuous map `ℤ_[p] → ℚ_[p]` agreeing with `n ↦ n.choose k` for `n ∈ ℕ`. -In future PR's, we will show that these functions give a Banach basis for the space of continuous -maps `ℤ_[p] → ℚ_[p]`. +We also show that for any continuous function `f` on `ℤ_[p]` (valued in a `p`-adic normed space), +the iterated forward differences `Δ^[n] f 0` tend to 0. For this, we follow the argument of +Bojanić [bojanic74]. + +In future PR's, we will show that the Mahler functions give a Banach basis for the space of +continuous maps `ℤ_[p] → ℚ_[p]`, with the basis coefficients of `f` given by the forward differences +`Δ^[n] f 0`. ## References +* [R. Bojanić, *A simple proof of Mahler's theorem on approximation of continuous functions of a + p-adic variable by polynomials*][bojanic74] * [P. Colmez, *Fonctions d'une variable p-adique*][colmez2010] + +## Tags + +Bojanic -/ -open Finset +open Finset fwdDiff IsUltrametricDist NNReal Filter Topology variable {p : ℕ} [hp : Fact p.Prime] @@ -95,3 +107,134 @@ The uniform norm of the `k`-th Mahler basis function is 1, for every `k`. · -- Show norm 1 is attained at `x = k` refine (le_of_eq ?_).trans ((mahler k).norm_coe_le_norm k) rw [mahler_natCast_eq, Nat.choose_self, Nat.cast_one, norm_one] + +section fwdDiff + +variable {M G : Type*} + +/-- Bound for iterated forward differences of a continuous function from a compact space to a +nonarchimedean seminormed group. -/ +lemma IsUltrametricDist.norm_fwdDiff_iter_apply_le [TopologicalSpace M] [CompactSpace M] + [AddCommMonoid M] [SeminormedAddCommGroup G] [IsUltrametricDist G] + (h : M) (f : C(M, G)) (m : M) (n : ℕ) : ‖Δ_[h]^[n] f m‖ ≤ ‖f‖ := by + -- A proof by induction on `n` would be possible but would involve some messing around to + -- define `Δ_[h]` as an operator on continuous maps (not just on bare functions). So instead we + -- use the formula for `Δ_[h]^[n] f` as a sum. + rw [fwdDiff_iter_eq_sum_shift] + refine norm_sum_le_of_forall_le_of_nonneg (norm_nonneg f) fun i _ ↦ ?_ + exact (norm_zsmul_le _ _).trans (f.norm_coe_le_norm _) + +/-- First step in Bojanić's proof of Mahler's theorem (equation (10) of [bojanic74]): rewrite +`Δ^[n + R] f 0` in a shape that makes it easy to bound `p`-adically. -/ +private lemma bojanic_mahler_step1 [AddCommMonoidWithOne M] [AddCommGroup G] (f : M → G) + (n : ℕ) {R : ℕ} (hR : 1 ≤ R) : + Δ_[1]^[n + R] f 0 = -∑ j ∈ range (R - 1), R.choose (j + 1) • Δ_[1]^[n + (j + 1)] f 0 + + ∑ k ∈ range (n + 1), ((-1 : ℤ) ^ (n - k) * n.choose k) • (f (k + R) - f k) := by + have aux : Δ_[1]^[n + R] f 0 = R.choose (R - 1 + 1) • Δ_[1]^[n + R] f 0 := by + rw [Nat.sub_add_cancel hR, Nat.choose_self, one_smul] + rw [neg_add_eq_sub, eq_sub_iff_add_eq, add_comm, aux, (by omega : n + R = (n + ((R - 1) + 1))), + ← sum_range_succ, Nat.sub_add_cancel hR, + ← sub_eq_iff_eq_add.mpr (sum_range_succ' (fun x ↦ R.choose x • Δ_[1]^[n + x] f 0) R), add_zero, + Nat.choose_zero_right, one_smul] + have : ∑ k ∈ Finset.range (R + 1), R.choose k • Δ_[1]^[n + k] f 0 = Δ_[1]^[n] f R := by + simpa only [← Function.iterate_add_apply, add_comm, nsmul_one, add_zero] using + (shift_eq_sum_fwdDiff_iter 1 (Δ_[1]^[n] f) R 0).symm + simp only [this, fwdDiff_iter_eq_sum_shift (1 : M) f n, mul_comm, nsmul_one, mul_smul, add_comm, + add_zero, smul_sub, sum_sub_distrib] + +end fwdDiff + +namespace PadicInt + +section norm_fwdDiff + +variable {p : ℕ} [hp : Fact p.Prime] {E : Type*} + [NormedAddCommGroup E] [NormedSpace ℚ_[p] E] [IsUltrametricDist E] + +/-- +Second step in Bojanić's proof of Mahler's theorem (equation (11) of [bojanic74]): show that values +`Δ_[1]^[n + p ^ t] f 0` for large enough `n` are bounded by the max of `(‖f‖ / p ^ s)` and `1 / p` +times a sup over values for smaller `n`. + +We use `nnnorm`s on the RHS since `Finset.sup` requires an order with a bottom element. +-/ +private lemma bojanic_mahler_step2 {f : C(ℤ_[p], E)} {s t : ℕ} + (hst : ∀ x y : ℤ_[p], ‖x - y‖ ≤ p ^ (-t : ℤ) → ‖f x - f y‖ ≤ ‖f‖ / p ^ s) (n : ℕ) : + ‖Δ_[1]^[n + p ^ t] f 0‖ ≤ max ↑((Finset.range (p ^ t - 1)).sup + fun j ↦ ‖Δ_[1]^[n + (j + 1)] f 0‖₊ / p) (‖f‖ / p ^ s) := by + -- Use previous lemma to rewrite in a convenient form. + rw [bojanic_mahler_step1 _ _ (one_le_pow₀ hp.out.one_le)] + -- Now use ultrametric property and bound each term separately. + refine (norm_add_le_max _ _).trans (max_le_max ?_ ?_) + · -- Bounding the sum over `range (p ^ t - 1)`: every term involves a value `Δ_[1]^[·] f 0` and + -- a binomial coefficient which is divisible by `p` + rw [norm_neg, ← coe_nnnorm, coe_le_coe] + refine nnnorm_sum_le_of_forall_le (fun i hi ↦ Finset.le_sup_of_le hi ?_) + rw [mem_range] at hi + rw [← Nat.cast_smul_eq_nsmul ℚ_[p], nnnorm_smul, div_eq_inv_mul] + refine mul_le_mul_of_nonneg_right ?_ (by simp only [zero_le]) + -- remains to show norm of binomial coeff is `≤ p⁻¹` + have : 0 < (p ^ t).choose (i + 1) := Nat.choose_pos (by omega) + rw [← zpow_neg_one, ← coe_le_coe, coe_nnnorm, Padic.norm_eq_pow_val (mod_cast this.ne'), + coe_zpow, NNReal.coe_natCast, (zpow_right_strictMono₀ (mod_cast hp.out.one_lt)).le_iff_le, + neg_le_neg_iff, Padic.valuation_natCast, Nat.one_le_cast] + exact one_le_padicValNat_of_dvd this <| hp.out.dvd_choose_pow (by omega) (by omega) + · -- Bounding the sum over `range (n + 1)`: every term is small by the choice of `t` + refine norm_sum_le_of_forall_le_of_nonempty nonempty_range_succ (fun i _ ↦ ?_) + calc ‖((-1 : ℤ) ^ (n - i) * n.choose i) • (f (i + ↑(p ^ t)) - f i)‖ + _ ≤ ‖f (i + ↑(p ^ t)) - f i‖ := by + rw [← Int.cast_smul_eq_zsmul ℚ_[p], norm_smul] + apply mul_le_of_le_one_left (norm_nonneg _) + simpa only [← coe_intCast] using norm_le_one _ + _ ≤ ‖f‖ / p ^ s := by + apply hst + rw [Nat.cast_pow, add_sub_cancel_left, norm_pow, norm_p, inv_pow, zpow_neg, zpow_natCast] + +/-- +Explicit bound for the decay rate of the Mahler coefficients of a continuous function on `ℤ_[p]`. +This will be used to prove Mahler's theorem. + -/ +lemma fwdDiff_iter_le_of_forall_le {f : C(ℤ_[p], E)} {s t : ℕ} + (hst : ∀ x y : ℤ_[p], ‖x - y‖ ≤ p ^ (-t : ℤ) → ‖f x - f y‖ ≤ ‖f‖ / p ^ s) (n : ℕ) : + ‖Δ_[1]^[n + s * p ^ t] f 0‖ ≤ ‖f‖ / p ^ s := by + -- We show the following more general statement by induction on `k`: + suffices ∀ {k : ℕ}, k ≤ s → ‖Δ_[1]^[n + k * p ^ t] f 0‖ ≤ ‖f‖ / p ^ k from this le_rfl + intro k hk + induction' k with k IH generalizing n + · -- base case just says that `‖Δ^[·] (⇑f) 0‖` is bounded by `‖f‖` + simpa only [zero_mul, pow_zero, add_zero, div_one] using norm_fwdDiff_iter_apply_le 1 f 0 n + · -- induction is the "step 2" lemma above + rw [add_mul, one_mul, ← add_assoc] + refine (bojanic_mahler_step2 hst (n + k * p ^ t)).trans (max_le ?_ ?_) + · rw [← coe_nnnorm, ← NNReal.coe_natCast, ← NNReal.coe_pow, ← NNReal.coe_div, NNReal.coe_le_coe] + refine Finset.sup_le fun j _ ↦ ?_ + rw [pow_succ, ← div_div, div_le_div_iff_of_pos_right (mod_cast hp.out.pos), add_right_comm] + exact_mod_cast IH (n + (j + 1)) (by omega) + · exact div_le_div_of_nonneg_left (norm_nonneg _) + (mod_cast pow_pos hp.out.pos _) (mod_cast pow_le_pow_right₀ hp.out.one_le hk) + +/-- Key lemma for Mahler's theorem: for `f` a continuous function on `ℤ_[p]`, the sequence +`n ↦ Δ^[n] f 0` tends to 0. See `PadicInt.fwdDiff_iter_le_of_forall_le` for an explicit +estimate of the decay rate. -/ +lemma fwdDiff_tendsto_zero (f : C(ℤ_[p], E)) : Tendsto (Δ_[1]^[·] f 0) atTop (𝓝 0) := by + -- first extract an `s` + refine NormedAddCommGroup.tendsto_nhds_zero.mpr (fun ε hε ↦ ?_) + have : Tendsto (fun s ↦ ‖f‖ / p ^ s) _ _ := tendsto_const_nhds.div_atTop + (tendsto_pow_atTop_atTop_of_one_lt (mod_cast hp.out.one_lt)) + obtain ⟨s, hs⟩ := (this.eventually_lt_const hε).exists + refine .mp ?_ (.of_forall fun x hx ↦ lt_of_le_of_lt hx hs) + -- use uniform continuity to find `t` + obtain ⟨t, ht⟩ : ∃ t : ℕ, ∀ x y, ‖x - y‖ ≤ p ^ (-t : ℤ) → ‖f x - f y‖ ≤ ‖f‖ / p ^ s := by + rcases eq_or_ne f 0 with rfl | hf + · -- silly case : f = 0 + simp + have : 0 < ‖f‖ / p ^ s := div_pos (norm_pos_iff.mpr hf) (mod_cast pow_pos hp.out.pos _) + obtain ⟨δ, hδpos, hδf⟩ := f.uniform_continuity _ this + obtain ⟨t, ht⟩ := PadicInt.exists_pow_neg_lt p hδpos + exact ⟨t, fun x y hxy ↦ by simpa only [dist_eq_norm_sub] using (hδf (hxy.trans_lt ht)).le⟩ + filter_upwards [eventually_ge_atTop (s * p ^ t)] with m hm + simpa only [Nat.sub_add_cancel hm] using fwdDiff_iter_le_of_forall_le ht (m - s * p ^ t) + +end norm_fwdDiff + +end PadicInt diff --git a/Mathlib/NumberTheory/Padics/PadicIntegers.lean b/Mathlib/NumberTheory/Padics/PadicIntegers.lean index 53e32586436a13..f9e0e0463f74b9 100644 --- a/Mathlib/NumberTheory/Padics/PadicIntegers.lean +++ b/Mathlib/NumberTheory/Padics/PadicIntegers.lean @@ -153,8 +153,7 @@ def Coe.ringHom : ℤ_[p] →+* ℚ_[p] := (subring p).subtype @[simp, norm_cast] theorem coe_pow (x : ℤ_[p]) (n : ℕ) : (↑(x ^ n) : ℚ_[p]) = (↑x : ℚ_[p]) ^ n := rfl --- @[simp] -- Porting note: not in simpNF -theorem mk_coe (k : ℤ_[p]) : (⟨k, k.2⟩ : ℤ_[p]) = k := Subtype.coe_eta _ _ +theorem mk_coe (k : ℤ_[p]) : (⟨k, k.2⟩ : ℤ_[p]) = k := by simp /-- The inverse of a `p`-adic integer with norm equal to `1` is also a `p`-adic integer. Otherwise, the inverse is defined to be `0`. -/ @@ -165,10 +164,8 @@ instance : CharZero ℤ_[p] where 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 - suffices (z1 : ℚ_[p]) = z2 ↔ z1 = z2 from Iff.trans (by norm_cast) this - norm_cast +@[norm_cast] +theorem intCast_eq (z1 z2 : ℤ) : (z1 : ℤ_[p]) = z2 ↔ z1 = z2 := by simp @[deprecated (since := "2024-04-05")] alias coe_int_eq := intCast_eq @@ -280,8 +277,7 @@ theorem norm_eq_padic_norm {q : ℚ_[p]} (hq : ‖q‖ ≤ 1) : @norm ℤ_[p] _ @[simp] theorem norm_p : ‖(p : ℤ_[p])‖ = (p : ℝ)⁻¹ := padicNormE.norm_p --- @[simp] -- Porting note: not in simpNF -theorem norm_p_pow (n : ℕ) : ‖(p : ℤ_[p]) ^ n‖ = (p : ℝ) ^ (-n : ℤ) := padicNormE.norm_p_pow n +theorem norm_p_pow (n : ℕ) : ‖(p : ℤ_[p]) ^ n‖ = (p : ℝ) ^ (-n : ℤ) := by simp private def cauSeq_to_rat_cauSeq (f : CauSeq ℤ_[p] norm) : CauSeq ℚ_[p] fun a => ‖a‖ := ⟨fun n => f n, fun _ hε => by simpa [norm, norm_def] using f.cauchy hε⟩ @@ -413,10 +409,12 @@ theorem norm_lt_one_mul {z1 z2 : ℤ_[p]} (hz2 : ‖z2‖ < 1) : ‖z1 * z2‖ < ‖z1 * z2‖ = ‖z1‖ * ‖z2‖ := by simp _ < 1 := mul_lt_one_of_nonneg_of_lt_one_right (norm_le_one _) (norm_nonneg _) hz2 --- @[simp] -- Porting note: not in simpNF theorem mem_nonunits {z : ℤ_[p]} : z ∈ nonunits ℤ_[p] ↔ ‖z‖ < 1 := by rw [lt_iff_le_and_ne]; simp [norm_le_one z, nonunits, isUnit_iff] +theorem not_isUnit_iff {z : ℤ_[p]} : ¬IsUnit z ↔ ‖z‖ < 1 := by + simpa using mem_nonunits + /-- A `p`-adic number `u` with `‖u‖ = 1` is a unit of `ℤ_[p]`. -/ def mkUnits {u : ℚ_[p]} (h : ‖u‖ = 1) : ℤ_[p]ˣ := let z : ℤ_[p] := ⟨u, le_of_eq h⟩ diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean index dab80d6e19bd61..b80610a74c52af 100644 --- a/Mathlib/NumberTheory/Padics/RingHoms.lean +++ b/Mathlib/NumberTheory/Padics/RingHoms.lean @@ -393,7 +393,7 @@ theorem ker_toZModPow (n : ℕ) : rw [zmod_congr_of_sub_mem_span n x _ 0 _ h, cast_zero] apply appr_spec --- @[simp] -- Porting note: not in simpNF +-- This is not a simp lemma; simp can't match the LHS. theorem zmod_cast_comp_toZModPow (m n : ℕ) (h : m ≤ n) : (ZMod.castHom (pow_dvd_pow p h) (ZMod (p ^ m))).comp (@toZModPow p _ n) = @toZModPow p _ m := by apply ZMod.ringHom_eq_of_ker_eq diff --git a/Mathlib/NumberTheory/Pell.lean b/Mathlib/NumberTheory/Pell.lean index e83f9f210649a1..c3559d516dd99c 100644 --- a/Mathlib/NumberTheory/Pell.lean +++ b/Mathlib/NumberTheory/Pell.lean @@ -337,7 +337,8 @@ theorem exists_of_not_isSquare (h₀ : 0 < d) (hd : ¬IsSquare d) : refine Infinite.mono (fun q h => ?_) (infinite_rat_abs_sub_lt_one_div_den_sq_of_irrational hξ) have h0 : 0 < (q.2 : ℝ) ^ 2 := pow_pos (Nat.cast_pos.mpr q.pos) 2 have h1 : (q.num : ℝ) / (q.den : ℝ) = q := mod_cast q.num_div_den - rw [mem_setOf, abs_sub_comm, ← @Int.cast_lt ℝ, ← div_lt_div_right (abs_pos_of_pos h0)] + rw [mem_setOf, abs_sub_comm, ← @Int.cast_lt ℝ, + ← div_lt_div_iff_of_pos_right (abs_pos_of_pos h0)] push_cast rw [← abs_div, abs_sq, sub_div, mul_div_cancel_right₀ _ h0.ne', ← div_pow, h1, ← sq_sqrt (Int.cast_pos.mpr h₀).le, sq_sub_sq, abs_mul, ← mul_one_div] diff --git a/Mathlib/NumberTheory/Primorial.lean b/Mathlib/NumberTheory/Primorial.lean index 3867a3aa0f8939..d2a7922592c846 100644 --- a/Mathlib/NumberTheory/Primorial.lean +++ b/Mathlib/NumberTheory/Primorial.lean @@ -27,8 +27,6 @@ open Finset open Nat -open Nat - /-- The primorial `n#` of `n` is the product of the primes less than or equal to `n`. -/ def primorial (n : ℕ) : ℕ := ∏ p ∈ range (n + 1) with p.Prime, p diff --git a/Mathlib/NumberTheory/Transcendental/Liouville/Basic.lean b/Mathlib/NumberTheory/Transcendental/Liouville/Basic.lean index 04403810047a70..b3587eda5cecf0 100644 --- a/Mathlib/NumberTheory/Transcendental/Liouville/Basic.lean +++ b/Mathlib/NumberTheory/Transcendental/Liouville/Basic.lean @@ -47,7 +47,7 @@ protected theorem irrational {x : ℝ} (h : Liouville x) : Irrational x := by have bq0 : (0 : ℝ) < b * q := mul_pos (Nat.cast_pos.mpr bN0.bot_lt) qR0 -- At a1, clear denominators... replace a1 : |a * q - b * p| * q ^ (b + 1) < b * q := by - rw [div_sub_div _ _ b0 qR0.ne', abs_div, div_lt_div_iff (abs_pos.mpr bq0.ne') (pow_pos qR0 _), + rw [div_sub_div _ _ b0 qR0.ne', abs_div, div_lt_div_iff₀ (abs_pos.mpr bq0.ne') (pow_pos qR0 _), abs_of_pos bq0, one_mul] at a1 exact mod_cast a1 -- At a0, clear denominators... diff --git a/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleNumber.lean b/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleNumber.lean index 72b1c28fd82b7b..2b9b52c60e4966 100644 --- a/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleNumber.lean +++ b/Mathlib/NumberTheory/Transcendental/Liouville/LiouvilleNumber.lean @@ -136,7 +136,7 @@ theorem aux_calc (n : ℕ) {m : ℝ} (hm : 2 ≤ m) : -- [NB: in this block, I do not follow the brace convention for subgoals -- I wait until -- I solve all extraneous goals at once with `exact pow_pos (zero_lt_two.trans_le hm) _`.] -- Clear denominators and massage* - apply (div_le_div_iff _ _).mpr + apply (div_le_div_iff₀ _ _).mpr focus conv_rhs => rw [one_mul, mul_add, pow_add, mul_one, pow_mul, mul_comm, ← pow_mul] -- the second factors coincide, so we prove the inequality of the first factors* diff --git a/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean b/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean index ca97dfa42b9e9d..8421fa4e65ef56 100644 --- a/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean +++ b/Mathlib/NumberTheory/Transcendental/Liouville/Measure.lean @@ -58,8 +58,8 @@ theorem setOf_liouvilleWith_subset_aux : _ ≤ (b : ℝ) ^ (2 + 1 / (n + 1 : ℕ) : ℝ) := rpow_le_rpow_of_exponent_le hb (one_le_two.trans ?_) simpa using n.cast_add_one_pos.le - rw [sub_div' _ _ _ hb0.ne', abs_div, abs_of_pos hb0, div_lt_div_right hb0, abs_sub_lt_iff, - sub_lt_iff_lt_add, sub_lt_iff_lt_add, ← sub_lt_iff_lt_add'] at hlt + rw [sub_div' _ _ _ hb0.ne', abs_div, abs_of_pos hb0, div_lt_div_iff_of_pos_right hb0, + abs_sub_lt_iff, sub_lt_iff_lt_add, sub_lt_iff_lt_add, ← sub_lt_iff_lt_add'] at hlt rw [Finset.mem_Icc, ← Int.lt_add_one_iff, ← Int.lt_add_one_iff, ← neg_lt_iff_pos_add, add_comm, ← @Int.cast_lt ℝ, ← @Int.cast_lt ℝ] push_cast diff --git a/Mathlib/Order/Antisymmetrization.lean b/Mathlib/Order/Antisymmetrization.lean index d098ac0bfffb11..75caf3593c355e 100644 --- a/Mathlib/Order/Antisymmetrization.lean +++ b/Mathlib/Order/Antisymmetrization.lean @@ -88,7 +88,7 @@ def toAntisymmetrization : α → Antisymmetrization α r := /-- Get a representative from the antisymmetrization. -/ noncomputable def ofAntisymmetrization : Antisymmetrization α r → α := - Quotient.out' + Quotient.out instance [Inhabited α] : Inhabited (Antisymmetrization α r) := by unfold Antisymmetrization; infer_instance diff --git a/Mathlib/Order/BooleanAlgebra.lean b/Mathlib/Order/BooleanAlgebra.lean index a2918657eefb8b..cbe13b58400f7a 100644 --- a/Mathlib/Order/BooleanAlgebra.lean +++ b/Mathlib/Order/BooleanAlgebra.lean @@ -681,7 +681,7 @@ theorem codisjoint_himp_self_right : Codisjoint x (x ⇨ y) := @disjoint_sdiff_self_right αᵒᵈ _ _ _ theorem himp_le : x ⇨ y ≤ z ↔ y ≤ z ∧ Codisjoint x z := - (@le_sdiff αᵒᵈ _ _ _ _).trans <| and_congr_right' <| @Codisjoint_comm _ (_) _ _ _ + (@le_sdiff αᵒᵈ _ _ _ _).trans <| and_congr_right' <| @codisjoint_comm _ (_) _ _ _ @[simp] lemma himp_le_iff : x ⇨ y ≤ x ↔ x = ⊤ := ⟨fun h ↦ codisjoint_self.1 <| codisjoint_himp_self_right.mono_right h, fun h ↦ le_top.trans h.ge⟩ diff --git a/Mathlib/Order/Closure.lean b/Mathlib/Order/Closure.lean index b9c15b5db30cc4..8fb5b69f0275c3 100644 --- a/Mathlib/Order/Closure.lean +++ b/Mathlib/Order/Closure.lean @@ -387,7 +387,7 @@ variable [PartialOrder α] [PartialOrder β] {u : β → α} (l : LowerAdjoint u theorem mem_closed_iff_closure_le (x : α) : x ∈ l.closed ↔ u (l x) ≤ x := l.closureOperator.isClosed_iff_closure_le -@[simp, nolint simpNF] -- Porting note: lemma does prove itself, seems to be a linter error +@[simp] theorem closure_is_closed (x : α) : u (l x) ∈ l.closed := l.idempotent x diff --git a/Mathlib/Order/CompactlyGenerated/Basic.lean b/Mathlib/Order/CompactlyGenerated/Basic.lean index f3bc338a1d2ea6..e802e01e3fb3e2 100644 --- a/Mathlib/Order/CompactlyGenerated/Basic.lean +++ b/Mathlib/Order/CompactlyGenerated/Basic.lean @@ -273,13 +273,14 @@ alias ⟨_, IsSupClosedCompact.isSupFiniteCompact⟩ := isSupFiniteCompact_iff_i alias ⟨_, WellFoundedGT.isSupClosedCompact⟩ := isSupClosedCompact_iff_wellFoundedGT -variable {α} +end CompleteLattice + -theorem WellFoundedGT.finite_of_setIndependent [WellFoundedGT α] {s : Set α} - (hs : SetIndependent s) : s.Finite := by +theorem WellFoundedGT.finite_of_sSupIndep [WellFoundedGT α] {s : Set α} + (hs : sSupIndep s) : s.Finite := by classical refine Set.not_infinite.mp fun contra => ?_ - obtain ⟨t, ht₁, ht₂⟩ := WellFoundedGT.isSupFiniteCompact α s + obtain ⟨t, ht₁, ht₂⟩ := CompleteLattice.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 @@ -290,41 +291,59 @@ theorem WellFoundedGT.finite_of_setIndependent [WellFoundedGT α] {s : Set α} simpa [Disjoint, hx₂, ← t.sup_id_eq_sSup, ← ht₂] using this.eq_bot apply hx₁ rw [← hs, eq_comm, inf_eq_left] - exact le_sSup _ _ hx₀ + exact le_sSup hx₀ -theorem WellFoundedGT.finite_ne_bot_of_independent [WellFoundedGT α] - {ι : Type*} {t : ι → α} (ht : Independent t) : Set.Finite {i | t i ≠ ⊥} := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedGT.finite_of_setIndependent := WellFoundedGT.finite_of_sSupIndep + +theorem WellFoundedGT.finite_ne_bot_of_iSupIndep [WellFoundedGT α] + {ι : Type*} {t : ι → α} (ht : iSupIndep t) : Set.Finite {i | t i ≠ ⊥} := by refine Finite.of_finite_image (Finite.subset ?_ (image_subset_range t _)) ht.injOn - exact WellFoundedGT.finite_of_setIndependent ht.setIndependent_range + exact WellFoundedGT.finite_of_sSupIndep ht.sSupIndep_range + +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent := + WellFoundedGT.finite_ne_bot_of_iSupIndep -theorem WellFoundedGT.finite_of_independent [WellFoundedGT α] {ι : Type*} - {t : ι → α} (ht : Independent t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Finite ι := - haveI := (WellFoundedGT.finite_of_setIndependent ht.setIndependent_range).to_subtype +theorem WellFoundedGT.finite_of_iSupIndep [WellFoundedGT α] {ι : Type*} + {t : ι → α} (ht : iSupIndep t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Finite ι := + haveI := (WellFoundedGT.finite_of_sSupIndep ht.sSupIndep_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 +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedGT.finite_of_independent := WellFoundedGT.finite_of_iSupIndep + +theorem WellFoundedLT.finite_of_sSupIndep [WellFoundedLT α] {s : Set α} + (hs : sSupIndep 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) + ((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 +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedLT.finite_of_setIndependent := WellFoundedLT.finite_of_sSupIndep + +theorem WellFoundedLT.finite_ne_bot_of_iSupIndep [WellFoundedLT α] + {ι : Type*} {t : ι → α} (ht : iSupIndep 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 + exact WellFoundedLT.finite_of_sSupIndep ht.sSupIndep_range + +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedLT.finite_ne_bot_of_independent := + WellFoundedLT.finite_ne_bot_of_iSupIndep -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 +theorem WellFoundedLT.finite_of_iSupIndep [WellFoundedLT α] {ι : Type*} + {t : ι → α} (ht : iSupIndep t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Finite ι := + haveI := (WellFoundedLT.finite_of_sSupIndep ht.sSupIndep_range).to_subtype Finite.of_injective_finite_range (ht.injective h_ne_bot) -end CompleteLattice +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.WellFoundedLT.finite_of_independent := WellFoundedLT.finite_of_iSupIndep /-- A complete lattice is said to be compactly generated if any element is the `sSup` of compact elements. -/ @@ -413,9 +432,9 @@ theorem inf_sSup_eq_iSup_inf_sup_finset : (iSup_le fun t => iSup_le fun h => inf_le_inf_left _ ((Finset.sup_id_eq_sSup t).symm ▸ sSup_le_sSup h)) -theorem CompleteLattice.setIndependent_iff_finite {s : Set α} : - CompleteLattice.SetIndependent s ↔ - ∀ t : Finset α, ↑t ⊆ s → CompleteLattice.SetIndependent (↑t : Set α) := +theorem sSupIndep_iff_finite {s : Set α} : + sSupIndep s ↔ + ∀ t : Finset α, ↑t ⊆ s → sSupIndep (↑t : Set α) := ⟨fun hs _ ht => hs.mono ht, fun h a ha => by rw [disjoint_iff, inf_sSup_eq_iSup_inf_sup_finset, iSup_eq_bot] intro t @@ -428,10 +447,13 @@ theorem CompleteLattice.setIndependent_iff_finite {s : Set α} : · rw [Finset.coe_insert, Set.insert_subset_iff] exact ⟨ha, Set.Subset.trans ht diff_subset⟩⟩ -lemma CompleteLattice.independent_iff_supIndep_of_injOn {ι : Type*} {f : ι → α} +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.setIndependent_iff_finite := sSupIndep_iff_finite + +lemma iSupIndep_iff_supIndep_of_injOn {ι : Type*} {f : ι → α} (hf : InjOn f {i | f i ≠ ⊥}) : - CompleteLattice.Independent f ↔ ∀ (s : Finset ι), s.SupIndep f := by - refine ⟨fun h ↦ h.supIndep', fun h ↦ CompleteLattice.independent_def'.mpr fun i ↦ ?_⟩ + iSupIndep f ↔ ∀ (s : Finset ι), s.SupIndep f := by + refine ⟨fun h ↦ h.supIndep', fun h ↦ iSupIndep_def'.mpr fun i ↦ ?_⟩ simp_rw [disjoint_iff, inf_sSup_eq_iSup_inf_sup_finset, iSup_eq_bot, ← disjoint_iff] intro s hs classical @@ -451,11 +473,14 @@ lemma CompleteLattice.independent_iff_supIndep_of_injOn {ι : Type*} {f : ι → rw [Finset.supIndep_iff_disjoint_erase] at h exact h i (Finset.mem_insert_self i _) -theorem CompleteLattice.setIndependent_iUnion_of_directed {η : Type*} {s : η → Set α} - (hs : Directed (· ⊆ ·) s) (h : ∀ i, CompleteLattice.SetIndependent (s i)) : - CompleteLattice.SetIndependent (⋃ i, s i) := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_iff_supIndep_of_injOn := iSupIndep_iff_supIndep_of_injOn + +theorem sSupIndep_iUnion_of_directed {η : Type*} {s : η → Set α} + (hs : Directed (· ⊆ ·) s) (h : ∀ i, sSupIndep (s i)) : + sSupIndep (⋃ i, s i) := by by_cases hη : Nonempty η - · rw [CompleteLattice.setIndependent_iff_finite] + · rw [sSupIndep_iff_finite] intro t ht obtain ⟨I, fi, hI⟩ := Set.finite_subset_iUnion t.finite_toSet ht obtain ⟨i, hi⟩ := hs.finset_le fi.toFinset @@ -465,10 +490,16 @@ theorem CompleteLattice.setIndependent_iUnion_of_directed {η : Type*} {s : η exfalso exact hη ⟨i⟩ -theorem CompleteLattice.independent_sUnion_of_directed {s : Set (Set α)} (hs : DirectedOn (· ⊆ ·) s) - (h : ∀ a ∈ s, CompleteLattice.SetIndependent a) : CompleteLattice.SetIndependent (⋃₀ s) := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.setIndependent_iUnion_of_directed := sSupIndep_iUnion_of_directed + +theorem iSupIndep_sUnion_of_directed {s : Set (Set α)} (hs : DirectedOn (· ⊆ ·) s) + (h : ∀ a ∈ s, sSupIndep a) : sSupIndep (⋃₀ s) := by rw [Set.sUnion_eq_iUnion] - exact CompleteLattice.setIndependent_iUnion_of_directed hs.directed_val (by simpa using h) + exact sSupIndep_iUnion_of_directed hs.directed_val (by simpa using h) + +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_sUnion_of_directed := iSupIndep_sUnion_of_directed end @@ -495,11 +526,11 @@ 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 +alias WellFounded.finite_of_setIndependent := WellFoundedGT.finite_of_sSupIndep @[deprecated (since := "2024-10-07")] -alias WellFounded.finite_ne_bot_of_independent := WellFoundedGT.finite_ne_bot_of_independent +alias WellFounded.finite_ne_bot_of_independent := WellFoundedGT.finite_ne_bot_of_iSupIndep @[deprecated (since := "2024-10-07")] -alias WellFounded.finite_of_independent := WellFoundedGT.finite_of_independent +alias WellFounded.finite_of_independent := WellFoundedGT.finite_of_iSupIndep @[deprecated (since := "2024-10-07")] alias isCompactlyGenerated_of_wellFounded := isCompactlyGenerated_of_wellFoundedGT @@ -578,16 +609,16 @@ Most explicitly, every element is the complement of a supremum of indepedendent /-- In an atomic lattice, every element `b` has a complement of the form `sSup s`, where each element of `s` is an atom. See also `complementedLattice_of_sSup_atoms_eq_top`. -/ -theorem exists_setIndependent_isCompl_sSup_atoms (h : sSup { a : α | IsAtom a } = ⊤) (b : α) : - ∃ s : Set α, CompleteLattice.SetIndependent s ∧ +theorem exists_sSupIndep_isCompl_sSup_atoms (h : sSup { a : α | IsAtom a } = ⊤) (b : α) : + ∃ s : Set α, sSupIndep s ∧ IsCompl b (sSup s) ∧ ∀ ⦃a⦄, a ∈ s → IsAtom a := by -- porting note(https://github.com/leanprover-community/mathlib4/issues/5732): -- `obtain` chokes on the placeholder. have zorn := zorn_subset - (S := {s : Set α | CompleteLattice.SetIndependent s ∧ Disjoint b (sSup s) ∧ ∀ a ∈ s, IsAtom a}) + (S := {s : Set α | sSupIndep s ∧ Disjoint b (sSup s) ∧ ∀ a ∈ s, IsAtom a}) fun c hc1 hc2 => ⟨⋃₀ c, - ⟨CompleteLattice.independent_sUnion_of_directed hc2.directedOn fun s hs => (hc1 hs).1, ?_, + ⟨iSupIndep_sUnion_of_directed hc2.directedOn fun s hs => (hc1 hs).1, ?_, fun a ⟨s, sc, as⟩ => (hc1 sc).2.2 a as⟩, fun _ => Set.subset_sUnion_of_mem⟩ swap @@ -633,16 +664,22 @@ theorem exists_setIndependent_isCompl_sSup_atoms (h : sSup { a : α | IsAtom a } · exact s_atoms x hx · exact ha -theorem exists_setIndependent_of_sSup_atoms_eq_top (h : sSup { a : α | IsAtom a } = ⊤) : - ∃ s : Set α, CompleteLattice.SetIndependent s ∧ sSup s = ⊤ ∧ ∀ ⦃a⦄, a ∈ s → IsAtom a := - let ⟨s, s_ind, s_top, s_atoms⟩ := exists_setIndependent_isCompl_sSup_atoms h ⊥ +@[deprecated (since := "2024-11-24")] +alias exists_setIndependent_isCompl_sSup_atoms := exists_sSupIndep_isCompl_sSup_atoms + +theorem exists_sSupIndep_of_sSup_atoms_eq_top (h : sSup { a : α | IsAtom a } = ⊤) : + ∃ s : Set α, sSupIndep s ∧ sSup s = ⊤ ∧ ∀ ⦃a⦄, a ∈ s → IsAtom a := + let ⟨s, s_ind, s_top, s_atoms⟩ := exists_sSupIndep_isCompl_sSup_atoms h ⊥ ⟨s, s_ind, eq_top_of_isCompl_bot s_top.symm, s_atoms⟩ +@[deprecated (since := "2024-11-24")] +alias exists_setIndependent_of_sSup_atoms_eq_top := exists_sSupIndep_of_sSup_atoms_eq_top + /-- See [Theorem 6.6][calugareanu]. -/ theorem complementedLattice_of_sSup_atoms_eq_top (h : sSup { a : α | IsAtom a } = ⊤) : ComplementedLattice α := ⟨fun b => - let ⟨s, _, s_top, _⟩ := exists_setIndependent_isCompl_sSup_atoms h b + let ⟨s, _, s_top, _⟩ := exists_sSupIndep_isCompl_sSup_atoms h b ⟨sSup s, s_top⟩⟩ /-- See [Theorem 6.6][calugareanu]. -/ diff --git a/Mathlib/Order/Compare.lean b/Mathlib/Order/Compare.lean index 9fd8b1100315ff..5e29b6e29a0690 100644 --- a/Mathlib/Order/Compare.lean +++ b/Mathlib/Order/Compare.lean @@ -137,8 +137,7 @@ theorem cmp_swap [Preorder α] [@DecidableRel α (· < ·)] (a b : α) : (cmp a by_cases h : a < b <;> by_cases h₂ : b < a <;> simp [h, h₂, Ordering.swap] exact lt_asymm h h₂ --- Porting note: Not sure why the simpNF linter doesn't like this. @semorrison -@[simp, nolint simpNF] +@[simp] theorem cmpLE_toDual [LE α] [@DecidableRel α (· ≤ ·)] (x y : α) : cmpLE (toDual x) (toDual y) = cmpLE y x := rfl @@ -148,8 +147,7 @@ theorem cmpLE_ofDual [LE α] [@DecidableRel α (· ≤ ·)] (x y : αᵒᵈ) : cmpLE (ofDual x) (ofDual y) = cmpLE y x := rfl --- Porting note: Not sure why the simpNF linter doesn't like this. @semorrison -@[simp, nolint simpNF] +@[simp] theorem cmp_toDual [LT α] [@DecidableRel α (· < ·)] (x y : α) : cmp (toDual x) (toDual y) = cmp y x := rfl diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index bf1aa9e9ffaec1..437a1e3d52e13f 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -3,11 +3,8 @@ Copyright (c) 2018 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Order.Bounds.Basic -import Mathlib.Order.WellFounded -import Mathlib.Data.Set.Image -import Mathlib.Order.Interval.Set.Basic import Mathlib.Data.Set.Lattice +import Mathlib.Order.ConditionallyCompleteLattice.Defs /-! # Theory of conditionally complete lattices @@ -119,50 +116,6 @@ theorem WithBot.coe_sInf' [InfSet α] {s : Set α} (hs : BddBelow s) : end -/-- A conditionally complete lattice is a lattice in which -every nonempty subset which is bounded above has a supremum, and -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 `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 - /-- `a ≤ sSup s` for all `a ∈ s`. -/ - le_csSup : ∀ s a, BddAbove s → a ∈ s → a ≤ sSup s - /-- `sSup s ≤ a` for all `a ∈ upperBounds s`. -/ - csSup_le : ∀ s a, Set.Nonempty s → a ∈ upperBounds s → sSup s ≤ a - /-- `sInf s ≤ a` for all `a ∈ s`. -/ - csInf_le : ∀ s a, BddBelow s → a ∈ s → sInf s ≤ a - /-- `a ≤ sInf s` for all `a ∈ lowerBounds s`. -/ - le_csInf : ∀ s a, Set.Nonempty s → a ∈ lowerBounds s → a ≤ sInf s - --- Porting note: mathlib3 used `renaming` -/-- A conditionally complete linear order is a linear order in which -every nonempty subset which is bounded above has a supremum, and -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 -hold in both worlds, sometimes with additional assumptions of nonemptiness or -boundedness. -/ -class ConditionallyCompleteLinearOrder (α : Type*) extends ConditionallyCompleteLattice α where - /-- A `ConditionallyCompleteLinearOrder` is total. -/ - le_total (a b : α) : a ≤ b ∨ b ≤ a - /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ - decidableLE : DecidableRel (· ≤ · : α → α → Prop) - /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ - decidableEq : DecidableEq α := @decidableEqOfDecidableLE _ _ decidableLE - /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ - decidableLT : DecidableRel (· < · : α → α → Prop) := - @decidableLTOfDecidableLE _ _ decidableLE - /-- If a set is not bounded above, its supremum is by convention `sSup ∅`. -/ - csSup_of_not_bddAbove : ∀ s, ¬BddAbove s → sSup s = sSup (∅ : Set α) - /-- If a set is not bounded below, its infimum is by convention `sInf ∅`. -/ - csInf_of_not_bddBelow : ∀ s, ¬BddBelow s → sInf s = sInf (∅ : Set α) - instance ConditionallyCompleteLinearOrder.toLinearOrder [ConditionallyCompleteLinearOrder α] : LinearOrder α := { ‹ConditionallyCompleteLinearOrder α› with @@ -179,19 +132,6 @@ instance ConditionallyCompleteLinearOrder.toLinearOrder [ConditionallyCompleteLi · simp [h₁] · simp [show ¬(a ≤ b) from fun h => hab (le_antisymm h h₂), h₂] } -/-- A conditionally complete linear order with `Bot` is a linear order with least element, in which -every nonempty subset which is bounded above has a supremum, and every nonempty subset (necessarily -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 -hold in both worlds, sometimes with additional assumptions of nonemptiness or -boundedness. -/ -class ConditionallyCompleteLinearOrderBot (α : Type*) extends ConditionallyCompleteLinearOrder α, - OrderBot α where - /-- The supremum of the empty set is special-cased to `⊥` -/ - csSup_empty : sSup ∅ = ⊥ - -- see Note [lower instance priority] attribute [instance 100] ConditionallyCompleteLinearOrderBot.toOrderBot @@ -214,36 +154,6 @@ instance (priority := 100) CompleteLinearOrder.toConditionallyCompleteLinearOrde csSup_of_not_bddAbove := fun s H ↦ (H (OrderTop.bddAbove s)).elim csInf_of_not_bddBelow := fun s H ↦ (H (OrderBot.bddBelow s)).elim } -open scoped Classical in -/-- A well founded linear order is conditionally complete, with a bottom element. -/ -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 ⊥ - csInf_le := fun s a _ has => by - have s_ne : s.Nonempty := ⟨a, has⟩ - simpa [s_ne] using not_lt.1 (h.wf.not_lt_min s s_ne has) - le_csInf := fun s a hs has => by - simp only [hs, dif_pos] - exact has (h.wf.min_mem s hs) - sSup := fun s => if hs : (upperBounds s).Nonempty then h.wf.min _ hs else ⊥ - le_csSup := fun s a hs has => by - have h's : (upperBounds s).Nonempty := hs - simp only [h's, dif_pos] - exact h.wf.min_mem _ h's has - csSup_le := fun s a _ has => by - have h's : (upperBounds s).Nonempty := ⟨a, has⟩ - simp only [h's, dif_pos] - simpa using h.wf.not_lt_min _ h's has - csSup_empty := by simpa using eq_bot_iff.2 (not_lt.1 <| h.wf.not_lt_min _ _ <| mem_univ ⊥) - csSup_of_not_bddAbove := by - intro s H - have B : ¬((upperBounds s).Nonempty) := H - simp only [B, dite_false, upperBounds_empty, univ_nonempty, dite_true] - exact le_antisymm bot_le (WellFounded.min_le _ (mem_univ _)) - csInf_of_not_bddBelow := fun s H ↦ (H (OrderBot.bddBelow s)).elim } - namespace OrderDual instance instConditionallyCompleteLattice (α : Type*) [ConditionallyCompleteLattice α] : @@ -261,132 +171,6 @@ instance (α : Type*) [ConditionallyCompleteLinearOrder α] : ConditionallyCompl end OrderDual -/-- Create a `ConditionallyCompleteLattice` from a `PartialOrder` and `sup` function -that returns the least upper bound of a nonempty set which is bounded above. Usually this -constructor provides poor definitional equalities. If other fields are known explicitly, they -should be provided; for example, if `inf` is known explicitly, construct the -`ConditionallyCompleteLattice` instance as -``` -instance : ConditionallyCompleteLattice my_T := - { inf := better_inf, - le_inf := ..., - inf_le_right := ..., - inf_le_left := ... - -- don't care to fix sup, sInf - ..conditionallyCompleteLatticeOfsSup my_T _ } -``` --/ -def conditionallyCompleteLatticeOfsSup (α : Type*) [H1 : PartialOrder α] [H2 : SupSet α] - (bddAbove_pair : ∀ a b : α, BddAbove ({a, b} : Set α)) - (bddBelow_pair : ∀ a b : α, BddBelow ({a, b} : Set α)) - (isLUB_sSup : ∀ s : Set α, BddAbove s → s.Nonempty → IsLUB s (sSup s)) : - ConditionallyCompleteLattice α := - { H1, H2 with - sup := fun a b => sSup {a, b} - le_sup_left := fun a b => - (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).1 (mem_insert _ _) - le_sup_right := fun a b => - (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).1 - (mem_insert_of_mem _ (mem_singleton _)) - sup_le := fun a b _ hac hbc => - (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).2 - (forall_insert_of_forall (forall_eq.mpr hbc) hac) - inf := fun a b => sSup (lowerBounds {a, b}) - inf_le_left := fun a b => - (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) - (bddBelow_pair a b)).2 - fun _ hc => hc <| mem_insert _ _ - inf_le_right := fun a b => - (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) - (bddBelow_pair a b)).2 - fun _ hc => hc <| mem_insert_of_mem _ (mem_singleton _) - le_inf := fun c a b hca hcb => - (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) - ⟨c, forall_insert_of_forall (forall_eq.mpr hcb) hca⟩).1 - (forall_insert_of_forall (forall_eq.mpr hcb) hca) - sInf := fun s => sSup (lowerBounds s) - csSup_le := fun s a hs ha => (isLUB_sSup s ⟨a, ha⟩ hs).2 ha - le_csSup := fun s a hs ha => (isLUB_sSup s hs ⟨a, ha⟩).1 ha - csInf_le := fun s a hs ha => - (isLUB_sSup (lowerBounds s) (Nonempty.bddAbove_lowerBounds ⟨a, ha⟩) hs).2 fun _ hb => hb ha - le_csInf := fun s a hs ha => - (isLUB_sSup (lowerBounds s) hs.bddAbove_lowerBounds ⟨a, ha⟩).1 ha } - -/-- Create a `ConditionallyCompleteLattice` from a `PartialOrder` and `inf` function -that returns the greatest lower bound of a nonempty set which is bounded below. Usually this -constructor provides poor definitional equalities. If other fields are known explicitly, they -should be provided; for example, if `inf` is known explicitly, construct the -`ConditionallyCompleteLattice` instance as -``` -instance : ConditionallyCompleteLattice my_T := - { inf := better_inf, - le_inf := ..., - inf_le_right := ..., - inf_le_left := ... - -- don't care to fix sup, sSup - ..conditionallyCompleteLatticeOfsInf my_T _ } -``` --/ -def conditionallyCompleteLatticeOfsInf (α : Type*) [H1 : PartialOrder α] [H2 : InfSet α] - (bddAbove_pair : ∀ a b : α, BddAbove ({a, b} : Set α)) - (bddBelow_pair : ∀ a b : α, BddBelow ({a, b} : Set α)) - (isGLB_sInf : ∀ s : Set α, BddBelow s → s.Nonempty → IsGLB s (sInf s)) : - ConditionallyCompleteLattice α := - { H1, H2 with - inf := fun a b => sInf {a, b} - inf_le_left := fun a b => - (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).1 (mem_insert _ _) - inf_le_right := fun a b => - (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).1 - (mem_insert_of_mem _ (mem_singleton _)) - le_inf := fun _ a b hca hcb => - (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).2 - (forall_insert_of_forall (forall_eq.mpr hcb) hca) - sup := fun a b => sInf (upperBounds {a, b}) - le_sup_left := fun a b => - (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) - (bddAbove_pair a b)).2 - fun _ hc => hc <| mem_insert _ _ - le_sup_right := fun a b => - (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) - (bddAbove_pair a b)).2 - fun _ hc => hc <| mem_insert_of_mem _ (mem_singleton _) - sup_le := fun a b c hac hbc => - (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) - ⟨c, forall_insert_of_forall (forall_eq.mpr hbc) hac⟩).1 - (forall_insert_of_forall (forall_eq.mpr hbc) hac) - sSup := fun s => sInf (upperBounds s) - le_csInf := fun s a hs ha => (isGLB_sInf s ⟨a, ha⟩ hs).2 ha - csInf_le := fun s a hs ha => (isGLB_sInf s hs ⟨a, ha⟩).1 ha - le_csSup := fun s a hs ha => - (isGLB_sInf (upperBounds s) (Nonempty.bddBelow_upperBounds ⟨a, ha⟩) hs).2 fun _ hb => hb ha - csSup_le := fun s a hs ha => - (isGLB_sInf (upperBounds s) hs.bddBelow_upperBounds ⟨a, ha⟩).1 ha } - -/-- A version of `conditionallyCompleteLatticeOfsSup` when we already know that `α` is a lattice. - -This should only be used when it is both hard and unnecessary to provide `inf` explicitly. -/ -def conditionallyCompleteLatticeOfLatticeOfsSup (α : Type*) [H1 : Lattice α] [SupSet α] - (isLUB_sSup : ∀ s : Set α, BddAbove s → s.Nonempty → IsLUB s (sSup s)) : - ConditionallyCompleteLattice α := - { H1, - conditionallyCompleteLatticeOfsSup α - (fun a b => ⟨a ⊔ b, forall_insert_of_forall (forall_eq.mpr le_sup_right) le_sup_left⟩) - (fun a b => ⟨a ⊓ b, forall_insert_of_forall (forall_eq.mpr inf_le_right) inf_le_left⟩) - isLUB_sSup with } - -/-- A version of `conditionallyCompleteLatticeOfsInf` when we already know that `α` is a lattice. - -This should only be used when it is both hard and unnecessary to provide `sup` explicitly. -/ -def conditionallyCompleteLatticeOfLatticeOfsInf (α : Type*) [H1 : Lattice α] [InfSet α] - (isGLB_sInf : ∀ s : Set α, BddBelow s → s.Nonempty → IsGLB s (sInf s)) : - ConditionallyCompleteLattice α := - { H1, - conditionallyCompleteLatticeOfsInf α - (fun a b => ⟨a ⊔ b, forall_insert_of_forall (forall_eq.mpr le_sup_right) le_sup_left⟩) - (fun a b => ⟨a ⊓ b, forall_insert_of_forall (forall_eq.mpr inf_le_right) inf_le_left⟩) - isGLB_sInf with } - section ConditionallyCompleteLattice variable [ConditionallyCompleteLattice α] {s t : Set α} {a b : α} diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Defs.lean b/Mathlib/Order/ConditionallyCompleteLattice/Defs.lean new file mode 100644 index 00000000000000..4a499bbdfdc7ad --- /dev/null +++ b/Mathlib/Order/ConditionallyCompleteLattice/Defs.lean @@ -0,0 +1,251 @@ +/- +Copyright (c) 2018 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastien Gouëzel +-/ +import Mathlib.Order.Bounds.Basic +import Mathlib.Order.SetNotation +import Mathlib.Order.WellFounded + +/-! +# Definitions of conditionally complete lattices + +A conditionally complete lattice is a lattice in which every non-empty bounded subset `s` +has a least upper bound and a greatest lower bound, denoted below by `sSup s` and `sInf s`. +Typical examples are `ℝ`, `ℕ`, and `ℤ` with their usual orders. + +The theory is very comparable to the theory of complete lattices, except that suitable +boundedness and nonemptiness assumptions have to be added to most statements. +We express these using the `BddAbove` and `BddBelow` predicates, which we use to prove +most useful properties of `sSup` and `sInf` in conditionally complete lattices. + +To differentiate the statements between complete lattices and conditionally complete +lattices, we prefix `sInf` and `sSup` in the statements by `c`, giving `csInf` and `csSup`. +For instance, `sInf_le` is a statement in complete lattices ensuring `sInf s ≤ x`, +while `csInf_le` is the same statement in conditionally complete lattices +with an additional assumption that `s` is bounded below. +-/ + +open Set + +variable {α β γ : Type*} {ι : Sort*} + +/-- A conditionally complete lattice is a lattice in which +every nonempty subset which is bounded above has a supremum, and +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 `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 + /-- `a ≤ sSup s` for all `a ∈ s`. -/ + le_csSup : ∀ s a, BddAbove s → a ∈ s → a ≤ sSup s + /-- `sSup s ≤ a` for all `a ∈ upperBounds s`. -/ + csSup_le : ∀ s a, Set.Nonempty s → a ∈ upperBounds s → sSup s ≤ a + /-- `sInf s ≤ a` for all `a ∈ s`. -/ + csInf_le : ∀ s a, BddBelow s → a ∈ s → sInf s ≤ a + /-- `a ≤ sInf s` for all `a ∈ lowerBounds s`. -/ + le_csInf : ∀ s a, Set.Nonempty s → a ∈ lowerBounds s → a ≤ sInf s + +-- Porting note: mathlib3 used `renaming` +/-- A conditionally complete linear order is a linear order in which +every nonempty subset which is bounded above has a supremum, and +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 +hold in both worlds, sometimes with additional assumptions of nonemptiness or +boundedness. -/ +class ConditionallyCompleteLinearOrder (α : Type*) extends ConditionallyCompleteLattice α where + /-- A `ConditionallyCompleteLinearOrder` is total. -/ + le_total (a b : α) : a ≤ b ∨ b ≤ a + /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ + decidableLE : DecidableRel (· ≤ · : α → α → Prop) + /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ + decidableEq : DecidableEq α := @decidableEqOfDecidableLE _ _ decidableLE + /-- In a `ConditionallyCompleteLinearOrder`, we assume the order relations are all decidable. -/ + decidableLT : DecidableRel (· < · : α → α → Prop) := + @decidableLTOfDecidableLE _ _ decidableLE + /-- If a set is not bounded above, its supremum is by convention `sSup ∅`. -/ + csSup_of_not_bddAbove : ∀ s, ¬BddAbove s → sSup s = sSup (∅ : Set α) + /-- If a set is not bounded below, its infimum is by convention `sInf ∅`. -/ + csInf_of_not_bddBelow : ∀ s, ¬BddBelow s → sInf s = sInf (∅ : Set α) + +/-- A conditionally complete linear order with `Bot` is a linear order with least element, in which +every nonempty subset which is bounded above has a supremum, and every nonempty subset (necessarily +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 +hold in both worlds, sometimes with additional assumptions of nonemptiness or +boundedness. -/ +class ConditionallyCompleteLinearOrderBot (α : Type*) extends ConditionallyCompleteLinearOrder α, + OrderBot α where + /-- The supremum of the empty set is special-cased to `⊥` -/ + csSup_empty : sSup ∅ = ⊥ + +-- see Note [lower instance priority] +attribute [instance 100] ConditionallyCompleteLinearOrderBot.toOrderBot + +open scoped Classical in +/-- A well founded linear order is conditionally complete, with a bottom element. -/ +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 ⊥ + csInf_le := fun s a _ has => by + have s_ne : s.Nonempty := ⟨a, has⟩ + simpa [s_ne] using not_lt.1 (h.wf.not_lt_min s s_ne has) + le_csInf := fun s a hs has => by + simp only [hs, dif_pos] + exact has (h.wf.min_mem s hs) + sSup := fun s => if hs : (upperBounds s).Nonempty then h.wf.min _ hs else ⊥ + le_csSup := fun s a hs has => by + have h's : (upperBounds s).Nonempty := hs + simp only [h's, dif_pos] + exact h.wf.min_mem _ h's has + csSup_le := fun s a _ has => by + have h's : (upperBounds s).Nonempty := ⟨a, has⟩ + simp only [h's, dif_pos] + simpa using h.wf.not_lt_min _ h's has + csSup_empty := by simpa using eq_bot_iff.2 (not_lt.1 <| h.wf.not_lt_min _ _ <| mem_univ ⊥) + csSup_of_not_bddAbove := by + intro s H + have B : ¬((upperBounds s).Nonempty) := H + simp only [B, dite_false, upperBounds_empty, univ_nonempty, dite_true] + exact le_antisymm bot_le (WellFounded.min_le _ (mem_univ _)) + csInf_of_not_bddBelow := fun s H ↦ (H (OrderBot.bddBelow s)).elim } + +namespace OrderDual + +end OrderDual + +/-- Create a `ConditionallyCompleteLattice` from a `PartialOrder` and `sup` function +that returns the least upper bound of a nonempty set which is bounded above. Usually this +constructor provides poor definitional equalities. If other fields are known explicitly, they +should be provided; for example, if `inf` is known explicitly, construct the +`ConditionallyCompleteLattice` instance as +``` +instance : ConditionallyCompleteLattice my_T := + { inf := better_inf, + le_inf := ..., + inf_le_right := ..., + inf_le_left := ... + -- don't care to fix sup, sInf + ..conditionallyCompleteLatticeOfsSup my_T _ } +``` +-/ +def conditionallyCompleteLatticeOfsSup (α : Type*) [H1 : PartialOrder α] [H2 : SupSet α] + (bddAbove_pair : ∀ a b : α, BddAbove ({a, b} : Set α)) + (bddBelow_pair : ∀ a b : α, BddBelow ({a, b} : Set α)) + (isLUB_sSup : ∀ s : Set α, BddAbove s → s.Nonempty → IsLUB s (sSup s)) : + ConditionallyCompleteLattice α := + { H1, H2 with + sup := fun a b => sSup {a, b} + le_sup_left := fun a b => + (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).1 (mem_insert _ _) + le_sup_right := fun a b => + (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).1 + (mem_insert_of_mem _ (mem_singleton _)) + sup_le := fun a b _ hac hbc => + (isLUB_sSup {a, b} (bddAbove_pair a b) (insert_nonempty _ _)).2 + (forall_insert_of_forall (forall_eq.mpr hbc) hac) + inf := fun a b => sSup (lowerBounds {a, b}) + inf_le_left := fun a b => + (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) + (bddBelow_pair a b)).2 + fun _ hc => hc <| mem_insert _ _ + inf_le_right := fun a b => + (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) + (bddBelow_pair a b)).2 + fun _ hc => hc <| mem_insert_of_mem _ (mem_singleton _) + le_inf := fun c a b hca hcb => + (isLUB_sSup (lowerBounds {a, b}) (Nonempty.bddAbove_lowerBounds ⟨a, mem_insert _ _⟩) + ⟨c, forall_insert_of_forall (forall_eq.mpr hcb) hca⟩).1 + (forall_insert_of_forall (forall_eq.mpr hcb) hca) + sInf := fun s => sSup (lowerBounds s) + csSup_le := fun s a hs ha => (isLUB_sSup s ⟨a, ha⟩ hs).2 ha + le_csSup := fun s a hs ha => (isLUB_sSup s hs ⟨a, ha⟩).1 ha + csInf_le := fun s a hs ha => + (isLUB_sSup (lowerBounds s) (Nonempty.bddAbove_lowerBounds ⟨a, ha⟩) hs).2 fun _ hb => hb ha + le_csInf := fun s a hs ha => + (isLUB_sSup (lowerBounds s) hs.bddAbove_lowerBounds ⟨a, ha⟩).1 ha } + +/-- Create a `ConditionallyCompleteLattice` from a `PartialOrder` and `inf` function +that returns the greatest lower bound of a nonempty set which is bounded below. Usually this +constructor provides poor definitional equalities. If other fields are known explicitly, they +should be provided; for example, if `inf` is known explicitly, construct the +`ConditionallyCompleteLattice` instance as +``` +instance : ConditionallyCompleteLattice my_T := + { inf := better_inf, + le_inf := ..., + inf_le_right := ..., + inf_le_left := ... + -- don't care to fix sup, sSup + ..conditionallyCompleteLatticeOfsInf my_T _ } +``` +-/ +def conditionallyCompleteLatticeOfsInf (α : Type*) [H1 : PartialOrder α] [H2 : InfSet α] + (bddAbove_pair : ∀ a b : α, BddAbove ({a, b} : Set α)) + (bddBelow_pair : ∀ a b : α, BddBelow ({a, b} : Set α)) + (isGLB_sInf : ∀ s : Set α, BddBelow s → s.Nonempty → IsGLB s (sInf s)) : + ConditionallyCompleteLattice α := + { H1, H2 with + inf := fun a b => sInf {a, b} + inf_le_left := fun a b => + (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).1 (mem_insert _ _) + inf_le_right := fun a b => + (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).1 + (mem_insert_of_mem _ (mem_singleton _)) + le_inf := fun _ a b hca hcb => + (isGLB_sInf {a, b} (bddBelow_pair a b) (insert_nonempty _ _)).2 + (forall_insert_of_forall (forall_eq.mpr hcb) hca) + sup := fun a b => sInf (upperBounds {a, b}) + le_sup_left := fun a b => + (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) + (bddAbove_pair a b)).2 + fun _ hc => hc <| mem_insert _ _ + le_sup_right := fun a b => + (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) + (bddAbove_pair a b)).2 + fun _ hc => hc <| mem_insert_of_mem _ (mem_singleton _) + sup_le := fun a b c hac hbc => + (isGLB_sInf (upperBounds {a, b}) (Nonempty.bddBelow_upperBounds ⟨a, mem_insert _ _⟩) + ⟨c, forall_insert_of_forall (forall_eq.mpr hbc) hac⟩).1 + (forall_insert_of_forall (forall_eq.mpr hbc) hac) + sSup := fun s => sInf (upperBounds s) + le_csInf := fun s a hs ha => (isGLB_sInf s ⟨a, ha⟩ hs).2 ha + csInf_le := fun s a hs ha => (isGLB_sInf s hs ⟨a, ha⟩).1 ha + le_csSup := fun s a hs ha => + (isGLB_sInf (upperBounds s) (Nonempty.bddBelow_upperBounds ⟨a, ha⟩) hs).2 fun _ hb => hb ha + csSup_le := fun s a hs ha => + (isGLB_sInf (upperBounds s) hs.bddBelow_upperBounds ⟨a, ha⟩).1 ha } + +/-- A version of `conditionallyCompleteLatticeOfsSup` when we already know that `α` is a lattice. + +This should only be used when it is both hard and unnecessary to provide `inf` explicitly. -/ +def conditionallyCompleteLatticeOfLatticeOfsSup (α : Type*) [H1 : Lattice α] [SupSet α] + (isLUB_sSup : ∀ s : Set α, BddAbove s → s.Nonempty → IsLUB s (sSup s)) : + ConditionallyCompleteLattice α := + { H1, + conditionallyCompleteLatticeOfsSup α + (fun a b => ⟨a ⊔ b, forall_insert_of_forall (forall_eq.mpr le_sup_right) le_sup_left⟩) + (fun a b => ⟨a ⊓ b, forall_insert_of_forall (forall_eq.mpr inf_le_right) inf_le_left⟩) + isLUB_sSup with } + +/-- A version of `conditionallyCompleteLatticeOfsInf` when we already know that `α` is a lattice. + +This should only be used when it is both hard and unnecessary to provide `sup` explicitly. -/ +def conditionallyCompleteLatticeOfLatticeOfsInf (α : Type*) [H1 : Lattice α] [InfSet α] + (isGLB_sInf : ∀ s : Set α, BddBelow s → s.Nonempty → IsGLB s (sInf s)) : + ConditionallyCompleteLattice α := + { H1, + conditionallyCompleteLatticeOfsInf α + (fun a b => ⟨a ⊔ b, forall_insert_of_forall (forall_eq.mpr le_sup_right) le_sup_left⟩) + (fun a b => ⟨a ⊓ b, forall_insert_of_forall (forall_eq.mpr inf_le_right) inf_le_left⟩) + isGLB_sInf with } diff --git a/Mathlib/Order/Defs.lean b/Mathlib/Order/Defs.lean index dc90cc7b0adbea..b97cdc2c979d62 100644 --- a/Mathlib/Order/Defs.lean +++ b/Mathlib/Order/Defs.lean @@ -206,11 +206,11 @@ theorem Equivalence.transitive (h : Equivalence r) : Transitive r := variable {β : Sort*} (r : β → β → Prop) (f : α → β) -@[deprecated (since := "2024-09-13")] +@[deprecated "No deprecation message was provided." (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")] +@[deprecated "No deprecation message was provided." (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₁ @@ -276,7 +276,7 @@ lemma lt_iff_le_not_le : a < b ↔ a ≤ b ∧ ¬b ≤ a := Preorder.lt_iff_le_n 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")] +@[deprecated "No deprecation message was provided." (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 @@ -502,7 +502,7 @@ namespace Nat /-! Deprecated properties of inequality on `Nat` -/ -@[deprecated (since := "2024-08-23")] +@[deprecated "No deprecation message was provided." (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) diff --git a/Mathlib/Order/Disjoint.lean b/Mathlib/Order/Disjoint.lean index b024a335e595cd..59bcd0815347da 100644 --- a/Mathlib/Order/Disjoint.lean +++ b/Mathlib/Order/Disjoint.lean @@ -205,12 +205,14 @@ arguments. -/ def Codisjoint (a b : α) : Prop := ∀ ⦃x⦄, a ≤ x → b ≤ x → ⊤ ≤ x -theorem Codisjoint_comm : Codisjoint a b ↔ Codisjoint b a := +theorem codisjoint_comm : Codisjoint a b ↔ Codisjoint b a := forall_congr' fun _ ↦ forall_swap +@[deprecated (since := "2024-11-23")] alias Codisjoint_comm := codisjoint_comm + @[symm] theorem Codisjoint.symm ⦃a b : α⦄ : Codisjoint a b → Codisjoint b a := - Codisjoint_comm.1 + codisjoint_comm.1 theorem symmetric_codisjoint : Symmetric (Codisjoint : α → α → Prop) := Codisjoint.symm diff --git a/Mathlib/Order/Filter/AtTopBot/Monoid.lean b/Mathlib/Order/Filter/AtTopBot/Monoid.lean index 0cfa275d9a4267..02cdf596f58540 100644 --- a/Mathlib/Order/Filter/AtTopBot/Monoid.lean +++ b/Mathlib/Order/Filter/AtTopBot/Monoid.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.Order.Monoid.OrderDual +import Mathlib.Algebra.Order.Monoid.Unbundled.Pow import Mathlib.Order.Filter.AtTopBot /-! diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean index ffd5fe2a6c9e40..ab8dd13872eb6c 100644 --- a/Mathlib/Order/Filter/Bases.lean +++ b/Mathlib/Order/Filter/Bases.lean @@ -5,7 +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.Basic +import Mathlib.Order.Filter.Finite /-! # Filter bases diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index ee7fd636ed4701..65c9595abbf402 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -3,7 +3,10 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jeremy Avigad -/ -import Mathlib.Data.Set.Finite.Lattice +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Group.Pi.Basic +import Mathlib.Control.Basic +import Mathlib.Data.Set.Lattice import Mathlib.Order.Filter.Defs /-! @@ -59,6 +62,7 @@ we do *not* require. This gives `Filter X` better formal properties, in particul -/ assert_not_exists OrderedSemiring +assert_not_exists Fintype open Function Set Order open scoped symmDiff @@ -103,27 +107,15 @@ theorem congr_sets (h : { x | x ∈ s ↔ x ∈ t } ∈ f) : s ∈ f ↔ t ∈ f lemma copy_eq {S} (hmem : ∀ s, s ∈ S ↔ s ∈ f) : f.copy S hmem = f := Filter.ext hmem -@[simp] -theorem biInter_mem {β : Type v} {s : β → Set α} {is : Set β} (hf : is.Finite) : - (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := - Finite.induction_on hf (by simp) fun _ _ hs => by simp [hs] - -@[simp] -theorem biInter_finset_mem {β : Type v} {s : β → Set α} (is : Finset β) : - (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := - biInter_mem is.finite_toSet - -alias _root_.Finset.iInter_mem_sets := biInter_finset_mem +/-- Weaker version of `Filter.biInter_mem` that assumes `Subsingleton β` rather than `Finite β`. -/ +theorem biInter_mem' {β : Type v} {s : β → Set α} {is : Set β} (hf : is.Subsingleton) : + (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := by + apply Subsingleton.induction_on hf <;> simp --- attribute [protected] Finset.iInter_mem_sets porting note: doesn't work - -@[simp] -theorem sInter_mem {s : Set (Set α)} (hfin : s.Finite) : ⋂₀ s ∈ f ↔ ∀ U ∈ s, U ∈ f := by - rw [sInter_eq_biInter, biInter_mem hfin] - -@[simp] -theorem iInter_mem {β : Sort v} {s : β → Set α} [Finite β] : (⋂ i, s i) ∈ f ↔ ∀ i, s i ∈ f := - (sInter_mem (finite_range _)).trans forall_mem_range +/-- Weaker version of `Filter.iInter_mem` that assumes `Subsingleton β` rather than `Finite β`. -/ +theorem iInter_mem' {β : Sort v} {s : β → Set α} [Subsingleton β] : + (⋂ i, s i) ∈ f ↔ ∀ i, s i ∈ f := by + rw [← sInter_range, sInter_eq_biInter, biInter_mem' (subsingleton_range s), forall_mem_range] theorem exists_mem_subset_iff : (∃ t ∈ f, t ⊆ s) ↔ s ∈ f := ⟨fun ⟨_, ht, ts⟩ => mem_of_superset ht ts, fun hs => ⟨s, hs, Subset.rfl⟩⟩ @@ -181,24 +173,6 @@ theorem le_generate_iff {s : Set (Set α)} {f : Filter α} : f ≤ generate s hu.recOn (fun h' => h h') univ_mem (fun _ hxy hx => mem_of_superset hx hxy) fun _ _ hx hy => inter_mem hx hy -theorem mem_generate_iff {s : Set <| Set α} {U : Set α} : - U ∈ generate s ↔ ∃ t ⊆ s, Set.Finite t ∧ ⋂₀ t ⊆ U := by - constructor <;> intro h - · induction h with - | @basic V V_in => - exact ⟨{V}, singleton_subset_iff.2 V_in, finite_singleton _, (sInter_singleton _).subset⟩ - | univ => exact ⟨∅, empty_subset _, finite_empty, subset_univ _⟩ - | superset _ hVW hV => - rcases hV with ⟨t, hts, ht, htV⟩ - exact ⟨t, hts, ht, htV.trans hVW⟩ - | inter _ _ hV hW => - rcases hV, hW with ⟨⟨t, hts, ht, htV⟩, u, hus, hu, huW⟩ - exact - ⟨t ∪ u, union_subset hts hus, ht.union hu, - (sInter_union _ _).subset.trans <| inter_subset_inter htV huW⟩ - · rcases h with ⟨t, hts, tfin, h⟩ - exact mem_of_superset ((sInter_mem tfin).2 fun V hV => GenerateSets.basic <| hts hV) h - @[simp] lemma generate_singleton (s : Set α) : generate {s} = 𝓟 s := le_antisymm (fun _t ht ↦ mem_of_superset (mem_generate_of_mem <| mem_singleton _) ht) <| le_generate_iff.2 <| singleton_subset_iff.2 Subset.rfl @@ -334,58 +308,6 @@ theorem iInf_eq_generate (s : ι → Filter α) : iInf s = generate (⋃ i, (s i theorem mem_iInf_of_mem {f : ι → Filter α} (i : ι) {s} (hs : s ∈ f i) : s ∈ ⨅ i, f i := 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 : 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 : 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 : I), V i ∈ s i := by - rintro i - have : ⋂₀ σ i ∈ s i := by - rw [sInter_mem (σfin _)] - apply σsub - exact mem_of_superset this subset_union_right - refine ⟨I, Ifin, V, V_in, ?_⟩ - rwa [hV, ← union_iInter, union_eq_self_of_subset_right] - · rintro ⟨I, Ifin, V, V_in, rfl⟩ - exact mem_iInf_of_iInter Ifin V_in Subset.rfl - -theorem mem_iInf' {ι} {s : ι → Filter α} {U : Set α} : - (U ∈ ⨅ i, s i) ↔ - ∃ I : Set ι, I.Finite ∧ ∃ V : ι → Set α, (∀ i, V i ∈ s i) ∧ - (∀ i ∉ I, V i = univ) ∧ (U = ⋂ i ∈ I, V i) ∧ U = ⋂ i, V i := by - classical - simp only [mem_iInf, SetCoe.forall', biInter_eq_iInter] - refine ⟨?_, fun ⟨I, If, V, hVs, _, hVU, _⟩ => ⟨I, If, fun i => V i, fun i => hVs i, hVU⟩⟩ - rintro ⟨I, If, V, hV, rfl⟩ - 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 ⟨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] - -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 := - let ⟨_, _, V, hVs, _, _, hVU'⟩ := mem_iInf'.1 hs; ⟨V, hVs, hVU'⟩ - -theorem mem_iInf_of_finite {ι : Type*} [Finite ι] {α : Type*} {f : ι → Filter α} (s) : - (s ∈ ⨅ i, f i) ↔ ∃ t : ι → Set α, (∀ i, t i ∈ f i) ∧ s = ⋂ i, t i := by - refine ⟨exists_iInter_of_mem_iInf, ?_⟩ - rintro ⟨t, ht, rfl⟩ - exact iInter_mem.2 fun i => mem_iInf_of_mem i (ht i) - @[simp] theorem le_principal_iff {s : Set α} {f : Filter α} : f ≤ 𝓟 s ↔ s ∈ f := ⟨fun h => h Subset.rfl, fun hs _ ht => mem_of_superset hs ht⟩ @@ -453,26 +375,6 @@ theorem NeBot.not_disjoint (hf : f.NeBot) (hs : s ∈ f) (ht : t ∈ f) : ¬Disj theorem inf_eq_bot_iff {f g : Filter α} : f ⊓ g = ⊥ ↔ ∃ U ∈ f, ∃ V ∈ g, U ∩ V = ∅ := by simp only [← disjoint_iff, Filter.disjoint_iff, Set.disjoint_iff_inter_eq_empty] -theorem _root_.Pairwise.exists_mem_filter_of_disjoint {ι : Type*} [Finite ι] {l : ι → Filter α} - (hd : Pairwise (Disjoint on l)) : - ∃ s : ι → Set α, (∀ i, s i ∈ l i) ∧ Pairwise (Disjoint on s) := by - have : Pairwise fun i j => ∃ (s : {s // s ∈ l i}) (t : {t // t ∈ l j}), Disjoint s.1 t.1 := by - simpa only [Pairwise, Function.onFun, Filter.disjoint_iff, exists_prop, Subtype.exists] using hd - choose! s t hst using this - refine ⟨fun i => ⋂ j, @s i j ∩ @t j i, fun i => ?_, fun i j hij => ?_⟩ - exacts [iInter_mem.2 fun j => inter_mem (@s i j).2 (@t j i).2, - (hst hij).mono ((iInter_subset _ j).trans inter_subset_left) - ((iInter_subset _ i).trans inter_subset_right)] - -theorem _root_.Set.PairwiseDisjoint.exists_mem_filter {ι : Type*} {l : ι → Filter α} {t : Set ι} - (hd : t.PairwiseDisjoint l) (ht : t.Finite) : - ∃ s : ι → Set α, (∀ i, s i ∈ l i) ∧ t.PairwiseDisjoint s := by - haveI := ht.to_subtype - rcases (hd.subtype _ _).exists_mem_filter_of_disjoint with ⟨s, hsl, hsd⟩ - lift s to (i : t) → {s // s ∈ l i} using hsl - rcases @Subtype.exists_pi_extension ι (fun i => { s // s ∈ l i }) _ _ s with ⟨s, rfl⟩ - exact ⟨fun i => s i, fun i => (s i).2, hsd.set_of_subtype _ _⟩ - /-- There is exactly one filter on an empty type. -/ instance unique [IsEmpty α] : Unique (Filter α) where default := ⊥ @@ -548,23 +450,6 @@ theorem biInf_sets_eq {f : β → Filter α} {s : Set β} (h : DirectedOn (f ⁻ (ne : s.Nonempty) : (⨅ i ∈ s, f i).sets = ⋃ i ∈ s, (f i).sets := ext fun t => by simp [mem_biInf_of_directed h ne] -theorem iInf_sets_eq_finite {ι : Type*} (f : ι → Filter α) : - (⨅ i, f i).sets = ⋃ t : Finset ι, (⨅ i ∈ t, f i).sets := by - rw [iInf_eq_iInf_finset, iInf_sets_eq] - exact directed_of_isDirected_le fun _ _ => biInf_mono - -theorem iInf_sets_eq_finite' (f : ι → Filter α) : - (⨅ i, f i).sets = ⋃ t : Finset (PLift ι), (⨅ i ∈ t, f (PLift.down i)).sets := by - rw [← iInf_sets_eq_finite, ← Equiv.plift.surjective.iInf_comp, Equiv.plift_apply] - -theorem mem_iInf_finite {ι : Type*} {f : ι → Filter α} (s) : - s ∈ iInf f ↔ ∃ t : Finset ι, s ∈ ⨅ i ∈ t, f i := - (Set.ext_iff.1 (iInf_sets_eq_finite f) s).trans mem_iUnion - -theorem mem_iInf_finite' {f : ι → Filter α} (s) : - s ∈ iInf f ↔ ∃ t : Finset (PLift ι), s ∈ ⨅ i ∈ t, f (PLift.down i) := - (Set.ext_iff.1 (iInf_sets_eq_finite' f) s).trans mem_iUnion - @[simp] theorem sup_join {f₁ f₂ : Filter (Filter α)} : join f₁ ⊔ join f₂ = join (f₁ ⊔ f₂) := Filter.ext fun x => by simp only [mem_sup, mem_join] @@ -583,38 +468,6 @@ instance : DistribLattice (Filter α) := ⟨t₁, x.sets_of_superset hs inter_subset_left, ht₁, t₂, x.sets_of_superset hs inter_subset_right, ht₂, rfl⟩ } -/-- The dual version does not hold! `Filter α` is not a `CompleteDistribLattice`. -/ --- See note [reducible non-instances] -abbrev coframeMinimalAxioms : Coframe.MinimalAxioms (Filter α) := - { Filter.instCompleteLatticeFilter with - iInf_sup_le_sup_sInf := fun f s t ⟨h₁, h₂⟩ => by - classical - rw [iInf_subtype'] - rw [sInf_eq_iInf', ← Filter.mem_sets, iInf_sets_eq_finite, mem_iUnion] at h₂ - obtain ⟨u, hu⟩ := h₂ - rw [← Finset.inf_eq_iInf] at hu - suffices ⨅ i : s, f ⊔ ↑i ≤ f ⊔ u.inf fun i => ↑i from this ⟨h₁, hu⟩ - refine Finset.induction_on u (le_sup_of_le_right le_top) ?_ - rintro ⟨i⟩ u _ ih - rw [Finset.inf_insert, sup_inf_left] - exact le_inf (iInf_le _ _) ih } - -instance instCoframe : Coframe (Filter α) := .ofMinimalAxioms coframeMinimalAxioms - -theorem mem_iInf_finset {s : Finset α} {f : α → Filter β} {t : Set β} : - (t ∈ ⨅ a ∈ s, f a) ↔ ∃ p : α → Set β, (∀ a ∈ s, p a ∈ f a) ∧ t = ⋂ a ∈ s, p a := by - classical - simp only [← Finset.set_biInter_coe, biInter_eq_iInter, iInf_subtype'] - refine ⟨fun h => ?_, ?_⟩ - · rcases (mem_iInf_of_finite _).1 h with ⟨p, hp, rfl⟩ - refine ⟨fun a => if h : a ∈ s then p ⟨a, h⟩ else univ, - fun a ha => by simpa [ha] using hp ⟨a, ha⟩, ?_⟩ - refine iInter_congr_of_surjective id surjective_id ?_ - rintro ⟨a, ha⟩ - simp [ha] - · rintro ⟨p, hpf, rfl⟩ - exact iInter_mem.2 fun a => mem_iInf_of_mem a (hpf a a.2) - /-- If `f : ι → Filter α` is directed, `ι` is not empty, and `∀ i, f i ≠ ⊥`, then `iInf f ≠ ⊥`. See also `iInf_neBot_of_directed` for a version assuming `Nonempty α` instead of `Nonempty ι`. -/ theorem iInf_neBot_of_directed' {f : ι → Filter α} [Nonempty ι] (hd : Directed (· ≥ ·) f) : @@ -650,20 +503,6 @@ theorem iInf_neBot_iff_of_directed {f : ι → Filter α} [Nonempty α] (hd : Di NeBot (iInf f) ↔ ∀ i, NeBot (f i) := ⟨fun H i => H.mono (iInf_le _ i), iInf_neBot_of_directed hd⟩ -@[elab_as_elim] -theorem iInf_sets_induct {f : ι → Filter α} {s : Set α} (hs : s ∈ iInf f) {p : Set α → Prop} - (uni : p univ) (ins : ∀ {i s₁ s₂}, s₁ ∈ f i → p s₂ → p (s₁ ∩ s₂)) : p s := by - classical - rw [mem_iInf_finite'] at hs - simp only [← Finset.inf_eq_iInf] at hs - rcases hs with ⟨is, his⟩ - induction is using Finset.induction_on generalizing s with - | empty => rwa [mem_top.1 his] - | insert _ ih => - rw [Finset.inf_insert, mem_inf_iff] at his - rcases his with ⟨s₁, hs₁, s₂, hs₂, rfl⟩ - exact ins hs₁ (ih hs₂) - /-! #### `principal` equations -/ @[simp] @@ -719,29 +558,6 @@ theorem diff_mem_inf_principal_compl {f : Filter α} {s : Set α} (hs : s ∈ f) theorem principal_le_iff {s : Set α} {f : Filter α} : 𝓟 s ≤ f ↔ ∀ V ∈ f, s ⊆ V := by simp_rw [le_def, mem_principal] -@[simp] -theorem iInf_principal_finset {ι : Type w} (s : Finset ι) (f : ι → Set α) : - ⨅ i ∈ s, 𝓟 (f i) = 𝓟 (⋂ i ∈ s, f i) := by - classical - induction' s using Finset.induction_on with i s _ hs - · simp - · rw [Finset.iInf_insert, Finset.set_biInter_insert, hs, inf_principal] - -theorem iInf_principal {ι : Sort w} [Finite ι] (f : ι → Set α) : ⨅ i, 𝓟 (f i) = 𝓟 (⋂ i, f i) := by - cases nonempty_fintype (PLift ι) - rw [← iInf_plift_down, ← iInter_plift_down] - simpa using iInf_principal_finset Finset.univ (f <| PLift.down ·) - -/-- A special case of `iInf_principal` that is safe to mark `simp`. -/ -@[simp] -theorem iInf_principal' {ι : Type w} [Finite ι] (f : ι → Set α) : ⨅ i, 𝓟 (f i) = 𝓟 (⋂ i, f i) := - iInf_principal _ - -theorem iInf_principal_finite {ι : Type w} {s : Set ι} (hs : s.Finite) (f : ι → Set α) : - ⨅ i ∈ s, 𝓟 (f i) = 𝓟 (⋂ i ∈ s, f i) := by - lift s to Finset ι using hs - exact mod_cast iInf_principal_finset s f - end Lattice @[mono, gcongr] @@ -820,28 +636,6 @@ theorem eventually_congr {f : Filter α} {p q : α → Prop} (h : ∀ᶠ x in f, (∀ᶠ x in f, p x) ↔ ∀ᶠ x in f, q x := ⟨fun hp => hp.congr h, fun hq => hq.congr <| by simpa only [Iff.comm] using h⟩ -@[simp] -theorem eventually_all {ι : Sort*} [Finite ι] {l} {p : ι → α → Prop} : - (∀ᶠ x in l, ∀ i, p i x) ↔ ∀ i, ∀ᶠ x in l, p i x := by - simpa only [Filter.Eventually, setOf_forall] using iInter_mem - -@[simp] -theorem eventually_all_finite {ι} {I : Set ι} (hI : I.Finite) {l} {p : ι → α → Prop} : - (∀ᶠ x in l, ∀ i ∈ I, p i x) ↔ ∀ i ∈ I, ∀ᶠ x in l, p i x := by - simpa only [Filter.Eventually, setOf_forall] using biInter_mem hI - -alias _root_.Set.Finite.eventually_all := eventually_all_finite - --- attribute [protected] Set.Finite.eventually_all - -@[simp] theorem eventually_all_finset {ι} (I : Finset ι) {l} {p : ι → α → Prop} : - (∀ᶠ x in l, ∀ i ∈ I, p i x) ↔ ∀ i ∈ I, ∀ᶠ x in l, p i x := - I.finite_toSet.eventually_all - -alias _root_.Finset.eventually_all := eventually_all_finset - --- attribute [protected] Finset.eventually_all - @[simp] theorem eventually_or_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : (∀ᶠ x in f, p ∨ q x) ↔ p ∨ ∀ᶠ x in f, q x := @@ -852,10 +646,6 @@ theorem eventually_or_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} (∀ᶠ x in f, p x ∨ q) ↔ (∀ᶠ x in f, p x) ∨ q := by simp only [@or_comm _ q, eventually_or_distrib_left] -theorem eventually_imp_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : - (∀ᶠ x in f, p → q x) ↔ p → ∀ᶠ x in f, q x := - eventually_all - @[simp] theorem eventually_bot {p : α → Prop} : ∀ᶠ x in ⊥, p x := ⟨⟩ @@ -895,6 +685,11 @@ theorem eventually_inf_principal {f : Filter α} {p : α → Prop} {s : Set α} (∀ᶠ x in f ⊓ 𝓟 s, p x) ↔ ∀ᶠ x in f, x ∈ s → p x := mem_inf_principal +theorem eventually_iff_all_subsets {f : Filter α} {p : α → Prop} : + (∀ᶠ x in f, p x) ↔ ∀ (s : Set α), ∀ᶠ x in f, x ∈ s → p x where + mp h _ := by filter_upwards [h] with _ pa _ using pa + mpr h := by filter_upwards [h univ] with _ pa using pa (by simp) + /-! ### Frequently -/ theorem Eventually.frequently {f : Filter α} [NeBot f] {p : α → Prop} (h : ∀ᶠ x in f, p x) : @@ -1003,16 +798,6 @@ theorem eventually_imp_distrib_right {f : Filter α} {p : α → Prop} {q : Prop (∀ᶠ x in f, p x → q) ↔ (∃ᶠ x in f, p x) → q := by simp only [imp_iff_not_or, eventually_or_distrib_right, not_frequently] -@[simp] -theorem frequently_and_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : - (∃ᶠ x in f, p ∧ q x) ↔ p ∧ ∃ᶠ x in f, q x := by - simp only [Filter.Frequently, not_and, eventually_imp_distrib_left, Classical.not_imp] - -@[simp] -theorem frequently_and_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} : - (∃ᶠ x in f, p x ∧ q) ↔ (∃ᶠ x in f, p x) ∧ q := by - simp only [@and_comm _ q, frequently_and_distrib_left] - @[simp] theorem frequently_bot {p : α → Prop} : ¬∃ᶠ x in ⊥, p x := by simp @@ -1224,6 +1009,10 @@ theorem eventuallyEq_iff_sub [AddGroup β] {f g : α → β} {l : Filter α} : f =ᶠ[l] g ↔ f - g =ᶠ[l] 0 := ⟨fun h => h.sub_eq, fun h => by simpa using h.add (EventuallyEq.refl l g)⟩ +theorem eventuallyEq_iff_all_subsets {f g : α → β} {l : Filter α} : + f =ᶠ[l] g ↔ ∀ s : Set α, ∀ᶠ x in l, x ∈ s → f x = g x := + eventually_iff_all_subsets + section LE variable [LE β] {l : Filter α} @@ -1236,6 +1025,10 @@ theorem eventuallyLE_congr {f f' g g' : α → β} (hf : f =ᶠ[l] f') (hg : g = f ≤ᶠ[l] g ↔ f' ≤ᶠ[l] g' := ⟨fun H => H.congr hf hg, fun H => H.congr hf.symm hg.symm⟩ +theorem eventuallyLE_iff_all_subsets {f g : α → β} {l : Filter α} : + f ≤ᶠ[l] g ↔ ∀ s : Set α, ∀ᶠ x in l, x ∈ s → f x ≤ g x := + eventually_iff_all_subsets + end LE section Preorder @@ -1315,69 +1108,6 @@ theorem EventuallyLE.union {s t s' t' : Set α} {l : Filter α} (h : s ≤ᶠ[l] (s ∪ s' : Set α) ≤ᶠ[l] (t ∪ t' : Set α) := h'.mp <| h.mono fun _ => Or.imp -protected lemma EventuallyLE.iUnion [Finite ι] {s t : ι → Set α} - (h : ∀ i, s i ≤ᶠ[l] t i) : (⋃ i, s i) ≤ᶠ[l] ⋃ i, t i := - (eventually_all.2 h).mono fun _x hx hx' ↦ - let ⟨i, hi⟩ := mem_iUnion.1 hx'; mem_iUnion.2 ⟨i, hx i hi⟩ - -protected lemma EventuallyEq.iUnion [Finite ι] {s t : ι → Set α} - (h : ∀ i, s i =ᶠ[l] t i) : (⋃ i, s i) =ᶠ[l] ⋃ i, t i := - (EventuallyLE.iUnion fun i ↦ (h i).le).antisymm <| .iUnion fun i ↦ (h i).symm.le - -protected lemma EventuallyLE.iInter [Finite ι] {s t : ι → Set α} - (h : ∀ i, s i ≤ᶠ[l] t i) : (⋂ i, s i) ≤ᶠ[l] ⋂ i, t i := - (eventually_all.2 h).mono fun _x hx hx' ↦ mem_iInter.2 fun i ↦ hx i (mem_iInter.1 hx' i) - -protected lemma EventuallyEq.iInter [Finite ι] {s t : ι → Set α} - (h : ∀ i, s i =ᶠ[l] t i) : (⋂ i, s i) =ᶠ[l] ⋂ i, t i := - (EventuallyLE.iInter fun i ↦ (h i).le).antisymm <| .iInter fun i ↦ (h i).symm.le - -lemma _root_.Set.Finite.eventuallyLE_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) - {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := by - have := hs.to_subtype - rw [biUnion_eq_iUnion, biUnion_eq_iUnion] - exact .iUnion fun i ↦ hle i.1 i.2 - -alias EventuallyLE.biUnion := Set.Finite.eventuallyLE_iUnion - -lemma _root_.Set.Finite.eventuallyEq_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) - {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := - (EventuallyLE.biUnion hs fun i hi ↦ (heq i hi).le).antisymm <| - .biUnion hs fun i hi ↦ (heq i hi).symm.le - -alias EventuallyEq.biUnion := Set.Finite.eventuallyEq_iUnion - -lemma _root_.Set.Finite.eventuallyLE_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) - {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := by - have := hs.to_subtype - rw [biInter_eq_iInter, biInter_eq_iInter] - exact .iInter fun i ↦ hle i.1 i.2 - -alias EventuallyLE.biInter := Set.Finite.eventuallyLE_iInter - -lemma _root_.Set.Finite.eventuallyEq_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) - {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := - (EventuallyLE.biInter hs fun i hi ↦ (heq i hi).le).antisymm <| - .biInter hs fun i hi ↦ (heq i hi).symm.le - -alias EventuallyEq.biInter := Set.Finite.eventuallyEq_iInter - -lemma _root_.Finset.eventuallyLE_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} - (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := - .biUnion s.finite_toSet hle - -lemma _root_.Finset.eventuallyEq_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} - (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := - .biUnion s.finite_toSet heq - -lemma _root_.Finset.eventuallyLE_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} - (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := - .biInter s.finite_toSet hle - -lemma _root_.Finset.eventuallyEq_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} - (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := - .biInter s.finite_toSet heq - @[mono] theorem EventuallyLE.compl {s t : Set α} {l : Filter α} (h : s ≤ᶠ[l] t) : (tᶜ : Set α) ≤ᶠ[l] (sᶜ : Set α) := @@ -2359,4 +2089,4 @@ lemma compl_mem_comk {p : Set α → Prop} {he hmono hunion s} : end Filter -set_option linter.style.longFile 2500 +set_option linter.style.longFile 2200 diff --git a/Mathlib/Order/Filter/CardinalInter.lean b/Mathlib/Order/Filter/CardinalInter.lean index 22967d8a816b3f..9a1e5bb744169a 100644 --- a/Mathlib/Order/Filter/CardinalInter.lean +++ b/Mathlib/Order/Filter/CardinalInter.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Josha Dekker -/ import Mathlib.Order.Filter.Tendsto +import Mathlib.Order.Filter.Finite import Mathlib.Order.Filter.CountableInter import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Cofinality diff --git a/Mathlib/Order/Filter/Cocardinal.lean b/Mathlib/Order/Filter/Cocardinal.lean index 25e10e20a8fa31..d3da9a3ef6505a 100644 --- a/Mathlib/Order/Filter/Cocardinal.lean +++ b/Mathlib/Order/Filter/Cocardinal.lean @@ -8,7 +8,6 @@ import Mathlib.Order.Filter.CountableInter import Mathlib.Order.Filter.CardinalInter import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Cofinality -import Mathlib.Order.Filter.Bases /-! # The cocardinal filter diff --git a/Mathlib/Order/Filter/CountableSeparatingOn.lean b/Mathlib/Order/Filter/CountableSeparatingOn.lean index b1f268cda8419f..552a128f17bc54 100644 --- a/Mathlib/Order/Filter/CountableSeparatingOn.lean +++ b/Mathlib/Order/Filter/CountableSeparatingOn.lean @@ -167,7 +167,7 @@ theorem exists_subset_subsingleton_mem_of_forall_separating (p : Set α → Prop | inr hsl => simp only [hx.2 s hsS hsl, hy.2 s hsS hsl] · exact inter_mem (inter_mem hs ((countable_sInter_mem (hSc.mono inter_subset_left)).2 fun _ h ↦ h.2)) - ((countable_bInter_mem hSc).2 fun U hU ↦ iInter_mem.2 id) + ((countable_bInter_mem hSc).2 fun U hU ↦ iInter_mem'.2 id) theorem exists_mem_singleton_mem_of_mem_of_nonempty_of_forall_separating (p : Set α → Prop) {s : Set α} [HasCountableSeparatingOn α p s] (hs : s ∈ l) (hne : s.Nonempty) diff --git a/Mathlib/Order/Filter/Defs.lean b/Mathlib/Order/Filter/Defs.lean index f03e4c29d02967..d0a00823afb8af 100644 --- a/Mathlib/Order/Filter/Defs.lean +++ b/Mathlib/Order/Filter/Defs.lean @@ -32,6 +32,11 @@ abstract two related kinds of ideas: 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. +* `Filter.IsBounded r f`: the filter `f` is eventually bounded w.r.t. the relation `r`, + i.e. eventually, it is bounded by some uniform bound. + `r` will be usually instantiated with `(· ≤ ·)` or `(· ≥ ·)`. +* `Filter.IsCobounded r f` states that the filter `f` does not tend to infinity w.r.t. `r`. + This is also called frequently bounded. Will be usually instantiated with `(· ≤ ·)` or `(· ≥ ·)`. ## Notations @@ -350,6 +355,36 @@ This is essentially a push-forward along a function mapping each set to a set. - protected def lift' (f : Filter α) (h : Set α → Set β) := f.lift (𝓟 ∘ h) +/-- `f.IsBounded r`: the filter `f` is eventually bounded w.r.t. the relation `r`, +i.e. eventually, it is bounded by some uniform bound. +`r` will be usually instantiated with `(· ≤ ·)` or `(· ≥ ·)`. -/ +def IsBounded (r : α → α → Prop) (f : Filter α) := + ∃ b, ∀ᶠ x in f, r x b + +/-- `f.IsBoundedUnder (≺) u`: the image of the filter `f` under `u` is eventually bounded w.r.t. +the relation `≺`, i.e. eventually, it is bounded by some uniform bound. -/ +def IsBoundedUnder (r : α → α → Prop) (f : Filter β) (u : β → α) := + (map u f).IsBounded r + +/-- `IsCobounded (≺) f` states that the filter `f` does not tend to infinity w.r.t. `≺`. This is +also called frequently bounded. Will be usually instantiated with `≤` or `≥`. + +There is a subtlety in this definition: we want `f.IsCobounded` to hold for any `f` in the case of +complete lattices. This will be relevant to deduce theorems on complete lattices from their +versions on conditionally complete lattices with additional assumptions. We have to be careful in +the edge case of the trivial filter containing the empty set: the other natural definition + `¬ ∀ a, ∀ᶠ n in f, a ≤ n` +would not work as well in this case. +-/ +def IsCobounded (r : α → α → Prop) (f : Filter α) := + ∃ b, ∀ a, (∀ᶠ x in f, r x a) → r b a + +/-- `IsCoboundedUnder (≺) f u` states that the image of the filter `f` under the map `u` does not +tend to infinity w.r.t. `≺`. This is also called frequently bounded. Will be usually instantiated +with `≤` or `≥`. -/ +def IsCoboundedUnder (r : α → α → Prop) (f : Filter β) (u : β → α) := + (map u f).IsCobounded r + end Filter namespace Mathlib.Tactic diff --git a/Mathlib/Order/Filter/Extr.lean b/Mathlib/Order/Filter/Extr.lean index ba1e7c93d08968..5f405e77557b17 100644 --- a/Mathlib/Order/Filter/Extr.lean +++ b/Mathlib/Order/Filter/Extr.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Order.Filter.Tendsto import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Algebra.Order.Group.Defs +import Mathlib.Data.Finset.Lattice.Fold /-! # Minimum and maximum w.r.t. a filter and on a set diff --git a/Mathlib/Order/Filter/Finite.lean b/Mathlib/Order/Filter/Finite.lean new file mode 100644 index 00000000000000..2c96231b9a89f4 --- /dev/null +++ b/Mathlib/Order/Filter/Finite.lean @@ -0,0 +1,359 @@ +/- +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.Finite.Lattice +import Mathlib.Order.Filter.Basic + +/-! +# Results filters related to finiteness. + +-/ + + + +open Function Set Order +open scoped symmDiff + +universe u v w x y + +namespace Filter + +variable {α : Type u} {f g : Filter α} {s t : Set α} + +@[simp] +theorem biInter_mem {β : Type v} {s : β → Set α} {is : Set β} (hf : is.Finite) : + (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := + Finite.induction_on hf (by simp) fun _ _ hs => by simp [hs] + +@[simp] +theorem biInter_finset_mem {β : Type v} {s : β → Set α} (is : Finset β) : + (⋂ i ∈ is, s i) ∈ f ↔ ∀ i ∈ is, s i ∈ f := + biInter_mem is.finite_toSet + +alias _root_.Finset.iInter_mem_sets := biInter_finset_mem + +-- attribute [protected] Finset.iInter_mem_sets porting note: doesn't work + +@[simp] +theorem sInter_mem {s : Set (Set α)} (hfin : s.Finite) : ⋂₀ s ∈ f ↔ ∀ U ∈ s, U ∈ f := by + rw [sInter_eq_biInter, biInter_mem hfin] + +@[simp] +theorem iInter_mem {β : Sort v} {s : β → Set α} [Finite β] : (⋂ i, s i) ∈ f ↔ ∀ i, s i ∈ f := + (sInter_mem (finite_range _)).trans forall_mem_range + +end Filter + + +namespace Filter + +variable {α : Type u} {β : Type v} {γ : Type w} {δ : Type*} {ι : Sort x} + +section Lattice + +variable {f g : Filter α} {s t : Set α} + +theorem mem_generate_iff {s : Set <| Set α} {U : Set α} : + U ∈ generate s ↔ ∃ t ⊆ s, Set.Finite t ∧ ⋂₀ t ⊆ U := by + constructor <;> intro h + · induction h with + | @basic V V_in => + exact ⟨{V}, singleton_subset_iff.2 V_in, finite_singleton _, (sInter_singleton _).subset⟩ + | univ => exact ⟨∅, empty_subset _, finite_empty, subset_univ _⟩ + | superset _ hVW hV => + rcases hV with ⟨t, hts, ht, htV⟩ + exact ⟨t, hts, ht, htV.trans hVW⟩ + | inter _ _ hV hW => + rcases hV, hW with ⟨⟨t, hts, ht, htV⟩, u, hus, hu, huW⟩ + exact + ⟨t ∪ u, union_subset hts hus, ht.union hu, + (sInter_union _ _).subset.trans <| inter_subset_inter htV huW⟩ + · rcases h with ⟨t, hts, tfin, h⟩ + exact mem_of_superset ((sInter_mem tfin).2 fun V hV => GenerateSets.basic <| hts hV) h + +theorem mem_iInf_of_iInter {ι} {s : ι → Filter α} {U : Set α} {I : Set ι} (I_fin : I.Finite) + {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 : 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 : I), V i ∈ s i := by + rintro i + have : ⋂₀ σ i ∈ s i := by + rw [sInter_mem (σfin _)] + apply σsub + exact mem_of_superset this subset_union_right + refine ⟨I, Ifin, V, V_in, ?_⟩ + rwa [hV, ← union_iInter, union_eq_self_of_subset_right] + · rintro ⟨I, Ifin, V, V_in, rfl⟩ + exact mem_iInf_of_iInter Ifin V_in Subset.rfl + +theorem mem_iInf' {ι} {s : ι → Filter α} {U : Set α} : + (U ∈ ⨅ i, s i) ↔ + ∃ I : Set ι, I.Finite ∧ ∃ V : ι → Set α, (∀ i, V i ∈ s i) ∧ + (∀ i ∉ I, V i = univ) ∧ (U = ⋂ i ∈ I, V i) ∧ U = ⋂ i, V i := by + classical + simp only [mem_iInf, SetCoe.forall', biInter_eq_iInter] + refine ⟨?_, fun ⟨I, If, V, hVs, _, hVU, _⟩ => ⟨I, If, fun i => V i, fun i => hVs i, hVU⟩⟩ + rintro ⟨I, If, V, hV, rfl⟩ + 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 ⟨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] + +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 := + let ⟨_, _, V, hVs, _, _, hVU'⟩ := mem_iInf'.1 hs; ⟨V, hVs, hVU'⟩ + +theorem mem_iInf_of_finite {ι : Type*} [Finite ι] {α : Type*} {f : ι → Filter α} (s) : + (s ∈ ⨅ i, f i) ↔ ∃ t : ι → Set α, (∀ i, t i ∈ f i) ∧ s = ⋂ i, t i := by + refine ⟨exists_iInter_of_mem_iInf, ?_⟩ + rintro ⟨t, ht, rfl⟩ + exact iInter_mem.2 fun i => mem_iInf_of_mem i (ht i) + +/-! ### Lattice equations -/ + +theorem _root_.Pairwise.exists_mem_filter_of_disjoint {ι : Type*} [Finite ι] {l : ι → Filter α} + (hd : Pairwise (Disjoint on l)) : + ∃ s : ι → Set α, (∀ i, s i ∈ l i) ∧ Pairwise (Disjoint on s) := by + have : Pairwise fun i j => ∃ (s : {s // s ∈ l i}) (t : {t // t ∈ l j}), Disjoint s.1 t.1 := by + simpa only [Pairwise, Function.onFun, Filter.disjoint_iff, exists_prop, Subtype.exists] using hd + choose! s t hst using this + refine ⟨fun i => ⋂ j, @s i j ∩ @t j i, fun i => ?_, fun i j hij => ?_⟩ + exacts [iInter_mem.2 fun j => inter_mem (@s i j).2 (@t j i).2, + (hst hij).mono ((iInter_subset _ j).trans inter_subset_left) + ((iInter_subset _ i).trans inter_subset_right)] + +theorem _root_.Set.PairwiseDisjoint.exists_mem_filter {ι : Type*} {l : ι → Filter α} {t : Set ι} + (hd : t.PairwiseDisjoint l) (ht : t.Finite) : + ∃ s : ι → Set α, (∀ i, s i ∈ l i) ∧ t.PairwiseDisjoint s := by + haveI := ht.to_subtype + rcases (hd.subtype _ _).exists_mem_filter_of_disjoint with ⟨s, hsl, hsd⟩ + lift s to (i : t) → {s // s ∈ l i} using hsl + rcases @Subtype.exists_pi_extension ι (fun i => { s // s ∈ l i }) _ _ s with ⟨s, rfl⟩ + exact ⟨fun i => s i, fun i => (s i).2, hsd.set_of_subtype _ _⟩ + + +theorem iInf_sets_eq_finite {ι : Type*} (f : ι → Filter α) : + (⨅ i, f i).sets = ⋃ t : Finset ι, (⨅ i ∈ t, f i).sets := by + rw [iInf_eq_iInf_finset, iInf_sets_eq] + exact directed_of_isDirected_le fun _ _ => biInf_mono + +theorem iInf_sets_eq_finite' (f : ι → Filter α) : + (⨅ i, f i).sets = ⋃ t : Finset (PLift ι), (⨅ i ∈ t, f (PLift.down i)).sets := by + rw [← iInf_sets_eq_finite, ← Equiv.plift.surjective.iInf_comp, Equiv.plift_apply] + +theorem mem_iInf_finite {ι : Type*} {f : ι → Filter α} (s) : + s ∈ iInf f ↔ ∃ t : Finset ι, s ∈ ⨅ i ∈ t, f i := + (Set.ext_iff.1 (iInf_sets_eq_finite f) s).trans mem_iUnion + +theorem mem_iInf_finite' {f : ι → Filter α} (s) : + s ∈ iInf f ↔ ∃ t : Finset (PLift ι), s ∈ ⨅ i ∈ t, f (PLift.down i) := + (Set.ext_iff.1 (iInf_sets_eq_finite' f) s).trans mem_iUnion + +/-- The dual version does not hold! `Filter α` is not a `CompleteDistribLattice`. -/ +-- See note [reducible non-instances] +abbrev coframeMinimalAxioms : Coframe.MinimalAxioms (Filter α) := + { Filter.instCompleteLatticeFilter with + iInf_sup_le_sup_sInf := fun f s t ⟨h₁, h₂⟩ => by + classical + rw [iInf_subtype'] + rw [sInf_eq_iInf', ← Filter.mem_sets, iInf_sets_eq_finite, mem_iUnion] at h₂ + obtain ⟨u, hu⟩ := h₂ + rw [← Finset.inf_eq_iInf] at hu + suffices ⨅ i : s, f ⊔ ↑i ≤ f ⊔ u.inf fun i => ↑i from this ⟨h₁, hu⟩ + refine Finset.induction_on u (le_sup_of_le_right le_top) ?_ + rintro ⟨i⟩ u _ ih + rw [Finset.inf_insert, sup_inf_left] + exact le_inf (iInf_le _ _) ih } + +instance instCoframe : Coframe (Filter α) := .ofMinimalAxioms coframeMinimalAxioms + +theorem mem_iInf_finset {s : Finset α} {f : α → Filter β} {t : Set β} : + (t ∈ ⨅ a ∈ s, f a) ↔ ∃ p : α → Set β, (∀ a ∈ s, p a ∈ f a) ∧ t = ⋂ a ∈ s, p a := by + classical + simp only [← Finset.set_biInter_coe, biInter_eq_iInter, iInf_subtype'] + refine ⟨fun h => ?_, ?_⟩ + · rcases (mem_iInf_of_finite _).1 h with ⟨p, hp, rfl⟩ + refine ⟨fun a => if h : a ∈ s then p ⟨a, h⟩ else univ, + fun a ha => by simpa [ha] using hp ⟨a, ha⟩, ?_⟩ + refine iInter_congr_of_surjective id surjective_id ?_ + rintro ⟨a, ha⟩ + simp [ha] + · rintro ⟨p, hpf, rfl⟩ + exact iInter_mem.2 fun a => mem_iInf_of_mem a (hpf a a.2) + + +@[elab_as_elim] +theorem iInf_sets_induct {f : ι → Filter α} {s : Set α} (hs : s ∈ iInf f) {p : Set α → Prop} + (uni : p univ) (ins : ∀ {i s₁ s₂}, s₁ ∈ f i → p s₂ → p (s₁ ∩ s₂)) : p s := by + classical + rw [mem_iInf_finite'] at hs + simp only [← Finset.inf_eq_iInf] at hs + rcases hs with ⟨is, his⟩ + induction is using Finset.induction_on generalizing s with + | empty => rwa [mem_top.1 his] + | insert _ ih => + rw [Finset.inf_insert, mem_inf_iff] at his + rcases his with ⟨s₁, hs₁, s₂, hs₂, rfl⟩ + exact ins hs₁ (ih hs₂) + +/-! #### `principal` equations -/ + +@[simp] +theorem iInf_principal_finset {ι : Type w} (s : Finset ι) (f : ι → Set α) : + ⨅ i ∈ s, 𝓟 (f i) = 𝓟 (⋂ i ∈ s, f i) := by + classical + induction' s using Finset.induction_on with i s _ hs + · simp + · rw [Finset.iInf_insert, Finset.set_biInter_insert, hs, inf_principal] + +theorem iInf_principal {ι : Sort w} [Finite ι] (f : ι → Set α) : ⨅ i, 𝓟 (f i) = 𝓟 (⋂ i, f i) := by + cases nonempty_fintype (PLift ι) + rw [← iInf_plift_down, ← iInter_plift_down] + simpa using iInf_principal_finset Finset.univ (f <| PLift.down ·) + +/-- A special case of `iInf_principal` that is safe to mark `simp`. -/ +@[simp] +theorem iInf_principal' {ι : Type w} [Finite ι] (f : ι → Set α) : ⨅ i, 𝓟 (f i) = 𝓟 (⋂ i, f i) := + iInf_principal _ + +theorem iInf_principal_finite {ι : Type w} {s : Set ι} (hs : s.Finite) (f : ι → Set α) : + ⨅ i ∈ s, 𝓟 (f i) = 𝓟 (⋂ i ∈ s, f i) := by + lift s to Finset ι using hs + exact mod_cast iInf_principal_finset s f + +end Lattice + +/-! ### Eventually -/ + +@[simp] +theorem eventually_all {ι : Sort*} [Finite ι] {l} {p : ι → α → Prop} : + (∀ᶠ x in l, ∀ i, p i x) ↔ ∀ i, ∀ᶠ x in l, p i x := by + simpa only [Filter.Eventually, setOf_forall] using iInter_mem + +@[simp] +theorem eventually_all_finite {ι} {I : Set ι} (hI : I.Finite) {l} {p : ι → α → Prop} : + (∀ᶠ x in l, ∀ i ∈ I, p i x) ↔ ∀ i ∈ I, ∀ᶠ x in l, p i x := by + simpa only [Filter.Eventually, setOf_forall] using biInter_mem hI + +alias _root_.Set.Finite.eventually_all := eventually_all_finite + +-- attribute [protected] Set.Finite.eventually_all + +@[simp] theorem eventually_all_finset {ι} (I : Finset ι) {l} {p : ι → α → Prop} : + (∀ᶠ x in l, ∀ i ∈ I, p i x) ↔ ∀ i ∈ I, ∀ᶠ x in l, p i x := + I.finite_toSet.eventually_all + +alias _root_.Finset.eventually_all := eventually_all_finset + +-- attribute [protected] Finset.eventually_all + +theorem eventually_imp_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : + (∀ᶠ x in f, p → q x) ↔ p → ∀ᶠ x in f, q x := + eventually_all + + +/-! ### Frequently -/ + +@[simp] +theorem frequently_and_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : + (∃ᶠ x in f, p ∧ q x) ↔ p ∧ ∃ᶠ x in f, q x := by + simp only [Filter.Frequently, not_and, eventually_imp_distrib_left, Classical.not_imp] + +@[simp] +theorem frequently_and_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} : + (∃ᶠ x in f, p x ∧ q) ↔ (∃ᶠ x in f, p x) ∧ q := by + simp only [@and_comm _ q, frequently_and_distrib_left] + +/-! +### Relation “eventually equal” +-/ + +section EventuallyEq +variable {l : Filter α} {f g : α → β} + +variable {l : Filter α} + +protected lemma EventuallyLE.iUnion [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i ≤ᶠ[l] t i) : (⋃ i, s i) ≤ᶠ[l] ⋃ i, t i := + (eventually_all.2 h).mono fun _x hx hx' ↦ + let ⟨i, hi⟩ := mem_iUnion.1 hx'; mem_iUnion.2 ⟨i, hx i hi⟩ + +protected lemma EventuallyEq.iUnion [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i =ᶠ[l] t i) : (⋃ i, s i) =ᶠ[l] ⋃ i, t i := + (EventuallyLE.iUnion fun i ↦ (h i).le).antisymm <| .iUnion fun i ↦ (h i).symm.le + +protected lemma EventuallyLE.iInter [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i ≤ᶠ[l] t i) : (⋂ i, s i) ≤ᶠ[l] ⋂ i, t i := + (eventually_all.2 h).mono fun _x hx hx' ↦ mem_iInter.2 fun i ↦ hx i (mem_iInter.1 hx' i) + +protected lemma EventuallyEq.iInter [Finite ι] {s t : ι → Set α} + (h : ∀ i, s i =ᶠ[l] t i) : (⋂ i, s i) =ᶠ[l] ⋂ i, t i := + (EventuallyLE.iInter fun i ↦ (h i).le).antisymm <| .iInter fun i ↦ (h i).symm.le + +lemma _root_.Set.Finite.eventuallyLE_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := by + have := hs.to_subtype + rw [biUnion_eq_iUnion, biUnion_eq_iUnion] + exact .iUnion fun i ↦ hle i.1 i.2 + +alias EventuallyLE.biUnion := Set.Finite.eventuallyLE_iUnion + +lemma _root_.Set.Finite.eventuallyEq_iUnion {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := + (EventuallyLE.biUnion hs fun i hi ↦ (heq i hi).le).antisymm <| + .biUnion hs fun i hi ↦ (heq i hi).symm.le + +alias EventuallyEq.biUnion := Set.Finite.eventuallyEq_iUnion + +lemma _root_.Set.Finite.eventuallyLE_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := by + have := hs.to_subtype + rw [biInter_eq_iInter, biInter_eq_iInter] + exact .iInter fun i ↦ hle i.1 i.2 + +alias EventuallyLE.biInter := Set.Finite.eventuallyLE_iInter + +lemma _root_.Set.Finite.eventuallyEq_iInter {ι : Type*} {s : Set ι} (hs : s.Finite) + {f g : ι → Set α} (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := + (EventuallyLE.biInter hs fun i hi ↦ (heq i hi).le).antisymm <| + .biInter hs fun i hi ↦ (heq i hi).symm.le + +alias EventuallyEq.biInter := Set.Finite.eventuallyEq_iInter + +lemma _root_.Finset.eventuallyLE_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋃ i ∈ s, f i) ≤ᶠ[l] (⋃ i ∈ s, g i) := + .biUnion s.finite_toSet hle + +lemma _root_.Finset.eventuallyEq_iUnion {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋃ i ∈ s, f i) =ᶠ[l] (⋃ i ∈ s, g i) := + .biUnion s.finite_toSet heq + +lemma _root_.Finset.eventuallyLE_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (hle : ∀ i ∈ s, f i ≤ᶠ[l] g i) : (⋂ i ∈ s, f i) ≤ᶠ[l] (⋂ i ∈ s, g i) := + .biInter s.finite_toSet hle + +lemma _root_.Finset.eventuallyEq_iInter {ι : Type*} (s : Finset ι) {f g : ι → Set α} + (heq : ∀ i ∈ s, f i =ᶠ[l] g i) : (⋂ i ∈ s, f i) =ᶠ[l] (⋂ i ∈ s, g i) := + .biInter s.finite_toSet heq + +end EventuallyEq + +end Filter + +open Filter diff --git a/Mathlib/Order/Filter/Germ/Basic.lean b/Mathlib/Order/Filter/Germ/Basic.lean index d855beedbbf222..c9ad7754c49464 100644 --- a/Mathlib/Order/Filter/Germ/Basic.lean +++ b/Mathlib/Order/Filter/Germ/Basic.lean @@ -3,8 +3,10 @@ Copyright (c) 2020 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Abhimanyu Pallavi Sudhir -/ -import Mathlib.Order.Filter.Tendsto import Mathlib.Algebra.Module.Pi +import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE +import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Order.Filter.Tendsto /-! # Germ of a function at a filter @@ -236,7 +238,7 @@ theorem coe_compTendsto (f : α → β) {lc : Filter γ} {g : γ → α} (hg : T rfl -- Porting note https://github.com/leanprover-community/mathlib4/issues/10959 --- simp cannot prove this +-- simp can't match the LHS. @[simp, nolint simpNF] theorem compTendsto'_coe (f : Germ l β) {lc : Filter γ} {g : γ → α} (hg : Tendsto g lc l) : f.compTendsto' _ hg.germ_tendsto = f.compTendsto g hg := diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index c76d14970e05ab..05f1a4c1cf4e00 100644 --- a/Mathlib/Order/Filter/Pointwise.lean +++ b/Mathlib/Order/Filter/Pointwise.lean @@ -146,9 +146,8 @@ theorem pureOneHom_apply (a : α) : pureOneHom a = pure a := variable [One β] @[to_additive] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it. protected theorem map_one [FunLike F α β] [OneHomClass F α β] (φ : F) : map φ 1 = 1 := by - rw [Filter.map_one', map_one, pure_one] + simp end One @@ -303,9 +302,7 @@ theorem mul_pure : f * pure b = f.map (· * b) := map₂_pure_right @[to_additive] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it. -theorem pure_mul_pure : (pure a : Filter α) * pure b = pure (a * b) := - map₂_pure +theorem pure_mul_pure : (pure a : Filter α) * pure b = pure (a * b) := by simp @[to_additive (attr := simp)] theorem le_mul_iff : h ≤ f * g ↔ ∀ ⦃s⦄, s ∈ f → ∀ ⦃t⦄, t ∈ g → s * t ∈ h := @@ -408,9 +405,7 @@ theorem div_pure : f / pure b = f.map (· / b) := map₂_pure_right @[to_additive] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it. -theorem pure_div_pure : (pure a : Filter α) / pure b = pure (a / b) := - map₂_pure +theorem pure_div_pure : (pure a : Filter α) / pure b = pure (a / b) := by simp @[to_additive] protected theorem div_le_div : f₁ ≤ f₂ → g₁ ≤ g₂ → f₁ / g₁ ≤ f₂ / g₂ := @@ -826,9 +821,7 @@ theorem smul_pure : f • pure b = f.map (· • b) := map₂_pure_right @[to_additive] --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it. -theorem pure_smul_pure : (pure a : Filter α) • (pure b : Filter β) = pure (a • b) := - map₂_pure +theorem pure_smul_pure : (pure a : Filter α) • (pure b : Filter β) = pure (a • b) := by simp @[to_additive] theorem smul_le_smul : f₁ ≤ f₂ → g₁ ≤ g₂ → f₁ • g₁ ≤ f₂ • g₂ := @@ -914,9 +907,7 @@ theorem pure_vsub : (pure a : Filter β) -ᵥ g = g.map (a -ᵥ ·) := theorem vsub_pure : f -ᵥ pure b = f.map (· -ᵥ b) := map₂_pure_right --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11119): removed `simp` attribute because `simpNF` says it can prove it. -theorem pure_vsub_pure : (pure a : Filter β) -ᵥ pure b = (pure (a -ᵥ b) : Filter α) := - map₂_pure +theorem pure_vsub_pure : (pure a : Filter β) -ᵥ pure b = (pure (a -ᵥ b) : Filter α) := by simp theorem vsub_le_vsub : f₁ ≤ f₂ → g₁ ≤ g₂ → f₁ -ᵥ g₁ ≤ f₂ -ᵥ g₂ := map₂_mono diff --git a/Mathlib/Order/Filter/Subsingleton.lean b/Mathlib/Order/Filter/Subsingleton.lean index e079522700c04d..c8d0816c3f17bf 100644 --- a/Mathlib/Order/Filter/Subsingleton.lean +++ b/Mathlib/Order/Filter/Subsingleton.lean @@ -3,7 +3,6 @@ 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.Order.Filter.Bases import Mathlib.Order.Filter.Ultrafilter /-! # Subsingleton filters diff --git a/Mathlib/Order/Filter/ZeroAndBoundedAtFilter.lean b/Mathlib/Order/Filter/ZeroAndBoundedAtFilter.lean index c7c14ca53e2129..fd33cad02fcd37 100644 --- a/Mathlib/Order/Filter/ZeroAndBoundedAtFilter.lean +++ b/Mathlib/Order/Filter/ZeroAndBoundedAtFilter.lean @@ -71,15 +71,16 @@ if `f =O[l] 1`. -/ def BoundedAtFilter [Norm β] (l : Filter α) (f : α → β) : Prop := Asymptotics.IsBigO l f (1 : α → ℝ) -theorem ZeroAtFilter.boundedAtFilter [NormedAddCommGroup β] {l : Filter α} {f : α → β} - (hf : ZeroAtFilter l f) : BoundedAtFilter l f := by - rw [ZeroAtFilter, ← Asymptotics.isLittleO_const_iff (one_ne_zero' ℝ)] at hf - exact hf.isBigO +theorem ZeroAtFilter.boundedAtFilter [SeminormedAddGroup β] {l : Filter α} {f : α → β} + (hf : ZeroAtFilter l f) : BoundedAtFilter l f := + ((Asymptotics.isLittleO_one_iff _).mpr hf).isBigO theorem const_boundedAtFilter [Norm β] (l : Filter α) (c : β) : BoundedAtFilter l (Function.const α c : α → β) := Asymptotics.isBigO_const_const c one_ne_zero l +-- TODO(https://github.com/leanprover-community/mathlib4/issues/19288): Remove all Comm in the next +-- three lemmas. This would require modifying the corresponding general asymptotics lemma. nonrec theorem BoundedAtFilter.add [SeminormedAddCommGroup β] {l : Filter α} {f g : α → β} (hf : BoundedAtFilter l f) (hg : BoundedAtFilter l g) : BoundedAtFilter l (f + g) := by simpa using hf.add hg diff --git a/Mathlib/Order/FixedPoints.lean b/Mathlib/Order/FixedPoints.lean index e6f40735b5ddc7..20419434bbcf62 100644 --- a/Mathlib/Order/FixedPoints.lean +++ b/Mathlib/Order/FixedPoints.lean @@ -51,76 +51,73 @@ def gfp : (α →o α) →o α where toFun f := sSup { a | a ≤ f a } monotone' _ _ hle := sSup_le_sSup fun a ha => le_trans ha (hle a) -theorem lfp_le {a : α} (h : f a ≤ a) : lfp f ≤ a := +theorem lfp_le {a : α} (h : f a ≤ a) : f.lfp ≤ a := sInf_le h -theorem lfp_le_fixed {a : α} (h : f a = a) : lfp f ≤ a := +theorem lfp_le_fixed {a : α} (h : f a = a) : f.lfp ≤ a := f.lfp_le h.le -theorem le_lfp {a : α} (h : ∀ b, f b ≤ b → a ≤ b) : a ≤ lfp f := +theorem le_lfp {a : α} (h : ∀ b, f b ≤ b → a ≤ b) : a ≤ f.lfp := le_sInf h --- Porting note: for the rest of the file, replace the dot notation `_.lfp` with `lfp _` --- same for `_.gfp`, `_.dual` --- Probably related to https://github.com/leanprover/lean4/issues/1910 -theorem map_le_lfp {a : α} (ha : a ≤ lfp f) : f a ≤ lfp f := +theorem map_le_lfp {a : α} (ha : a ≤ f.lfp) : f a ≤ f.lfp := f.le_lfp fun _ hb => (f.mono <| le_sInf_iff.1 ha _ hb).trans hb @[simp] -theorem map_lfp : f (lfp f) = lfp f := - have h : f (lfp f) ≤ lfp f := f.map_le_lfp le_rfl +theorem map_lfp : f f.lfp = f.lfp := + have h : f f.lfp ≤ f.lfp := f.map_le_lfp le_rfl h.antisymm <| f.lfp_le <| f.mono h -theorem isFixedPt_lfp : IsFixedPt f (lfp f) := +theorem isFixedPt_lfp : IsFixedPt f f.lfp := f.map_lfp -theorem lfp_le_map {a : α} (ha : lfp f ≤ a) : lfp f ≤ f a := +theorem lfp_le_map {a : α} (ha : f.lfp ≤ a) : f.lfp ≤ f a := calc - lfp f = f (lfp f) := f.map_lfp.symm + f.lfp = f f.lfp := f.map_lfp.symm _ ≤ f a := f.mono ha -theorem isLeast_lfp_le : IsLeast { a | f a ≤ a } (lfp f) := +theorem isLeast_lfp_le : IsLeast { a | f a ≤ a } f.lfp := ⟨f.map_lfp.le, fun _ => f.lfp_le⟩ -theorem isLeast_lfp : IsLeast (fixedPoints f) (lfp f) := +theorem isLeast_lfp : IsLeast (fixedPoints f) f.lfp := ⟨f.isFixedPt_lfp, fun _ => f.lfp_le_fixed⟩ -theorem lfp_induction {p : α → Prop} (step : ∀ a, p a → a ≤ lfp f → p (f a)) - (hSup : ∀ s, (∀ a ∈ s, p a) → p (sSup s)) : p (lfp f) := by - set s := { a | a ≤ lfp f ∧ p a } +theorem lfp_induction {p : α → Prop} (step : ∀ a, p a → a ≤ f.lfp → p (f a)) + (hSup : ∀ s, (∀ a ∈ s, p a) → p (sSup s)) : p f.lfp := by + set s := { a | a ≤ f.lfp ∧ p a } specialize hSup s fun a => And.right - suffices sSup s = lfp f from this ▸ hSup - have h : sSup s ≤ lfp f := sSup_le fun b => And.left + suffices sSup s = f.lfp from this ▸ hSup + have h : sSup s ≤ f.lfp := sSup_le fun b => And.left have hmem : f (sSup s) ∈ s := ⟨f.map_le_lfp h, step _ hSup h⟩ exact h.antisymm (f.lfp_le <| le_sSup hmem) -theorem le_gfp {a : α} (h : a ≤ f a) : a ≤ gfp f := +theorem le_gfp {a : α} (h : a ≤ f a) : a ≤ f.gfp := le_sSup h -theorem gfp_le {a : α} (h : ∀ b, b ≤ f b → b ≤ a) : gfp f ≤ a := +theorem gfp_le {a : α} (h : ∀ b, b ≤ f b → b ≤ a) : f.gfp ≤ a := sSup_le h -theorem isFixedPt_gfp : IsFixedPt f (gfp f) := +theorem isFixedPt_gfp : IsFixedPt f f.gfp := f.dual.isFixedPt_lfp @[simp] -theorem map_gfp : f (gfp f) = gfp f := +theorem map_gfp : f f.gfp = f.gfp := f.dual.map_lfp -theorem map_le_gfp {a : α} (ha : a ≤ gfp f) : f a ≤ gfp f := +theorem map_le_gfp {a : α} (ha : a ≤ f.gfp) : f a ≤ f.gfp := f.dual.lfp_le_map ha -theorem gfp_le_map {a : α} (ha : gfp f ≤ a) : gfp f ≤ f a := +theorem gfp_le_map {a : α} (ha : f.gfp ≤ a) : f.gfp ≤ f a := f.dual.map_le_lfp ha -theorem isGreatest_gfp_le : IsGreatest { a | a ≤ f a } (gfp f) := +theorem isGreatest_gfp_le : IsGreatest { a | a ≤ f a } f.gfp := f.dual.isLeast_lfp_le -theorem isGreatest_gfp : IsGreatest (fixedPoints f) (gfp f) := +theorem isGreatest_gfp : IsGreatest (fixedPoints f) f.gfp := f.dual.isLeast_lfp -theorem gfp_induction {p : α → Prop} (step : ∀ a, p a → gfp f ≤ a → p (f a)) - (hInf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : p (gfp f) := +theorem gfp_induction {p : α → Prop} (step : ∀ a, p a → f.gfp ≤ a → p (f a)) + (hInf : ∀ s, (∀ a ∈ s, p a) → p (sInf s)) : p f.gfp := f.dual.lfp_induction step hInf end Basic @@ -130,27 +127,26 @@ section Eqn variable [CompleteLattice α] [CompleteLattice β] (f : β →o α) (g : α →o β) -- Rolling rule -theorem map_lfp_comp : f (lfp (g.comp f)) = lfp (f.comp g) := +theorem map_lfp_comp : f (g.comp f).lfp = (f.comp g).lfp := le_antisymm ((f.comp g).map_lfp ▸ f.mono (lfp_le_fixed _ <| congr_arg g (f.comp g).map_lfp)) <| lfp_le _ (congr_arg f (g.comp f).map_lfp).le -theorem map_gfp_comp : f (gfp (g.comp f)) = gfp (f.comp g) := - f.dual.map_lfp_comp (OrderHom.dual g) +theorem map_gfp_comp : f (g.comp f).gfp = (f.comp g).gfp := + f.dual.map_lfp_comp g.dual -- Diagonal rule -theorem lfp_lfp (h : α →o α →o α) : lfp (lfp.comp h) = lfp h.onDiag := by - let a := lfp (lfp.comp h) +theorem lfp_lfp (h : α →o α →o α) : (lfp.comp h).lfp = h.onDiag.lfp := by + let a := (lfp.comp h).lfp refine (lfp_le _ ?_).antisymm (lfp_le _ (Eq.le ?_)) · exact lfp_le _ h.onDiag.map_lfp.le have ha : (lfp ∘ h) a = a := (lfp.comp h).map_lfp calc - h a a = h a (lfp (h a)) := congr_arg (h a) ha.symm - _ = lfp (h a) := (h a).map_lfp + h a a = h a (h a).lfp := congr_arg (h a) ha.symm + _ = (h a).lfp := (h a).map_lfp _ = a := ha -theorem gfp_gfp (h : α →o α →o α) : gfp (gfp.comp h) = gfp h.onDiag := - @lfp_lfp αᵒᵈ _ <| (OrderHom.dualIso αᵒᵈ αᵒᵈ).symm.toOrderEmbedding.toOrderHom.comp - (OrderHom.dual h) +theorem gfp_gfp (h : α →o α →o α) : (gfp.comp h).gfp = h.onDiag.gfp := + @lfp_lfp αᵒᵈ _ <| (OrderHom.dualIso αᵒᵈ αᵒᵈ).symm.toOrderEmbedding.toOrderHom.comp h.dual end Eqn @@ -158,25 +154,25 @@ section PrevNext variable [CompleteLattice α] (f : α →o α) -theorem gfp_const_inf_le (x : α) : gfp (const α x ⊓ f) ≤ x := +theorem gfp_const_inf_le (x : α) : (const α x ⊓ f).gfp ≤ x := (gfp_le _) fun _ hb => hb.trans inf_le_left /-- Previous fixed point of a monotone map. If `f` is a monotone self-map of a complete lattice and `x` is a point such that `f x ≤ x`, then `f.prevFixed x hx` is the greatest fixed point of `f` that is less than or equal to `x`. -/ def prevFixed (x : α) (hx : f x ≤ x) : fixedPoints f := - ⟨gfp (const α x ⊓ f), + ⟨(const α x ⊓ f).gfp, calc - f (gfp (const α x ⊓ f)) = x ⊓ f (gfp (const α x ⊓ f)) := + f (const α x ⊓ f).gfp = x ⊓ f (const α x ⊓ f).gfp := Eq.symm <| inf_of_le_right <| (f.mono <| f.gfp_const_inf_le x).trans hx - _ = gfp (const α x ⊓ f) := (const α x ⊓ f).map_gfp + _ = (const α x ⊓ f).gfp := (const α x ⊓ f).map_gfp ⟩ /-- Next fixed point of a monotone map. If `f` is a monotone self-map of a complete lattice and `x` is a point such that `x ≤ f x`, then `f.nextFixed x hx` is the least fixed point of `f` that is greater than or equal to `x`. -/ def nextFixed (x : α) (hx : x ≤ f x) : fixedPoints f := - { f.dual.prevFixed x hx with val := lfp (const α x ⊔ f) } + { f.dual.prevFixed x hx with val := (const α x ⊔ f).lfp } theorem prevFixed_le {x : α} (hx : f x ≤ x) : ↑(f.prevFixed x hx) ≤ x := f.gfp_const_inf_le x @@ -240,7 +236,7 @@ instance : SemilatticeSup (fixedPoints f) := /- porting note: removed `Subtype.partialOrder _` from mathlib3port version, threw `typeclass instance` error and was seemingly unnecessary?-/ instance : SemilatticeInf (fixedPoints f) := - { OrderDual.instSemilatticeInf (fixedPoints (OrderHom.dual f)) with + { OrderDual.instSemilatticeInf (fixedPoints f.dual) with inf := fun x y => f.prevFixed (x ⊓ y) (f.map_inf_fixedPoints_le x y) } -- Porting note: `coe` replaced with `Subtype.val` @@ -271,8 +267,8 @@ instance completeLattice : CompleteLattice (fixedPoints f) where __ := inferInstanceAs (SemilatticeSup (fixedPoints f)) __ := inferInstanceAs (CompleteSemilatticeInf (fixedPoints f)) __ := inferInstanceAs (CompleteSemilatticeSup (fixedPoints f)) - top := ⟨gfp f, f.isFixedPt_gfp⟩ - bot := ⟨lfp f, f.isFixedPt_lfp⟩ + top := ⟨f.gfp, f.isFixedPt_gfp⟩ + bot := ⟨f.lfp, f.isFixedPt_lfp⟩ le_top x := f.le_gfp x.2.ge bot_le x := f.lfp_le x.2.le @@ -281,7 +277,7 @@ 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 + f.lfp = ⨆ n, f^[n] ⊥ := by apply le_antisymm · apply lfp_le_fixed exact Function.mem_fixedPoints.mp (ωSup_iterate_mem_fixedPoint @@ -290,8 +286,8 @@ theorem lfp_eq_sSup_iterate (h : ωScottContinuous f) : 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 +theorem gfp_eq_sInf_iterate (h : ωScottContinuous f.dual) : + f.gfp = ⨅ n, f^[n] ⊤ := + lfp_eq_sSup_iterate f.dual h end fixedPoints diff --git a/Mathlib/Order/Heyting/Basic.lean b/Mathlib/Order/Heyting/Basic.lean index 4c1f777c64b8f2..1252f8884377c4 100644 --- a/Mathlib/Order/Heyting/Basic.lean +++ b/Mathlib/Order/Heyting/Basic.lean @@ -794,7 +794,7 @@ theorem hnot_le_iff_codisjoint_right : ¬a ≤ b ↔ Codisjoint a b := by rw [← top_sdiff', sdiff_le_iff, codisjoint_iff_le_sup] theorem hnot_le_iff_codisjoint_left : ¬a ≤ b ↔ Codisjoint b a := - hnot_le_iff_codisjoint_right.trans Codisjoint_comm + hnot_le_iff_codisjoint_right.trans codisjoint_comm theorem hnot_le_comm : ¬a ≤ b ↔ ¬b ≤ a := by rw [hnot_le_iff_codisjoint_right, hnot_le_iff_codisjoint_left] @@ -1084,11 +1084,11 @@ theorem top_eq : (⊤ : PUnit) = unit := theorem bot_eq : (⊥ : PUnit) = unit := rfl -@[simp, nolint simpNF] +@[simp] theorem sup_eq : a ⊔ b = unit := rfl -@[simp, nolint simpNF] +@[simp] theorem inf_eq : a ⊓ b = unit := rfl @@ -1096,16 +1096,15 @@ theorem inf_eq : a ⊓ b = unit := theorem compl_eq : aᶜ = unit := rfl -@[simp, nolint simpNF] +@[simp] theorem sdiff_eq : a \ b = unit := rfl -@[simp, nolint simpNF] +@[simp] theorem hnot_eq : ¬a = unit := rfl --- eligible for `dsimp` -@[simp, nolint simpNF] +@[simp] theorem himp_eq : a ⇨ b = unit := rfl diff --git a/Mathlib/Order/Hom/Basic.lean b/Mathlib/Order/Hom/Basic.lean index aaa22efefcb3ec..ef9ebbb809b7f6 100644 --- a/Mathlib/Order/Hom/Basic.lean +++ b/Mathlib/Order/Hom/Basic.lean @@ -488,16 +488,13 @@ protected def dual : (α →o β) ≃ (αᵒᵈ →o βᵒᵈ) where left_inv _ := rfl right_inv _ := rfl --- Porting note: We used to be able to write `(OrderHom.id : α →o α).dual` here rather than --- `OrderHom.dual (OrderHom.id : α →o α)`. --- See https://github.com/leanprover/lean4/issues/1910 @[simp] -theorem dual_id : OrderHom.dual (OrderHom.id : α →o α) = OrderHom.id := +theorem dual_id : (OrderHom.id : α →o α).dual = OrderHom.id := rfl @[simp] theorem dual_comp (g : β →o γ) (f : α →o β) : - OrderHom.dual (g.comp f) = (OrderHom.dual g).comp (OrderHom.dual f) := + (g.comp f).dual = g.dual.comp f.dual := rfl @[simp] diff --git a/Mathlib/Order/Hom/Bounded.lean b/Mathlib/Order/Hom/Bounded.lean index 00886351437d41..6466c90ddaf430 100644 --- a/Mathlib/Order/Hom/Bounded.lean +++ b/Mathlib/Order/Hom/Bounded.lean @@ -725,18 +725,18 @@ protected def dual : BoundedOrderHom α β ≃ BoundedOrderHom αᵒᵈ βᵒᵈ where - toFun f := ⟨OrderHom.dual f.toOrderHom, f.map_bot', f.map_top'⟩ + toFun f := ⟨f.toOrderHom.dual, f.map_bot', f.map_top'⟩ invFun f := ⟨OrderHom.dual.symm f.toOrderHom, f.map_bot', f.map_top'⟩ left_inv _ := ext fun _ => rfl right_inv _ := ext fun _ => rfl @[simp] -theorem dual_id : BoundedOrderHom.dual (BoundedOrderHom.id α) = BoundedOrderHom.id _ := +theorem dual_id : (BoundedOrderHom.id α).dual = BoundedOrderHom.id _ := rfl @[simp] theorem dual_comp (g : BoundedOrderHom β γ) (f : BoundedOrderHom α β) : - BoundedOrderHom.dual (g.comp f) = g.dual.comp (BoundedOrderHom.dual f) := + (g.comp f).dual = g.dual.comp f.dual := rfl @[simp] diff --git a/Mathlib/Order/Interval/Basic.lean b/Mathlib/Order/Interval/Basic.lean index 9ef57523db1f8d..55171625e65d7a 100644 --- a/Mathlib/Order/Interval/Basic.lean +++ b/Mathlib/Order/Interval/Basic.lean @@ -109,7 +109,6 @@ theorem mem_mk {hx : x.1 ≤ x.2} : a ∈ mk x hx ↔ x.1 ≤ a ∧ a ≤ x.2 := theorem mem_def : a ∈ s ↔ s.fst ≤ a ∧ a ≤ s.snd := Iff.rfl --- @[simp] -- Porting note: not in simpNF theorem coe_nonempty (s : NonemptyInterval α) : (s : Set α).Nonempty := nonempty_Icc.2 s.fst_le_snd @@ -153,7 +152,7 @@ theorem map_map (g : β →o γ) (f : α →o β) (a : NonemptyInterval α) : @[simp] theorem dual_map (f : α →o β) (a : NonemptyInterval α) : - dual (a.map f) = a.dual.map (OrderHom.dual f) := + dual (a.map f) = a.dual.map f.dual := rfl /-- Binary pushforward of nonempty intervals. -/ @@ -360,7 +359,7 @@ theorem map_map (g : β →o γ) (f : α →o β) (s : Interval α) : (s.map f). Option.map_map _ _ _ @[simp] -theorem dual_map (f : α →o β) (s : Interval α) : dual (s.map f) = s.dual.map (OrderHom.dual f) := by +theorem dual_map (f : α →o β) (s : Interval α) : dual (s.map f) = s.dual.map f.dual := by cases s · rfl · exact WithBot.map_comm rfl _ diff --git a/Mathlib/Order/Interval/Set/IsoIoo.lean b/Mathlib/Order/Interval/Set/IsoIoo.lean index f44e1e48225717..649d99a424435c 100644 --- a/Mathlib/Order/Interval/Set/IsoIoo.lean +++ b/Mathlib/Order/Interval/Set/IsoIoo.lean @@ -35,7 +35,7 @@ def orderIsoIooNegOneOne (k : Type*) [LinearOrderedField k] : k ≃o Ioo (-1 : k · intro x simp only [abs_neg, neg_div] · rintro x (hx : 0 ≤ x) y (hy : 0 ≤ y) hxy - simp [abs_of_nonneg, mul_add, mul_comm x y, div_lt_div_iff, hx.trans_lt (lt_one_add _), + simp [abs_of_nonneg, mul_add, mul_comm x y, div_lt_div_iff₀, hx.trans_lt (lt_one_add _), hy.trans_lt (lt_one_add _), *] · refine fun x ↦ Subtype.ext ?_ have : 0 < 1 - |(x : k)| := sub_pos.2 (abs_lt.2 x.2) diff --git a/Mathlib/Order/KrullDimension.lean b/Mathlib/Order/KrullDimension.lean index 836303c212832e..1b435cca658776 100644 --- a/Mathlib/Order/KrullDimension.lean +++ b/Mathlib/Order/KrullDimension.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang, Fangming Li, Joachim Breitner -/ -import Mathlib.Order.RelSeries -import Mathlib.Order.Minimal +import Mathlib.Algebra.Order.Group.Int import Mathlib.Data.ENat.Lattice +import Mathlib.Order.Minimal +import Mathlib.Order.RelSeries /-! # Krull dimension of a preordered set and height of an element @@ -18,16 +19,32 @@ In case that `α` is empty, then its Krull dimension is defined to be negative i 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 +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`). -* The Krull dimension is the supremum of the heights of the elements (`krullDim_eq_iSup_height`). +* The Krull dimension is the supremum of the heights of the elements (`krullDim_eq_iSup_height`), + or their coheights (`krullDim_eq_iSup_coheight`), or their sums of height and coheight + (`krullDim_eq_iSup_height_add_coheight_of_nonempty`) + +* The height in the dual order equals the coheight, and vice versa. + +* The height is monotone (`height_mono`), and strictly monotone if finite (`height_strictMono`). + +* The coheight is antitone (`coheight_anti`), and strictly antitone if finite + (`coheight_strictAnti`). -* The height is monotone. +* The height is the supremum of the successor of the height of all smaller elements + (`height_eq_iSup_lt_height`). + +* The elements of height zero are the minimal elements (`height_eq_zero`), and the elements of + height `n` are minimal among those of height `≥ n` (`height_eq_coe_iff_minimal_le_height`). + +* Concrete calculations for the height, coheight and Krull dimension in `ℕ`, `ℤ`, `WithTop`, + `WithBot` and `ℕ∞`. ## Design notes @@ -239,6 +256,9 @@ lemma height_mono : Monotone (α := α) height := lemma coheight_anti : Antitone (α := α) coheight := (height_mono (α := αᵒᵈ)).dual_left +@[gcongr] protected lemma _root_.GCongr.coheight_le_coheight (a b : α) (hba : b ≤ a) : + coheight a ≤ coheight b := coheight_anti hba + private lemma height_add_const (a : α) (n : ℕ∞) : height a + n = ⨆ (p : LTSeries α) (_ : p.last = a), p.length + n := by have hne : Nonempty { p : LTSeries α // p.last = a } := ⟨RelSeries.singleton _ a, rfl⟩ @@ -252,6 +272,11 @@ private lemma height_add_const (a : α) (n : ℕ∞) : have := length_le_height_last (p := p.snoc y (by simp [*])) simpa using this +/- For elements of finite height, `coheight` is strictly antitone. -/ +@[gcongr] lemma coheight_strictAnti {x y : α} (hyx : y < x) (hfin : coheight x < ⊤) : + coheight x < coheight y := + height_strictMono (α := αᵒᵈ) hyx hfin + lemma height_le_height_apply_of_strictMono (f : α → β) (hf : StrictMono f) (x : α) : height x ≤ height (f x) := by simp only [height_eq_iSup_last_eq] @@ -648,4 +673,157 @@ lemma coheight_bot_eq_krullDim [OrderBot α] : coheight (⊥ : α) = krullDim α end krullDim +/-! +## Concrete calculations +-/ + +section calculations + +variable {α : Type*} [Preorder α] + +/- +These two lemmas could possibly be used to simplify the subsequent calculations, +especially once the `Set.encard` api is richer. + +(Commented out to avoid importing modules purely for `proof_wanted`.) +proof_wanted height_of_linearOrder {α : Type*} [LinearOrder α] (a : α) : + height a = (Set.Iio a).encard + +proof_wanted coheight_of_linearOrder {α : Type*} [LinearOrder α] (a : α) : + coheight a = (Set.Ioi a).encard +-/ + +@[simp] lemma height_nat (n : ℕ) : height n = n := by + induction n using Nat.strongRecOn with | ind n ih => + apply le_antisymm + · apply height_le_coe_iff.mpr + simp +contextual only [ih, Nat.cast_lt, implies_true] + · exact length_le_height_last (p := LTSeries.range n) + +@[simp] lemma coheight_of_noMaxOrder [NoMaxOrder α] (a : α) : coheight a = ⊤ := by + obtain ⟨f, hstrictmono⟩ := Nat.exists_strictMono ↑(Set.Ioi a) + apply coheight_eq_top_iff.mpr + intro m + use {length := m, toFun := fun i => if i = 0 then a else f i, step := ?step } + case h => simp [RelSeries.head] + case step => + intro ⟨i, hi⟩ + by_cases hzero : i = 0 + · subst i + exact (f 1).prop + · suffices f i < f (i + 1) by simp [Fin.ext_iff, hzero, this] + apply hstrictmono + omega + +@[simp] lemma height_of_noMinOrder [NoMinOrder α] (a : α) : height a = ⊤ := + -- Implementation note: Here it's a bit easier to define the coheight variant first + coheight_of_noMaxOrder (α := αᵒᵈ) a + +@[simp] lemma krullDim_of_noMaxOrder [Nonempty α] [NoMaxOrder α] : krullDim α = ⊤ := by + simp [krullDim_eq_iSup_coheight, coheight_of_noMaxOrder] + +@[simp] lemma krullDim_of_noMinOrder [Nonempty α] [NoMinOrder α] : krullDim α = ⊤ := by + simp [krullDim_eq_iSup_height, height_of_noMinOrder] + +lemma coheight_nat (n : ℕ) : coheight n = ⊤ := coheight_of_noMaxOrder .. + +lemma krullDim_nat : krullDim ℕ = ⊤ := krullDim_of_noMaxOrder .. + +lemma height_int (n : ℤ) : height n = ⊤ := height_of_noMinOrder .. + +lemma coheight_int (n : ℤ) : coheight n = ⊤ := coheight_of_noMaxOrder .. + +lemma krullDim_int : krullDim ℤ = ⊤ := krullDim_of_noMaxOrder .. + +@[simp] lemma height_coe_withBot (x : α) : height (x : WithBot α) = height x + 1 := by + apply le_antisymm + · apply height_le + intro p hlast + wlog hlenpos : p.length ≠ 0 + · simp_all + -- essentially p' := (p.drop 1).map unbot + let p' : LTSeries α := { + length := p.length - 1 + toFun := fun ⟨i, hi⟩ => (p ⟨i+1, by omega⟩).unbot (by + apply LT.lt.ne_bot (a := p.head) + apply p.strictMono + exact compare_gt_iff_gt.mp rfl) + step := fun i => by simpa [WithBot.unbot_lt_iff] using p.step ⟨i + 1, by omega⟩ } + have hlast' : p'.last = x := by + simp only [RelSeries.last, Fin.val_last, WithBot.unbot_eq_iff, ← hlast, Fin.last] + congr + omega + suffices p'.length ≤ height p'.last by + simpa [p', hlast'] using this + apply length_le_height_last + · rw [height_add_const] + apply iSup₂_le + intro p hlast + let p' := (p.map _ WithBot.coe_strictMono).cons ⊥ (by simp) + apply le_iSup₂_of_le p' (by simp [p', hlast]) (by simp [p']) + +@[simp] lemma coheight_coe_withTop (x : α) : coheight (x : WithTop α) = coheight x + 1 := + height_coe_withBot (α := αᵒᵈ) x + +@[simp] lemma height_coe_withTop (x : α) : height (x : WithTop α) = height x := by + apply le_antisymm + · apply height_le + intro p hlast + -- essentially p' := p.map untop + let p' : LTSeries α := { + length := p.length + toFun := fun i => (p i).untop (by + apply WithTop.lt_top_iff_ne_top.mp + apply lt_of_le_of_lt + · exact p.monotone (Fin.le_last _) + · rw [RelSeries.last] at hlast + simp [hlast]) + step := fun i => by simpa only [WithTop.untop_lt_iff, WithTop.coe_untop] using p.step i } + have hlast' : p'.last = x := by + simp only [RelSeries.last, Fin.val_last, WithTop.untop_eq_iff, ← hlast] + suffices p'.length ≤ height p'.last by + rw [hlast'] at this + simpa [p'] using this + apply length_le_height_last + · apply height_le + intro p hlast + let p' := p.map _ WithTop.coe_strictMono + apply le_iSup₂_of_le p' (by simp [p', hlast]) (by simp [p']) + +@[simp] lemma coheight_coe_withBot (x : α) : coheight (x : WithBot α) = coheight x := + height_coe_withTop (α := αᵒᵈ) x + +@[simp] lemma krullDim_WithTop [Nonempty α] : krullDim (WithTop α) = krullDim α + 1 := by + rw [← height_top_eq_krullDim, krullDim_eq_iSup_height_of_nonempty, height_eq_iSup_lt_height] + norm_cast + simp_rw [WithTop.lt_top_iff_ne_top] + rw [ENat.iSup_add, iSup_subtype'] + symm + apply Equiv.withTopSubtypeNe.symm.iSup_congr + simp + +@[simp] lemma krullDim_withBot [Nonempty α] : krullDim (WithBot α) = krullDim α + 1 := by + conv_lhs => rw [← krullDim_orderDual] + conv_rhs => rw [← krullDim_orderDual] + exact krullDim_WithTop (α := αᵒᵈ) + +@[simp] +lemma krullDim_enat : krullDim ℕ∞ = ⊤ := by + show (krullDim (WithTop ℕ) = ⊤) + simp only [krullDim_WithTop, krullDim_nat] + rfl + +@[simp] +lemma height_enat (n : ℕ∞) : height n = n := by + cases n with + | top => simp only [← WithBot.coe_eq_coe, height_top_eq_krullDim, krullDim_enat, WithBot.coe_top] + | coe n => exact (height_coe_withTop _).trans (height_nat _) + +@[simp] +lemma coheight_coe_enat (n : ℕ) : coheight (n : ℕ∞) = ⊤ := by + apply (coheight_coe_withTop _).trans + simp only [Nat.cast_id, coheight_nat, top_add] + +end calculations + end Order diff --git a/Mathlib/Order/LiminfLimsup.lean b/Mathlib/Order/LiminfLimsup.lean index 25404163646dc6..6cdea2ca4d772c 100644 --- a/Mathlib/Order/LiminfLimsup.lean +++ b/Mathlib/Order/LiminfLimsup.lean @@ -46,17 +46,6 @@ namespace Filter section Relation -/-- `f.IsBounded (≺)`: the filter `f` is eventually bounded w.r.t. the relation `≺`, i.e. -eventually, it is bounded by some uniform bound. -`r` will be usually instantiated with `≤` or `≥`. -/ -def IsBounded (r : α → α → Prop) (f : Filter α) := - ∃ b, ∀ᶠ x in f, r x b - -/-- `f.IsBoundedUnder (≺) u`: the image of the filter `f` under `u` is eventually bounded w.r.t. -the relation `≺`, i.e. eventually, it is bounded by some uniform bound. -/ -def IsBoundedUnder (r : α → α → Prop) (f : Filter β) (u : β → α) := - (map u f).IsBounded r - variable {r : α → α → Prop} {f g : Filter α} /-- `f` is eventually bounded if and only if, there exists an admissible set on which it is @@ -218,25 +207,6 @@ theorem IsBoundedUnder.bddBelow_range [Preorder β] [IsDirected β (· ≥ ·)] (hf : IsBoundedUnder (· ≥ ·) atTop f) : BddBelow (range f) := IsBoundedUnder.bddAbove_range (β := βᵒᵈ) hf -/-- `IsCobounded (≺) f` states that the filter `f` does not tend to infinity w.r.t. `≺`. This is -also called frequently bounded. Will be usually instantiated with `≤` or `≥`. - -There is a subtlety in this definition: we want `f.IsCobounded` to hold for any `f` in the case of -complete lattices. This will be relevant to deduce theorems on complete lattices from their -versions on conditionally complete lattices with additional assumptions. We have to be careful in -the edge case of the trivial filter containing the empty set: the other natural definition - `¬ ∀ a, ∀ᶠ n in f, a ≤ n` -would not work as well in this case. --/ -def IsCobounded (r : α → α → Prop) (f : Filter α) := - ∃ b, ∀ a, (∀ᶠ x in f, r x a) → r b a - -/-- `IsCoboundedUnder (≺) f u` states that the image of the filter `f` under the map `u` does not -tend to infinity w.r.t. `≺`. This is also called frequently bounded. Will be usually instantiated -with `≤` or `≥`. -/ -def IsCoboundedUnder (r : α → α → Prop) (f : Filter β) (u : β → α) := - (map u f).IsCobounded r - /-- To check that a filter is frequently bounded, it suffices to have a witness which bounds `f` at some point for every admissible set. @@ -829,15 +799,13 @@ theorem HasBasis.limsup_eq_sInf_univ_of_empty {f : ι → α} {v : Filter ι} limsup f v = sInf univ := HasBasis.liminf_eq_sSup_univ_of_empty (α := αᵒᵈ) hv i hi h'i --- Porting note: simp_nf linter incorrectly says: lhs does not simplify when using simp on itself. -@[simp, nolint simpNF] +@[simp] theorem liminf_nat_add (f : ℕ → α) (k : ℕ) : liminf (fun i => f (i + k)) atTop = liminf f atTop := by change liminf (f ∘ (· + k)) atTop = liminf f atTop rw [liminf, liminf, ← map_map, map_add_atTop_eq_nat] --- Porting note: simp_nf linter incorrectly says: lhs does not simplify when using simp on itself. -@[simp, nolint simpNF] +@[simp] theorem limsup_nat_add (f : ℕ → α) (k : ℕ) : limsup (fun i => f (i + k)) atTop = limsup f atTop := @liminf_nat_add αᵒᵈ _ f k diff --git a/Mathlib/Order/Max.lean b/Mathlib/Order/Max.lean index 36518a3cb4aa5b..7cf8fc7da8e5c5 100644 --- a/Mathlib/Order/Max.lean +++ b/Mathlib/Order/Max.lean @@ -200,6 +200,14 @@ protected theorem IsBot.isMin (h : IsBot a) : IsMin a := fun b _ => h b protected theorem IsTop.isMax (h : IsTop a) : IsMax a := fun b _ => h b +theorem IsTop.isMax_iff {α} [PartialOrder α] {i j : α} (h : IsTop i) : IsMax j ↔ j = i := by + simp_rw [le_antisymm_iff, h j, true_and] + exact ⟨(· (h j)), Function.swap (fun _ ↦ h · |>.trans ·)⟩ + +theorem IsBot.isMin_iff {α} [PartialOrder α] {i j : α} (h : IsBot i) : IsMin j ↔ j = i := by + simp_rw [le_antisymm_iff, h j, and_true] + exact ⟨fun a ↦ a (h j), fun a h' ↦ fun _ ↦ Preorder.le_trans j i h' a (h h')⟩ + @[simp] theorem isBot_toDual_iff : IsBot (toDual a) ↔ IsTop a := Iff.rfl diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index 309394381dfc2e..c34eaa969055e8 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -731,7 +731,7 @@ theorem apply_mono {f g : α →𝒄 β} {x y : α} (h₁ : f ≤ g) (h₂ : x OrderHom.apply_mono (show (f : α →o β) ≤ g from h₁) h₂ set_option linter.deprecated false in -@[deprecated (since := "2024-07-27")] +@[deprecated "No deprecation message was provided." (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 [*] @@ -802,11 +802,11 @@ theorem seq_continuous' {β γ : Type v} (f : α → Part (β → γ)) (g : α intro apply map_continuous' _ _ hg +set_option linter.deprecated true + theorem continuous (F : α →𝒄 β) (C : Chain α) : F (ωSup C) = ωSup (C.map F) := F.ωScottContinuous.map_ωSup _ -set_option linter.deprecated true - /-- Construct a continuous function from a bare function, a continuous function, and a proof that they are equal. -/ -- Porting note: removed `@[reducible]` diff --git a/Mathlib/Order/RelClasses.lean b/Mathlib/Order/RelClasses.lean index 6fb587d189e2c8..0acae0e49466b4 100644 --- a/Mathlib/Order/RelClasses.lean +++ b/Mathlib/Order/RelClasses.lean @@ -17,8 +17,6 @@ extend `LE` and/or `LT` while these classes take a relation as an explicit argum -/ -set_option linter.deprecated false - universe u v variable {α : Type u} {β : Type v} {r : α → α → Prop} {s : β → β → Prop} @@ -88,7 +86,7 @@ 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")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] theorem IsLinearOrder.swap (r) [IsLinearOrder α r] : IsLinearOrder α (swap r) := { @IsPartialOrder.swap α r _, @IsTotal.swap α r _ with } @@ -214,7 +212,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")] +@[deprecated "No deprecation message was provided." (since := "2024-07-30")] instance (priority := 100) isStrictTotalOrder_of_isStrictTotalOrder [IsStrictTotalOrder α r] : IsStrictWeakOrder α r := { isStrictWeakOrder_of_isOrderConnected with } @@ -782,7 +780,7 @@ instance [LinearOrder α] : IsStrictTotalOrder α (· < ·) where instance [LinearOrder α] : IsOrderConnected α (· < ·) := by infer_instance -@[deprecated (since := "2024-07-30")] +@[deprecated "No deprecation message was provided." (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 721ef0208ee6d9..cc0083a0b26765 100644 --- a/Mathlib/Order/RelIso/Basic.lean +++ b/Mathlib/Order/RelIso/Basic.lean @@ -363,13 +363,17 @@ noncomputable def Quotient.outRelEmbedding {_ : Setoid α} {r : α → α → Pr refine @fun x y => Quotient.inductionOn₂ x y fun a b => ?_ apply iff_iff_eq.2 (H _ _ _ _ _ _) <;> apply Quotient.mk_out⟩ +set_option linter.deprecated false in /-- `Quotient.out'` as a relation embedding between the lift of a relation and the relation. -/ -@[simps] +@[deprecated Quotient.outRelEmbedding (since := "2024-10-19"), simps] noncomputable def Quotient.out'RelEmbedding {_ : Setoid α} {r : α → α → Prop} (H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂) : (fun a b => Quotient.liftOn₂' a b r H) ↪r r := { Quotient.outRelEmbedding H with toFun := Quotient.out' } +attribute [deprecated Quotient.outRelEmbedding_apply (since := "2024-10-19")] + Quotient.out'RelEmbedding_apply + @[simp] theorem acc_lift₂_iff {_ : Setoid α} {r : α → α → Prop} {H : ∀ (a₁ b₁ a₂ b₂ : α), a₁ ≈ a₂ → b₁ ≈ b₂ → r a₁ b₁ = r a₂ b₂} {a} : diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index b2c41395b294b7..e385b759958c2f 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -112,9 +112,9 @@ corresponds to each other. -/ protected def Equiv : RelSeries r ≃ {x : List α | x ≠ [] ∧ x.Chain' r} where toFun x := ⟨_, x.toList_ne_nil, x.toList_chain'⟩ invFun x := fromListChain' _ x.2.1 x.2.2 - left_inv x := ext (by simp [toList]) <| by ext; apply List.get_ofFn + left_inv x := ext (by simp [toList]) <| by ext; dsimp; apply List.get_ofFn right_inv x := by - refine Subtype.ext (List.ext_get ?_ fun n hn1 _ => List.get_ofFn _ _) + refine Subtype.ext (List.ext_get ?_ fun n hn1 _ => by dsimp; apply List.get_ofFn) have := Nat.succ_pred_eq_of_pos <| List.length_pos.mpr x.2.1 simp_all [toList] diff --git a/Mathlib/Order/SuccPred/Basic.lean b/Mathlib/Order/SuccPred/Basic.lean index 55b6157d4a5db5..ac3781d7a43509 100644 --- a/Mathlib/Order/SuccPred/Basic.lean +++ b/Mathlib/Order/SuccPred/Basic.lean @@ -992,7 +992,7 @@ namespace WithTop section Succ -variable [DecidableEq α] [PartialOrder α] [SuccOrder α] +variable [PartialOrder α] [SuccOrder α] [∀ a : α, Decidable (succ a = a)] instance : SuccOrder (WithTop α) where succ a := @@ -1144,7 +1144,7 @@ end Succ section Pred -variable [DecidableEq α] [PartialOrder α] [PredOrder α] +variable [PartialOrder α] [PredOrder α] [∀ a : α, Decidable (pred a = a)] instance : PredOrder (WithBot α) where pred a := diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index 61ddd8850360c8..84fdcccc76f9d8 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -79,6 +79,17 @@ lemma supClosed_pi {ι : Type*} {α : ι → Type*} [∀ i, SemilatticeSup (α i {t : ∀ i, Set (α i)} (ht : ∀ i ∈ s, SupClosed (t i)) : SupClosed (s.pi t) := fun _a ha _b hb _i hi ↦ ht _ hi (ha _ hi) (hb _ hi) +lemma SupClosed.insert_upperBounds {s : Set α} {a : α} (hs : SupClosed s) (ha : a ∈ upperBounds s) : + SupClosed (insert a s) := by + rw [SupClosed] + aesop + +lemma SupClosed.insert_lowerBounds {s : Set α} {a : α} (h : SupClosed s) (ha : a ∈ lowerBounds s) : + SupClosed (insert a s) := by + rw [SupClosed] + have ha' : ∀ b ∈ s, a ≤ b := fun _ a ↦ ha a + aesop + end Set section Finset @@ -144,6 +155,17 @@ lemma infClosed_pi {ι : Type*} {α : ι → Type*} [∀ i, SemilatticeInf (α i {t : ∀ i, Set (α i)} (ht : ∀ i ∈ s, InfClosed (t i)) : InfClosed (s.pi t) := fun _a ha _b hb _i hi ↦ ht _ hi (ha _ hi) (hb _ hi) +lemma InfClosed.insert_upperBounds {s : Set α} {a : α} (hs : InfClosed s) (ha : a ∈ upperBounds s) : + InfClosed (insert a s) := by + rw [InfClosed] + have ha' : ∀ b ∈ s, b ≤ a := fun _ a ↦ ha a + aesop + +lemma InfClosed.insert_lowerBounds {s : Set α} {a : α} (h : InfClosed s) (ha : a ∈ lowerBounds s) : + InfClosed (insert a s) := by + rw [InfClosed] + aesop + end Set section Finset diff --git a/Mathlib/Order/SupIndep.lean b/Mathlib/Order/SupIndep.lean index 72e6dee904d747..2e74039869f405 100644 --- a/Mathlib/Order/SupIndep.lean +++ b/Mathlib/Order/SupIndep.lean @@ -18,19 +18,19 @@ sup-independent if, for all `a`, `f a` and the supremum of the rest are disjoint ## Main definitions * `Finset.SupIndep s f`: a family of elements `f` are supremum independent on the finite set `s`. -* `CompleteLattice.SetIndependent s`: a set of elements are supremum independent. -* `CompleteLattice.Independent f`: a family of elements are supremum independent. +* `sSupIndep s`: a set of elements are supremum independent. +* `iSupIndep f`: a family of elements are supremum independent. ## Main statements * In a distributive lattice, supremum independence is equivalent to pairwise disjointness: * `Finset.supIndep_iff_pairwiseDisjoint` - * `CompleteLattice.setIndependent_iff_pairwiseDisjoint` - * `CompleteLattice.independent_iff_pairwiseDisjoint` + * `CompleteLattice.sSupIndep_iff_pairwiseDisjoint` + * `CompleteLattice.iSupIndep_iff_pairwiseDisjoint` * Otherwise, supremum independence is stronger than pairwise disjointness: * `Finset.SupIndep.pairwiseDisjoint` - * `CompleteLattice.SetIndependent.pairwiseDisjoint` - * `CompleteLattice.Independent.pairwiseDisjoint` + * `sSupIndep.pairwiseDisjoint` + * `iSupIndep.pairwiseDisjoint` ## Implementation notes @@ -88,7 +88,7 @@ theorem SupIndep.le_sup_iff (hs : s.SupIndep f) (hts : t ⊆ s) (hi : i ∈ s) ( by_contra hit exact hf i (disjoint_self.1 <| (hs hts hi hit).mono_right h) -/-- The RHS looks like the definition of `CompleteLattice.Independent`. -/ +/-- The RHS looks like the definition of `iSupIndep`. -/ theorem supIndep_iff_disjoint_erase [DecidableEq ι] : s.SupIndep f ↔ ∀ i ∈ s, Disjoint (f i) ((s.erase i).sup f) := ⟨fun hs _ hi => hs (erase_subset _ _) hi (not_mem_erase _ _), fun hs _ ht i hi hit => @@ -181,19 +181,7 @@ theorem SupIndep.attach (hs : s.SupIndep f) : s.attach.SupIndep fun a => f a := obtain ⟨j, hj, hji⟩ := hi' rwa [Subtype.ext hji] at hj -/- -Porting note: simpNF linter returns - -"Left-hand side does not simplify, when using the simp lemma on itself." - -However, simp does indeed solve the following. - -example {α ι} [Lattice α] [OrderBot α] (s : Finset ι) (f : ι → α) : - (s.attach.SupIndep fun a => f a) ↔ s.SupIndep f := by simp - -See https://github.com/leanprover-community/batteries/issues/71 for the simpNF issue. --/ -@[simp, nolint simpNF] +@[simp] theorem supIndep_attach : (s.attach.SupIndep fun a => f a) ↔ s.SupIndep f := by refine ⟨fun h t ht i his hit => ?_, SupIndep.attach⟩ classical @@ -282,38 +270,48 @@ end Finset /-! ### On complete lattices via `sSup` -/ - -namespace CompleteLattice - +section CompleteLattice variable [CompleteLattice α] open Set Function /-- An independent set of elements in a complete lattice is one in which every element is disjoint from the `Sup` of the rest. -/ -def SetIndependent (s : Set α) : Prop := +def sSupIndep (s : Set α) : Prop := ∀ ⦃a⦄, a ∈ s → Disjoint a (sSup (s \ {a})) -variable {s : Set α} (hs : SetIndependent s) +@[deprecated (since := "2024-11-24")] alias CompleteLattice.SetIndependent := sSupIndep + +variable {s : Set α} (hs : sSupIndep s) @[simp] -theorem setIndependent_empty : SetIndependent (∅ : Set α) := fun x hx => +theorem sSupIndep_empty : sSupIndep (∅ : Set α) := fun x hx => (Set.not_mem_empty x hx).elim +@[deprecated (since := "2024-11-24")] alias CompleteLattice.setIndependent_empty := sSupIndep_empty + include hs in -theorem SetIndependent.mono {t : Set α} (hst : t ⊆ s) : SetIndependent t := fun _ ha => +theorem sSupIndep.mono {t : Set α} (hst : t ⊆ s) : sSupIndep t := fun _ ha => (hs (hst ha)).mono_right (sSup_le_sSup (diff_subset_diff_left hst)) +@[deprecated (since := "2024-11-24")] alias CompleteLattice.SetIndependent.mono := sSupIndep.mono + include hs in /-- If the elements of a set are independent, then any pair within that set is disjoint. -/ -theorem SetIndependent.pairwiseDisjoint : s.PairwiseDisjoint id := fun _ hx y hy h => +theorem sSupIndep.pairwiseDisjoint : s.PairwiseDisjoint id := fun _ hx y hy h => disjoint_sSup_right (hs hx) ((mem_diff y).mpr ⟨hy, h.symm⟩) -theorem setIndependent_singleton (a : α) : SetIndependent ({a} : Set α) := fun i hi ↦ by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.SetIndependent.pairwiseDisjoint := sSupIndep.pairwiseDisjoint + +theorem sSupIndep_singleton (a : α) : sSupIndep ({a} : Set α) := fun i hi ↦ by simp_all -theorem setIndependent_pair {a b : α} (hab : a ≠ b) : - SetIndependent ({a, b} : Set α) ↔ Disjoint a b := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.setIndependent_singleton := sSupIndep_singleton + +theorem sSupIndep_pair {a b : α} (hab : a ≠ b) : + sSupIndep ({a, b} : Set α) ↔ Disjoint a b := by constructor · intro h exact h.pairwiseDisjoint (mem_insert _ _) (mem_insert_of_mem _ (mem_singleton _)) hab @@ -323,15 +321,20 @@ theorem setIndependent_pair {a b : α} (hab : a ≠ b) : · convert h.symm using 1 simp [hab, sSup_singleton] +@[deprecated (since := "2024-11-24")] alias CompleteLattice.setIndependent_pair := sSupIndep_pair + include hs in /-- If the elements of a set are independent, then any element is disjoint from the `sSup` of some subset of the rest. -/ -theorem SetIndependent.disjoint_sSup {x : α} {y : Set α} (hx : x ∈ s) (hy : y ⊆ s) (hxy : x ∉ y) : +theorem sSupIndep.disjoint_sSup {x : α} {y : Set α} (hx : x ∈ s) (hy : y ⊆ s) (hxy : x ∉ y) : Disjoint x (sSup y) := by have := (hs.mono <| insert_subset_iff.mpr ⟨hx, hy⟩) (mem_insert x _) rw [insert_diff_of_mem _ (mem_singleton _), diff_singleton_eq_self hxy] at this exact this +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.SetIndependent.disjoint_sSup := sSupIndep.disjoint_sSup + /-- An independent indexed family of elements in a complete lattice is one in which every element is disjoint from the `iSup` of the rest. @@ -341,70 +344,96 @@ theorem SetIndependent.disjoint_sSup {x : α} {y : Set α} (hx : x ∈ s) (hy : Example: an indexed family of submodules of a module is independent in this sense if and only the natural map from the direct sum of the submodules to the module is injective. -/ -def Independent {ι : Sort*} {α : Type*} [CompleteLattice α] (t : ι → α) : Prop := +def iSupIndep {ι : Sort*} {α : Type*} [CompleteLattice α] (t : ι → α) : Prop := ∀ i : ι, Disjoint (t i) (⨆ (j) (_ : j ≠ i), t j) -theorem setIndependent_iff {α : Type*} [CompleteLattice α] (s : Set α) : - SetIndependent s ↔ Independent ((↑) : s → α) := by - simp_rw [Independent, SetIndependent, SetCoe.forall, sSup_eq_iSup] +@[deprecated (since := "2024-11-24")] alias CompleteLattice.Independent := iSupIndep + +theorem sSupIndep_iff {α : Type*} [CompleteLattice α] (s : Set α) : + sSupIndep s ↔ iSupIndep ((↑) : s → α) := by + simp_rw [iSupIndep, sSupIndep, SetCoe.forall, sSup_eq_iSup] refine forall₂_congr fun a ha => ?_ simp [iSup_subtype, iSup_and] -variable {t : ι → α} (ht : Independent t) +@[deprecated (since := "2024-11-24")] alias CompleteLattice.setIndependent_iff := sSupIndep_iff -theorem independent_def : Independent t ↔ ∀ i : ι, Disjoint (t i) (⨆ (j) (_ : j ≠ i), t j) := +variable {t : ι → α} (ht : iSupIndep t) + +theorem iSupIndep_def : iSupIndep t ↔ ∀ i, Disjoint (t i) (⨆ (j) (_ : j ≠ i), t j) := Iff.rfl -theorem independent_def' : Independent t ↔ ∀ i, Disjoint (t i) (sSup (t '' { j | j ≠ i })) := by +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_def := iSupIndep_def + +theorem iSupIndep_def' : iSupIndep t ↔ ∀ i, Disjoint (t i) (sSup (t '' { j | j ≠ i })) := by simp_rw [sSup_image] rfl -theorem independent_def'' : - Independent t ↔ ∀ i, Disjoint (t i) (sSup { a | ∃ j ≠ i, t j = a }) := by - rw [independent_def'] +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_def' := iSupIndep_def' + +theorem iSupIndep_def'' : + iSupIndep t ↔ ∀ i, Disjoint (t i) (sSup { a | ∃ j ≠ i, t j = a }) := by + rw [iSupIndep_def'] aesop +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_def'' := iSupIndep_def'' + @[simp] -theorem independent_empty (t : Empty → α) : Independent t := +theorem iSupIndep_empty (t : Empty → α) : iSupIndep t := nofun +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_empty := iSupIndep_empty + @[simp] -theorem independent_pempty (t : PEmpty → α) : Independent t := +theorem iSupIndep_pempty (t : PEmpty → α) : iSupIndep t := nofun +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_pempty := iSupIndep_pempty + include ht in /-- If the elements of a set are independent, then any pair within that set is disjoint. -/ -theorem Independent.pairwiseDisjoint : Pairwise (Disjoint on t) := fun x y h => +theorem iSupIndep.pairwiseDisjoint : Pairwise (Disjoint on t) := fun x y h => disjoint_sSup_right (ht x) ⟨y, iSup_pos h.symm⟩ -theorem Independent.mono {s t : ι → α} (hs : Independent s) (hst : t ≤ s) : Independent t := +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.pairwiseDisjoint := iSupIndep.pairwiseDisjoint + +theorem iSupIndep.mono {s t : ι → α} (hs : iSupIndep s) (hst : t ≤ s) : iSupIndep t := fun i => (hs i).mono (hst i) <| iSup₂_mono fun j _ => hst j +@[deprecated (since := "2024-11-24")] alias CompleteLattice.Independent.mono := iSupIndep.mono + /-- Composing an independent indexed family with an injective function on the index results in another indepedendent indexed family. -/ -theorem Independent.comp {ι ι' : Sort*} {t : ι → α} {f : ι' → ι} (ht : Independent t) - (hf : Injective f) : Independent (t ∘ f) := fun i => +theorem iSupIndep.comp {ι ι' : Sort*} {t : ι → α} {f : ι' → ι} (ht : iSupIndep t) + (hf : Injective f) : iSupIndep (t ∘ f) := fun i => (ht (f i)).mono_right <| by refine (iSup_mono fun i => ?_).trans (iSup_comp_le _ f) exact iSup_const_mono hf.ne -theorem Independent.comp' {ι ι' : Sort*} {t : ι → α} {f : ι' → ι} (ht : Independent <| t ∘ f) - (hf : Surjective f) : Independent t := by +@[deprecated (since := "2024-11-24")] alias CompleteLattice.Independent.comp := iSupIndep.comp + +theorem iSupIndep.comp' {ι ι' : Sort*} {t : ι → α} {f : ι' → ι} (ht : iSupIndep <| t ∘ f) + (hf : Surjective f) : iSupIndep t := by intro i obtain ⟨i', rfl⟩ := hf i rw [← hf.iSup_comp] exact (ht i').mono_right (biSup_mono fun j' hij => mt (congr_arg f) hij) -theorem Independent.setIndependent_range (ht : Independent t) : SetIndependent <| range t := by - rw [setIndependent_iff] +@[deprecated (since := "2024-11-24")] alias CompleteLattice.Independent.comp' := iSupIndep.comp' + +theorem iSupIndep.sSupIndep_range (ht : iSupIndep t) : sSupIndep <| range t := by + rw [sSupIndep_iff] rw [← coe_comp_rangeFactorization t] at ht exact ht.comp' surjective_onto_range +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.setIndependent_range := iSupIndep.sSupIndep_range + @[simp] -theorem independent_ne_bot_iff_independent : - Independent (fun i : {i // t i ≠ ⊥} ↦ t i) ↔ Independent t := by +theorem iSupIndep_ne_bot : + iSupIndep (fun i : {i // t i ≠ ⊥} ↦ t i) ↔ iSupIndep t := by refine ⟨fun h ↦ ?_, fun h ↦ h.comp Subtype.val_injective⟩ - simp only [independent_def] at h ⊢ + simp only [iSupIndep_def] at h ⊢ intro i cases eq_or_ne (t i) ⊥ with | inl hi => simp [hi] @@ -415,7 +444,10 @@ theorem independent_ne_bot_iff_independent : simp only [iSup_comm (ι' := _ ≠ i), this, ne_eq, sup_of_le_right, Subtype.mk.injEq, iSup_bot, bot_le] -theorem Independent.injOn (ht : Independent t) : InjOn t {i | t i ≠ ⊥} := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_ne_bot_iff_independent := iSupIndep_ne_bot + +theorem iSupIndep.injOn (ht : iSupIndep t) : InjOn t {i | t i ≠ ⊥} := by rintro i _ j (hj : t j ≠ ⊥) h by_contra! contra apply hj @@ -426,12 +458,17 @@ theorem Independent.injOn (ht : Independent t) : InjOn t {i | t i ≠ ⊥} := by -- Porting note: needs explicit `f` exact le_iSup₂ (f := fun x _ ↦ t x) j contra -theorem Independent.injective (ht : Independent t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Injective t := by +@[deprecated (since := "2024-11-24")] alias CompleteLattice.Independent.injOn := iSupIndep.injOn + +theorem iSupIndep.injective (ht : iSupIndep t) (h_ne_bot : ∀ i, t i ≠ ⊥) : Injective t := by suffices univ = {i | t i ≠ ⊥} by rw [injective_iff_injOn_univ, this]; exact ht.injOn aesop -theorem independent_pair {i j : ι} (hij : i ≠ j) (huniv : ∀ k, k = i ∨ k = j) : - Independent t ↔ Disjoint (t i) (t j) := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.injective := iSupIndep.injective + +theorem iSupIndep_pair {i j : ι} (hij : i ≠ j) (huniv : ∀ k, k = i ∨ k = j) : + iSupIndep t ↔ Disjoint (t i) (t j) := by constructor · exact fun h => h.pairwiseDisjoint hij · rintro h k @@ -441,37 +478,49 @@ theorem independent_pair {i j : ι} (hij : i ≠ j) (huniv : ∀ k, k = i ∨ k · refine h.symm.mono_right (iSup_le fun j => iSup_le fun hj => Eq.le ?_) rw [(huniv j).resolve_right hj] +@[deprecated (since := "2024-11-24")] alias CompleteLattice.independent_pair := iSupIndep_pair + /-- Composing an independent indexed family with an order isomorphism on the elements results in another independent indexed family. -/ -theorem Independent.map_orderIso {ι : Sort*} {α β : Type*} [CompleteLattice α] - [CompleteLattice β] (f : α ≃o β) {a : ι → α} (ha : Independent a) : Independent (f ∘ a) := +theorem iSupIndep.map_orderIso {ι : Sort*} {α β : Type*} [CompleteLattice α] + [CompleteLattice β] (f : α ≃o β) {a : ι → α} (ha : iSupIndep a) : iSupIndep (f ∘ a) := fun i => ((ha i).map_orderIso f).mono_right (f.monotone.le_map_iSup₂ _) +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.map_orderIso := iSupIndep.map_orderIso + @[simp] -theorem independent_map_orderIso_iff {ι : Sort*} {α β : Type*} [CompleteLattice α] - [CompleteLattice β] (f : α ≃o β) {a : ι → α} : Independent (f ∘ a) ↔ Independent a := +theorem iSupIndep_map_orderIso_iff {ι : Sort*} {α β : Type*} [CompleteLattice α] + [CompleteLattice β] (f : α ≃o β) {a : ι → α} : iSupIndep (f ∘ a) ↔ iSupIndep a := ⟨fun h => have hf : f.symm ∘ f ∘ a = a := congr_arg (· ∘ a) f.left_inv.comp_eq_id hf ▸ h.map_orderIso f.symm, fun h => h.map_orderIso f⟩ +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_map_orderIso_iff := iSupIndep_map_orderIso_iff + /-- If the elements of a set are independent, then any element is disjoint from the `iSup` of some subset of the rest. -/ -theorem Independent.disjoint_biSup {ι : Type*} {α : Type*} [CompleteLattice α] {t : ι → α} - (ht : Independent t) {x : ι} {y : Set ι} (hx : x ∉ y) : Disjoint (t x) (⨆ i ∈ y, t i) := +theorem iSupIndep.disjoint_biSup {ι : Type*} {α : Type*} [CompleteLattice α] {t : ι → α} + (ht : iSupIndep t) {x : ι} {y : Set ι} (hx : x ∉ y) : Disjoint (t x) (⨆ i ∈ y, t i) := Disjoint.mono_right (biSup_mono fun _ hi => (ne_of_mem_of_not_mem hi hx : _)) (ht x) -lemma independent_of_independent_coe_Iic_comp {ι : Sort*} {a : α} {t : ι → Set.Iic a} - (ht : Independent ((↑) ∘ t : ι → α)) : Independent t := by +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.disjoint_biSup := iSupIndep.disjoint_biSup + +lemma iSupIndep.of_coe_Iic_comp {ι : Sort*} {a : α} {t : ι → Set.Iic a} + (ht : iSupIndep ((↑) ∘ t : ι → α)) : iSupIndep t := by intro i x specialize ht i simp_rw [Function.comp_apply, ← Set.Iic.coe_iSup] at ht exact @ht x -end CompleteLattice +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_of_independent_coe_Iic_comp := iSupIndep.of_coe_Iic_comp -theorem CompleteLattice.independent_iff_supIndep [CompleteLattice α] {s : Finset ι} {f : ι → α} : - CompleteLattice.Independent (f ∘ ((↑) : s → ι)) ↔ s.SupIndep f := by +theorem iSupIndep_iff_supIndep {s : Finset ι} {f : ι → α} : + iSupIndep (f ∘ ((↑) : s → ι)) ↔ s.SupIndep f := by classical rw [Finset.supIndep_iff_disjoint_erase] refine Subtype.forall.trans (forall₂_congr fun a b => ?_) @@ -481,39 +530,47 @@ theorem CompleteLattice.independent_iff_supIndep [CompleteLattice α] {s : Finse congr! 1 simp [iSup_and, @iSup_comm _ (_ ∈ s)] -alias ⟨CompleteLattice.Independent.supIndep, Finset.SupIndep.independent⟩ := - CompleteLattice.independent_iff_supIndep +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_iff_supIndep := iSupIndep_iff_supIndep + +alias ⟨iSupIndep.supIndep, Finset.SupIndep.independent⟩ := iSupIndep_iff_supIndep + +theorem iSupIndep.supIndep' {f : ι → α} (s : Finset ι) (h : iSupIndep f) : s.SupIndep f := + iSupIndep.supIndep (h.comp Subtype.coe_injective) -theorem CompleteLattice.Independent.supIndep' [CompleteLattice α] {f : ι → α} (s : Finset ι) - (h : CompleteLattice.Independent f) : s.SupIndep f := - CompleteLattice.Independent.supIndep (h.comp Subtype.coe_injective) +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.Independent.supIndep' := iSupIndep.supIndep' -/-- A variant of `CompleteLattice.independent_iff_supIndep` for `Fintype`s. -/ -theorem CompleteLattice.independent_iff_supIndep_univ [CompleteLattice α] [Fintype ι] {f : ι → α} : - CompleteLattice.Independent f ↔ Finset.univ.SupIndep f := by +/-- A variant of `CompleteLattice.iSupIndep_iff_supIndep` for `Fintype`s. -/ +theorem iSupIndep_iff_supIndep_univ [Fintype ι] {f : ι → α} : + iSupIndep f ↔ Finset.univ.SupIndep f := by classical - simp [Finset.supIndep_iff_disjoint_erase, CompleteLattice.Independent, Finset.sup_eq_iSup] + simp [Finset.supIndep_iff_disjoint_erase, iSupIndep, Finset.sup_eq_iSup] -alias ⟨CompleteLattice.Independent.sup_indep_univ, Finset.SupIndep.independent_of_univ⟩ := - CompleteLattice.independent_iff_supIndep_univ +@[deprecated (since := "2024-11-24")] +alias CompleteLattice.independent_iff_supIndep_univ := iSupIndep_iff_supIndep_univ -section Frame +alias ⟨iSupIndep.sup_indep_univ, Finset.SupIndep.iSupIndep_of_univ⟩ := iSupIndep_iff_supIndep_univ -namespace CompleteLattice +end CompleteLattice +section Frame variable [Order.Frame α] -theorem setIndependent_iff_pairwiseDisjoint {s : Set α} : - SetIndependent s ↔ s.PairwiseDisjoint id := - ⟨SetIndependent.pairwiseDisjoint, fun hs _ hi => +theorem sSupIndep_iff_pairwiseDisjoint {s : Set α} : sSupIndep s ↔ s.PairwiseDisjoint id := + ⟨sSupIndep.pairwiseDisjoint, fun hs _ hi => disjoint_sSup_iff.2 fun _ hj => hs hi hj.1 <| Ne.symm hj.2⟩ -alias ⟨_, _root_.Set.PairwiseDisjoint.setIndependent⟩ := setIndependent_iff_pairwiseDisjoint +@[deprecated (since := "2024-11-24")] +alias setIndependent_iff_pairwiseDisjoint := sSupIndep_iff_pairwiseDisjoint -theorem independent_iff_pairwiseDisjoint {f : ι → α} : Independent f ↔ Pairwise (Disjoint on f) := - ⟨Independent.pairwiseDisjoint, fun hs _ => +alias ⟨_, _root_.Set.PairwiseDisjoint.sSupIndep⟩ := sSupIndep_iff_pairwiseDisjoint + +theorem iSupIndep_iff_pairwiseDisjoint {f : ι → α} : iSupIndep f ↔ Pairwise (Disjoint on f) := + ⟨iSupIndep.pairwiseDisjoint, fun hs _ => disjoint_iSup_iff.2 fun _ => disjoint_iSup_iff.2 fun hij => hs hij.symm⟩ -end CompleteLattice +@[deprecated (since := "2024-11-24")] +alias independent_iff_pairwiseDisjoint := iSupIndep_iff_pairwiseDisjoint end Frame diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index d49c2f822a4fbb..5be2bf90e11575 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -158,6 +158,13 @@ theorem eq_unbot_iff {a : α} {b : WithBot α} (h : b ≠ ⊥) : · simpa using h rfl · simp +/-- The equivalence between the non-bottom elements of `WithBot α` and `α`. -/ +@[simps] def _root_.Equiv.withBotSubtypeNe : {y : WithBot α // y ≠ ⊥} ≃ α where + toFun := fun ⟨x,h⟩ => WithBot.unbot x h + invFun x := ⟨x, WithBot.coe_ne_bot⟩ + left_inv _ := by simp + right_inv _ := by simp + section LE variable [LE α] @@ -729,6 +736,13 @@ theorem eq_untop_iff {a : α} {b : WithTop α} (h : b ≠ ⊤) : a = b.untop h ↔ a = b := WithBot.eq_unbot_iff (α := αᵒᵈ) h +/-- The equivalence between the non-top elements of `WithTop α` and `α`. -/ +@[simps] def _root_.Equiv.withTopSubtypeNe : {y : WithTop α // y ≠ ⊤} ≃ α where + toFun := fun ⟨x,h⟩ => WithTop.untop x h + invFun x := ⟨x, WithTop.coe_ne_top⟩ + left_inv _ := by simp + right_inv _:= by simp + section LE variable [LE α] diff --git a/Mathlib/Probability/ConditionalProbability.lean b/Mathlib/Probability/ConditionalProbability.lean index 6dcf1ba7c951b2..4e4d89fc5ac915 100644 --- a/Mathlib/Probability/ConditionalProbability.lean +++ b/Mathlib/Probability/ConditionalProbability.lean @@ -70,8 +70,8 @@ and scaled by the inverse of `μ s` (to make it a probability measure): def cond (s : Set Ω) : Measure Ω := (μ s)⁻¹ • μ.restrict s -@[inherit_doc] scoped notation:max μ "[" t " | " s "]" => ProbabilityTheory.cond μ s t @[inherit_doc] scoped notation:max μ "[|" s "]" => ProbabilityTheory.cond μ s +@[inherit_doc cond] scoped notation3:max μ "[" t " | " s "]" => ProbabilityTheory.cond μ s t /-- The conditional probability measure of measure `μ` on `{ω | X ω ∈ s}`. @@ -172,7 +172,7 @@ theorem inter_pos_of_cond_ne_zero (hms : MeasurableSet s) (hcst : μ[t|s] ≠ 0) simp [hms, Set.inter_comm, cond] lemma cond_pos_of_inter_ne_zero [IsFiniteMeasure μ] (hms : MeasurableSet s) (hci : μ (s ∩ t) ≠ 0) : - 0 < μ[|s] t := by + 0 < μ[t | s] := by rw [cond_apply hms] refine ENNReal.mul_pos ?_ hci exact ENNReal.inv_ne_zero.mpr (measure_ne_top _ _) diff --git a/Mathlib/Probability/Independence/Basic.lean b/Mathlib/Probability/Independence/Basic.lean index cfa5d0c19e7b76..a7ef0fcd188d8e 100644 --- a/Mathlib/Probability/Independence/Basic.lean +++ b/Mathlib/Probability/Independence/Basic.lean @@ -721,4 +721,61 @@ theorem iIndepSet.iIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β end IndepFun +variable {ι Ω α β : Type*} {mΩ : MeasurableSpace Ω} {mα : MeasurableSpace α} + {mβ : MeasurableSpace β} {μ : Measure Ω} {X : ι → Ω → α} {Y : ι → Ω → β} {f : _ → Set Ω} + {t : ι → Set β} {s : Finset ι} + +/-- The probability of an intersection of preimages conditioning on another intersection factors +into a product. -/ +lemma cond_iInter [Finite ι] (hY : ∀ i, Measurable (Y i)) + (hindep : iIndepFun (fun _ ↦ mα.prod mβ) (fun i ω ↦ (X i ω, Y i ω)) μ) + (hf : ∀ i ∈ s, MeasurableSet[mα.comap (X i)] (f i)) + (hy : ∀ i ∉ s, μ (Y i ⁻¹' t i) ≠ 0) (ht : ∀ i, MeasurableSet (t i)) : + μ[⋂ i ∈ s, f i | ⋂ i, Y i ⁻¹' t i] = ∏ i ∈ s, μ[f i | Y i in t i] := by + have : IsProbabilityMeasure (μ : Measure Ω) := hindep.isProbabilityMeasure + classical + cases nonempty_fintype ι + let g (i' : ι) := if i' ∈ s then Y i' ⁻¹' t i' ∩ f i' else Y i' ⁻¹' t i' + calc + _ = (μ (⋂ i, Y i ⁻¹' t i))⁻¹ * μ ((⋂ i, Y i ⁻¹' t i) ∩ ⋂ i ∈ s, f i) := by + rw [cond_apply]; exact .iInter fun i ↦ hY i (ht i) + _ = (μ (⋂ i, Y i ⁻¹' t i))⁻¹ * μ (⋂ i, g i) := by + congr + calc + _ = (⋂ i, Y i ⁻¹' t i) ∩ ⋂ i, if i ∈ s then f i else .univ := by + congr + simp only [Set.iInter_ite, Set.iInter_univ, Set.inter_univ] + _ = ⋂ i, Y i ⁻¹' t i ∩ (if i ∈ s then f i else .univ) := by rw [Set.iInter_inter_distrib] + _ = _ := Set.iInter_congr fun i ↦ by by_cases hi : i ∈ s <;> simp [hi, g] + _ = (∏ i, μ (Y i ⁻¹' t i))⁻¹ * μ (⋂ i, g i) := by + rw [hindep.meas_iInter] + exact fun i ↦ ⟨.univ ×ˢ t i, MeasurableSet.univ.prod (ht _), by ext; simp [eq_comm]⟩ + _ = (∏ i, μ (Y i ⁻¹' t i))⁻¹ * ∏ i, μ (g i) := by + rw [hindep.meas_iInter] + intro i + by_cases hi : i ∈ s <;> simp only [hi, ↓reduceIte, g] + · obtain ⟨A, hA, hA'⟩ := hf i hi + exact .inter ⟨.univ ×ˢ t i, MeasurableSet.univ.prod (ht _), by ext; simp [eq_comm]⟩ + ⟨A ×ˢ Set.univ, hA.prod .univ, by ext; simp [← hA']⟩ + · exact ⟨.univ ×ˢ t i, MeasurableSet.univ.prod (ht _), by ext; simp [eq_comm]⟩ + _ = ∏ i, (μ (Y i ⁻¹' t i))⁻¹ * μ (g i) := by + rw [Finset.prod_mul_distrib, ENNReal.prod_inv_distrib] + exact fun _ _ i _ _ ↦ .inr <| measure_ne_top _ _ + _ = ∏ i, if i ∈ s then μ[f i | Y i ⁻¹' t i] else 1 := by + refine Finset.prod_congr rfl fun i _ ↦ ?_ + by_cases hi : i ∈ s + · simp only [hi, ↓reduceIte, g, cond_apply (hY i (ht i))] + · simp only [hi, ↓reduceIte, g, ENNReal.inv_mul_cancel (hy i hi) (measure_ne_top μ _)] + _ = _ := by simp + +lemma iIndepFun.cond [Finite ι] (hY : ∀ i, Measurable (Y i)) + (hindep : iIndepFun (fun _ ↦ mα.prod mβ) (fun i ω ↦ (X i ω, Y i ω)) μ) + (hy : ∀ i, μ (Y i ⁻¹' t i) ≠ 0) (ht : ∀ i, MeasurableSet (t i)) : + iIndepFun (fun _ ↦ mα) X μ[|⋂ i, Y i ⁻¹' t i] := by + rw [iIndepFun_iff] + intro s f hf + convert cond_iInter hY hindep hf (fun i _ ↦ hy _) ht using 2 with i hi + simpa using cond_iInter hY hindep (fun j hj ↦ hf _ <| Finset.mem_singleton.1 hj ▸ hi) + (fun i _ ↦ hy _) ht + end ProbabilityTheory diff --git a/Mathlib/Probability/Independence/Kernel.lean b/Mathlib/Probability/Independence/Kernel.lean index 85ed49143dcc16..3f4c1971fcafe4 100644 --- a/Mathlib/Probability/Independence/Kernel.lean +++ b/Mathlib/Probability/Independence/Kernel.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémy Degenne -/ import Mathlib.MeasureTheory.Constructions.Pi +import Mathlib.Probability.ConditionalProbability import Mathlib.Probability.Kernel.Basic import Mathlib.Tactic.Peel @@ -1212,4 +1213,56 @@ theorem iIndepSet.iIndepFun_indicator [Zero β] [One β] {m : MeasurableSpace β end IndepFun +variable {ι Ω α β : Type*} {mΩ : MeasurableSpace Ω} {mα : MeasurableSpace α} + {mβ : MeasurableSpace β} {κ : Kernel α Ω} {μ : Measure α} {X : ι → Ω → α} {Y : ι → Ω → β} + {f : _ → Set Ω} {t : ι → Set β} {s : Finset ι} + +/-- The probability of an intersection of preimages conditioning on another intersection factors +into a product. -/ +lemma iIndepFun.cond_iInter [Finite ι] (hY : ∀ i, Measurable (Y i)) + (hindep : iIndepFun (fun _ ↦ mα.prod mβ) (fun i ω ↦ (X i ω, Y i ω)) κ μ) + (hf : ∀ i ∈ s, MeasurableSet[mα.comap (X i)] (f i)) + (hy : ∀ᵐ a ∂μ, ∀ i ∉ s, κ a (Y i ⁻¹' t i) ≠ 0) (ht : ∀ i, MeasurableSet (t i)) : + ∀ᵐ a ∂μ, (κ a)[⋂ i ∈ s, f i | ⋂ i, Y i ⁻¹' t i] = ∏ i ∈ s, (κ a)[f i | Y i in t i] := by + classical + cases nonempty_fintype ι + let g (i' : ι) := if i' ∈ s then Y i' ⁻¹' t i' ∩ f i' else Y i' ⁻¹' t i' + have hYt i : MeasurableSet[(mα.prod mβ).comap fun ω ↦ (X i ω, Y i ω)] (Y i ⁻¹' t i) := + ⟨.univ ×ˢ t i, .prod .univ (ht _), by ext; simp [eq_comm]⟩ + have hg i : MeasurableSet[(mα.prod mβ).comap fun ω ↦ (X i ω, Y i ω)] (g i) := by + by_cases hi : i ∈ s <;> simp only [hi, ↓reduceIte, g] + · obtain ⟨A, hA, hA'⟩ := hf i hi + exact (hYt _).inter ⟨A ×ˢ .univ, hA.prod .univ, by ext; simp [← hA']⟩ + · exact hYt _ + filter_upwards [hy, hindep.ae_isProbabilityMeasure, hindep.meas_iInter hYt, hindep.meas_iInter hg] + with a hy _ hYt hg + calc + _ = (κ a (⋂ i, Y i ⁻¹' t i))⁻¹ * κ a ((⋂ i, Y i ⁻¹' t i) ∩ ⋂ i ∈ s, f i) := by + rw [cond_apply]; exact .iInter fun i ↦ hY i (ht i) + _ = (κ a (⋂ i, Y i ⁻¹' t i))⁻¹ * κ a (⋂ i, g i) := by + congr + calc + _ = (⋂ i, Y i ⁻¹' t i) ∩ ⋂ i, if i ∈ s then f i else .univ := by + congr + simp only [Set.iInter_ite, Set.iInter_univ, Set.inter_univ] + _ = ⋂ i, Y i ⁻¹' t i ∩ (if i ∈ s then f i else .univ) := by rw [Set.iInter_inter_distrib] + _ = _ := Set.iInter_congr fun i ↦ by by_cases hi : i ∈ s <;> simp [hi, g] + _ = (∏ i, κ a (Y i ⁻¹' t i))⁻¹ * κ a (⋂ i, g i) := by + rw [hYt] + _ = (∏ i, κ a (Y i ⁻¹' t i))⁻¹ * ∏ i, κ a (g i) := by + rw [hg] + _ = ∏ i, (κ a (Y i ⁻¹' t i))⁻¹ * κ a (g i) := by + rw [Finset.prod_mul_distrib, ENNReal.prod_inv_distrib] + exact fun _ _ i _ _ ↦ .inr <| measure_ne_top _ _ + _ = ∏ i, if i ∈ s then (κ a)[f i | Y i ⁻¹' t i] else 1 := by + refine Finset.prod_congr rfl fun i _ ↦ ?_ + by_cases hi : i ∈ s + · simp only [hi, ↓reduceIte, g, cond_apply (hY i (ht i))] + · simp only [hi, ↓reduceIte, g, ENNReal.inv_mul_cancel (hy i hi) (measure_ne_top _ _)] + _ = _ := by simp + +-- TODO: We can't state `Kernel.iIndepFun.cond` (the `Kernel` analogue of +-- `ProbabilityTheory.iIndepFun.cond`) because we don't have a version of `ProbabilityTheory.cond` +-- for kernels + end ProbabilityTheory.Kernel diff --git a/Mathlib/Probability/UniformOn.lean b/Mathlib/Probability/UniformOn.lean index 524e33e17554c3..828768e8f16106 100644 --- a/Mathlib/Probability/UniformOn.lean +++ b/Mathlib/Probability/UniformOn.lean @@ -42,7 +42,7 @@ open MeasureTheory MeasurableSpace namespace ProbabilityTheory -variable {Ω : Type*} [MeasurableSpace Ω] +variable {Ω : Type*} [MeasurableSpace Ω] {s : Set Ω} /-- 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 @@ -70,6 +70,16 @@ theorem uniformOn_empty {s : Set Ω} : uniformOn s ∅ = 0 := by simp @[deprecated (since := "2024-10-09")] alias condCount_empty := uniformOn_empty +/-- See `uniformOn_eq_zero` for a version assuming `MeasurableSingletonClass Ω` instead of +`MeasurableSet s`. -/ +@[simp] lemma uniformOn_eq_zero' (hs : MeasurableSet s) : uniformOn s = 0 ↔ s.Infinite ∨ s = ∅ := by + simp [uniformOn, hs] + +/-- See `uniformOn_eq_zero'` for a version assuming `MeasurableSet s` instead of +`MeasurableSingletonClass Ω`. -/ +@[simp] lemma uniformOn_eq_zero [MeasurableSingletonClass Ω] : + uniformOn s = 0 ↔ s.Infinite ∨ s = ∅ := by simp [uniformOn] + 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 @@ -93,7 +103,7 @@ 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 + · rwa [Measure.count_ne_zero_iff] · exact (Measure.count_apply_lt_top.2 hs).ne @[deprecated (since := "2024-10-09")] @@ -120,7 +130,7 @@ 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 + · rwa [Measure.count_ne_zero_iff] · exact (Measure.count_apply_lt_top.2 hs).ne @[deprecated (since := "2024-10-09")] diff --git a/Mathlib/RepresentationTheory/Basic.lean b/Mathlib/RepresentationTheory/Basic.lean index fbac878c2ff515..f17cfb213b7e52 100644 --- a/Mathlib/RepresentationTheory/Basic.lean +++ b/Mathlib/RepresentationTheory/Basic.lean @@ -292,7 +292,7 @@ def ofMulDistribMulAction : Representation ℤ M (Additive G) := ((monoidEndToAdditive G : _ →* _).comp (MulDistribMulAction.toMonoidEnd M G)) @[simp] theorem ofMulDistribMulAction_apply_apply (g : M) (a : Additive G) : - ofMulDistribMulAction M G g a = Additive.ofMul (g • Additive.toMul a) := rfl + ofMulDistribMulAction M G g a = Additive.ofMul (g • a.toMul) := rfl end MulDistribMulAction section Group diff --git a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean index b05641a81a752f..24d8d8f5bd37c5 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean @@ -710,7 +710,7 @@ theorem H1LequivOfIsTrivial_comp_H1_π [A.IsTrivial] : @[simp] theorem H1LequivOfIsTrivial_H1_π_apply_apply [A.IsTrivial] (f : oneCocycles A) (x : Additive G) : - H1LequivOfIsTrivial A (H1_π A f) x = f (Additive.toMul x) := rfl + H1LequivOfIsTrivial A (H1_π A f) x = f x.toMul := rfl @[simp] theorem H1LequivOfIsTrivial_symm_apply [A.IsTrivial] (f : Additive G →+ A) : (H1LequivOfIsTrivial A).symm f = H1_π A ((oneCocyclesLequivOfIsTrivial A).symm f) := diff --git a/Mathlib/RepresentationTheory/Rep.lean b/Mathlib/RepresentationTheory/Rep.lean index d4ddfa12b4c679..0a14328b88a96a 100644 --- a/Mathlib/RepresentationTheory/Rep.lean +++ b/Mathlib/RepresentationTheory/Rep.lean @@ -254,7 +254,7 @@ variable (M G : Type) [Monoid M] [CommGroup G] [MulDistribMulAction M G] def ofMulDistribMulAction : Rep ℤ M := Rep.of (Representation.ofMulDistribMulAction M G) @[simp] theorem ofMulDistribMulAction_ρ_apply_apply (g : M) (a : Additive G) : - (ofMulDistribMulAction M G).ρ g a = Additive.ofMul (g • Additive.toMul a) := rfl + (ofMulDistribMulAction M G).ρ g a = Additive.ofMul (g • a.toMul) := rfl /-- Given an `R`-algebra `S`, the `ℤ`-linear representation associated to the natural action of `S ≃ₐ[R] S` on `Sˣ`. -/ diff --git a/Mathlib/RingTheory/Adjoin/PowerBasis.lean b/Mathlib/RingTheory/Adjoin/PowerBasis.lean index 115e9eae03f82b..2a3bbcac0b3453 100644 --- a/Mathlib/RingTheory/Adjoin/PowerBasis.lean +++ b/Mathlib/RingTheory/Adjoin/PowerBasis.lean @@ -79,8 +79,6 @@ namespace PowerBasis open Polynomial -open Polynomial - variable {R : Type*} [CommRing R] [Algebra R S] [Algebra R K] [IsScalarTower R K S] variable {A : Type*} [CommRing A] [Algebra R A] [Algebra S A] variable [IsScalarTower R S A] {B : PowerBasis S A} diff --git a/Mathlib/RingTheory/Algebraic.lean b/Mathlib/RingTheory/Algebraic.lean index e8fe139139573d..4752101e3862df 100644 --- a/Mathlib/RingTheory/Algebraic.lean +++ b/Mathlib/RingTheory/Algebraic.lean @@ -499,31 +499,34 @@ variable [Algebra R S] [Algebra S A] [Algebra R A] [IsScalarTower R S A] /-- If `x` is algebraic over `R`, then `x` is algebraic over `S` when `S` is an extension of `R`, and the map from `R` to `S` is injective. -/ -theorem IsAlgebraic.tower_top_of_injective - (hinj : Function.Injective (algebraMap R S)) {x : A} +theorem IsAlgebraic.extendScalars (hinj : Function.Injective (algebraMap R S)) {x : A} (A_alg : IsAlgebraic R x) : IsAlgebraic S x := let ⟨p, hp₁, hp₂⟩ := A_alg ⟨p.map (algebraMap _ _), by rwa [Ne, ← degree_eq_bot, degree_map_eq_of_injective hinj, degree_eq_bot], by simpa⟩ -/-- A special case of `IsAlgebraic.tower_top_of_injective`. This is extracted as a theorem - because in some cases `IsAlgebraic.tower_top_of_injective` will just runs out of memory. -/ +@[deprecated (since := "2024-11-18")] +alias IsAlgebraic.tower_top_of_injective := IsAlgebraic.extendScalars + +/-- A special case of `IsAlgebraic.extendScalars`. This is extracted as a theorem + because in some cases `IsAlgebraic.extendScalars` will just runs out of memory. -/ theorem IsAlgebraic.tower_top_of_subalgebra_le {A B : Subalgebra R S} (hle : A ≤ B) {x : S} (h : IsAlgebraic A x) : IsAlgebraic B x := by letI : Algebra A B := (Subalgebra.inclusion hle).toAlgebra haveI : IsScalarTower A B S := .of_algebraMap_eq fun _ ↦ rfl - exact h.tower_top_of_injective (Subalgebra.inclusion_injective hle) + exact h.extendScalars (Subalgebra.inclusion_injective hle) /-- If `x` is transcendental over `S`, then `x` is transcendental over `R` when `S` is an extension of `R`, and the map from `R` to `S` is injective. -/ -theorem Transcendental.of_tower_top_of_injective - (hinj : Function.Injective (algebraMap R S)) {x : A} - (h : Transcendental S x) : Transcendental R x := - fun H ↦ h (H.tower_top_of_injective hinj) +theorem Transcendental.restrictScalars (hinj : Function.Injective (algebraMap R S)) {x : A} + (h : Transcendental S x) : Transcendental R x := fun H ↦ h (H.extendScalars hinj) + +@[deprecated (since := "2024-11-18")] +alias Transcendental.of_tower_top_of_injective := Transcendental.restrictScalars -/-- A special case of `Transcendental.of_tower_top_of_injective`. This is extracted as a theorem - because in some cases `Transcendental.of_tower_top_of_injective` will just runs out of memory. -/ +/-- A special case of `Transcendental.restrictScalars`. This is extracted as a theorem + because in some cases `Transcendental.restrictScalars` will just runs out of memory. -/ theorem Transcendental.of_tower_top_of_subalgebra_le {A B : Subalgebra R S} (hle : A ≤ B) {x : S} (h : Transcendental B x) : Transcendental A x := @@ -531,9 +534,12 @@ theorem Transcendental.of_tower_top_of_subalgebra_le /-- If A is an algebraic algebra over R, then A is algebraic over S when S is an extension of R, and the map from `R` to `S` is injective. -/ -theorem Algebra.IsAlgebraic.tower_top_of_injective (hinj : Function.Injective (algebraMap R S)) +theorem Algebra.IsAlgebraic.extendScalars (hinj : Function.Injective (algebraMap R S)) [Algebra.IsAlgebraic R A] : Algebra.IsAlgebraic S A := - ⟨fun _ ↦ _root_.IsAlgebraic.tower_top_of_injective hinj (Algebra.IsAlgebraic.isAlgebraic _)⟩ + ⟨fun _ ↦ _root_.IsAlgebraic.extendScalars hinj (Algebra.IsAlgebraic.isAlgebraic _)⟩ + +@[deprecated (since := "2024-11-18")] +alias Algebra.IsAlgebraic.tower_top_of_injective := Algebra.IsAlgebraic.extendScalars theorem Algebra.IsAlgebraic.tower_bot_of_injective [Algebra.IsAlgebraic R A] (hinj : Function.Injective (algebraMap S A)) : @@ -553,7 +559,7 @@ variable (L) @[stacks 09GF "part one"] theorem IsAlgebraic.tower_top {x : A} (A_alg : IsAlgebraic K x) : IsAlgebraic L x := - A_alg.tower_top_of_injective (algebraMap K L).injective + A_alg.extendScalars (algebraMap K L).injective variable {L} (K) in /-- If `x` is transcendental over `L`, then `x` is transcendental over `K` when @@ -564,7 +570,7 @@ theorem Transcendental.of_tower_top {x : A} (h : Transcendental L x) : /-- If A is an algebraic algebra over K, then A is algebraic over L when L is an extension of K -/ @[stacks 09GF "part two"] theorem Algebra.IsAlgebraic.tower_top [Algebra.IsAlgebraic K A] : Algebra.IsAlgebraic L A := - Algebra.IsAlgebraic.tower_top_of_injective (algebraMap K L).injective + Algebra.IsAlgebraic.extendScalars (algebraMap K L).injective variable (K) @@ -928,7 +934,7 @@ theorem transcendental_supported_polynomial_aeval_X_iff exact Algebra.adjoin_mono (Set.singleton_subset_iff.2 (Set.mem_image_of_mem _ h)) (Polynomial.aeval_mem_adjoin_singleton _ _) · rw [← transcendental_polynomial_aeval_X_iff R i] - refine h.of_tower_top_of_injective fun _ _ heq ↦ MvPolynomial.C_injective σ R ?_ + refine h.restrictScalars fun _ _ heq ↦ MvPolynomial.C_injective σ R ?_ simp_rw [← MvPolynomial.algebraMap_eq] exact congr($(heq).1) diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean index 6865dee0854054..7109a5bc4b4025 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent.lean @@ -724,8 +724,7 @@ theorem IsTranscendenceBasis.isAlgebraic_field {F E : Type*} {x : ι → E} (Subalgebra.inclusion (IntermediateField.algebra_adjoin_le_adjoin F S)).toRingHom.toAlgebra haveI : IsScalarTower (adjoin F S) (IntermediateField.adjoin F S) E := IsScalarTower.of_algebraMap_eq (congrFun rfl) - exact Algebra.IsAlgebraic.tower_top_of_injective (R := adjoin F S) - (Subalgebra.inclusion_injective _) + exact Algebra.IsAlgebraic.extendScalars (R := adjoin F S) (Subalgebra.inclusion_injective _) section Field diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index f61383992490d3..2911d10aa8bb93 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -10,6 +10,7 @@ import Mathlib.Order.Filter.EventuallyConst import Mathlib.RingTheory.Nakayama import Mathlib.RingTheory.SimpleModule import Mathlib.Tactic.RSuffices +import Mathlib.Tactic.StacksAttribute /-! # Artinian rings and modules @@ -347,6 +348,7 @@ end CommRing Strictly speaking, this should be called `IsLeftArtinianRing` but we omit the `Left` for convenience in the commutative case. For a right Artinian ring, use `IsArtinian Rᵐᵒᵖ R`. -/ +@[stacks 00J5] abbrev IsArtinianRing (R) [Ring R] := IsArtinian R R @@ -418,6 +420,7 @@ open IsArtinian variable {R : Type*} [CommRing R] [IsArtinianRing R] +@[stacks 00J8] theorem isNilpotent_jacobson_bot : IsNilpotent (Ideal.jacobson (⊥ : Ideal R)) := by let Jac := Ideal.jacobson (⊥ : Ideal R) let f : ℕ →o (Ideal R)ᵒᵈ := ⟨fun n => Jac ^ n, fun _ _ h => Ideal.pow_le_pow_right h⟩ @@ -504,9 +507,7 @@ lemma primeSpectrum_finite : {I : Ideal R | I.IsPrime}.Finite := by rwa [← Subtype.ext <| (@isMaximal_of_isPrime _ _ _ _ q.2).eq_of_le p.2.1 hq2] variable (R) -/-- -[Stacks Lemma 00J7](https://stacks.math.columbia.edu/tag/00J7) --/ +@[stacks 00J7] lemma maximal_ideals_finite : {I : Ideal R | I.IsMaximal}.Finite := by simp_rw [← isPrime_iff_isMaximal] apply primeSpectrum_finite R diff --git a/Mathlib/RingTheory/ChainOfDivisors.lean b/Mathlib/RingTheory/ChainOfDivisors.lean index f22b75532ab931..a1921d9752ce62 100644 --- a/Mathlib/RingTheory/ChainOfDivisors.lean +++ b/Mathlib/RingTheory/ChainOfDivisors.lean @@ -3,10 +3,11 @@ Copyright (c) 2021 Paul Lezeau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen, Paul Lezeau -/ +import Mathlib.Algebra.GCDMonoid.Basic import Mathlib.Algebra.IsPrimePow import Mathlib.Algebra.Squarefree.Basic -import Mathlib.Algebra.GCDMonoid.Basic import Mathlib.Data.ZMod.Defs +import Mathlib.Order.Atoms import Mathlib.Order.Hom.Bounded /-! diff --git a/Mathlib/RingTheory/Complex.lean b/Mathlib/RingTheory/Complex.lean index 68be8e6b337a34..1f3b98e14ae268 100644 --- a/Mathlib/RingTheory/Complex.lean +++ b/Mathlib/RingTheory/Complex.lean @@ -18,11 +18,11 @@ theorem Algebra.leftMulMatrix_complex (z : ℂ) : rw [Algebra.leftMulMatrix_eq_repr_mul, Complex.coe_basisOneI_repr, Complex.coe_basisOneI, mul_re, mul_im, Matrix.of_apply] fin_cases j - · simp only [Fin.mk_zero, Matrix.cons_val_zero, one_re, mul_one, one_im, mul_zero, sub_zero, - zero_add] + · simp only [Fin.zero_eta, id_eq, Matrix.cons_val_zero, one_re, mul_one, one_im, mul_zero, + sub_zero, zero_add, Matrix.cons_val_fin_one] fin_cases i <;> rfl - · simp only [Fin.mk_one, Matrix.cons_val_one, Matrix.head_cons, I_re, mul_zero, I_im, mul_one, - zero_sub, add_zero] + · simp only [Fin.mk_one, id_eq, Matrix.cons_val_one, Matrix.head_cons, I_re, mul_zero, I_im, + mul_one, zero_sub, add_zero, Matrix.cons_val_fin_one] fin_cases i <;> rfl theorem Algebra.trace_complex_apply (z : ℂ) : Algebra.trace ℝ ℂ z = 2 * z.re := by diff --git a/Mathlib/RingTheory/DedekindDomain/Factorization.lean b/Mathlib/RingTheory/DedekindDomain/Factorization.lean index 9a837256ab9a21..61803b29f13c4e 100644 --- a/Mathlib/RingTheory/DedekindDomain/Factorization.lean +++ b/Mathlib/RingTheory/DedekindDomain/Factorization.lean @@ -5,6 +5,7 @@ Authors: María Inés de Frutos-Fernández -/ import Mathlib.Order.Filter.Cofinite import Mathlib.RingTheory.DedekindDomain.Ideal +import Mathlib.RingTheory.UniqueFactorizationDomain.Finite /-! # Factorization of ideals and fractional ideals of Dedekind domains diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 22365ec289413a..2533459ec47713 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -129,7 +129,6 @@ open Submodule Submodule.IsPrincipal theorem spanSingleton_inv (x : K) : (spanSingleton R₁⁰ x)⁻¹ = spanSingleton _ x⁻¹ := one_div_spanSingleton x --- @[simp] -- Porting note: not in simpNF form theorem spanSingleton_div_spanSingleton (x y : K) : spanSingleton R₁⁰ x / spanSingleton R₁⁰ y = spanSingleton R₁⁰ (x / y) := by rw [div_spanSingleton, mul_comm, spanSingleton_mul_spanSingleton, div_eq_mul_inv] @@ -1058,7 +1057,6 @@ variable [IsDedekindDomain R] (f : R ⧸ I ≃+* A ⧸ J) /-- The bijection between ideals of `R` dividing `I` and the ideals of `A` dividing `J` induced by an isomorphism `f : R/I ≅ A/J`. -/ --- @[simps] -- Porting note: simpNF complains about the lemmas generated by simps def idealFactorsEquivOfQuotEquiv : { p : Ideal R | p ∣ I } ≃o { p : Ideal A | p ∣ J } := by have f_surj : Function.Surjective (f : R ⧸ I →+* A ⧸ J) := f.surjective have fsym_surj : Function.Surjective (f.symm : A ⧸ J →+* R ⧸ I) := f.symm.surjective @@ -1101,7 +1099,6 @@ theorem idealFactorsEquivOfQuotEquiv_mem_normalizedFactors_of_mem_normalizedFact /-- The bijection between the sets of normalized factors of I and J induced by a ring isomorphism `f : R/I ≅ A/J`. -/ --- @[simps apply] -- Porting note: simpNF complains about the lemmas generated by simps def normalizedFactorsEquivOfQuotEquiv (hI : I ≠ ⊥) (hJ : J ≠ ⊥) : { L : Ideal R | L ∈ normalizedFactors I } ≃ { M : Ideal A | M ∈ normalizedFactors J } where toFun j := @@ -1379,7 +1376,6 @@ variable [NormalizationMonoid R] /-- The bijection between the (normalized) prime factors of `r` and the (normalized) prime factors of `span {r}` -/ --- @[simps] -- Porting note: simpNF complains about the lemmas generated by simps noncomputable def normalizedFactorsEquivSpanNormalizedFactors {r : R} (hr : r ≠ 0) : { d : R | d ∈ normalizedFactors r } ≃ { I : Ideal R | I ∈ normalizedFactors (Ideal.span ({r} : Set R)) } := by diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 77679db0fe1c64..f38e19b607e419 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -185,6 +185,14 @@ theorem IsIntegralClosure.isNoetherianRing [IsIntegrallyClosed A] [IsNoetherianR IsNoetherianRing C := isNoetherianRing_iff.mpr <| isNoetherian_of_tower A (IsIntegralClosure.isNoetherian A K L C) +/-- If `L` is a finite separable extension of `K = Frac(A)`, where `A` is +integrally closed and Noetherian, the integral closure `C` of `A` in `L` is +finite over `A`. -/ +theorem IsIntegralClosure.finite [IsIntegrallyClosed A] [IsNoetherianRing A] : + Module.Finite A C := by + haveI := IsIntegralClosure.isNoetherian A K L C + exact Module.IsNoetherian.finite A C + /-- If `L` is a finite separable extension of `K = Frac(A)`, where `A` is a principal ring and `L` has no zero smul divisors by `A`, the integral closure `C` of `A` in `L` is a free `A`-module. -/ diff --git a/Mathlib/RingTheory/DedekindDomain/SInteger.lean b/Mathlib/RingTheory/DedekindDomain/SInteger.lean index 83b4fe6cf90212..7568c704d46d49 100644 --- a/Mathlib/RingTheory/DedekindDomain/SInteger.lean +++ b/Mathlib/RingTheory/DedekindDomain/SInteger.lean @@ -96,7 +96,6 @@ theorem unit_valuation_eq_one (x : S.unit K) {v : HeightOneSpectrum R} (hv : v v.valuation ((x : Kˣ) : K) = 1 := x.property v hv --- Porting note: `apply_inv_coe` fails the simpNF linter /-- The group of `S`-units is the group of units of the ring of `S`-integers. -/ @[simps apply_val_coe symm_apply_coe] def unitEquivUnitsInteger : S.unit K ≃* (S.integer K)ˣ where diff --git a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean index cbcfd6561f1b76..33a536b988ff1b 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean @@ -5,6 +5,7 @@ Authors: Kevin Buzzard -/ import Mathlib.RingTheory.AdicCompletion.Basic import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic import Mathlib.RingTheory.Valuation.PrimeMultiplicity import Mathlib.RingTheory.Valuation.ValuationRing diff --git a/Mathlib/RingTheory/DividedPowers/Basic.lean b/Mathlib/RingTheory/DividedPowers/Basic.lean new file mode 100644 index 00000000000000..b07b6b0ac8aea9 --- /dev/null +++ b/Mathlib/RingTheory/DividedPowers/Basic.lean @@ -0,0 +1,418 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir & María-Inés de Frutos—Fernández. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir, María-Inés de Frutos—Fernández +-/ + +import Mathlib.RingTheory.PowerSeries.Basic +import Mathlib.Combinatorics.Enumerative.Bell +import Mathlib.Data.Nat.Choose.Multinomial + +/-! # Divided powers + +Let `A` be a commutative (semi)ring and `I` be an ideal of `A`. +A *divided power* structure on `I` is the datum of operations `a n ↦ dpow a n` +satisfying relations that model the intuitive formula `dpow n a = a ^ n / n !` and +collected by the structure `DividedPowers`. The list of axioms is embedded in the structure: +To avoid coercions, we rather consider `DividedPowers.dpow : ℕ → A → A`, extended by 0. + +* `DividedPowers.dpow_null` asserts that `dpow n x = 0` for `x ∉ I` + +* `DividedPowers.dpow_mem` : `dpow n x ∈ I` for `n ≠ 0` +For `x y : A` and `m n : ℕ` such that `x ∈ I` and `y ∈ I`, one has +* `DividedPowers.dpow_zero` : `dpow 0 x = 1` +* `DividedPowers.dpow_one` : `dpow 1 x = 1` +* `DividedPowers.dpow_add` : `dpow n (x + y) = +(antidiagonal n).sum fun k ↦ dpow k.1 x * dpow k.2 y`, +this is the binomial theorem without binomial coefficients. +* `DividedPowers.dpow_mul`: `dpow n (a * x) = a ^ n * dpow n x` +* `DividedPowers.mul_dpow` : `dpow m x * dpow n x = choose (m + n) m * dpow (m + n) x` +* `DividedPowers.dpow_comp` : `dpow m (dpow n x) = uniformBell m n * dpow (m * n) x` + +* `DividedPowers.dividedPowersBot` : the trivial divided powers structure on the zero ideal + +* `DividedPowers.prod_dpow`: a product of divided powers is a multinomial coefficients +times a divided power + +* `DividedPowers.dpow_sum`: the multinomial theorem for divided powers, +without multinomial coefficients. + +* `DividedPowers.ofRingEquiv`: transfer divided powers along `RingEquiv` + +* `DividedPowers.equiv`: the equivalence `DividedPowers I ≃ DividedPowers J`, +for `e : R ≃+* S`, and `I : Ideal R`, `J : Ideal S` such that `I.map e = J` + +* `DividedPowers.exp`: the power series `Σ (dpow n a) X ^n` + +* `DividedPowers.exp_add`: its multiplicativity + +## References + +* [P. Berthelot (1974), *Cohomologie cristalline des schémas de +caractéristique $p$ > 0*][Berthelot-1974] + +* [P. Berthelot and A. Ogus (1978), *Notes on crystalline +cohomology*][BerthelotOgus-1978] + +* [N. Roby (1963), *Lois polynomes et lois formelles en théorie des +modules*][Roby-1963] + +* [N. Roby (1965), *Les algèbres à puissances dividées*][Roby-1965] + +## Discussion + +* In practice, one often has a single such structure to handle on a given ideal, +but several ideals of the same ring might be considered. +Without any explicit mention of the ideal, it is not clear whether such structures +should be provided as instances. + +* We do not provide any notation such as `a ^[n]` for `dpow a n`. + +-/ + +open Finset Nat Ideal + +section DividedPowersDefinition +/- ## Definition of divided powers -/ + +variable {A : Type*} [CommSemiring A] (I : Ideal A) + +/-- The divided power structure on an ideal I of a commutative ring A -/ +structure DividedPowers where + /-- The divided power function underlying a divided power structure -/ + dpow : ℕ → A → A + dpow_null : ∀ {n x} (_ : x ∉ I), dpow n x = 0 + dpow_zero : ∀ {x} (_ : x ∈ I), dpow 0 x = 1 + dpow_one : ∀ {x} (_ : x ∈ I), dpow 1 x = x + dpow_mem : ∀ {n x} (_ : n ≠ 0) (_ : x ∈ I), dpow n x ∈ I + dpow_add : ∀ (n) {x y} (_ : x ∈ I) (_ : y ∈ I), + dpow n (x + y) = (antidiagonal n).sum fun k ↦ dpow k.1 x * dpow k.2 y + dpow_mul : ∀ (n) {a : A} {x} (_ : x ∈ I), + dpow n (a * x) = a ^ n * dpow n x + mul_dpow : ∀ (m n) {x} (_ : x ∈ I), + dpow m x * dpow n x = choose (m + n) m * dpow (m + n) x + dpow_comp : ∀ (m) {n x} (_ : n ≠ 0) (_ : x ∈ I), + dpow m (dpow n x) = uniformBell m n * dpow (m * n) x + +variable (A) in +/-- The canonical `DividedPowers` structure on the zero ideal -/ +def dividedPowersBot [DecidableEq A] : DividedPowers (⊥ : Ideal A) where + dpow n a := ite (a = 0 ∧ n = 0) 1 0 + dpow_null {n a} ha := by + simp only [mem_bot] at ha + dsimp + rw [if_neg] + exact not_and_of_not_left (n = 0) ha + dpow_zero {a} ha := by + rw [mem_bot.mp ha] + simp only [and_self, ite_true] + dpow_one {a} ha := by + simp [mem_bot.mp ha] + dpow_mem {n a} hn _ := by + simp only [mem_bot, ite_eq_right_iff, and_imp] + exact fun _ a ↦ False.elim (hn a) + dpow_add n a b ha hb := by + rw [mem_bot.mp ha, mem_bot.mp hb, add_zero] + simp only [true_and, ge_iff_le, tsub_eq_zero_iff_le, mul_ite, mul_one, mul_zero] + split_ifs with h + · simp [h] + · symm + apply sum_eq_zero + intro i hi + simp only [mem_antidiagonal] at hi + split_ifs with h2 h1 + · rw [h1, h2, add_zero] at hi + exfalso + exact h hi.symm + · rfl + · rfl + dpow_mul n {a x} hx := by + rw [mem_bot.mp hx] + simp only [mul_zero, true_and, mul_ite, mul_one] + by_cases hn : n = 0 + · rw [if_pos hn, hn, if_pos rfl, _root_.pow_zero] + · simp only [if_neg hn] + mul_dpow m n {x} hx := by + rw [mem_bot.mp hx] + simp only [true_and, mul_ite, mul_one, mul_zero, add_eq_zero] + by_cases hn : n = 0 + · simp only [hn, ite_true, and_true, add_zero, choose_self, cast_one] + · rw [if_neg hn, if_neg] + exact not_and_of_not_right (m = 0) hn + dpow_comp m {n a} hn ha := by + rw [mem_bot.mp ha] + simp only [true_and, ite_eq_right_iff, _root_.mul_eq_zero, mul_ite, mul_one, mul_zero] + by_cases hm: m = 0 + · simp only [hm, and_true, true_or, ite_true, uniformBell_zero_left, cast_one] + rw [if_pos] + exact fun h ↦ False.elim (hn h) + · simp only [hm, and_false, ite_false, false_or, if_neg hn] + +instance [DecidableEq A] : Inhabited (DividedPowers (⊥ : Ideal A)) := + ⟨dividedPowersBot A⟩ + +/-- The coercion from the divided powers structures to functions -/ +instance : CoeFun (DividedPowers I) fun _ ↦ ℕ → A → A := ⟨fun hI ↦ hI.dpow⟩ + +variable {I} in +@[ext] +theorem DividedPowers.ext (hI : DividedPowers I) (hI' : DividedPowers I) + (h_eq : ∀ (n : ℕ) {x : A} (_ : x ∈ I), hI.dpow n x = hI'.dpow n x) : + hI = hI' := by + obtain ⟨hI, h₀, _⟩ := hI + obtain ⟨hI', h₀', _⟩ := hI' + simp only [mk.injEq] + ext n x + by_cases hx : x ∈ I + · exact h_eq n hx + · rw [h₀ hx, h₀' hx] + +theorem DividedPowers.coe_injective : + Function.Injective (fun (h : DividedPowers I) ↦ (h : ℕ → A → A)) := fun hI hI' h ↦ by + ext n x + exact congr_fun (congr_fun h n) x + +end DividedPowersDefinition + +namespace DividedPowers + +section BasicLemmas + +/- ## Basic lemmas for divided powers -/ + +variable {A : Type*} [CommSemiring A] {I : Ideal A} {a b : A} + +/-- Variant of `DividedPowers.dpow_add` with a sum on `range (n + 1)` -/ +theorem dpow_add' (hI : DividedPowers I) (n : ℕ) (ha : a ∈ I) (hb : b ∈ I) : + hI.dpow n (a + b) = (range (n + 1)).sum fun k ↦ hI.dpow k a * hI.dpow (n - k) b := by + rw [hI.dpow_add n ha hb, sum_antidiagonal_eq_sum_range_succ_mk] + +/-- The exponential series of an element in the context of divided powers, +`Σ (dpow n a) X ^ n` -/ +def exp (hI : DividedPowers I) (a : A) : PowerSeries A := + PowerSeries.mk fun n ↦ hI.dpow n a + +/-- A more general of `DividedPowers.exp_add` -/ +theorem exp_add' (dp : ℕ → A → A) + (dp_add : ∀ n, dp n (a + b) = (antidiagonal n).sum fun k ↦ dp k.1 a * dp k.2 b) : + PowerSeries.mk (fun n ↦ dp n (a + b)) = + (PowerSeries.mk fun n ↦ dp n a) * (PowerSeries.mk fun n ↦ dp n b) := by + ext n + simp only [exp, PowerSeries.coeff_mk, PowerSeries.coeff_mul, dp_add n, + sum_antidiagonal_eq_sum_range_succ_mk] + +theorem exp_add (hI : DividedPowers I) (ha : a ∈ I) (hb : b ∈ I) : + hI.exp (a + b) = hI.exp a * hI.exp b := + exp_add' _ (fun n ↦ hI.dpow_add n ha hb) + +variable (hI : DividedPowers I) + +/- ## Rewriting lemmas -/ + +theorem dpow_smul (n : ℕ) (ha : a ∈ I) : + hI.dpow n (b • a) = b ^ n • hI.dpow n a := by + simp only [smul_eq_mul, hI.dpow_mul, ha] + +theorem dpow_mul_right (n : ℕ) (ha : a ∈ I) : + hI.dpow n (a * b) = hI.dpow n a * b ^ n := by + rw [mul_comm, hI.dpow_mul n ha, mul_comm] + +theorem dpow_smul_right (n : ℕ) (ha : a ∈ I) : + hI.dpow n (a • b) = hI.dpow n a • b ^ n := by + rw [smul_eq_mul, hI.dpow_mul_right n ha, smul_eq_mul] + +theorem factorial_mul_dpow_eq_pow (n : ℕ) (ha : a ∈ I) : + (n ! : A) * hI.dpow n a = a ^ n := by + induction n with + | zero => rw [factorial_zero, cast_one, one_mul, pow_zero, hI.dpow_zero ha] + | succ n ih => + rw [factorial_succ, mul_comm (n + 1)] + nth_rewrite 1 [← (n + 1).choose_one_right] + rw [← choose_symm_add, cast_mul, mul_assoc, + ← hI.mul_dpow n 1 ha, ← mul_assoc, ih, hI.dpow_one ha, pow_succ, mul_comm] + +theorem dpow_eval_zero {n : ℕ} (hn : n ≠ 0) : hI.dpow n 0 = 0 := by + rw [← MulZeroClass.mul_zero (0 : A), hI.dpow_mul n I.zero_mem, + zero_pow hn, zero_mul, zero_mul] + +/-- If an element of a divided power ideal is killed by multiplication +by some nonzero integer `n`, then its `n`th power is zero. + +Proposition 1.2.7 of [Berthelot-1974], part (i). -/ +theorem nilpotent_of_mem_dpIdeal {n : ℕ} (hn : n ≠ 0) (hnI : ∀ {y} (_ : y ∈ I), n • y = 0) + (hI : DividedPowers I) (ha : a ∈ I) : a ^ n = 0 := by + have h_fac : (n ! : A) * hI.dpow n a = + n • ((n - 1)! : A) * hI.dpow n a := by + rw [nsmul_eq_mul, ← cast_mul, mul_factorial_pred (Nat.pos_of_ne_zero hn)] + rw [← hI.factorial_mul_dpow_eq_pow n ha, h_fac, smul_mul_assoc] + exact hnI (I.mul_mem_left ((n - 1)! : A) (hI.dpow_mem hn ha)) + +/-- If J is another ideal of A with divided powers, +then the divided powers of I and J coincide on I • J + +[Berthelot-1974], 1.6.1 (ii) -/ +theorem coincide_on_smul {J : Ideal A} (hJ : DividedPowers J) {n : ℕ} (ha : a ∈ I • J) : + hI.dpow n a = hJ.dpow n a := by + induction ha using Submodule.smul_induction_on' generalizing n with + | smul a ha b hb => + rw [Algebra.id.smul_eq_mul, hJ.dpow_mul n hb, mul_comm a b, hI.dpow_mul n ha, ← + hJ.factorial_mul_dpow_eq_pow n hb, ← hI.factorial_mul_dpow_eq_pow n ha] + ring + | add x hx y hy hx' hy' => + rw [hI.dpow_add n (mul_le_right hx) (mul_le_right hy), + hJ.dpow_add n (mul_le_left hx) (mul_le_left hy)] + apply sum_congr rfl + intro k _ + rw [hx', hy'] + +/-- A product of divided powers is a multinomial coefficient times the divided power + +[Roby-1965], formula (III') -/ +theorem prod_dpow {ι : Type*} {s : Finset ι} (n : ι → ℕ) (ha : a ∈ I) : + (s.prod fun i ↦ hI.dpow (n i) a) = multinomial s n * hI.dpow (s.sum n) a := by + classical + induction s using Finset.induction with + | empty => + simp only [prod_empty, multinomial_empty, cast_one, sum_empty, one_mul] + rw [hI.dpow_zero ha] + | insert hi hrec => + rw [prod_insert hi, hrec, ← mul_assoc, mul_comm (hI.dpow (n _) a), + mul_assoc, mul_dpow _ _ _ ha, ← sum_insert hi, ← mul_assoc] + apply congr_arg₂ _ _ rfl + rw [multinomial_insert hi, mul_comm, cast_mul, sum_insert hi] + +-- TODO : can probably be simplified using `DividedPowers.exp` + +/-- Lemma towards `dpow_sum` when we only have partial information on a divided power ideal -/ +theorem dpow_sum' {M : Type*} [AddCommMonoid M] {I : AddSubmonoid M} (dpow : ℕ → M → A) + (dpow_zero : ∀ {x} (_ : x ∈ I), dpow 0 x = 1) + (dpow_add : ∀ (n) {x y} (_ : x ∈ I) (_ : y ∈ I), + dpow n (x + y) = (antidiagonal n).sum fun k ↦ dpow k.1 x * dpow k.2 y) + (dpow_eval_zero : ∀ {n : ℕ} (_ : n ≠ 0), dpow n 0 = 0) + {ι : Type*} [DecidableEq ι] {s : Finset ι} {x : ι → M} (hx : ∀ i ∈ s, x i ∈ I) (n : ℕ) : + dpow n (s.sum x) = (s.sym n).sum fun k ↦ s.prod fun i ↦ dpow (Multiset.count i k) (x i) := by + simp only [sum_antidiagonal_eq_sum_range_succ_mk] at dpow_add + induction s using Finset.induction generalizing n with + | empty => + simp only [sum_empty, prod_empty, sum_const, nsmul_eq_mul, mul_one] + by_cases hn : n = 0 + · rw [hn] + rw [dpow_zero I.zero_mem] + simp only [sym_zero, card_singleton, cast_one] + · rw [dpow_eval_zero hn, eq_comm, ← cast_zero] + apply congr_arg + rw [card_eq_zero, sym_eq_empty] + exact ⟨hn, rfl⟩ + | @insert a s ha ih => + -- This should be golfable using `Finset.symInsertEquiv` + have hx' : ∀ i, i ∈ s → x i ∈ I := fun i hi ↦ hx i (mem_insert_of_mem hi) + simp_rw [sum_insert ha, + dpow_add n (hx a (mem_insert_self a s)) (I.sum_mem fun i ↦ hx' i), + sum_range, ih hx', mul_sum, sum_sigma', eq_comm] + apply sum_bij' + (fun m _ ↦ m.filterNe a) + (fun m _ ↦ m.2.fill a m.1) + (fun m hm ↦ mem_sigma.2 ⟨mem_univ _, _⟩) + (fun m hm ↦ by + simp only [succ_eq_add_one, mem_sym_iff, mem_insert, Sym.mem_fill_iff] + simp only [mem_sigma, mem_univ, mem_sym_iff, true_and] at hm + intro b + apply Or.imp (fun h ↦ h.2) (fun h ↦ hm b h)) + (fun m _ ↦ m.fill_filterNe a) + · intro m hm + simp only [mem_sigma, mem_univ, mem_sym_iff, true_and] at hm + exact Sym.filter_ne_fill a m fun a_1 ↦ ha (hm a a_1) + · intro m hm + simp only [mem_sym_iff, mem_insert] at hm + rw [prod_insert ha] + apply congr_arg₂ _ rfl + apply prod_congr rfl + intro i hi + apply congr_arg₂ _ _ rfl + conv_lhs => rw [← m.fill_filterNe a] + exact Sym.count_coe_fill_of_ne (ne_of_mem_of_not_mem hi ha) + · intro m hm + convert sym_filterNe_mem a hm + rw [erase_insert ha] + +/-- A “multinomial” theorem for divided powers — without multinomial coefficients -/ +theorem dpow_sum {ι : Type*} [DecidableEq ι] {s : Finset ι} {x : ι → A} + (hx : ∀ i ∈ s, x i ∈ I) (n : ℕ) : + hI.dpow n (s.sum x) = + (s.sym n).sum fun k ↦ s.prod fun i ↦ hI.dpow (Multiset.count i k) (x i) := + dpow_sum' hI.dpow hI.dpow_zero hI.dpow_add hI.dpow_eval_zero hx n + +end BasicLemmas + +section Equiv +/- ## Relation of divided powers with ring equivalences -/ + +variable {A B : Type*} [CommSemiring A] {I : Ideal A} [CommSemiring B] {J : Ideal B} + {e : A ≃+* B} (h : I.map e = J) + +/-- Transfer divided powers under an equivalence -/ +def ofRingEquiv (hI : DividedPowers I) : DividedPowers J where + dpow n b := e (hI.dpow n (e.symm b)) + dpow_null {n} {x} hx := by + rw [EmbeddingLike.map_eq_zero_iff, hI.dpow_null] + rwa [symm_apply_mem_of_equiv_iff, h] + dpow_zero {x} hx := by + rw [EmbeddingLike.map_eq_one_iff, hI.dpow_zero] + rwa [symm_apply_mem_of_equiv_iff, h] + dpow_one {x} hx := by + simp only + rw [dpow_one, RingEquiv.apply_symm_apply] + rwa [I.symm_apply_mem_of_equiv_iff, h] + dpow_mem {n} {x} hn hx := by + simp only + rw [← h, I.apply_mem_of_equiv_iff] + apply hI.dpow_mem hn + rwa [I.symm_apply_mem_of_equiv_iff, h] + dpow_add n {x y} hx hy := by + simp only [map_add] + rw [hI.dpow_add n (symm_apply_mem_of_equiv_iff.mpr (h ▸ hx)) + (symm_apply_mem_of_equiv_iff.mpr (h ▸ hy))] + simp only [map_sum, _root_.map_mul] + dpow_mul n {a x} hx := by + simp only [_root_.map_mul] + rw [hI.dpow_mul n (symm_apply_mem_of_equiv_iff.mpr (h ▸ hx))] + rw [_root_.map_mul, map_pow] + simp only [RingEquiv.apply_symm_apply] + mul_dpow m n {x} hx := by + simp only + rw [← _root_.map_mul, hI.mul_dpow, _root_.map_mul] + · simp only [map_natCast] + · rwa [symm_apply_mem_of_equiv_iff, h] + dpow_comp m {n x} hn hx := by + simp only [RingEquiv.symm_apply_apply] + rw [hI.dpow_comp _ hn] + · simp only [_root_.map_mul, map_natCast] + · rwa [symm_apply_mem_of_equiv_iff, h] + +@[simp] +theorem ofRingEquiv_dpow (hI : DividedPowers I) (n : ℕ) (b : B) : + (ofRingEquiv h hI).dpow n b = e (hI.dpow n (e.symm b)) := rfl + +theorem ofRingEquiv_dpow_apply (hI : DividedPowers I) (n : ℕ) (a : A) : + (ofRingEquiv h hI).dpow n (e a) = e (hI.dpow n a) := by + simp + +/-- Transfer divided powers under an equivalence (Equiv version) -/ +def equiv : DividedPowers I ≃ DividedPowers J where + toFun := ofRingEquiv h + invFun := ofRingEquiv (show map e.symm J = I by rw [← h]; exact I.map_of_equiv e) + left_inv := fun hI ↦ by ext n a; simp [ofRingEquiv] + right_inv := fun hJ ↦ by ext n b; simp [ofRingEquiv] + +theorem equiv_apply (hI : DividedPowers I) (n : ℕ) (b : B) : + (equiv h hI).dpow n b = e (hI.dpow n (e.symm b)) := rfl + +/-- Variant of `DividedPowers.equiv_apply` -/ +theorem equiv_apply' (hI : DividedPowers I) (n : ℕ) (a : A) : + (equiv h hI).dpow n (e a) = e (hI.dpow n a) := + ofRingEquiv_dpow_apply h hI n a + +end Equiv + +end DividedPowers + diff --git a/Mathlib/RingTheory/EisensteinCriterion.lean b/Mathlib/RingTheory/EisensteinCriterion.lean index 216ad0c0c0a4d9..0e246b9233e418 100644 --- a/Mathlib/RingTheory/EisensteinCriterion.lean +++ b/Mathlib/RingTheory/EisensteinCriterion.lean @@ -22,8 +22,6 @@ variable {R : Type*} [CommRing R] namespace Polynomial -open Polynomial - namespace EisensteinCriterionAux -- Section for auxiliary lemmas used in the proof of `irreducible_of_eisenstein_criterion` diff --git a/Mathlib/RingTheory/FiniteLength.lean b/Mathlib/RingTheory/FiniteLength.lean index b1cf98eb550b87..8eea41b4e20e28 100644 --- a/Mathlib/RingTheory/FiniteLength.lean +++ b/Mathlib/RingTheory/FiniteLength.lean @@ -78,13 +78,13 @@ theorem isFiniteLength_iff_exists_compositionSeries : theorem IsSemisimpleModule.finite_tfae [IsSemisimpleModule R M] : List.TFAE [Module.Finite R M, IsNoetherian R M, IsArtinian R M, IsFiniteLength R M, - ∃ s : Set (Submodule R M), s.Finite ∧ CompleteLattice.SetIndependent s ∧ + ∃ s : Set (Submodule R M), s.Finite ∧ sSupIndep s ∧ sSup s = ⊤ ∧ ∀ m ∈ s, IsSimpleModule R m] := by rw [isFiniteLength_iff_isNoetherian_isArtinian] - obtain ⟨s, hs⟩ := IsSemisimpleModule.exists_setIndependent_sSup_simples_eq_top R M + obtain ⟨s, hs⟩ := IsSemisimpleModule.exists_sSupIndep_sSup_simples_eq_top R M tfae_have 1 ↔ 2 := ⟨fun _ ↦ inferInstance, fun _ ↦ inferInstance⟩ - tfae_have 2 → 5 := fun _ ↦ ⟨s, CompleteLattice.WellFoundedGT.finite_of_setIndependent hs.1, hs⟩ - tfae_have 3 → 5 := fun _ ↦ ⟨s, CompleteLattice.WellFoundedLT.finite_of_setIndependent hs.1, hs⟩ + tfae_have 2 → 5 := fun _ ↦ ⟨s, WellFoundedGT.finite_of_sSupIndep hs.1, hs⟩ + tfae_have 3 → 5 := fun _ ↦ ⟨s, WellFoundedLT.finite_of_sSupIndep hs.1, hs⟩ tfae_have 5 → 4 := fun ⟨s, fin, _, sSup_eq_top, simple⟩ ↦ by rw [← isNoetherian_top_iff, ← Submodule.topEquiv.isArtinian_iff, ← sSup_eq_top, sSup_eq_iSup, ← iSup_subtype''] diff --git a/Mathlib/RingTheory/Finiteness/Basic.lean b/Mathlib/RingTheory/Finiteness/Basic.lean index f68cde85ea80cc..73248997ca909e 100644 --- a/Mathlib/RingTheory/Finiteness/Basic.lean +++ b/Mathlib/RingTheory/Finiteness/Basic.lean @@ -119,6 +119,17 @@ theorem fg_restrictScalars {R S M : Type*} [CommSemiring R] [Semiring S] [Algebr use X exact (Submodule.restrictScalars_span R S h (X : Set M)).symm +lemma FG.of_restrictScalars (R) {A M} [CommSemiring R] [Semiring A] [AddCommMonoid M] + [Algebra R A] [Module R M] [Module A M] [IsScalarTower R A M] (S : Submodule A M) + (hS : (S.restrictScalars R).FG) : S.FG := by + obtain ⟨s, e⟩ := hS + refine ⟨s, Submodule.restrictScalars_injective R _ _ (le_antisymm ?_ ?_)⟩ + · show Submodule.span A s ≤ S + have := Submodule.span_le.mp e.le + rwa [Submodule.span_le] + · rw [← e] + exact Submodule.span_le_restrictScalars _ _ _ + theorem FG.stabilizes_of_iSup_eq {M' : Submodule R M} (hM' : M'.FG) (N : ℕ →o Submodule R M) (H : iSup N = M') : ∃ n, M' = N n := by obtain ⟨S, hS⟩ := hM' diff --git a/Mathlib/RingTheory/Finiteness/Defs.lean b/Mathlib/RingTheory/Finiteness/Defs.lean index 289071d1c70646..a56606fa8c8e97 100644 --- a/Mathlib/RingTheory/Finiteness/Defs.lean +++ b/Mathlib/RingTheory/Finiteness/Defs.lean @@ -100,7 +100,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. -/ +/-- A module over a semiring is `Module.Finite` if it is finitely generated as a module. -/ protected class Module.Finite [Semiring R] [AddCommMonoid M] [Module R M] : Prop where out : (⊤ : Submodule R M).FG @@ -142,7 +142,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. -/ +/-- A ring morphism `A →+* B` is `RingHom.Finite` if `B` is finitely generated as `A`-module. -/ @[algebraize Module.Finite] def Finite (f : A →+* B) : Prop := letI : Algebra A B := f.toAlgebra diff --git a/Mathlib/RingTheory/FreeCommRing.lean b/Mathlib/RingTheory/FreeCommRing.lean index 6efc6c11c1cd61..e1b0736aa14049 100644 --- a/Mathlib/RingTheory/FreeCommRing.lean +++ b/Mathlib/RingTheory/FreeCommRing.lean @@ -134,7 +134,7 @@ private def liftToMultiset : (α → R) ≃ (Multiplicative (Multiset α) →* R left_inv f := funext fun x => show (Multiset.map f {x}).prod = _ by simp right_inv F := MonoidHom.ext fun x => let F' := MonoidHom.toAdditive'' F - let x' := Multiplicative.toAdd x + let x' := x.toAdd show (Multiset.map (fun a => F' {a}) x').sum = F' x' by erw [← Multiset.map_map (fun x => F' x) (fun x => {x}), ← AddMonoidHom.map_multiset_sum] exact DFunLike.congr_arg F (Multiset.sum_map_singleton x') diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean index 553951dd2ce186..82a5c54c0a72c9 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean @@ -6,6 +6,7 @@ Authors: Jujian Zhang, Eric Wieser import Mathlib.Order.Filter.AtTopBot import Mathlib.RingTheory.Localization.AtPrime import Mathlib.RingTheory.GradedAlgebra.Basic +import Mathlib.RingTheory.Localization.Away.Basic /-! # Homogeneous Localization @@ -473,6 +474,11 @@ def fromZeroRingHom : 𝒜 0 →+* HomogeneousLocalization 𝒜 x where map_zero' := rfl map_add' f g := by ext; simp [Localization.add_mk, add_comm f.1 g.1] +instance : Algebra (𝒜 0) (HomogeneousLocalization 𝒜 x) := + (fromZeroRingHom 𝒜 x).toAlgebra + +lemma algebraMap_eq : algebraMap (𝒜 0) (HomogeneousLocalization 𝒜 x) = fromZeroRingHom 𝒜 x := rfl + end HomogeneousLocalization namespace HomogeneousLocalization @@ -483,25 +489,25 @@ variable {𝒜} {x} /-- Numerator of an element in `HomogeneousLocalization x`. -/ def num (f : HomogeneousLocalization 𝒜 x) : A := - (Quotient.out' f).num + (Quotient.out f).num /-- Denominator of an element in `HomogeneousLocalization x`. -/ def den (f : HomogeneousLocalization 𝒜 x) : A := - (Quotient.out' f).den + (Quotient.out f).den /-- For an element in `HomogeneousLocalization x`, degree is the natural number `i` such that `𝒜 i` contains both numerator and denominator. -/ def deg (f : HomogeneousLocalization 𝒜 x) : ι := - (Quotient.out' f).deg + (Quotient.out f).deg theorem den_mem (f : HomogeneousLocalization 𝒜 x) : f.den ∈ x := - (Quotient.out' f).den_mem + (Quotient.out f).den_mem theorem num_mem_deg (f : HomogeneousLocalization 𝒜 x) : f.num ∈ 𝒜 f.deg := - (Quotient.out' f).num.2 + (Quotient.out f).num.2 theorem den_mem_deg (f : HomogeneousLocalization 𝒜 x) : f.den ∈ 𝒜 f.deg := - (Quotient.out' f).den.2 + (Quotient.out f).den.2 theorem eq_num_div_den (f : HomogeneousLocalization 𝒜 x) : f.val = Localization.mk f.num ⟨f.den, f.den_mem⟩ := @@ -627,4 +633,87 @@ lemma map_mk (g : A →+* B) end +section mapAway + +variable [AddCommMonoid ι] [DecidableEq ι] [GradedAlgebra 𝒜] +variable {e : ι} {f : A} {g : A} (hg : g ∈ 𝒜 e) {x : A} (hx : x = f * g) + +variable (𝒜) + +/-- Given `f ∣ x`, this is the map `A_{(f)} → A_f → A_x`. We will lift this to a map +`A_{(f)} → A_{(x)}` in `awayMap`. -/ +private def awayMapAux (hx : f ∣ x) : Away 𝒜 f →+* Localization.Away x := + (Localization.awayLift (algebraMap A _) _ + (isUnit_of_dvd_unit (map_dvd _ hx) (IsLocalization.Away.algebraMap_isUnit x))).comp + (algebraMap (Away 𝒜 f) (Localization.Away f)) + +lemma awayMapAux_mk (n a i hi) : + awayMapAux 𝒜 ⟨_, hx⟩ (mk ⟨n, a, ⟨f ^ i, hi⟩, ⟨i, rfl⟩⟩) = + Localization.mk (a * g ^ i) ⟨x ^ i, (Submonoid.mem_powers_iff _ _).mpr ⟨i, rfl⟩⟩ := by + have : algebraMap A (Localization.Away x) f * + (Localization.mk g ⟨f * g, (Submonoid.mem_powers_iff _ _).mpr ⟨1, by simp [hx]⟩⟩) = 1 := by + rw [← Algebra.smul_def, Localization.smul_mk] + exact Localization.mk_self ⟨f*g, _⟩ + simp [awayMapAux] + rw [Localization.awayLift_mk (hv := this), ← Algebra.smul_def, + Localization.mk_pow, Localization.smul_mk] + subst hx + rfl + +include hg in +lemma range_awayMapAux_subset : + Set.range (awayMapAux 𝒜 (f := f) ⟨_, hx⟩) ⊆ Set.range (val (𝒜 := 𝒜)) := by + rintro _ ⟨z, rfl⟩ + obtain ⟨⟨n, ⟨a, ha⟩, ⟨b, hb'⟩, j, rfl : _ = b⟩, rfl⟩ := mk_surjective z + use mk ⟨n+j•e,⟨a*g^j, ?_⟩ ,⟨x^j, ?_⟩, j, rfl⟩ + · simp [awayMapAux_mk 𝒜 (hx := hx)] + · apply SetLike.mul_mem_graded ha + exact SetLike.pow_mem_graded _ hg + · rw [hx, mul_pow] + apply SetLike.mul_mem_graded hb' + exact SetLike.pow_mem_graded _ hg + +/-- Given `x = f * g` with `g` homogeneous of positive degree, +this is the map `A_{(f)} → A_{(x)}` taking `a/f^i` to `ag^i/(fg)^i`. -/ +def awayMap : Away 𝒜 f →+* Away 𝒜 x := by + let e := RingEquiv.ofLeftInverse (f := algebraMap (Away 𝒜 x) (Localization.Away x)) + (h := (val_injective _).hasLeftInverse.choose_spec) + refine RingHom.comp (e.symm.toRingHom.comp (Subring.inclusion ?_)) + (awayMapAux 𝒜 (f := f) ⟨_, hx⟩).rangeRestrict + exact range_awayMapAux_subset 𝒜 hg hx + +lemma val_awayMap_eq_aux (a) : (awayMap 𝒜 hg hx a).val = awayMapAux 𝒜 ⟨_, hx⟩ a := by + let e := RingEquiv.ofLeftInverse (f := algebraMap (Away 𝒜 x) (Localization.Away x)) + (h := (val_injective _).hasLeftInverse.choose_spec) + dsimp [awayMap] + convert_to (e (e.symm ⟨awayMapAux 𝒜 (f := f) ⟨_, hx⟩ a, + range_awayMapAux_subset 𝒜 hg hx ⟨_, rfl⟩⟩)).1 = _ + rw [e.apply_symm_apply] + +lemma val_awayMap (a) : (awayMap 𝒜 hg hx a).val = Localization.awayLift (algebraMap A _) _ + (isUnit_of_dvd_unit (map_dvd _ ⟨_, hx⟩) (IsLocalization.Away.algebraMap_isUnit x)) a.val := by + rw [val_awayMap_eq_aux] + rfl + +lemma awayMap_fromZeroRingHom (a) : + awayMap 𝒜 hg hx (fromZeroRingHom 𝒜 _ a) = fromZeroRingHom 𝒜 _ a := by + ext + simp only [fromZeroRingHom, RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk, + val_awayMap, val_mk, SetLike.GradeZero.coe_one] + convert IsLocalization.lift_eq _ _ + +lemma val_awayMap_mk (n a i hi) : (awayMap 𝒜 hg hx (mk ⟨n, a, ⟨f ^ i, hi⟩, ⟨i, rfl⟩⟩)).val = + Localization.mk (a * g ^ i) ⟨x ^ i, (Submonoid.mem_powers_iff _ _).mpr ⟨i, rfl⟩⟩ := by + rw [val_awayMap_eq_aux, awayMapAux_mk 𝒜 (hx := hx)] + +/-- Given `x = f * g` with `g` homogeneous of positive degree, +this is the map `A_{(f)} → A_{(x)}` taking `a/f^i` to `ag^i/(fg)^i`. -/ +def awayMapₐ : Away 𝒜 f →ₐ[𝒜 0] Away 𝒜 x where + __ := awayMap 𝒜 hg hx + commutes' _ := awayMap_fromZeroRingHom .. + +@[simp] lemma awayMapₐ_apply (a) : awayMapₐ 𝒜 hg hx a = awayMap 𝒜 hg hx a := rfl + +end mapAway + end HomogeneousLocalization diff --git a/Mathlib/RingTheory/GradedAlgebra/Noetherian.lean b/Mathlib/RingTheory/GradedAlgebra/Noetherian.lean index cba8dab1966288..9bd8cc5122295b 100644 --- a/Mathlib/RingTheory/GradedAlgebra/Noetherian.lean +++ b/Mathlib/RingTheory/GradedAlgebra/Noetherian.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Fangming Li -/ import Mathlib.RingTheory.GradedAlgebra.Basic -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic /-! # The properties of a graded Noetherian ring. diff --git a/Mathlib/RingTheory/HahnSeries/Basic.lean b/Mathlib/RingTheory/HahnSeries/Basic.lean index aa4ddc454c2dce..b074a86e1aa3b3 100644 --- a/Mathlib/RingTheory/HahnSeries/Basic.lean +++ b/Mathlib/RingTheory/HahnSeries/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ import Mathlib.Algebra.Group.Support +import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop import Mathlib.Order.WellFoundedSet /-! diff --git a/Mathlib/RingTheory/Ideal/Defs.lean b/Mathlib/RingTheory/Ideal/Defs.lean index d2eb82b15fdd49..ba78f8a4b205b5 100644 --- a/Mathlib/RingTheory/Ideal/Defs.lean +++ b/Mathlib/RingTheory/Ideal/Defs.lean @@ -68,6 +68,15 @@ theorem unit_mul_mem_iff_mem {x y : α} (hy : IsUnit y) : y * x ∈ I ↔ x ∈ end Ideal +/-- For two elements `m` and `m'` in an `R`-module `M`, the set of elements `r : R` with +equal scalar product with `m` and `m'` is an ideal of `R`. If `M` is a group, this coincides +with the kernel of `LinearMap.toSpanSingleton R M (m - m')`. -/ +def Module.eqIdeal (R) {M} [Semiring R] [AddCommMonoid M] [Module R M] (m m' : M) : Ideal R where + carrier := {r : R | r • m = r • m'} + add_mem' h h' := by simpa [add_smul] using congr($h + $h') + zero_mem' := by simp_rw [Set.mem_setOf, zero_smul] + smul_mem' _ _ h := by simpa [mul_smul] using congr(_ • $h) + end Semiring section CommSemiring diff --git a/Mathlib/RingTheory/Ideal/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index 7a67ded065aff6..e2a631a34c0a91 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -362,9 +362,20 @@ theorem comap_symm {I : Ideal R} (f : R ≃+* S) : I.comap f.symm = I.map f := /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `map f.symm I = comap f I`. -/ @[simp] + theorem map_symm {I : Ideal S} (f : R ≃+* S) : I.map f.symm = I.comap f := map_comap_of_equiv (RingEquiv.symm f) +@[simp] +theorem symm_apply_mem_of_equiv_iff {I : Ideal R} {f : R ≃+* S} {y : S} : + f.symm y ∈ I ↔ y ∈ I.map f := by + rw [← comap_symm, mem_comap] + +@[simp] +theorem apply_mem_of_equiv_iff {I : Ideal R} {f : R ≃+* S} {x : R} : + f x ∈ I.map f ↔ x ∈ I := by + rw [← comap_symm, Ideal.mem_comap, f.symm_apply_apply] + theorem mem_map_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e : E) {I : Ideal R} (y : S) : y ∈ map e I ↔ ∃ x ∈ I, e x = y := by constructor diff --git a/Mathlib/RingTheory/Ideal/Maximal.lean b/Mathlib/RingTheory/Ideal/Maximal.lean index 591bb5e34a064d..c3cb20cf054d0a 100644 --- a/Mathlib/RingTheory/Ideal/Maximal.lean +++ b/Mathlib/RingTheory/Ideal/Maximal.lean @@ -162,6 +162,15 @@ theorem IsMaximal.isPrime {I : Ideal α} (H : I.IsMaximal) : I.IsPrime := instance (priority := 100) IsMaximal.isPrime' (I : Ideal α) : ∀ [_H : I.IsMaximal], I.IsPrime := @IsMaximal.isPrime _ _ _ +theorem exists_disjoint_powers_of_span_eq_top (s : Set α) (hs : span s = ⊤) (I : Ideal α) + (hI : I ≠ ⊤) : ∃ r ∈ s, Disjoint (I : Set α) (Submonoid.powers r) := by + have ⟨M, hM, le⟩ := exists_le_maximal I hI + have := hM.1.1 + rw [Ne, eq_top_iff, ← hs, span_le, Set.not_subset] at this + have ⟨a, has, haM⟩ := this + exact ⟨a, has, Set.disjoint_left.mpr fun x hx ⟨n, hn⟩ ↦ + haM (hM.isPrime.mem_of_pow_mem _ (le <| hn ▸ hx))⟩ + theorem span_singleton_lt_span_singleton [IsDomain α] {x y : α} : span ({x} : Set α) < span ({y} : Set α) ↔ DvdNotUnit y x := by rw [lt_iff_le_not_le, span_singleton_le_span_singleton, span_singleton_le_span_singleton, @@ -191,6 +200,26 @@ lemma isPrime_of_maximally_disjoint (I : Ideal α) rw [← hr₁, ← hr₂] ring +theorem exists_le_prime_disjoint (S : Submonoid α) (disjoint : Disjoint (I : Set α) S) : + ∃ p : Ideal α, p.IsPrime ∧ I ≤ p ∧ Disjoint (p : Set α) S := by + have ⟨p, hIp, hp⟩ := zorn_le_nonempty₀ {p : Ideal α | Disjoint (p : Set α) S} + (fun c hc hc' x hx ↦ ?_) I disjoint + · exact ⟨p, isPrime_of_maximally_disjoint _ _ hp.1 (fun _ ↦ hp.not_prop_of_gt), hIp, hp.1⟩ + cases isEmpty_or_nonempty c + · exact ⟨I, disjoint, fun J hJ ↦ isEmptyElim (⟨J, hJ⟩ : c)⟩ + refine ⟨sSup c, Set.disjoint_left.mpr fun x hx ↦ ?_, fun _ ↦ le_sSup⟩ + have ⟨p, hp⟩ := (Submodule.mem_iSup_of_directed _ hc'.directed).mp (sSup_eq_iSup' c ▸ hx) + exact Set.disjoint_left.mp (hc p.2) hp + +theorem exists_le_prime_nmem_of_isIdempotentElem (a : α) (ha : IsIdempotentElem a) (haI : a ∉ I) : + ∃ p : Ideal α, p.IsPrime ∧ I ≤ p ∧ a ∉ p := + have : Disjoint (I : Set α) (Submonoid.powers a) := Set.disjoint_right.mpr <| by + rw [ha.coe_powers] + rintro _ (rfl|rfl) + exacts [I.ne_top_iff_one.mp (ne_of_mem_of_not_mem' Submodule.mem_top haI).symm, haI] + have ⟨p, h1, h2, h3⟩ := exists_le_prime_disjoint _ _ this + ⟨p, h1, h2, Set.disjoint_right.mp h3 (Submonoid.mem_powers a)⟩ + end Ideal end CommSemiring diff --git a/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean b/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean index 69f9fc150ca4f7..bf904f8bef341a 100644 --- a/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean +++ b/Mathlib/RingTheory/Ideal/Norm/AbsNorm.lean @@ -11,6 +11,7 @@ import Mathlib.LinearAlgebra.FreeModule.IdealQuotient import Mathlib.RingTheory.DedekindDomain.Dvr import Mathlib.RingTheory.DedekindDomain.Ideal import Mathlib.RingTheory.Norm.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicative /-! diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index e18052a266b00f..7218ec0a9688e6 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -287,9 +287,7 @@ variable {R : Type u} [Semiring R] theorem add_eq_sup {I J : Ideal R} : I + J = I ⊔ J := rfl --- dsimp loops when applying this lemma to its LHS, --- probably https://github.com/leanprover/lean4/pull/2867 -@[simp, nolint simpNF] +@[simp] theorem zero_eq_bot : (0 : Ideal R) = ⊥ := rfl @@ -441,9 +439,7 @@ lemma sup_pow_add_le_pow_sup_pow {n m : ℕ} : (I ⊔ J) ^ (n + m) ≤ I ^ n ⊔ ((Ideal.pow_le_pow_right hn).trans le_sup_left))) · refine (Ideal.mul_le_right.trans (Ideal.mul_le_left.trans ((Ideal.pow_le_pow_right ?_).trans le_sup_right))) - simp only [Finset.mem_range, Nat.lt_succ] at hi - rw [Nat.le_sub_iff_add_le hi] - nlinarith + omega variable (I J K) diff --git a/Mathlib/RingTheory/Ideal/Quotient/Basic.lean b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean index 190587bcc84f3c..244da7d3aada9a 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Basic.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Basic.lean @@ -191,7 +191,7 @@ noncomputable def piQuotEquiv : ((ι → R) ⧸ I.pi ι) ≃ₗ[R ⧸ I] ι → funext fun i => (Submodule.Quotient.eq' _).2 (QuotientAddGroup.leftRel_apply.mp hab i) map_add' := by rintro ⟨_⟩ ⟨_⟩; rfl map_smul' := by rintro ⟨_⟩ ⟨_⟩; rfl - invFun := fun x ↦ Ideal.Quotient.mk (I.pi ι) fun i ↦ Quotient.out' (x i) + invFun := fun x ↦ Ideal.Quotient.mk (I.pi ι) fun i ↦ Quotient.out (x i) left_inv := by rintro ⟨x⟩ exact Ideal.Quotient.eq.2 fun i => Ideal.Quotient.eq.1 (Quotient.out_eq' _) @@ -216,7 +216,7 @@ end Pi open scoped Pointwise in /-- A ring is made up of a disjoint union of cosets of an ideal. -/ lemma univ_eq_iUnion_image_add {R : Type*} [Ring R] (I : Ideal R) : - (Set.univ (α := R)) = ⋃ x : R ⧸ I, x.out' +ᵥ (I : Set R) := + (Set.univ (α := R)) = ⋃ x : R ⧸ I, x.out +ᵥ (I : Set R) := QuotientAddGroup.univ_eq_iUnion_vadd I.toAddSubgroup lemma _root_.Finite.of_finite_quot_finite_ideal {R : Type*} [Ring R] {I : Ideal R} diff --git a/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean b/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean index abe698078c1999..2f2f268de19984 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Noetherian.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.RingTheory.Ideal.Quotient.Operations -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic /-! # Noetherian quotient rings and quotient modules diff --git a/Mathlib/RingTheory/Ideal/Span.lean b/Mathlib/RingTheory/Ideal/Span.lean index e2f263723ce31d..1b10889acf12fa 100644 --- a/Mathlib/RingTheory/Ideal/Span.lean +++ b/Mathlib/RingTheory/Ideal/Span.lean @@ -237,3 +237,22 @@ theorem span_singleton_neg (x : α) : (span {-x} : Ideal α) = span {x} := by end Ideal end Ring + +namespace IsIdempotentElem + +variable {R} [CommRing R] {e : R} (he : IsIdempotentElem e) +include he + +theorem ker_toSpanSingleton_eq_span : + LinearMap.ker (LinearMap.toSpanSingleton R R e) = Ideal.span {1 - e} := SetLike.ext fun x ↦ by + rw [Ideal.mem_span_singleton'] + refine ⟨fun h ↦ ⟨x, by rw [mul_sub, show x * e = 0 from h, mul_one, sub_zero]⟩, fun h ↦ ?_⟩ + obtain ⟨x, rfl⟩ := h + show x * (1 - e) * e = 0 + rw [mul_assoc, sub_mul, one_mul, he, sub_self, mul_zero] + +theorem ker_toSpanSingleton_one_sub_eq_span : + LinearMap.ker (LinearMap.toSpanSingleton R R (1 - e)) = Ideal.span {e} := by + rw [ker_toSpanSingleton_eq_span he.one_sub, sub_sub_cancel] + +end IsIdempotentElem diff --git a/Mathlib/RingTheory/Idempotents.lean b/Mathlib/RingTheory/Idempotents.lean index ffc85853ec287b..65b8c4836a131e 100644 --- a/Mathlib/RingTheory/Idempotents.lean +++ b/Mathlib/RingTheory/Idempotents.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Nilpotent.Defs +import Mathlib.Tactic.StacksAttribute /-! @@ -346,6 +347,7 @@ theorem eq_of_isNilpotent_sub_of_isIdempotentElem {e₁ e₂ : R} e₁ = e₂ := eq_of_isNilpotent_sub_of_isIdempotentElem_of_commute he₁ he₂ H (.all _ _) +@[stacks 00J9] theorem existsUnique_isIdempotentElem_eq_of_ker_isNilpotent (h : ∀ x ∈ RingHom.ker f, IsNilpotent x) (e : S) (he : e ∈ f.range) (he' : IsIdempotentElem e) : ∃! e' : R, IsIdempotentElem e' ∧ f e' = e := by diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index b292e8b1c1ffc0..a44906bcb806f8 100644 --- a/Mathlib/RingTheory/IntegralDomain.lean +++ b/Mathlib/RingTheory/IntegralDomain.lean @@ -149,8 +149,6 @@ section EuclideanDivision namespace Polynomial -open Polynomial - variable (K : Type) [Field K] [Algebra R[X] K] [IsFractionRing R[X] K] theorem div_eq_quo_add_rem_div (f : R[X]) {g : R[X]} (hg : g.Monic) : diff --git a/Mathlib/RingTheory/Jacobson.lean b/Mathlib/RingTheory/Jacobson.lean index 14e36f678fd84e..56997e889c66f4 100644 --- a/Mathlib/RingTheory/Jacobson.lean +++ b/Mathlib/RingTheory/Jacobson.lean @@ -247,8 +247,6 @@ end Localization namespace Polynomial -open Polynomial - section CommRing -- Porting note: move to better place diff --git a/Mathlib/RingTheory/LaurentSeries.lean b/Mathlib/RingTheory/LaurentSeries.lean index 2d9c6f7c2f02ee..1e09014fa6640d 100644 --- a/Mathlib/RingTheory/LaurentSeries.lean +++ b/Mathlib/RingTheory/LaurentSeries.lean @@ -869,7 +869,7 @@ theorem Cauchy.eventually_mem_nhds {ℱ : Filter K⸨X⸩} (hℱ : Cauchy ℱ) 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₀ + set D := -((WithZero.unzero γ.ne_zero).toAdd - 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] @@ -911,7 +911,8 @@ theorem exists_Polynomial_intValuation_lt (F : K⟦X⟧) (η : ℤₘ₀ˣ) : rw [← valuation_of_algebraMap (K := K⸨X⸩) (PowerSeries.idealX K) (F - F.trunc (d + 1))] apply lt_of_le_of_lt this rw [← mul_one (η : ℤₘ₀), mul_assoc, one_mul] - apply mul_lt_mul_of_lt_of_le₀ (le_refl _) η.ne_zero + gcongr + · exact zero_lt_iff.2 η.ne_zero rw [← WithZero.coe_one, coe_lt_coe, ofAdd_neg, Right.inv_lt_one_iff, ← ofAdd_zero, Multiplicative.ofAdd_lt] exact Int.zero_lt_one @@ -932,7 +933,7 @@ theorem exists_ratFunc_val_lt (f : K⸨X⸩) (γ : ℤₘ₀ˣ) : · erw [hs, ← F_mul, PowerSeries.coe_pow, PowerSeries.coe_X, RatFunc.coe_mul, zpow_neg, zpow_ofNat, inv_eq_one_div (RatFunc.X ^ s), RatFunc.coe_div, RatFunc.coe_pow, RatFunc.coe_X, RatFunc.coe_one, ← inv_eq_one_div, ← mul_sub, map_mul, map_inv₀, ← PowerSeries.coe_X, - valuation_X_pow, ← hs, ← RatFunc.coe_coe, ← coe_sub, ← coe_algebraMap, + valuation_X_pow, ← hs, ← RatFunc.coe_coe, ← PowerSeries.coe_sub, ← coe_algebraMap, valuation_of_algebraMap, ← Units.val_mk0 (a := ((Multiplicative.ofAdd f.order : Multiplicative ℤ) : ℤₘ₀)), ← hη] apply inv_mul_lt_of_lt_mul₀ @@ -942,8 +943,8 @@ theorem exists_ratFunc_val_lt (f : K⸨X⸩) (γ : ℤₘ₀ˣ) : · obtain ⟨s, hs⟩ := Int.exists_eq_neg_ofNat (Int.neg_nonpos_of_nonneg (not_lt.mp ord_nonpos)) obtain ⟨P, hP⟩ := exists_Polynomial_intValuation_lt (PowerSeries.X ^ s * F) γ use P - erw [← X_order_mul_powerSeriesPart (neg_inj.1 hs).symm, ← RatFunc.coe_coe, ← coe_sub, - ← coe_algebraMap, valuation_of_algebraMap] + erw [← X_order_mul_powerSeriesPart (neg_inj.1 hs).symm, ← RatFunc.coe_coe, + ← PowerSeries.coe_sub, ← coe_algebraMap, valuation_of_algebraMap] exact hP theorem coe_range_dense : DenseRange ((↑) : RatFunc K → K⸨X⸩) := by @@ -980,7 +981,7 @@ theorem inducing_coe : IsUniformInducing ((↑) : RatFunc K → K⸨X⸩) := by refine ⟨⟨d, by rfl⟩, subset_trans (fun _ _ ↦ pre_R ?_) pre_T⟩ apply hd simp only [sub_zero, Set.mem_setOf_eq] - erw [← coe_sub, ← valuation_eq_LaurentSeries_valuation] + erw [← RatFunc.coe_sub, ← valuation_eq_LaurentSeries_valuation] assumption · rintro ⟨_, ⟨hT, pre_T⟩⟩ obtain ⟨d, hd⟩ := Valued.mem_nhds.mp hT @@ -992,7 +993,7 @@ theorem inducing_coe : IsUniformInducing ((↑) : RatFunc K → K⸨X⸩) := by · refine subset_trans (fun _ _ ↦ ?_) pre_T apply hd erw [Set.mem_setOf_eq, sub_zero, valuation_eq_LaurentSeries_valuation, - coe_sub] + RatFunc.coe_sub] assumption theorem continuous_coe : Continuous ((↑) : RatFunc K → K⸨X⸩) := diff --git a/Mathlib/RingTheory/LocalProperties/Exactness.lean b/Mathlib/RingTheory/LocalProperties/Exactness.lean new file mode 100644 index 00000000000000..3c6ae6bb837c7a --- /dev/null +++ b/Mathlib/RingTheory/LocalProperties/Exactness.lean @@ -0,0 +1,194 @@ +/- +Copyright (c) 2024 Sihan Su. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sihan Su, Yongle Hu, Yi Song +-/ +import Mathlib.Algebra.Exact +import Mathlib.RingTheory.LocalProperties.Submodule +import Mathlib.RingTheory.Localization.Away.Basic + +/-! +# Local properties about linear maps + +In this file, we show that +injectivity, surjectivity, bijectivity and exactness of linear maps are local properties. +More precisely, we show that these can be checked at maximal ideals and on standard covers. + +-/ +open Submodule LocalizedModule Ideal LinearMap + +section isLocalized_maximal + +open IsLocalizedModule + +variable {R M N L : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [AddCommMonoid N] [Module R N] [AddCommMonoid L] [Module R L] + +variable + (Mₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) + [∀ (P : Ideal R) [P.IsMaximal], AddCommMonoid (Mₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], Module R (Mₚ P)] + (f : ∀ (P : Ideal R) [P.IsMaximal], M →ₗ[R] Mₚ P) + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (f P)] + (Nₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) + [∀ (P : Ideal R) [P.IsMaximal], AddCommMonoid (Nₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], Module R (Nₚ P)] + (g : ∀ (P : Ideal R) [P.IsMaximal], N →ₗ[R] Nₚ P) + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (g P)] + (Lₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) + [∀ (P : Ideal R) [P.IsMaximal], AddCommMonoid (Lₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], Module R (Lₚ P)] + (h : ∀ (P : Ideal R) [P.IsMaximal], L →ₗ[R] Lₚ P) + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (h P)] + (F : M →ₗ[R] N) (G : N →ₗ[R] L) + +theorem injective_of_isLocalized_maximal + (H : ∀ (P : Ideal R) [P.IsMaximal], Function.Injective (map P.primeCompl (f P) (g P) F)) : + Function.Injective F := + fun x y eq ↦ Module.eq_of_localization_maximal _ f _ _ fun P _ ↦ H P <| by simp [eq] + +theorem surjective_of_isLocalized_maximal + (H : ∀ (P : Ideal R) [P.IsMaximal], Function.Surjective (map P.primeCompl (f P) (g P) F)) : + Function.Surjective F := + range_eq_top.mp <| eq_top_of_localization₀_maximal Nₚ g _ <| + fun P _ ↦ (range_localizedMap_eq_localized₀_range _ (f P) (g P) F).symm.trans <| + range_eq_top.mpr <| H P + +theorem bijective_of_isLocalized_maximal + (H : ∀ (P : Ideal R) [P.IsMaximal], Function.Bijective (map P.primeCompl (f P) (g P) F)) : + Function.Bijective F := + ⟨injective_of_isLocalized_maximal Mₚ f Nₚ g F fun J _ ↦ (H J).1, + surjective_of_isLocalized_maximal Mₚ f Nₚ g F fun J _ ↦ (H J).2⟩ + +theorem exact_of_isLocalized_maximal (H : ∀ (J : Ideal R) [J.IsMaximal], + Function.Exact (map J.primeCompl (f J) (g J) F) (map J.primeCompl (g J) (h J) G)) : + Function.Exact F G := by + simp only [LinearMap.exact_iff] at H ⊢ + apply eq_of_localization₀_maximal Nₚ g + intro J hJ + rw [← LinearMap.range_localizedMap_eq_localized₀_range _ (f J) (g J) F, + ← LinearMap.ker_localizedMap_eq_localized₀_ker J.primeCompl (g J) (h J) G] + have := SetLike.ext_iff.mp <| H J + ext x + simp only [mem_range, mem_ker] at this ⊢ + exact this x + +end isLocalized_maximal + +section localized_maximal + +variable {R M N L : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [AddCommMonoid N] [Module R N] [AddCommMonoid L] [Module R L] (f : M →ₗ[R] N) (g : N →ₗ[R] L) + +theorem injective_of_localized_maximal + (h : ∀ (J : Ideal R) [J.IsMaximal], Function.Injective (map J.primeCompl f)) : + Function.Injective f := + injective_of_isLocalized_maximal _ (fun _ _ ↦ mkLinearMap _ _) _ (fun _ _ ↦ mkLinearMap _ _) f h + +theorem surjective_of_localized_maximal + (h : ∀ (J : Ideal R) [J.IsMaximal], Function.Surjective (map J.primeCompl f)) : + Function.Surjective f := + surjective_of_isLocalized_maximal _ (fun _ _ ↦ mkLinearMap _ _) _ (fun _ _ ↦ mkLinearMap _ _) f h + +theorem bijective_of_localized_maximal + (h : ∀ (J : Ideal R) [J.IsMaximal], Function.Bijective (map J.primeCompl f)) : + Function.Bijective f := + ⟨injective_of_localized_maximal _ fun J _ ↦ (h J).1, + surjective_of_localized_maximal _ fun J _ ↦ (h J).2⟩ + +theorem exact_of_localized_maximal + (h : ∀ (J : Ideal R) [J.IsMaximal], Function.Exact (map J.primeCompl f) (map J.primeCompl g)) : + Function.Exact f g := + exact_of_isLocalized_maximal _ (fun _ _ ↦ mkLinearMap _ _) _ (fun _ _ ↦ mkLinearMap _ _) + _ (fun _ _ ↦ mkLinearMap _ _) f g h + +end localized_maximal + +section isLocalized_span + +open IsLocalizedModule + +variable {R M N L : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [AddCommMonoid N] [Module R N] [AddCommMonoid L] [Module R L] (s : Set R) (spn : Ideal.span s = ⊤) +include spn + +variable + (Mₚ : ∀ _ : s, Type*) + [∀ r : s, AddCommMonoid (Mₚ r)] + [∀ r : s, Module R (Mₚ r)] + (f : ∀ r : s, M →ₗ[R] Mₚ r) + [∀ r : s, IsLocalizedModule (.powers r.1) (f r)] + (Nₚ : ∀ _ : s, Type*) + [∀ r : s, AddCommMonoid (Nₚ r)] + [∀ r : s, Module R (Nₚ r)] + (g : ∀ r : s, N →ₗ[R] Nₚ r) + [∀ r : s, IsLocalizedModule (.powers r.1) (g r)] + (Lₚ : ∀ _ : s, Type*) + [∀ r : s, AddCommMonoid (Lₚ r)] + [∀ r : s, Module R (Lₚ r)] + (h : ∀ r : s, L →ₗ[R] Lₚ r) + [∀ r : s, IsLocalizedModule (.powers r.1) (h r)] + (F : M →ₗ[R] N) (G : N →ₗ[R] L) + +theorem injective_of_isLocalized_span + (H : ∀ r : s, Function.Injective (map (.powers r.1) (f r) (g r) F)) : + Function.Injective F := + fun x y eq ↦ Module.eq_of_isLocalized_span _ spn _ f _ _ fun P ↦ H P <| by simp [eq] + +theorem surjective_of_isLocalized_span + (H : ∀ r : s, Function.Surjective (map (.powers r.1) (f r) (g r) F)) : + Function.Surjective F := + range_eq_top.mp <| eq_top_of_isLocalized₀_span s spn Nₚ g fun r ↦ + (range_localizedMap_eq_localized₀_range _ (f r) (g r) F).symm.trans <| range_eq_top.mpr <| H r + +theorem bijective_of_isLocalized_span + (H : ∀ r : s, Function.Bijective (map (.powers r.1) (f r) (g r) F)) : + Function.Bijective F := + ⟨injective_of_isLocalized_span _ spn Mₚ f Nₚ g F fun r ↦ (H r).1, + surjective_of_isLocalized_span _ spn Mₚ f Nₚ g F fun r ↦ (H r).2⟩ + +lemma exact_of_isLocalized_span (H : ∀ r : s, Function.Exact + (map (.powers r.1) (f r) (g r) F) (map (.powers r.1) (g r) (h r) G)) : + Function.Exact F G := by + simp only [LinearMap.exact_iff] at H ⊢ + apply Submodule.eq_of_isLocalized₀_span s spn Nₚ g + intro r + rw [← LinearMap.range_localizedMap_eq_localized₀_range _ (f r) (g r) F] + rw [← LinearMap.ker_localizedMap_eq_localized₀_ker (.powers r.1) (g r) (h r) G] + have := SetLike.ext_iff.mp <| H r + ext x + simp only [mem_range, mem_ker] at this ⊢ + exact this x + +end isLocalized_span + +section localized_span + +variable {R M N L : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [AddCommMonoid N] [Module R N] [AddCommMonoid L] [Module R L] + (s : Set R) (spn : span s = ⊤) (f : M →ₗ[R] N) (g : N →ₗ[R] L) +include spn + +theorem injective_of_localized_span + (h : ∀ r : s, Function.Injective (map (.powers r.1) f)) : + Function.Injective f := + injective_of_isLocalized_span s spn _ (fun _ ↦ mkLinearMap _ _) _ (fun _ ↦ mkLinearMap _ _) f h + +theorem surjective_of_localized_span + (h : ∀ r : s, Function.Surjective (map (.powers r.1) f)) : + Function.Surjective f := + surjective_of_isLocalized_span s spn _ (fun _ ↦ mkLinearMap _ _) _ (fun _ ↦ mkLinearMap _ _) f h + +theorem bijective_of_localized_span + (h : ∀ r : s, Function.Bijective (map (.powers r.1) f)) : + Function.Bijective f := + ⟨injective_of_localized_span _ spn _ fun r ↦ (h r).1, + surjective_of_localized_span _ spn _ fun r ↦ (h r).2⟩ + +lemma exact_of_localized_span + (h : ∀ r : s, Function.Exact (map (.powers r.1) f) (map (.powers r.1) g)) : + Function.Exact f g := + exact_of_isLocalized_span s spn _ (fun _ ↦ mkLinearMap _ _) _ (fun _ ↦ mkLinearMap _ _) + _ (fun _ ↦ mkLinearMap _ _) f g h + +end localized_span diff --git a/Mathlib/RingTheory/LocalProperties/Projective.lean b/Mathlib/RingTheory/LocalProperties/Projective.lean index d6a190e4ac15fc..d6c0268663ed75 100644 --- a/Mathlib/RingTheory/LocalProperties/Projective.lean +++ b/Mathlib/RingTheory/LocalProperties/Projective.lean @@ -5,9 +5,9 @@ Authors: Andrew Yang, David Swinarski -/ import Mathlib.Algebra.Module.FinitePresentation import Mathlib.Algebra.Module.Projective -import Mathlib.LinearAlgebra.FreeModule.Basic +import Mathlib.LinearAlgebra.Dimension.Constructions +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.RingTheory.LocalProperties.Submodule -import Mathlib.RingTheory.Localization.BaseChange /-! @@ -25,14 +25,49 @@ import Mathlib.RingTheory.Localization.BaseChange -/ -variable {R M N N'} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] -variable [AddCommGroup N'] [Module R N'] (S : Submonoid R) +universe uM + +variable {R N N' : Type*} {M : Type uM} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] +variable [Module R N] [AddCommGroup N'] [Module R N'] (S : Submonoid R) + +theorem Module.free_of_isLocalizedModule {Rₛ Mₛ} [AddCommGroup Mₛ] [Module R Mₛ] + [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ Mₛ] [IsScalarTower R Rₛ Mₛ] + (S) (f : M →ₗ[R] Mₛ) [IsLocalization S Rₛ] [IsLocalizedModule S f] [Module.Free R M] : + Module.Free Rₛ Mₛ := + Free.of_equiv (IsLocalizedModule.isBaseChange S Rₛ f).equiv + +universe uR' uM' in +/-- +Also see `IsLocalizedModule.lift_rank_eq` for a version for non-free modules, +but requires `S` to not contain any zero-divisors. +-/ +theorem Module.lift_rank_of_isLocalizedModule_of_free + (Rₛ : Type uR') {Mₛ : Type uM'} [AddCommGroup Mₛ] [Module R Mₛ] + [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ Mₛ] [IsScalarTower R Rₛ Mₛ] (S : Submonoid R) + (f : M →ₗ[R] Mₛ) [IsLocalization S Rₛ] [IsLocalizedModule S f] [Module.Free R M] + [Nontrivial Rₛ] : + Cardinal.lift.{uM} (Module.rank Rₛ Mₛ) = Cardinal.lift.{uM'} (Module.rank R M) := by + apply Cardinal.lift_injective.{max uM' uR'} + have := (algebraMap R Rₛ).domain_nontrivial + have := (IsLocalizedModule.isBaseChange S Rₛ f).equiv.lift_rank_eq.symm + simp only [rank_tensorProduct, rank_self, + Cardinal.lift_one, one_mul, Cardinal.lift_lift] at this ⊢ + convert this + exact Cardinal.lift_umax + +theorem Module.finrank_of_isLocalizedModule_of_free + (Rₛ : Type*) {Mₛ : Type*} [AddCommGroup Mₛ] [Module R Mₛ] + [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ Mₛ] [IsScalarTower R Rₛ Mₛ] (S : Submonoid R) + (f : M →ₗ[R] Mₛ) [IsLocalization S Rₛ] [IsLocalizedModule S f] [Module.Free R M] + [Nontrivial Rₛ] : + Module.finrank Rₛ Mₛ = Module.finrank R M := by + simpa using congr(Cardinal.toNat $(Module.lift_rank_of_isLocalizedModule_of_free Rₛ S f)) theorem Module.projective_of_isLocalizedModule {Rₛ Mₛ} [AddCommGroup Mₛ] [Module R Mₛ] [CommRing Rₛ] [Algebra R Rₛ] [Module Rₛ Mₛ] [IsScalarTower R Rₛ Mₛ] (S) (f : M →ₗ[R] Mₛ) [IsLocalization S Rₛ] [IsLocalizedModule S f] [Module.Projective R M] : - Module.Projective Rₛ Mₛ := - Projective.of_equiv (IsLocalizedModule.isBaseChange S Rₛ f).equiv + Module.Projective Rₛ Mₛ := + Projective.of_equiv (IsLocalizedModule.isBaseChange S Rₛ f).equiv theorem LinearMap.split_surjective_of_localization_maximal (f : M →ₗ[R] N) [Module.FinitePresentation R N] @@ -41,18 +76,8 @@ theorem LinearMap.split_surjective_of_localization_maximal (LocalizedModule.map I.primeCompl f).comp g = LinearMap.id) : ∃ (g : N →ₗ[R] M), f.comp g = LinearMap.id := by show LinearMap.id ∈ LinearMap.range (LinearMap.llcomp R N M N f) - have inst₁ (I : Ideal R) [I.IsMaximal] : - IsLocalizedModule I.primeCompl (LocalizedModule.map (M := N) (N := N) I.primeCompl) := - inferInstance - have inst₂ (I : Ideal R) [I.IsMaximal] : - IsLocalizedModule I.primeCompl (LocalizedModule.map (M := N) (N := M) I.primeCompl) := - inferInstance - apply - @Submodule.mem_of_localization_maximal R (N →ₗ[R] N) _ _ _ - (fun P _ ↦ Localization.AtPrime P) _ _ _ _ _ _ _ _ - (fun P _ ↦ LocalizedModule.map P.primeCompl) - (fun P _ ↦ inst₁ P) - intro I hI + refine Submodule.mem_of_localization_maximal _ (fun P _ ↦ LocalizedModule.map P.primeCompl) _ _ + fun I hI ↦ ?_ rw [LocalizedModule.map_id] have : LinearMap.id ∈ LinearMap.range (LinearMap.llcomp _ (LocalizedModule I.primeCompl N) _ _ (LocalizedModule.map I.primeCompl f)) := H I hI diff --git a/Mathlib/RingTheory/LocalProperties/Submodule.lean b/Mathlib/RingTheory/LocalProperties/Submodule.lean index f4e9274c697bdc..90ade41827edf1 100644 --- a/Mathlib/RingTheory/LocalProperties/Submodule.lean +++ b/Mathlib/RingTheory/LocalProperties/Submodule.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang, David Swinarski -/ import Mathlib.Algebra.Module.LocalizedModule.Submodule -import Mathlib.RingTheory.Ideal.Colon import Mathlib.RingTheory.Localization.AtPrime +import Mathlib.RingTheory.Localization.Away.Basic /-! # Local properties of modules and submodules @@ -15,87 +15,189 @@ In this file, we show that several conditions on submodules can be checked on st open scoped nonZeroDivisors -variable {R A M} [CommRing R] [CommRing A] [AddCommGroup M] [Algebra R A] [Module R M] [Module A M] +variable {R M M₁ : Type*} [CommSemiring R] [AddCommMonoid M] [Module R M] + [AddCommMonoid M₁] [Module R M₁] + +section maximal variable (Rₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) - [∀ (P : Ideal R) [P.IsMaximal], CommRing (Rₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], CommSemiring (Rₚ P)] [∀ (P : Ideal R) [P.IsMaximal], Algebra R (Rₚ P)] [∀ (P : Ideal R) [P.IsMaximal], IsLocalization.AtPrime (Rₚ P) P] (Mₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) - [∀ (P : Ideal R) [P.IsMaximal], AddCommGroup (Mₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], AddCommMonoid (Mₚ P)] [∀ (P : Ideal R) [P.IsMaximal], Module R (Mₚ P)] [∀ (P : Ideal R) [P.IsMaximal], Module (Rₚ P) (Mₚ P)] [∀ (P : Ideal R) [P.IsMaximal], IsScalarTower R (Rₚ P) (Mₚ P)] (f : ∀ (P : Ideal R) [P.IsMaximal], M →ₗ[R] Mₚ P) - [inst : ∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (f P)] + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (f P)] + (M₁ₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) + [∀ (P : Ideal R) [P.IsMaximal], AddCommMonoid (M₁ₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], Module R (M₁ₚ P)] + (f₁ : ∀ (P : Ideal R) [P.IsMaximal], M₁ →ₗ[R] M₁ₚ P) + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (f₁ P)] + +theorem Submodule.mem_of_localization_maximal (m : M) (N : Submodule R M) + (h : ∀ (P : Ideal R) [P.IsMaximal], f P m ∈ N.localized₀ P.primeCompl (f P)) : + m ∈ N := by + let I : Ideal R := N.comap (LinearMap.toSpanSingleton R M m) + suffices I = ⊤ by simpa [I] using I.eq_top_iff_one.mp this + refine Not.imp_symm I.exists_le_maximal fun ⟨P, hP, le⟩ ↦ ?_ + obtain ⟨a, ha, s, e⟩ := h P + rw [← IsLocalizedModule.mk'_one P.primeCompl, IsLocalizedModule.mk'_eq_mk'_iff] at e + obtain ⟨t, ht⟩ := e + simp_rw [smul_smul] at ht + exact (t * s).2 (le <| by apply ht ▸ smul_mem _ _ ha) /-- Let `N₁ N₂ : Submodule R M`. If the localization of `N₁` at each maximal ideal `P` is included in the localization of `N₂` at `P`, then `N₁ ≤ N₂`. -/ theorem Submodule.le_of_localization_maximal {N₁ N₂ : Submodule R M} (h : ∀ (P : Ideal R) [P.IsMaximal], - N₁.localized' (Rₚ P) P.primeCompl (f P) ≤ N₂.localized' (Rₚ P) P.primeCompl (f P)) : - N₁ ≤ N₂ := by - intro x hx - suffices N₂.colon (Submodule.span R {x}) = ⊤ by - simpa using Submodule.mem_colon.mp - (show (1 : R) ∈ N₂.colon (Submodule.span R {x}) from this.symm ▸ Submodule.mem_top) x - (Submodule.mem_span_singleton_self x) - refine Not.imp_symm (N₂.colon (Submodule.span R {x})).exists_le_maximal ?_ - push_neg - intro P hP le - obtain ⟨a, ha, s, e⟩ := h P ⟨x, hx, 1, rfl⟩ - rw [IsLocalizedModule.mk'_eq_mk'_iff] at e - obtain ⟨t, ht⟩ := e - simp at ht - refine (t * s).2 (le (Submodule.mem_colon_singleton.mpr ?_)) - simp only [Submonoid.coe_mul, mul_smul, ← Submonoid.smul_def, ht] - exact N₂.smul_mem _ ha + N₁.localized₀ P.primeCompl (f P) ≤ N₂.localized₀ P.primeCompl (f P)) : + N₁ ≤ N₂ := + fun m hm ↦ mem_of_localization_maximal _ f _ _ fun P hP ↦ h P ⟨m, hm, 1, by simp⟩ /-- Let `N₁ N₂ : Submodule R M`. If the localization of `N₁` at each maximal ideal `P` is equal to the localization of `N₂` at `P`, then `N₁ = N₂`. -/ -theorem Submodule.eq_of_localization_maximal {N₁ N₂ : Submodule R M} +theorem Submodule.eq_of_localization₀_maximal {N₁ N₂ : Submodule R M} (h : ∀ (P : Ideal R) [P.IsMaximal], - N₁.localized' (Rₚ P) P.primeCompl (f P) = N₂.localized' (Rₚ P) P.primeCompl (f P)) : + N₁.localized₀ P.primeCompl (f P) = N₂.localized₀ P.primeCompl (f P)) : N₁ = N₂ := - le_antisymm (Submodule.le_of_localization_maximal Rₚ Mₚ f fun P _ => (h P).le) - (Submodule.le_of_localization_maximal Rₚ Mₚ f fun P _ => (h P).ge) + le_antisymm (Submodule.le_of_localization_maximal Mₚ f fun P _ ↦ (h P).le) + (Submodule.le_of_localization_maximal Mₚ f fun P _ ↦ (h P).ge) /-- A submodule is trivial if its localization at every maximal ideal is trivial. -/ -theorem Submodule.eq_bot_of_localization_maximal (N₁ : Submodule R M) +theorem Submodule.eq_bot_of_localization₀_maximal (N : Submodule R M) + (h : ∀ (P : Ideal R) [P.IsMaximal], N.localized₀ P.primeCompl (f P) = ⊥) : + N = ⊥ := + Submodule.eq_of_localization₀_maximal Mₚ f fun P hP ↦ by simpa using h P + +theorem Submodule.eq_top_of_localization₀_maximal (N : Submodule R M) + (h : ∀ (P : Ideal R) [P.IsMaximal], N.localized₀ P.primeCompl (f P) = ⊤) : + N = ⊤ := + Submodule.eq_of_localization₀_maximal Mₚ f fun P hP ↦ by simpa using h P + +theorem Module.eq_of_localization_maximal (m m' : M) + (h : ∀ (P : Ideal R) [P.IsMaximal], f P m = f P m') : + m = m' := by + rw [← one_smul R m, ← one_smul R m'] + by_contra ne + have ⟨P, mP, le⟩ := (eqIdeal R m m').exists_le_maximal ((Ideal.ne_top_iff_one _).mpr ne) + have ⟨s, hs⟩ := (IsLocalizedModule.eq_iff_exists P.primeCompl _).mp (h P) + exact s.2 (le hs) + +theorem Module.eq_zero_of_localization_maximal (m : M) + (h : ∀ (P : Ideal R) [P.IsMaximal], f P m = 0) : + m = 0 := + eq_of_localization_maximal _ f _ _ fun P _ ↦ by rw [h, map_zero] + +theorem LinearMap.eq_of_localization_maximal (g g' : M →ₗ[R] M₁) (h : ∀ (P : Ideal R) [P.IsMaximal], - N₁.localized' (Rₚ P) P.primeCompl (f P) = ⊥) : - N₁ = ⊥ := - Submodule.eq_of_localization_maximal Rₚ Mₚ f fun P hP => by simpa using h P - -theorem Submodule.mem_of_localization_maximal (r : M) (N₁ : Submodule R M) - (h : ∀ (P : Ideal R) [P.IsMaximal], f P r ∈ N₁.localized' (Rₚ P) P.primeCompl (f P)) : - r ∈ N₁ := by - rw [← SetLike.mem_coe, ← Set.singleton_subset_iff, ← Submodule.span_le] - apply Submodule.le_of_localization_maximal Rₚ Mₚ f - intro N₂ hJ - rw [Submodule.localized'_span, Submodule.span_le, Set.image_subset_iff, Set.singleton_subset_iff] - exact h N₂ - -include Rₚ in -theorem Module.eq_zero_of_localization_maximal (r : M) - (h : ∀ (P : Ideal R) [P.IsMaximal], f P r = 0) : - r = 0 := by - rw [← Submodule.mem_bot (R := R)] - apply Submodule.mem_of_localization_maximal Rₚ Mₚ f r ⊥ (by simpa using h) - -include Rₚ in -theorem Module.eq_of_localization_maximal (r s : M) - (h : ∀ (P : Ideal R) [P.IsMaximal], f P r = f P s) : - r = s := by - rw [← sub_eq_zero] - simp_rw [← @sub_eq_zero _ _ (f _ _), ← map_sub] at h - exact Module.eq_zero_of_localization_maximal Rₚ Mₚ f _ h - -include Rₚ f in + IsLocalizedModule.map P.primeCompl (f P) (f₁ P) g = + IsLocalizedModule.map P.primeCompl (f P) (f₁ P) g') : + g = g' := + ext fun x ↦ Module.eq_of_localization_maximal _ f₁ _ _ fun P _ ↦ by + simpa only [IsLocalizedModule.map_apply] using DFunLike.congr_fun (h P) (f P x) + +include f in theorem Module.subsingleton_of_localization_maximal (h : ∀ (P : Ideal R) [P.IsMaximal], Subsingleton (Mₚ P)) : Subsingleton M := by rw [subsingleton_iff_forall_eq 0] intro x - exact Module.eq_of_localization_maximal Rₚ Mₚ f x 0 fun _ _ ↦ Subsingleton.elim _ _ + exact Module.eq_of_localization_maximal Mₚ f x 0 fun _ _ ↦ Subsingleton.elim _ _ + +theorem Submodule.eq_of_localization_maximal {N₁ N₂ : Submodule R M} + (h : ∀ (P : Ideal R) [P.IsMaximal], + N₁.localized' (Rₚ P) P.primeCompl (f P) = N₂.localized' (Rₚ P) P.primeCompl (f P)) : + N₁ = N₂ := + eq_of_localization₀_maximal Mₚ f fun P _ ↦ congr(restrictScalars _ $(h P)) + +theorem Submodule.eq_bot_of_localization_maximal (N : Submodule R M) + (h : ∀ (P : Ideal R) [P.IsMaximal], N.localized' (Rₚ P) P.primeCompl (f P) = ⊥) : + N = ⊥ := + Submodule.eq_of_localization_maximal Rₚ Mₚ f fun P hP ↦ by simpa using h P + +theorem Submodule.eq_top_of_localization_maximal (N : Submodule R M) + (h : ∀ (P : Ideal R) [P.IsMaximal], N.localized' (Rₚ P) P.primeCompl (f P) = ⊤) : + N = ⊤ := + Submodule.eq_of_localization_maximal Rₚ Mₚ f fun P hP ↦ by simpa using h P + +end maximal + +section span + +open IsLocalizedModule LocalizedModule Ideal + +variable (s : Set R) (span_eq : Ideal.span s = ⊤) +include span_eq + +variable + (Rₚ : ∀ _ : s, Type*) + [∀ r : s, CommSemiring (Rₚ r)] + [∀ r : s, Algebra R (Rₚ r)] + [∀ r : s, IsLocalization.Away r.1 (Rₚ r)] + (Mₚ : ∀ _ : s, Type*) + [∀ r : s, AddCommMonoid (Mₚ r)] + [∀ r : s, Module R (Mₚ r)] + [∀ r : s, Module (Rₚ r) (Mₚ r)] + [∀ r : s, IsScalarTower R (Rₚ r) (Mₚ r)] + (f : ∀ r : s, M →ₗ[R] Mₚ r) + [∀ r : s, IsLocalizedModule (.powers r.1) (f r)] + +theorem Module.eq_of_isLocalized_span (x y : M) (h : ∀ r : s, f r x = f r y) : x = y := by + suffices Module.eqIdeal R x y = ⊤ by simpa [Module.eqIdeal] using (eq_top_iff_one _).mp this + by_contra ne + have ⟨r, hrs, disj⟩ := exists_disjoint_powers_of_span_eq_top s span_eq _ ne + let r : s := ⟨r, hrs⟩ + have ⟨⟨_, n, rfl⟩, eq⟩ := (IsLocalizedModule.eq_iff_exists (.powers r.1) _).mp (h r) + exact Set.disjoint_left.mp disj eq ⟨n, rfl⟩ + +theorem Module.eq_zero_of_isLocalized_span (x : M) (h : ∀ r : s, f r x = 0) : x = 0 := + eq_of_isLocalized_span s span_eq _ f x 0 <| by simpa only [map_zero] using h + +theorem Submodule.mem_of_isLocalized_span {m : M} {N : Submodule R M} + (h : ∀ r : s, f r m ∈ N.localized₀ (.powers r.1) (f r)) : m ∈ N := by + let I : Ideal R := N.comap (LinearMap.toSpanSingleton R M m) + suffices I = ⊤ by simpa [I] using I.eq_top_iff_one.mp this + by_contra! ne + have ⟨r, hrs, disj⟩ := exists_disjoint_powers_of_span_eq_top s span_eq _ ne + let r : s := ⟨r, hrs⟩ + obtain ⟨a, ha, t, e⟩ := h r + rw [← IsLocalizedModule.mk'_one (.powers r.1), IsLocalizedModule.mk'_eq_mk'_iff] at e + have ⟨u, hu⟩ := e + simp_rw [smul_smul] at hu + exact Set.disjoint_right.mp disj (u * t).2 (by apply hu ▸ smul_mem _ _ ha) + +theorem Submodule.le_of_isLocalized_span {N P : Submodule R M} + (h : ∀ r : s, N.localized₀ (.powers r.1) (f r) ≤ P.localized₀ (.powers r.1) (f r)) : N ≤ P := + fun m hm ↦ mem_of_isLocalized_span s span_eq _ f fun r ↦ h r ⟨m, hm, 1, by simp⟩ + +theorem Submodule.eq_of_isLocalized₀_span {N P : Submodule R M} + (h : ∀ r : s, N.localized₀ (.powers r.1) (f r) = P.localized₀ (.powers r.1) (f r)) : N = P := + le_antisymm (le_of_isLocalized_span s span_eq _ _ fun r ↦ (h r).le) + (le_of_isLocalized_span s span_eq _ _ fun r ↦ (h r).ge) + +theorem Submodule.eq_bot_of_isLocalized₀_span {N : Submodule R M} + (h : ∀ r : s, N.localized₀ (.powers r.1) (f r) = ⊥) : N = ⊥ := + eq_of_isLocalized₀_span s span_eq Mₚ f fun _ ↦ by simp only [h, Submodule.localized₀_bot] + +theorem Submodule.eq_top_of_isLocalized₀_span {N : Submodule R M} + (h : ∀ r : s, N.localized₀ (.powers r.1) (f r) = ⊤) : N = ⊤ := + eq_of_isLocalized₀_span s span_eq Mₚ f fun _ ↦ by simp only [h, Submodule.localized₀_top] + +theorem Submodule.eq_of_isLocalized'_span {N P : Submodule R M} + (h : ∀ r, N.localized' (Rₚ r) (.powers r.1) (f r) = P.localized' (Rₚ r) (.powers r.1) (f r)) : + N = P := + eq_of_isLocalized₀_span s span_eq _ f fun r ↦ congr(restrictScalars _ $(h r)) + +theorem Submodule.eq_bot_of_isLocalized'_span {N : Submodule R M} + (h : ∀ r : s, N.localized' (Rₚ r) (.powers r.1) (f r) = ⊥) : N = ⊥ := + eq_of_isLocalized'_span s span_eq Rₚ Mₚ f fun _ ↦ by simp only [h, Submodule.localized'_bot] + +theorem Submodule.eq_top_of_isLocalized'_span {N : Submodule R M} + (h : ∀ r : s, N.localized' (Rₚ r) (.powers r.1) (f r) = ⊤) : N = ⊤ := + eq_of_isLocalized'_span s span_eq Rₚ Mₚ f fun _ ↦ by simp only [h, Submodule.localized'_top] + +end span diff --git a/Mathlib/RingTheory/Localization/AtPrime.lean b/Mathlib/RingTheory/Localization/AtPrime.lean index 65cccdc214ca96..1337c943de11ef 100644 --- a/Mathlib/RingTheory/Localization/AtPrime.lean +++ b/Mathlib/RingTheory/Localization/AtPrime.lean @@ -31,7 +31,7 @@ commutative ring, field of fractions -/ -variable {R : Type*} [CommSemiring R] (M : Submonoid R) (S : Type*) [CommSemiring S] +variable {R : Type*} [CommSemiring R] (S : Type*) [CommSemiring S] variable [Algebra R S] {P : Type*} [CommSemiring P] section AtPrime @@ -250,3 +250,23 @@ theorem localRingHom_comp {S : Type*} [CommSemiring S] (J : Ideal S) [hJ : J.IsP simp only [Function.comp_apply, RingHom.coe_comp, localRingHom_to_map] end Localization + +namespace RingHom + +variable (R) + +/-- The canonical ring homomorphism from a commutative semiring to the product of its +localizations at all maximal ideals. It is always injective. -/ +def toLocalizationIsMaximal : R →+* + Π I : {I : Ideal R // I.IsMaximal}, haveI : I.1.IsMaximal := I.2; Localization.AtPrime I.1 := + Pi.ringHom fun _ ↦ algebraMap R _ + +theorem toLocalizationIsMaximal_injective : + Function.Injective (RingHom.toLocalizationIsMaximal R) := fun r r' eq ↦ by + rw [← one_mul r, ← one_mul r'] + by_contra ne + have ⟨I, mI, hI⟩ := (Module.eqIdeal R r r').exists_le_maximal ((Ideal.ne_top_iff_one _).mpr ne) + have ⟨s, hs⟩ := (IsLocalization.eq_iff_exists I.primeCompl _).mp (congr_fun eq ⟨I, mI⟩) + exact s.2 (hI hs) + +end RingHom diff --git a/Mathlib/RingTheory/Localization/Away/Basic.lean b/Mathlib/RingTheory/Localization/Away/Basic.lean index 3f7cd7a8e49b61..ae069a4b510725 100644 --- a/Mathlib/RingTheory/Localization/Away/Basic.lean +++ b/Mathlib/RingTheory/Localization/Away/Basic.lean @@ -6,7 +6,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Localization.Basic -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicity /-! # Localizations away from an element @@ -297,53 +297,42 @@ end AtUnits section Prod -lemma away_of_isIdempotentElem {R S} [CommRing R] [CommRing S] [Algebra R S] +lemma away_of_isIdempotentElem_of_mul {R S} [CommSemiring R] [CommSemiring S] [Algebra R S] {e : R} (he : IsIdempotentElem e) - (H : RingHom.ker (algebraMap R S) = Ideal.span {1 - e}) + (H : ∀ x y, algebraMap R S x = algebraMap R S y ↔ e * x = e * y) (H' : Function.Surjective (algebraMap R S)) : IsLocalization.Away e S where map_units' r := by - have : algebraMap R S e = 1 := by - rw [← (algebraMap R S).map_one, eq_comm, ← sub_eq_zero, ← map_sub, ← RingHom.mem_ker, - H, Ideal.mem_span_singleton] obtain ⟨r, n, rfl⟩ := r - simp [this] + simp [show algebraMap R S e = 1 by rw [← (algebraMap R S).map_one, H, mul_one, he]] surj' z := by obtain ⟨z, rfl⟩ := H' z exact ⟨⟨z, 1⟩, by simp⟩ - exists_of_eq {x y} h := by - rw [← sub_eq_zero, ← map_sub, ← RingHom.mem_ker, H, Ideal.mem_span_singleton] at h - obtain ⟨k, hk⟩ := h - refine ⟨⟨e, Submonoid.mem_powers e⟩, ?_⟩ - rw [← sub_eq_zero, ← mul_sub, hk, ← mul_assoc, mul_sub, mul_one, he.eq, sub_self, zero_mul] + exists_of_eq {x y} h := ⟨⟨e, Submonoid.mem_powers e⟩, (H x y).mp h⟩ + +lemma away_of_isIdempotentElem {R S} [CommRing R] [CommRing S] [Algebra R S] + {e : R} (he : IsIdempotentElem e) + (H : RingHom.ker (algebraMap R S) = Ideal.span {1 - e}) + (H' : Function.Surjective (algebraMap R S)) : + IsLocalization.Away e S := + away_of_isIdempotentElem_of_mul he (fun x y ↦ by + rw [← sub_eq_zero, ← map_sub, ← RingHom.mem_ker, H, ← he.ker_toSpanSingleton_eq_span, + LinearMap.mem_ker, LinearMap.toSpanSingleton_apply, sub_smul, sub_eq_zero] + simp_rw [mul_comm e, smul_eq_mul]) H' -instance away_fst {R S} [CommRing R] [CommRing S] : +instance away_fst {R S} [CommSemiring R] [CommSemiring S] : letI := (RingHom.fst R S).toAlgebra - IsLocalization.Away (R := R × S) (1, 0) R := by + IsLocalization.Away (R := R × S) (1, 0) R := letI := (RingHom.fst R S).toAlgebra - apply away_of_isIdempotentElem - · ext <;> simp - · ext x - simp only [RingHom.algebraMap_toAlgebra, RingHom.mem_ker, RingHom.coe_fst, - Ideal.mem_span_singleton, Prod.one_eq_mk, Prod.mk_sub_mk, sub_self, sub_zero] - constructor - · intro e; use x; ext <;> simp [e] - · rintro ⟨⟨i, j⟩, rfl⟩; simp - · exact Prod.fst_surjective - -instance away_snd {R S} [CommRing R] [CommRing S] : + away_of_isIdempotentElem_of_mul (by ext <;> simp) + (fun ⟨xR, xS⟩ ⟨yR, yS⟩ ↦ show xR = yR ↔ _ by simp) Prod.fst_surjective + +instance away_snd {R S} [CommSemiring R] [CommSemiring S] : letI := (RingHom.snd R S).toAlgebra - IsLocalization.Away (R := R × S) (0, 1) S := by + IsLocalization.Away (R := R × S) (0, 1) S := letI := (RingHom.snd R S).toAlgebra - apply away_of_isIdempotentElem - · ext <;> simp - · ext x - simp only [RingHom.algebraMap_toAlgebra, RingHom.mem_ker, RingHom.coe_snd, - Ideal.mem_span_singleton, Prod.one_eq_mk, Prod.mk_sub_mk, sub_self, sub_zero] - constructor - · intro e; use x; ext <;> simp [e] - · rintro ⟨⟨i, j⟩, rfl⟩; simp - · exact Prod.snd_surjective + away_of_isIdempotentElem_of_mul (by ext <;> simp) + (fun ⟨xR, xS⟩ ⟨yR, yS⟩ ↦ show xS = yS ↔ _ by simp) Prod.snd_surjective end Prod @@ -361,6 +350,15 @@ noncomputable abbrev awayLift (f : R →+* P) (r : R) (hr : IsUnit (f r)) : Localization.Away r →+* P := IsLocalization.Away.lift r hr +lemma awayLift_mk {A : Type*} [CommRing A] (f : R →+* A) (r : R) + (a : R) (v : A) (hv : f r * v = 1) (j : ℕ) : + Localization.awayLift f r (isUnit_iff_exists_inv.mpr ⟨v, hv⟩) + (Localization.mk a ⟨r ^ j, j, rfl⟩) = f a * v ^ j := by + rw [Localization.mk_eq_mk'] + erw [IsLocalization.lift_mk'] + rw [Units.mul_inv_eq_iff_eq_mul] + simp [IsUnit.liftRight, mul_assoc, ← mul_pow, (mul_comm _ _).trans hv] + /-- Given a map `f : R →+* S` and an element `r : R`, we may construct a map `Rᵣ →+* Sᵣ`. -/ noncomputable abbrev awayMap (f : R →+* P) (r : R) : Localization.Away r →+* Localization.Away (f r) := diff --git a/Mathlib/RingTheory/Localization/Away/Lemmas.lean b/Mathlib/RingTheory/Localization/Away/Lemmas.lean index 640763c874cbe3..dc5d5600d2f7f0 100644 --- a/Mathlib/RingTheory/Localization/Away/Lemmas.lean +++ b/Mathlib/RingTheory/Localization/Away/Lemmas.lean @@ -15,9 +15,7 @@ This file contains lemmas on localization away from an element requiring more im variable {R : Type*} [CommRing R] -namespace IsLocalization - -namespace Away +namespace IsLocalization.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 @@ -61,6 +59,8 @@ lemma span_range_mulNumerator_eq_top {s : Set R} use n + m simpa [pow_add, hc] using Ideal.mul_mem_left _ _ hy -end Away +lemma quotient_of_isIdempotentElem {e : R} (he : IsIdempotentElem e) : + IsLocalization.Away e (R ⧸ Ideal.span {1 - e}) := + away_of_isIdempotentElem he Ideal.mk_ker Quotient.mk_surjective -end IsLocalization +end IsLocalization.Away diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index f2d6adffdcf45b..9159d55e9cdbd9 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -73,7 +73,7 @@ open Function section CommSemiring -variable {R : Type*} [CommSemiring R] {M : Submonoid R} {S : Type*} [CommSemiring S] +variable {R : Type*} [CommSemiring R] {M N : Submonoid R} {S : Type*} [CommSemiring S] variable [Algebra R S] {P : Type*} [CommSemiring P] namespace IsLocalization @@ -237,7 +237,7 @@ end IsLocalization section -variable (M) +variable (M N) theorem isLocalization_of_algEquiv [Algebra R P] [IsLocalization M S] (h : S ≃ₐ[R] P) : IsLocalization M P := by @@ -265,6 +265,14 @@ theorem isLocalization_iff_of_ringEquiv (h : S ≃+* P) : letI := (h.toRingHom.comp <| algebraMap R S).toAlgebra isLocalization_iff_of_algEquiv M { h with commutes' := fun _ => rfl } +variable (S) in +/-- If an algebra is simultaneously localizations for two submonoids, then an arbitrary algebra +is a localization of one submonoid iff it is a localization of the other. -/ +theorem isLocalization_iff_of_isLocalization [IsLocalization M S] [IsLocalization N S] + [Algebra R P] : IsLocalization M P ↔ IsLocalization N P := + ⟨fun _ ↦ isLocalization_of_algEquiv N (algEquiv M S P), + fun _ ↦ isLocalization_of_algEquiv M (algEquiv N S P)⟩ + end variable (M) diff --git a/Mathlib/RingTheory/Localization/Defs.lean b/Mathlib/RingTheory/Localization/Defs.lean index 486cd6a8eb03ea..60509638366d37 100644 --- a/Mathlib/RingTheory/Localization/Defs.lean +++ b/Mathlib/RingTheory/Localization/Defs.lean @@ -140,6 +140,11 @@ theorem of_le (N : Submonoid R) (h₁ : M ≤ N) (h₂ : ∀ r ∈ N, IsUnit (al rintro ⟨c, hc⟩ exact ⟨⟨c, h₁ c.2⟩, hc⟩ +theorem of_le_of_exists_dvd (N : Submonoid R) (h₁ : M ≤ N) (h₂ : ∀ n ∈ N, ∃ m ∈ M, n ∣ m) : + IsLocalization N S := + of_le M N h₁ fun n hn ↦ have ⟨m, hm, dvd⟩ := h₂ n hn + isUnit_of_dvd_unit (map_dvd _ dvd) (map_units S ⟨m, hm⟩) + variable (S) /-- `IsLocalization.toLocalizationWithZeroMap M S` shows `S` is the monoid localization of diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index fb9b40025a8df7..155c5ec2966a35 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -39,7 +39,7 @@ variable [Algebra R S] {P : Type*} [CommRing P] variable {A : Type*} [CommRing A] (K : Type*) -- TODO: should this extend `Algebra` instead of assuming it? -/-- `IsFractionRing R K` states `K` is the field of fractions of an integral domain `R`. -/ +/-- `IsFractionRing R K` states `K` is the ring of fractions of a commutative ring `R`. -/ abbrev IsFractionRing [CommRing K] [Algebra R K] := IsLocalization (nonZeroDivisors R) K @@ -186,8 +186,8 @@ theorem mk'_eq_one_iff_eq {x : A} {y : nonZeroDivisors A} : mk' K x y = 1 ↔ x section Subfield variable (A K) in -/-- If `A` is a ring with fraction field `K`, then the subfield of `K` generated by the image of -`algebraMap A K` is equal to the whole field `K`. -/ +/-- If `A` is a commutative ring with fraction field `K`, then the subfield of `K` generated by +the image of `algebraMap A K` is equal to the whole field `K`. -/ theorem closure_range_algebraMap : Subfield.closure (Set.range (algebraMap A K)) = ⊤ := top_unique fun z _ ↦ by obtain ⟨_, _, -, rfl⟩ := div_surjective (A := A) z @@ -195,16 +195,16 @@ theorem closure_range_algebraMap : Subfield.closure (Set.range (algebraMap A K)) variable {L : Type*} [Field L] {g : A →+* L} {f : K →+* L} -/-- If `A` is a ring with fraction field `K`, `L` is a field, `g : A →+* L` lifts to `f : K →+* L`, -then the image of `f` is the field generated by the image of `g`. -/ +/-- If `A` is a commutative ring with fraction field `K`, `L` is a field, `g : A →+* L` lifts to +`f : K →+* L`, then the image of `f` is the subfield generated by the image of `g`. -/ theorem ringHom_fieldRange_eq_of_comp_eq (h : RingHom.comp f (algebraMap A K) = g) : f.fieldRange = Subfield.closure g.range := by rw [f.fieldRange_eq_map, ← closure_range_algebraMap A K, f.map_field_closure, ← Set.range_comp, ← f.coe_comp, h, g.coe_range] -/-- If `A` is a ring with fraction field `K`, `L` is a field, `g : A →+* L` lifts to `f : K →+* L`, -`s` is a set such that the image of `g` is the subring generated by `s`, -then the image of `f` is the field generated by `s`. -/ +/-- If `A` is a commutative ring with fraction field `K`, `L` is a field, `g : A →+* L` lifts to +`f : K →+* L`, `s` is a set such that the image of `g` is the subring generated by `s`, +then the image of `f` is the subfield generated by `s`. -/ theorem ringHom_fieldRange_eq_of_comp_eq_of_range_eq (h : RingHom.comp f (algebraMap A K) = g) {s : Set L} (hs : g.range = Subring.closure s) : f.fieldRange = Subfield.closure s := by rw [ringHom_fieldRange_eq_of_comp_eq h, hs] @@ -215,7 +215,7 @@ end Subfield open Function -/-- Given an integral domain `A` with field of fractions `K`, +/-- Given a commutative ring `A` with field of fractions `K`, and an injective ring hom `g : A →+* L` where `L` is a field, we get a field hom sending `z : K` to `g x * (g y)⁻¹`, where `(x, y) : A × (NonZeroDivisors A)` are such that `z = f x * (f y)⁻¹`. -/ @@ -241,7 +241,7 @@ theorem liftAlgHom_apply : liftAlgHom hg x = lift hg x := rfl end liftAlgHom -/-- Given an integral domain `A` with field of fractions `K`, +/-- Given a commutative ring `A` with field of fractions `K`, and an injective ring hom `g : A →+* L` where `L` is a field, the field hom induced from `K` to `L` maps `x` to `g x` for all `x : A`. -/ @@ -249,15 +249,28 @@ the field hom induced from `K` to `L` maps `x` to `g x` for all theorem lift_algebraMap (hg : Injective g) (x) : lift hg (algebraMap A K x) = g x := lift_eq _ _ -/-- Given an integral domain `A` with field of fractions `K`, +/-- The image of `IsFractionRing.lift` is the subfield generated by the image +of the ring hom. -/ +theorem lift_fieldRange (hg : Injective g) : + (lift hg : K →+* L).fieldRange = Subfield.closure g.range := + ringHom_fieldRange_eq_of_comp_eq (by ext; simp) + +/-- The image of `IsFractionRing.lift` is the subfield generated by `s`, if the image +of the ring hom is the subring generated by `s`. -/ +theorem lift_fieldRange_eq_of_range_eq (hg : Injective g) + {s : Set L} (hs : g.range = Subring.closure s) : + (lift hg : K →+* L).fieldRange = Subfield.closure s := + ringHom_fieldRange_eq_of_comp_eq_of_range_eq (by ext; simp) hs + +/-- Given a commutative ring `A` with field of fractions `K`, and an injective ring hom `g : A →+* L` where `L` is a field, field hom induced from `K` to `L` maps `f x / f y` to `g x / g y` for all `x : A, y ∈ NonZeroDivisors A`. -/ theorem lift_mk' (hg : Injective g) (x) (y : nonZeroDivisors A) : lift hg (mk' K x y) = g x / g y := by simp only [mk'_eq_div, map_div₀, lift_algebraMap] -/-- Given integral domains `A, B` with fields of fractions `K`, `L` -and an injective ring hom `j : A →+* B`, we get a field hom +/-- Given commutative rings `A, B` where `B` is an integral domain, with fraction rings `K`, `L` +and an injective ring hom `j : A →+* B`, we get a ring hom sending `z : K` to `g (j x) * (g (j y))⁻¹`, where `(x, y) : A × (NonZeroDivisors A)` are such that `z = f x * (f y)⁻¹`. -/ noncomputable def map {A B K L : Type*} [CommRing A] [CommRing B] [IsDomain B] [CommRing K] diff --git a/Mathlib/RingTheory/Localization/Integral.lean b/Mathlib/RingTheory/Localization/Integral.lean index d2b5cef36d5e29..ad327225f2383f 100644 --- a/Mathlib/RingTheory/Localization/Integral.lean +++ b/Mathlib/RingTheory/Localization/Integral.lean @@ -25,7 +25,7 @@ commutative ring, field of fractions variable {R : Type*} [CommRing R] (M : Submonoid R) {S : Type*} [CommRing S] -variable [Algebra R S] {P : Type*} [CommRing P] +variable [Algebra R S] open Polynomial @@ -366,7 +366,7 @@ theorem isAlgebraic_iff' [Field K] [IsDomain R] [IsDomain S] [Algebra R K] [Alge rw [div_eq_mul_inv] refine IsIntegral.mul ?_ ?_ · rw [← isAlgebraic_iff_isIntegral] - refine .tower_top_of_injective + refine .extendScalars (NoZeroSMulDivisors.algebraMap_injective R (FractionRing R)) ?_ exact .algebraMap (h a) · rw [← isAlgebraic_iff_isIntegral] diff --git a/Mathlib/RingTheory/Localization/LocalizationLocalization.lean b/Mathlib/RingTheory/Localization/LocalizationLocalization.lean index 62db6f2a127617..0637b7cd2c4703 100644 --- a/Mathlib/RingTheory/Localization/LocalizationLocalization.lean +++ b/Mathlib/RingTheory/Localization/LocalizationLocalization.lean @@ -27,8 +27,7 @@ namespace IsLocalization section LocalizationLocalization -variable {R : Type*} [CommSemiring R] (M : Submonoid R) {S : Type*} [CommSemiring S] -variable [Algebra R S] {P : Type*} [CommSemiring P] +variable {R : Type*} [CommSemiring R] (M : Submonoid R) {S : Type*} [CommSemiring S] [Algebra R S] variable (N : Submonoid S) (T : Type*) [CommSemiring T] [Algebra R T] @@ -251,7 +250,7 @@ end IsLocalization namespace IsFractionRing -variable {R : Type*} [CommRing R] (M : Submonoid R) {S : Type*} [CommRing S] +variable {R : Type*} [CommRing R] (M : Submonoid R) open IsLocalization diff --git a/Mathlib/RingTheory/Localization/NumDen.lean b/Mathlib/RingTheory/Localization/NumDen.lean index 9d72b32932ecc2..290ca0e0004410 100644 --- a/Mathlib/RingTheory/Localization/NumDen.lean +++ b/Mathlib/RingTheory/Localization/NumDen.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan -/ import Mathlib.RingTheory.Localization.FractionRing import Mathlib.RingTheory.Localization.Integer -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.GCDMonoid /-! # Numerator and denominator in a localization diff --git a/Mathlib/RingTheory/MatrixAlgebra.lean b/Mathlib/RingTheory/MatrixAlgebra.lean index 0750d234243443..8fcf5dc5f622ca 100644 --- a/Mathlib/RingTheory/MatrixAlgebra.lean +++ b/Mathlib/RingTheory/MatrixAlgebra.lean @@ -14,13 +14,7 @@ suppress_compilation universe u v w -open TensorProduct - -open TensorProduct - -open Algebra.TensorProduct - -open Matrix +open TensorProduct Algebra.TensorProduct Matrix variable {R : Type u} [CommSemiring R] variable {A : Type v} [Semiring A] [Algebra R A] diff --git a/Mathlib/RingTheory/Multiplicity.lean b/Mathlib/RingTheory/Multiplicity.lean index 85ab17ad0be89d..c095227abd535b 100644 --- a/Mathlib/RingTheory/Multiplicity.lean +++ b/Mathlib/RingTheory/Multiplicity.lean @@ -5,8 +5,9 @@ Authors: Robert Y. Lewis, Chris Hughes, Daniel Weber -/ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.Finset -import Mathlib.Tactic.Linarith +import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.ENat.Basic +import Mathlib.Tactic.Linarith /-! # Multiplicity of a divisor diff --git a/Mathlib/RingTheory/Nilpotent/Basic.lean b/Mathlib/RingTheory/Nilpotent/Basic.lean index 9eddb6417010ad..602de4bcb8dbd1 100644 --- a/Mathlib/RingTheory/Nilpotent/Basic.lean +++ b/Mathlib/RingTheory/Nilpotent/Basic.lean @@ -91,6 +91,14 @@ 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) +lemma IsIdempotentElem.eq_zero_of_isNilpotent [MonoidWithZero R] {e : R} + (idem : IsIdempotentElem e) (nilp : IsNilpotent e) : e = 0 := by + obtain ⟨rfl | n, hn⟩ := nilp + · rw [pow_zero] at hn; rw [← one_mul e, hn, zero_mul] + · rw [← hn, idem.pow_succ_eq] + +alias IsNilpotent.eq_zero_of_isIdempotentElem := IsIdempotentElem.eq_zero_of_isNilpotent + 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/Noetherian/Basic.lean b/Mathlib/RingTheory/Noetherian/Basic.lean new file mode 100644 index 00000000000000..38156a143989da --- /dev/null +++ b/Mathlib/RingTheory/Noetherian/Basic.lean @@ -0,0 +1,366 @@ +/- +Copyright (c) 2018 Mario Carneiro, Kevin Buzzard. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Kevin Buzzard +-/ +import Mathlib.LinearAlgebra.Quotient.Basic +import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Finiteness.Cardinality +import Mathlib.RingTheory.Finiteness.Finsupp +import Mathlib.RingTheory.Ideal.Maps + +/-! +# Noetherian rings and modules + +The following are equivalent for a module M over a ring R: +1. Every increasing chain of submodules M₁ ⊆ M₂ ⊆ M₃ ⊆ ⋯ eventually stabilises. +2. Every submodule is finitely generated. + +A module satisfying these equivalent conditions is said to be a *Noetherian* R-module. +A ring is a *Noetherian ring* if it is Noetherian as a module over itself. + +(Note that we do not assume yet that our rings are commutative, +so perhaps this should be called "left Noetherian". +To avoid cumbersome names once we specialize to the commutative case, +we don't make this explicit in the declaration names.) + +## Main definitions + +Let `R` be a ring and let `M` and `P` be `R`-modules. Let `N` be an `R`-submodule of `M`. + +* `IsNoetherian R M` is the proposition that `M` is a Noetherian `R`-module. It is a class, + implemented as the predicate that all `R`-submodules of `M` are finitely generated. + +## Main statements + +* `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`. + +## References + +* [M. F. Atiyah and I. G. Macdonald, *Introduction to commutative algebra*][atiyah-macdonald] +* [samuel1967] + +## Tags + +Noetherian, noetherian, Noetherian ring, Noetherian module, noetherian ring, noetherian module + +-/ + +assert_not_exists Matrix + +open Set Pointwise + +section + +variable {R : Type*} {M : Type*} {P : Type*} +variable [Semiring R] [AddCommMonoid M] [AddCommMonoid P] +variable [Module R M] [Module R P] + +open IsNoetherian + +variable (M) + +theorem isNoetherian_of_surjective (f : M →ₗ[R] P) (hf : LinearMap.range f = ⊤) [IsNoetherian R M] : + IsNoetherian R P := + ⟨fun s => + have : (s.comap f).map f = s := Submodule.map_comap_eq_self <| hf.symm ▸ le_top + this ▸ (noetherian _).map _⟩ + +variable {M} + +instance isNoetherian_range (f : M →ₗ[R] P) [IsNoetherian R M] : + IsNoetherian R (LinearMap.range f) := + isNoetherian_of_surjective _ _ f.range_rangeRestrict + +instance isNoetherian_quotient {A M : Type*} [Ring A] [AddCommGroup M] [SMul R A] [Module R M] + [Module A M] [IsScalarTower R A M] (N : Submodule A M) [IsNoetherian R M] : + IsNoetherian R (M ⧸ N) := + isNoetherian_of_surjective M ((Submodule.mkQ N).restrictScalars R) <| + LinearMap.range_eq_top.mpr N.mkQ_surjective + +@[deprecated (since := "2024-04-27"), nolint defLemma] +alias Submodule.Quotient.isNoetherian := isNoetherian_quotient + +theorem isNoetherian_of_linearEquiv (f : M ≃ₗ[R] P) [IsNoetherian R M] : IsNoetherian R P := + isNoetherian_of_surjective _ f.toLinearMap f.range + +theorem LinearEquiv.isNoetherian_iff (f : M ≃ₗ[R] P) : IsNoetherian R M ↔ IsNoetherian R P := + ⟨fun _ ↦ isNoetherian_of_linearEquiv f, fun _ ↦ isNoetherian_of_linearEquiv f.symm⟩ + +theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := + Submodule.topEquiv.isNoetherian_iff + +theorem isNoetherian_of_injective [IsNoetherian R P] (f : M →ₗ[R] P) (hf : Function.Injective f) : + IsNoetherian R M := + isNoetherian_of_linearEquiv (LinearEquiv.ofInjective f hf).symm + +theorem fg_of_injective [IsNoetherian R P] {N : Submodule R M} (f : M →ₗ[R] P) + (hf : Function.Injective f) : N.FG := + haveI := isNoetherian_of_injective f hf + IsNoetherian.noetherian N + +end + +namespace Module + +variable {R M N : Type*} +variable [Semiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module R N] +variable (R M) + +-- see Note [lower instance priority] +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) : 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) : + Module.Finite R M := + ⟨fg_of_injective f hf⟩ + +end Module + +section + +variable {R : Type*} {M : Type*} {P : Type*} +variable [Ring R] [AddCommGroup M] [AddCommGroup P] +variable [Module R M] [Module R P] + +open IsNoetherian + +theorem isNoetherian_of_ker_bot [IsNoetherian R P] (f : M →ₗ[R] P) (hf : LinearMap.ker f = ⊥) : + IsNoetherian R M := + isNoetherian_of_linearEquiv (LinearEquiv.ofInjective f <| LinearMap.ker_eq_bot.mp hf).symm + +theorem fg_of_ker_bot [IsNoetherian R P] {N : Submodule R M} (f : M →ₗ[R] P) + (hf : LinearMap.ker f = ⊥) : N.FG := + haveI := isNoetherian_of_ker_bot f hf + IsNoetherian.noetherian N + +instance isNoetherian_prod [IsNoetherian R M] [IsNoetherian R P] : IsNoetherian R (M × P) := + ⟨fun s => + Submodule.fg_of_fg_map_of_fg_inf_ker (LinearMap.snd R M P) (noetherian _) <| + have : s ⊓ LinearMap.ker (LinearMap.snd R M P) ≤ LinearMap.range (LinearMap.inl R M P) := + 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_sup (M₁ M₂ : Submodule R P) [IsNoetherian R M₁] [IsNoetherian R M₂] : + IsNoetherian R ↥(M₁ ⊔ M₂) := by + have := isNoetherian_range (M₁.subtype.coprod M₂.subtype) + rwa [LinearMap.range_coprod, Submodule.range_subtype, Submodule.range_subtype] at this + +variable {ι : Type*} [Finite ι] + +instance isNoetherian_pi : + ∀ {M : ι → Type*} [∀ i, AddCommGroup (M i)] + [∀ i, Module R (M i)] [∀ i, IsNoetherian R (M i)], IsNoetherian R (∀ i, M i) := by + apply Finite.induction_empty_option _ _ _ ι + · exact fun e h ↦ isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R _ e) + · infer_instance + · exact fun ih ↦ isNoetherian_of_linearEquiv (LinearEquiv.piOptionEquivProd R).symm + +/-- A version of `isNoetherian_pi` for non-dependent functions. We need this instance because +sometimes Lean fails to apply the dependent version in non-dependent settings (e.g., it fails to +prove that `ι → ℝ` is finite dimensional over `ℝ`). -/ +instance isNoetherian_pi' [IsNoetherian R M] : IsNoetherian R (ι → M) := + isNoetherian_pi + +instance isNoetherian_iSup : + ∀ {M : ι → Submodule R P} [∀ i, IsNoetherian R (M i)], IsNoetherian R ↥(⨆ i, M i) := by + apply Finite.induction_empty_option _ _ _ ι + · intro _ _ e h _ _; rw [← e.iSup_comp]; apply h + · intros; rw [iSup_of_empty]; infer_instance + · intro _ _ ih _ _; rw [iSup_option]; infer_instance + +end + +section CommRing + +variable (R M N : Type*) [CommRing R] [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] + [IsNoetherian R M] [Module.Finite R N] + +instance isNoetherian_linearMap_pi {ι : Type*} [Finite ι] : IsNoetherian R ((ι → R) →ₗ[R] M) := + let _i : Fintype ι := Fintype.ofFinite ι; isNoetherian_of_linearEquiv (Module.piEquiv ι R M) + +instance isNoetherian_linearMap : IsNoetherian R (N →ₗ[R] M) := by + obtain ⟨n, f, hf⟩ := Module.Finite.exists_fin' R N + let g : (N →ₗ[R] M) →ₗ[R] (Fin n → R) →ₗ[R] M := (LinearMap.llcomp R (Fin n → R) N M).flip f + exact isNoetherian_of_injective g hf.injective_linearMapComp_right + +end CommRing + +open IsNoetherian Submodule Function + +section + +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] + +/-- 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 := + IsWellFounded.induction _ I hgt + +end + +section + +universe w + +variable {R M P : Type*} {N : Type w} [Ring R] [AddCommGroup M] [Module R M] [AddCommGroup N] + [Module R N] [AddCommGroup P] [Module R P] [IsNoetherian R M] + +lemma Submodule.finite_ne_bot_of_iSupIndep {ι : Type*} {N : ι → Submodule R M} + (h : iSupIndep N) : + Set.Finite {i | N i ≠ ⊥} := + WellFoundedGT.finite_ne_bot_of_iSupIndep h + +@[deprecated (since := "2024-11-24")] +alias Submodule.finite_ne_bot_of_independent := Submodule.finite_ne_bot_of_iSupIndep + +/-- A linearly-independent family of vectors in a module over a non-trivial ring must be finite if +the module is Noetherian. -/ +theorem LinearIndependent.finite_of_isNoetherian [Nontrivial R] {ι} {v : ι → M} + (hv : LinearIndependent R v) : Finite ι := by + refine WellFoundedGT.finite_of_iSupIndep + hv.iSupIndep_span_singleton + fun i contra => ?_ + apply hv.ne_zero i + have : v i ∈ R ∙ v i := Submodule.mem_span_singleton_self (v i) + rwa [contra, Submodule.mem_bot] at this + +theorem LinearIndependent.set_finite_of_isNoetherian [Nontrivial R] {s : Set M} + (hi : LinearIndependent R ((↑) : s → M)) : s.Finite := + @Set.toFinite _ _ hi.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_mk <| + wellFounded_gt_exact_sequence + (LinearMap.range f) + (Submodule.map (f.ker.liftQ f le_rfl)) + (Submodule.comap (f.ker.liftQ f le_rfl)) + (Submodule.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 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] + +/-- 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. -/ +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 + -- A little off-by-one cleanup first: + suffices t : ∃ n : ℕ, ∀ m, n ≤ m → f (m + 1) = ⊥ by + obtain ⟨n, w⟩ := t + use n + 1 + rintro (_ | m) p + · cases p + · apply w + exact Nat.succ_le_succ_iff.mp p + obtain ⟨n, w⟩ := monotone_stabilizes_iff_noetherian.mpr inferInstance (partialSups f) + exact + ⟨n, fun m p => + (h m).eq_bot_of_ge <| sup_eq_left.1 <| (w (m + 1) <| le_add_right p).symm.trans <| w m p⟩ + +end + +-- see Note [lower instance priority] +/-- Modules over the trivial ring are Noetherian. -/ +instance (priority := 100) isNoetherian_of_subsingleton (R M) [Subsingleton R] [Semiring R] + [AddCommMonoid M] [Module R M] : IsNoetherian R M := + haveI := Module.subsingleton R M + 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 := + 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 := + 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 + let ⟨s, hs⟩ := hN + haveI := Classical.decEq M + haveI := Classical.decEq R + have : ∀ x ∈ s, x ∈ N := fun x hx => hs ▸ Submodule.subset_span hx + refine + @isNoetherian_of_surjective + R ((↑s : Set M) → R) N _ _ _ (Pi.module _ _ _) _ ?_ ?_ isNoetherian_pi + · fapply LinearMap.mk + · fapply AddHom.mk + · exact fun f => ⟨∑ i ∈ s.attach, f i • i.1, N.sum_mem fun c _ => N.smul_mem _ <| this _ c.2⟩ + · intro f g + apply Subtype.eq + change (∑ i ∈ s.attach, (f i + g i) • _) = _ + simp only [add_smul, Finset.sum_add_distrib] + rfl + · intro c f + apply Subtype.eq + change (∑ i ∈ s.attach, (c • f i) • _) = _ + simp only [smul_eq_mul, mul_smul] + exact Finset.smul_sum.symm + · 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_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.linearCombination_apply, Finsupp.sum, eq_comm] + refine Finset.sum_subset hl1 fun x _ hx => ?_ + rw [Finsupp.not_mem_support_iff.1 hx, zero_smul] + +instance isNoetherian_of_isNoetherianRing_of_finite (R M : Type*) + [Ring R] [AddCommGroup M] [Module R M] [IsNoetherianRing R] [Module.Finite R M] : + IsNoetherian R M := + have : IsNoetherian R (⊤ : Submodule R M) := + isNoetherian_of_fg_of_noetherian _ <| Module.finite_def.mp inferInstance + isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl) + +/-- In a module over a Noetherian ring, the submodule generated by finitely many vectors is +Noetherian. -/ +theorem isNoetherian_span_of_finite (R) {M} [Ring R] [AddCommGroup M] [Module R M] + [IsNoetherianRing R] {A : Set M} (hA : A.Finite) : IsNoetherian R (Submodule.span R A) := + 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 := + 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 := + isNoetherianRing_of_surjective R f.range f.rangeRestrict f.rangeRestrict_surjective + +theorem isNoetherianRing_of_ringEquiv (R) [Ring R] {S} [Ring S] (f : R ≃+* S) [IsNoetherianRing R] : + IsNoetherianRing S := + isNoetherianRing_of_surjective R S f.toRingHom f.toEquiv.surjective diff --git a/Mathlib/RingTheory/Noetherian/Defs.lean b/Mathlib/RingTheory/Noetherian/Defs.lean index 953d4b72654117..e14e88932c6a3d 100644 --- a/Mathlib/RingTheory/Noetherian/Defs.lean +++ b/Mathlib/RingTheory/Noetherian/Defs.lean @@ -3,10 +3,7 @@ Copyright (c) 2018 Mario Carneiro, Kevin Buzzard. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kevin Buzzard -/ -import Mathlib.LinearAlgebra.Quotient.Basic -import Mathlib.RingTheory.Finiteness.Cardinality -import Mathlib.RingTheory.Finiteness.Finsupp -import Mathlib.RingTheory.Ideal.Maps +import Mathlib.RingTheory.Finiteness.Basic /-! # Noetherian rings and modules @@ -49,6 +46,9 @@ Noetherian, noetherian, Noetherian ring, Noetherian module, noetherian ring, noe -/ +assert_not_exists Finsupp.linearCombination +assert_not_exists Matrix +assert_not_exists Pi.basis open Set Pointwise @@ -100,144 +100,8 @@ theorem isNoetherian_of_le {s t : Submodule R M} [ht : IsNoetherian R t] (h : s IsNoetherian R s := isNoetherian_submodule.mpr fun _ hs' => isNoetherian_submodule.mp ht _ (le_trans hs' h) -variable (M) - -theorem isNoetherian_of_surjective (f : M →ₗ[R] P) (hf : LinearMap.range f = ⊤) [IsNoetherian R M] : - IsNoetherian R P := - ⟨fun s => - have : (s.comap f).map f = s := Submodule.map_comap_eq_self <| hf.symm ▸ le_top - this ▸ (noetherian _).map _⟩ - -variable {M} - -instance isNoetherian_range (f : M →ₗ[R] P) [IsNoetherian R M] : - IsNoetherian R (LinearMap.range f) := - isNoetherian_of_surjective _ _ f.range_rangeRestrict - -instance isNoetherian_quotient {A M : Type*} [Ring A] [AddCommGroup M] [SMul R A] [Module R M] - [Module A M] [IsScalarTower R A M] (N : Submodule A M) [IsNoetherian R M] : - IsNoetherian R (M ⧸ N) := - isNoetherian_of_surjective M ((Submodule.mkQ N).restrictScalars R) <| - LinearMap.range_eq_top.mpr N.mkQ_surjective - -@[deprecated (since := "2024-04-27"), nolint defLemma] -alias Submodule.Quotient.isNoetherian := isNoetherian_quotient - -theorem isNoetherian_of_linearEquiv (f : M ≃ₗ[R] P) [IsNoetherian R M] : IsNoetherian R P := - isNoetherian_of_surjective _ f.toLinearMap f.range - -theorem LinearEquiv.isNoetherian_iff (f : M ≃ₗ[R] P) : IsNoetherian R M ↔ IsNoetherian R P := - ⟨fun _ ↦ isNoetherian_of_linearEquiv f, fun _ ↦ isNoetherian_of_linearEquiv f.symm⟩ - -theorem isNoetherian_top_iff : IsNoetherian R (⊤ : Submodule R M) ↔ IsNoetherian R M := - Submodule.topEquiv.isNoetherian_iff - -theorem isNoetherian_of_injective [IsNoetherian R P] (f : M →ₗ[R] P) (hf : Function.Injective f) : - IsNoetherian R M := - isNoetherian_of_linearEquiv (LinearEquiv.ofInjective f hf).symm - -theorem fg_of_injective [IsNoetherian R P] {N : Submodule R M} (f : M →ₗ[R] P) - (hf : Function.Injective f) : N.FG := - haveI := isNoetherian_of_injective f hf - IsNoetherian.noetherian N - -end - -namespace Module - -variable {R M N : Type*} -variable [Semiring R] [AddCommMonoid M] [AddCommMonoid N] [Module R M] [Module R N] -variable (R M) - --- see Note [lower instance priority] -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) : 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) : - Module.Finite R M := - ⟨fg_of_injective f hf⟩ - -end Module - -section - -variable {R : Type*} {M : Type*} {P : Type*} -variable [Ring R] [AddCommGroup M] [AddCommGroup P] -variable [Module R M] [Module R P] - -open IsNoetherian - -theorem isNoetherian_of_ker_bot [IsNoetherian R P] (f : M →ₗ[R] P) (hf : LinearMap.ker f = ⊥) : - IsNoetherian R M := - isNoetherian_of_linearEquiv (LinearEquiv.ofInjective f <| LinearMap.ker_eq_bot.mp hf).symm - -theorem fg_of_ker_bot [IsNoetherian R P] {N : Submodule R M} (f : M →ₗ[R] P) - (hf : LinearMap.ker f = ⊥) : N.FG := - haveI := isNoetherian_of_ker_bot f hf - IsNoetherian.noetherian N - -instance isNoetherian_prod [IsNoetherian R M] [IsNoetherian R P] : IsNoetherian R (M × P) := - ⟨fun s => - Submodule.fg_of_fg_map_of_fg_inf_ker (LinearMap.snd R M P) (noetherian _) <| - have : s ⊓ LinearMap.ker (LinearMap.snd R M P) ≤ LinearMap.range (LinearMap.inl R M P) := - 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_sup (M₁ M₂ : Submodule R P) [IsNoetherian R M₁] [IsNoetherian R M₂] : - IsNoetherian R ↥(M₁ ⊔ M₂) := by - have := isNoetherian_range (M₁.subtype.coprod M₂.subtype) - rwa [LinearMap.range_coprod, Submodule.range_subtype, Submodule.range_subtype] at this - -variable {ι : Type*} [Finite ι] - -instance isNoetherian_pi : - ∀ {M : ι → Type*} [∀ i, AddCommGroup (M i)] - [∀ i, Module R (M i)] [∀ i, IsNoetherian R (M i)], IsNoetherian R (∀ i, M i) := by - apply Finite.induction_empty_option _ _ _ ι - · exact fun e h ↦ isNoetherian_of_linearEquiv (LinearEquiv.piCongrLeft R _ e) - · infer_instance - · exact fun ih ↦ isNoetherian_of_linearEquiv (LinearEquiv.piOptionEquivProd R).symm - -/-- A version of `isNoetherian_pi` for non-dependent functions. We need this instance because -sometimes Lean fails to apply the dependent version in non-dependent settings (e.g., it fails to -prove that `ι → ℝ` is finite dimensional over `ℝ`). -/ -instance isNoetherian_pi' [IsNoetherian R M] : IsNoetherian R (ι → M) := - isNoetherian_pi - -instance isNoetherian_iSup : - ∀ {M : ι → Submodule R P} [∀ i, IsNoetherian R (M i)], IsNoetherian R ↥(⨆ i, M i) := by - apply Finite.induction_empty_option _ _ _ ι - · intro _ _ e h _ _; rw [← e.iSup_comp]; apply h - · intros; rw [iSup_of_empty]; infer_instance - · intro _ _ ih _ _; rw [iSup_option]; infer_instance - end -section CommRing - -variable (R M N : Type*) [CommRing R] [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] - [IsNoetherian R M] [Module.Finite R N] - -instance isNoetherian_linearMap_pi {ι : Type*} [Finite ι] : IsNoetherian R ((ι → R) →ₗ[R] M) := - let _i : Fintype ι := Fintype.ofFinite ι; isNoetherian_of_linearEquiv (Module.piEquiv ι R M) - -instance isNoetherian_linearMap : IsNoetherian R (N →ₗ[R] M) := by - obtain ⟨n, f, hf⟩ := Module.Finite.exists_fin' R N - let g : (N →ₗ[R] M) →ₗ[R] (Fin n → R) →ₗ[R] M := (LinearMap.llcomp R (Fin n → R) N M).flip f - exact isNoetherian_of_injective g hf.injective_linearMapComp_right - -end CommRing - open IsNoetherian Submodule Function section @@ -299,81 +163,6 @@ 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.monotone_chain_condition] -/-- 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 := - IsWellFounded.induction _ I hgt - -end - -section - -universe w - -variable {R M P : Type*} {N : Type w} [Ring R] [AddCommGroup M] [Module R M] [AddCommGroup N] - [Module R N] [AddCommGroup P] [Module R P] [IsNoetherian R M] - -lemma Submodule.finite_ne_bot_of_independent {ι : Type*} {N : ι → Submodule R M} - (h : CompleteLattice.Independent N) : - Set.Finite {i | N i ≠ ⊥} := - CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent h - -/-- A linearly-independent family of vectors in a module over a non-trivial ring must be finite if -the module is Noetherian. -/ -theorem LinearIndependent.finite_of_isNoetherian [Nontrivial R] {ι} {v : ι → M} - (hv : LinearIndependent R v) : Finite ι := by - refine CompleteLattice.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) - rwa [contra, Submodule.mem_bot] at this - -theorem LinearIndependent.set_finite_of_isNoetherian [Nontrivial R] {s : Set M} - (hi : LinearIndependent R ((↑) : s → M)) : s.Finite := - @Set.toFinite _ _ hi.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_mk <| - wellFounded_gt_exact_sequence - (LinearMap.range f) - (Submodule.map (f.ker.liftQ f le_rfl)) - (Submodule.comap (f.ker.liftQ f le_rfl)) - (Submodule.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 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] - -/-- 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. -/ -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 - -- A little off-by-one cleanup first: - suffices t : ∃ n : ℕ, ∀ m, n ≤ m → f (m + 1) = ⊥ by - obtain ⟨n, w⟩ := t - use n + 1 - rintro (_ | m) p - · cases p - · apply w - exact Nat.succ_le_succ_iff.mp p - obtain ⟨n, w⟩ := monotone_stabilizes_iff_noetherian.mpr inferInstance (partialSups f) - exact - ⟨n, fun m p => - (h m).eq_bot_of_ge <| sup_eq_left.1 <| (w (m + 1) <| le_add_right p).symm.trans <| w m p⟩ - end /-- A (semi)ring is Noetherian if it is Noetherian as a module over itself, @@ -388,79 +177,3 @@ theorem isNoetherianRing_iff {R} [Semiring R] : IsNoetherianRing R ↔ IsNoether 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] -/-- Modules over the trivial ring are Noetherian. -/ -instance (priority := 100) isNoetherian_of_subsingleton (R M) [Subsingleton R] [Semiring R] - [AddCommMonoid M] [Module R M] : IsNoetherian R M := - haveI := Module.subsingleton R M - 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 := - 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 := - 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 - let ⟨s, hs⟩ := hN - haveI := Classical.decEq M - haveI := Classical.decEq R - have : ∀ x ∈ s, x ∈ N := fun x hx => hs ▸ Submodule.subset_span hx - refine - @isNoetherian_of_surjective - R ((↑s : Set M) → R) N _ _ _ (Pi.module _ _ _) _ ?_ ?_ isNoetherian_pi - · fapply LinearMap.mk - · fapply AddHom.mk - · exact fun f => ⟨∑ i ∈ s.attach, f i • i.1, N.sum_mem fun c _ => N.smul_mem _ <| this _ c.2⟩ - · intro f g - apply Subtype.eq - change (∑ i ∈ s.attach, (f i + g i) • _) = _ - simp only [add_smul, Finset.sum_add_distrib] - rfl - · intro c f - apply Subtype.eq - change (∑ i ∈ s.attach, (c • f i) • _) = _ - simp only [smul_eq_mul, mul_smul] - exact Finset.smul_sum.symm - · 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_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.linearCombination_apply, Finsupp.sum, eq_comm] - refine Finset.sum_subset hl1 fun x _ hx => ?_ - rw [Finsupp.not_mem_support_iff.1 hx, zero_smul] - -instance isNoetherian_of_isNoetherianRing_of_finite (R M : Type*) - [Ring R] [AddCommGroup M] [Module R M] [IsNoetherianRing R] [Module.Finite R M] : - IsNoetherian R M := - have : IsNoetherian R (⊤ : Submodule R M) := - isNoetherian_of_fg_of_noetherian _ <| Module.finite_def.mp inferInstance - isNoetherian_of_linearEquiv (LinearEquiv.ofTop (⊤ : Submodule R M) rfl) - -/-- In a module over a Noetherian ring, the submodule generated by finitely many vectors is -Noetherian. -/ -theorem isNoetherian_span_of_finite (R) {M} [Ring R] [AddCommGroup M] [Module R M] - [IsNoetherianRing R] {A : Set M} (hA : A.Finite) : IsNoetherian R (Submodule.span R A) := - 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 := - 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 := - isNoetherianRing_of_surjective R f.range f.rangeRestrict f.rangeRestrict_surjective - -theorem isNoetherianRing_of_ringEquiv (R) [Ring R] {S} [Ring S] (f : R ≃+* S) [IsNoetherianRing R] : - IsNoetherianRing S := - isNoetherianRing_of_surjective R S f.toRingHom f.toEquiv.surjective diff --git a/Mathlib/RingTheory/Noetherian/Orzech.lean b/Mathlib/RingTheory/Noetherian/Orzech.lean index 8858b55202f80d..da0b31cf04f088 100644 --- a/Mathlib/RingTheory/Noetherian/Orzech.lean +++ b/Mathlib/RingTheory/Noetherian/Orzech.lean @@ -6,7 +6,7 @@ Authors: Mario Carneiro, Kevin Buzzard import Mathlib.Algebra.Module.Submodule.IterateMapComap import Mathlib.Algebra.Order.Archimedean.Basic import Mathlib.Order.PartialSups -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic import Mathlib.RingTheory.OrzechProperty import Mathlib.Order.Filter.AtTopBot diff --git a/Mathlib/RingTheory/Noetherian/UniqueFactorizationDomain.lean b/Mathlib/RingTheory/Noetherian/UniqueFactorizationDomain.lean index a56bfca5ca1bf6..b4751612885123 100644 --- a/Mathlib/RingTheory/Noetherian/UniqueFactorizationDomain.lean +++ b/Mathlib/RingTheory/Noetherian/UniqueFactorizationDomain.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ import Mathlib.RingTheory.Noetherian.Defs -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.Ideal /-! # Noetherian domains have unique factorization diff --git a/Mathlib/RingTheory/Nullstellensatz.lean b/Mathlib/RingTheory/Nullstellensatz.lean index f28499af60736c..71d381cfeb3406 100644 --- a/Mathlib/RingTheory/Nullstellensatz.lean +++ b/Mathlib/RingTheory/Nullstellensatz.lean @@ -28,8 +28,6 @@ noncomputable section namespace MvPolynomial -open MvPolynomial - variable {k : Type*} [Field k] variable {σ : Type*} diff --git a/Mathlib/RingTheory/Perfection.lean b/Mathlib/RingTheory/Perfection.lean index 013131970238e5..7d7e45a3a19295 100644 --- a/Mathlib/RingTheory/Perfection.lean +++ b/Mathlib/RingTheory/Perfection.lean @@ -349,13 +349,13 @@ attribute [local instance] Classical.dec /-- For a field `K` with valuation `v : K → ℝ≥0` and ring of integers `O`, a function `O/(p) → ℝ≥0` that sends `0` to `0` and `x + (p)` to `v(x)` as long as `x ∉ (p)`. -/ noncomputable def preVal (x : ModP K v O hv p) : ℝ≥0 := - if x = 0 then 0 else v (algebraMap O K x.out') + if x = 0 then 0 else v (algebraMap O K x.out) variable {K v O hv p} theorem preVal_mk {x : O} (hx : (Ideal.Quotient.mk _ x : ModP K v O hv p) ≠ 0) : preVal K v O hv p (Ideal.Quotient.mk _ x) = v (algebraMap O K x) := by - obtain ⟨r, hr⟩ : ∃ (a : O), a * (p : O) = (Quotient.mk'' x).out' - x := + obtain ⟨r, hr⟩ : ∃ (a : O), a * (p : O) = (Quotient.mk'' x).out - x := Ideal.mem_span_singleton'.1 <| Ideal.Quotient.eq.1 <| Quotient.sound' <| Quotient.mk_out' _ refine (if_neg hx).trans (v.map_eq_of_sub_lt <| lt_of_not_le ?_) erw [← RingHom.map_sub, ← hr, hv.le_iff_dvd] @@ -424,7 +424,7 @@ theorem mul_ne_zero_of_pow_p_ne_zero {x y : ModP K v O hv p} (hx : x ^ p ≠ 0) rw [← v_p_lt_val hv] at hx hy ⊢ rw [RingHom.map_pow, v.map_pow, ← rpow_lt_rpow_iff h1p, ← rpow_natCast, ← rpow_mul, mul_one_div_cancel (Nat.cast_ne_zero.2 hp.1.ne_zero : (p : ℝ) ≠ 0), rpow_one] at hx hy - rw [RingHom.map_mul, v.map_mul]; refine lt_of_le_of_lt ?_ (mul_lt_mul₀ hx hy) + rw [RingHom.map_mul, v.map_mul]; refine lt_of_le_of_lt ?_ (mul_lt_mul'' hx hy zero_le' zero_le') by_cases hvp : v p = 0 · rw [hvp]; exact zero_le _ replace hvp := zero_lt_iff.2 hvp diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index 99c10175f0d494..4bee44c7de8c55 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.GeomSum import Mathlib.Algebra.MvPolynomial.CommRing import Mathlib.Algebra.MvPolynomial.Equiv import Mathlib.Algebra.Polynomial.BigOperators -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic /-! # Ring-theoretic supplement of Algebra.Polynomial. diff --git a/Mathlib/RingTheory/Polynomial/Content.lean b/Mathlib/RingTheory/Polynomial/Content.lean index c92ff552d810e2..394d392597e7be 100644 --- a/Mathlib/RingTheory/Polynomial/Content.lean +++ b/Mathlib/RingTheory/Polynomial/Content.lean @@ -30,8 +30,6 @@ Let `p : R[X]`. namespace Polynomial -open Polynomial - section Primitive variable {R : Type*} [CommSemiring R] diff --git a/Mathlib/RingTheory/Polynomial/Dickson.lean b/Mathlib/RingTheory/Polynomial/Dickson.lean index d5d51a3dee789d..1872e6ac8a9e2b 100644 --- a/Mathlib/RingTheory/Polynomial/Dickson.lean +++ b/Mathlib/RingTheory/Polynomial/Dickson.lean @@ -52,8 +52,6 @@ noncomputable section namespace Polynomial -open Polynomial - variable {R S : Type*} [CommRing R] [CommRing S] (k : ℕ) (a : R) /-- `dickson` is the `n`-th (generalised) Dickson polynomial of the `k`-th kind associated to the diff --git a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean index fa81775947129b..13f33a3208377a 100644 --- a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2023 Luke Mantle. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Luke Mantle -/ -import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Algebra.Polynomial.Derivative import Mathlib.Data.Nat.Factorial.DoubleFactorial diff --git a/Mathlib/RingTheory/Polynomial/Pochhammer.lean b/Mathlib/RingTheory/Polynomial/Pochhammer.lean index 63708f272d1ed7..d6872afb27cbc6 100644 --- a/Mathlib/RingTheory/Polynomial/Pochhammer.lean +++ b/Mathlib/RingTheory/Polynomial/Pochhammer.lean @@ -38,8 +38,6 @@ universe u v open Polynomial -open Polynomial - section Semiring variable (S : Type u) [Semiring S] diff --git a/Mathlib/RingTheory/Polynomial/Radical.lean b/Mathlib/RingTheory/Polynomial/Radical.lean index 71a22fad747613..4a8f0a57af1e62 100644 --- a/Mathlib/RingTheory/Polynomial/Radical.lean +++ b/Mathlib/RingTheory/Polynomial/Radical.lean @@ -6,6 +6,7 @@ Authors: Jineon Baek, Seewoo Lee import Mathlib.Algebra.Polynomial.FieldDivision import Mathlib.RingTheory.Polynomial.Wronskian import Mathlib.RingTheory.Radical +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicative /-! # Radical of a polynomial diff --git a/Mathlib/RingTheory/Polynomial/ScaleRoots.lean b/Mathlib/RingTheory/Polynomial/ScaleRoots.lean index dce2e27c493007..38ee5b2e413445 100644 --- a/Mathlib/RingTheory/Polynomial/ScaleRoots.lean +++ b/Mathlib/RingTheory/Polynomial/ScaleRoots.lean @@ -20,8 +20,6 @@ variable {R S A K : Type*} namespace Polynomial -open Polynomial - section Semiring variable [Semiring R] [Semiring S] diff --git a/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean b/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean index bf2b2308eda3bc..6e24a23d71aeef 100644 --- a/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean +++ b/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean @@ -5,6 +5,9 @@ Authors: Kenny Lau -/ import Mathlib.RingTheory.Polynomial.Basic import Mathlib.RingTheory.Polynomial.Content +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Finite +import Mathlib.RingTheory.UniqueFactorizationDomain.GCDMonoid /-! # Unique factorization for univariate and multivariate polynomials diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index 6030481adc2e7b..85884f5a241545 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -758,6 +758,7 @@ namespace Polynomial open Finsupp Polynomial +section CommSemiring variable {R : Type*} [CommSemiring R] (φ ψ : R[X]) -- Porting note: added so we can add the `@[coe]` attribute @@ -877,6 +878,21 @@ theorem coeToPowerSeries.algHom_apply : coeToPowerSeries.algHom A φ = PowerSeries.map (algebraMap R A) ↑φ := rfl +end CommSemiring + +section CommRing +variable {R : Type*} [CommRing R] + +@[simp, norm_cast] +lemma coe_neg (p : R[X]) : ((- p : R[X]) : PowerSeries R) = - p := + coeToPowerSeries.ringHom.map_neg p + +@[simp, norm_cast] +lemma coe_sub (p q : R[X]) : ((p - q : R[X]) : PowerSeries R) = p - q := + coeToPowerSeries.ringHom.map_sub p q + +end CommRing + end Polynomial namespace PowerSeries diff --git a/Mathlib/RingTheory/PowerSeries/Inverse.lean b/Mathlib/RingTheory/PowerSeries/Inverse.lean index c8bef18f0aeb42..f69014616a2de3 100644 --- a/Mathlib/RingTheory/PowerSeries/Inverse.lean +++ b/Mathlib/RingTheory/PowerSeries/Inverse.lean @@ -10,6 +10,7 @@ import Mathlib.RingTheory.MvPowerSeries.Inverse import Mathlib.RingTheory.PowerSeries.Basic import Mathlib.RingTheory.PowerSeries.Order import Mathlib.RingTheory.LocalRing.ResidueField.Defs +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicity /-! # Formal power series - Inverses diff --git a/Mathlib/RingTheory/PowerSeries/WellKnown.lean b/Mathlib/RingTheory/PowerSeries/WellKnown.lean index 292659bb8862fb..ef67977a0a5d28 100644 --- a/Mathlib/RingTheory/PowerSeries/WellKnown.lean +++ b/Mathlib/RingTheory/PowerSeries/WellKnown.lean @@ -5,7 +5,6 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.Algebra.Rat import Mathlib.Algebra.BigOperators.NatAntidiagonal -import Mathlib.Algebra.Order.Ring.Abs import Mathlib.Data.Nat.Choose.Sum import Mathlib.RingTheory.PowerSeries.Basic diff --git a/Mathlib/RingTheory/PrimeSpectrum.lean b/Mathlib/RingTheory/PrimeSpectrum.lean index 29c25b19c2cf9d..5ac44c10a7f5f1 100644 --- a/Mathlib/RingTheory/PrimeSpectrum.lean +++ b/Mathlib/RingTheory/PrimeSpectrum.lean @@ -7,7 +7,7 @@ import Mathlib.LinearAlgebra.Finsupp.SumProd import Mathlib.RingTheory.Ideal.Prod import Mathlib.RingTheory.Localization.Ideal import Mathlib.RingTheory.Nilpotent.Lemmas -import Mathlib.RingTheory.Noetherian.Defs +import Mathlib.RingTheory.Noetherian.Basic /-! # Prime spectrum of a commutative (semi)ring as a type @@ -83,6 +83,14 @@ instance [Subsingleton R] : IsEmpty (PrimeSpectrum R) := variable (R S) +/-- The prime spectrum is in bijection with the set of prime ideals. -/ +@[simps] +def equivSubtype : PrimeSpectrum R ≃ {I : Ideal R // I.IsPrime} where + toFun I := ⟨I.asIdeal, I.2⟩ + invFun I := ⟨I, I.2⟩ + left_inv _ := rfl + right_inv _ := rfl + /-- The map from the direct sum of prime spectra to the prime spectrum of a direct product. -/ @[simp] def primeSpectrumProdOfSum : PrimeSpectrum R ⊕ PrimeSpectrum S → PrimeSpectrum (R × S) diff --git a/Mathlib/RingTheory/PrincipalIdealDomain.lean b/Mathlib/RingTheory/PrincipalIdealDomain.lean index 53c6974d87d3ac..5343a17c2253ad 100644 --- a/Mathlib/RingTheory/PrincipalIdealDomain.lean +++ b/Mathlib/RingTheory/PrincipalIdealDomain.lean @@ -4,6 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Morenikeji Neri -/ import Mathlib.Algebra.EuclideanDomain.Field +import Mathlib.Algebra.GCDMonoid.Basic +import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Ideal.Nonunits import Mathlib.RingTheory.Noetherian.UniqueFactorizationDomain @@ -13,20 +15,21 @@ import Mathlib.RingTheory.Noetherian.UniqueFactorizationDomain A principal ideal ring (PIR) is a ring in which all left ideals are principal. A principal ideal domain (PID) is an integral domain which is a principal ideal ring. +The definition of `IsPrincipalIdealRing` can be found in `Mathlib.RingTheory.Ideal.Span`. + # Main definitions Note that for principal ideal domains, one should use `[IsDomain R] [IsPrincipalIdealRing R]`. There is no explicit definition of a PID. -Theorems about PID's are in the `principal_ideal_ring` namespace. +Theorems about PID's are in the `PrincipalIdealRing` namespace. -- `IsPrincipalIdealRing`: a predicate on rings, saying that every left ideal is principal. - `IsBezout`: the predicate saying that every finitely generated left ideal is principal. - `generator`: a generator of a principal ideal (or more generally submodule) - `to_uniqueFactorizationMonoid`: a PID is a unique factorization domain # Main results -- `to_maximal_ideal`: a non-zero prime ideal in a PID is maximal. +- `Ideal.IsPrime.to_maximal_ideal`: a non-zero prime ideal in a PID is maximal. - `EuclideanDomain.to_principal_ideal_domain` : a Euclidean domain is a PID. - `IsBezout.nonemptyGCDMonoid`: Every Bézout domain is a GCD domain. diff --git a/Mathlib/RingTheory/Radical.lean b/Mathlib/RingTheory/Radical.lean index dbf09f0b12caa7..a4558ba7c2ec99 100644 --- a/Mathlib/RingTheory/Radical.lean +++ b/Mathlib/RingTheory/Radical.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jineon Baek, Seewoo Lee -/ import Mathlib.Algebra.EuclideanDomain.Basic -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.Coprime.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors /-! # Radical of an element of a unique factorization normalization monoid diff --git a/Mathlib/RingTheory/ReesAlgebra.lean b/Mathlib/RingTheory/ReesAlgebra.lean index 127232d147d6d0..2069a0781786a2 100644 --- a/Mathlib/RingTheory/ReesAlgebra.lean +++ b/Mathlib/RingTheory/ReesAlgebra.lean @@ -30,8 +30,6 @@ variable {R M : Type u} [CommRing R] [AddCommGroup M] [Module R M] (I : Ideal R) open Polynomial -open Polynomial - /-- The Rees algebra of an ideal `I`, defined as the subalgebra of `R[X]` whose `i`-th coefficient falls in `I ^ i`. -/ def reesAlgebra : Subalgebra R R[X] where diff --git a/Mathlib/RingTheory/RingHom/Integral.lean b/Mathlib/RingTheory/RingHom/Integral.lean index 62662762e06d70..2662ea9b1ccba8 100644 --- a/Mathlib/RingTheory/RingHom/Integral.lean +++ b/Mathlib/RingTheory/RingHom/Integral.lean @@ -3,8 +3,8 @@ 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.IntegralClosure.IsIntegralClosure.Basic +import Mathlib.RingTheory.LocalProperties.Basic +import Mathlib.RingTheory.Localization.Integral /-! @@ -36,4 +36,32 @@ theorem isIntegral_isStableUnderBaseChange : IsStableUnderBaseChange fun f => f. · intro x y; exact IsIntegral.tmul x (h y) · intro x y hx hy; exact IsIntegral.add hx hy +open Polynomial in +/-- `S` is an integral `R`-algebra if there exists a set `{ r }` that + spans `R` such that each `Sᵣ` is an integral `Rᵣ`-algebra. -/ +theorem isIntegral_ofLocalizationSpan : + OfLocalizationSpan (RingHom.IsIntegral ·) := by + introv R hs H r + letI := f.toAlgebra + show r ∈ (integralClosure R S).toSubmodule + apply Submodule.mem_of_span_eq_top_of_smul_pow_mem _ s hs + rintro ⟨t, ht⟩ + letI := (Localization.awayMap f t).toAlgebra + haveI : IsScalarTower R (Localization.Away t) (Localization.Away (f t)) := .of_algebraMap_eq' + (IsLocalization.lift_comp _).symm + have : _root_.IsIntegral (Localization.Away t) (algebraMap S (Localization.Away (f t)) r) := + H ⟨t, ht⟩ (algebraMap _ _ r) + obtain ⟨⟨_, n, rfl⟩, p, hp, hp'⟩ := this.exists_multiple_integral_of_isLocalization (.powers t) + rw [IsScalarTower.algebraMap_eq R S, Submonoid.smul_def, Algebra.smul_def, + IsScalarTower.algebraMap_apply R S, ← map_mul, ← hom_eval₂, + IsLocalization.map_eq_zero_iff (.powers (f t))] at hp' + obtain ⟨⟨x, m, (rfl : algebraMap R S t ^ m = x)⟩, e⟩ := hp' + by_cases hp' : 1 ≤ p.natDegree; swap + · obtain rfl : p = 1 := eq_one_of_monic_natDegree_zero hp (by nlinarith) + exact ⟨m, by simp [Algebra.smul_def, show algebraMap R S t ^ m = 0 by simpa using e]⟩ + refine ⟨m + n, p.scaleRoots (t ^ m), (monic_scaleRoots_iff _).mpr hp, ?_⟩ + have := p.scaleRoots_eval₂_mul (algebraMap R S) (t ^ n • r) (t ^ m) + simp only [pow_add, ← Algebra.smul_def, mul_smul, ← map_pow] at e this ⊢ + rw [this, ← tsub_add_cancel_of_le hp', pow_succ, mul_smul, e, smul_zero] + end RingHom diff --git a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean index 992c920e1efc92..34a8597d9b7084 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean @@ -3,10 +3,11 @@ Copyright (c) 2020 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca, Johan Commelin -/ -import Mathlib.RingTheory.RootsOfUnity.PrimitiveRoots -import Mathlib.FieldTheory.Minpoly.IsIntegrallyClosed import Mathlib.Algebra.GCDMonoid.IntegrallyClosed import Mathlib.FieldTheory.Finite.Basic +import Mathlib.FieldTheory.Minpoly.IsIntegrallyClosed +import Mathlib.RingTheory.RootsOfUnity.PrimitiveRoots +import Mathlib.RingTheory.UniqueFactorizationDomain.Nat /-! # Minimal polynomial of roots of unity diff --git a/Mathlib/RingTheory/SimpleModule.lean b/Mathlib/RingTheory/SimpleModule.lean index 66282ba413b641..dbae9bcb743edf 100644 --- a/Mathlib/RingTheory/SimpleModule.lean +++ b/Mathlib/RingTheory/SimpleModule.lean @@ -198,12 +198,14 @@ theorem exists_simple_submodule [Nontrivial M] : ∃ m : Submodule R M, IsSimple theorem sSup_simples_eq_top : sSup { m : Submodule R M | IsSimpleModule R m } = ⊤ := by simpa only [isSimpleModule_iff_isAtom] using sSup_atoms_eq_top -theorem exists_setIndependent_sSup_simples_eq_top : - ∃ s : Set (Submodule R M), CompleteLattice.SetIndependent s ∧ - sSup s = ⊤ ∧ ∀ m ∈ s, IsSimpleModule R m := by +theorem exists_sSupIndep_sSup_simples_eq_top : + ∃ s : Set (Submodule R M), sSupIndep s ∧ sSup s = ⊤ ∧ ∀ m ∈ s, IsSimpleModule R m := by have := sSup_simples_eq_top R M simp_rw [isSimpleModule_iff_isAtom] at this ⊢ - exact exists_setIndependent_of_sSup_atoms_eq_top this + exact exists_sSupIndep_of_sSup_atoms_eq_top this + +@[deprecated (since := "2024-11-24")] +alias exists_setIndependent_sSup_simples_eq_top := exists_sSupIndep_sSup_simples_eq_top /-- The annihilator of a semisimple module over a commutative ring is a radical ideal. -/ theorem annihilator_isRadical (R) [CommRing R] [Module R M] [IsSemisimpleModule R M] : diff --git a/Mathlib/RingTheory/TensorProduct/Free.lean b/Mathlib/RingTheory/TensorProduct/Free.lean index 1f644e47cf5686..a857cfdf874c66 100644 --- a/Mathlib/RingTheory/TensorProduct/Free.lean +++ b/Mathlib/RingTheory/TensorProduct/Free.lean @@ -30,7 +30,7 @@ namespace Algebra namespace TensorProduct -variable {R S A : Type*} +variable {R A : Type*} section Basis diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean index 669cd384177746..a941b75c4e02ad 100644 --- a/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean +++ b/Mathlib/RingTheory/TwoSidedIdeal/Operations.lean @@ -3,12 +3,12 @@ Copyright (c) 2024 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang, Jireh Loreaux -/ - +import Mathlib.Algebra.Group.Subgroup.Map +import Mathlib.Algebra.Module.Opposite import Mathlib.Algebra.Module.Submodule.Lattice import Mathlib.RingTheory.Congruence.Opposite import Mathlib.RingTheory.Ideal.Defs import Mathlib.RingTheory.TwoSidedIdeal.Lattice -import Mathlib.Algebra.Module.Opposite /-! # Operations on two-sided ideals diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain.lean b/Mathlib/RingTheory/UniqueFactorizationDomain.lean deleted file mode 100644 index a5f452067a1209..00000000000000 --- a/Mathlib/RingTheory/UniqueFactorizationDomain.lean +++ /dev/null @@ -1,2017 +0,0 @@ -/- -Copyright (c) 2018 Johannes Hölzl. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson --/ -import Mathlib.Algebra.BigOperators.Associated -import Mathlib.Algebra.GCDMonoid.Basic -import Mathlib.Data.ENat.Lattice -import Mathlib.Data.Finsupp.Multiset -import Mathlib.Data.Nat.Factors -import Mathlib.RingTheory.Multiplicity -import Mathlib.RingTheory.Ideal.Operations - -/-! - -# Unique factorization - -## Main Definitions -* `WfDvdMonoid` holds for `Monoid`s for which a strict divisibility relation is - well-founded. -* `UniqueFactorizationMonoid` holds for `WfDvdMonoid`s where - `Irreducible` is equivalent to `Prime` - -## Main results -* `Ideal.setOf_isPrincipal_wellFoundedOn_gt`, `WfDvdMonoid.of_setOf_isPrincipal_wellFoundedOn_gt` - in a domain, well-foundedness of the strict version of ∣ is equivalent to the ascending - chain condition on principal ideals. - -## TODO -* set up the complete lattice structure on `FactorSet`. - --/ - - -variable {α : Type*} - -local infixl:50 " ~ᵤ " => Associated - -/-- Well-foundedness of the strict version of ∣, which is equivalent to the descending chain -condition on divisibility and to the ascending chain condition on -principal ideals in an integral domain. - -/ -abbrev WfDvdMonoid (α : Type*) [CommMonoidWithZero α] : Prop := - IsWellFounded α DvdNotUnit - -theorem wellFounded_dvdNotUnit {α : Type*} [CommMonoidWithZero α] [h : WfDvdMonoid α] : - WellFounded (DvdNotUnit (α := α)) := - h.wf - -namespace WfDvdMonoid - -variable [CommMonoidWithZero α] - -open Associates Nat - -theorem of_wfDvdMonoid_associates (_ : WfDvdMonoid (Associates α)) : WfDvdMonoid α := - ⟨(mk_surjective.wellFounded_iff mk_dvdNotUnit_mk_iff.symm).2 wellFounded_dvdNotUnit⟩ - -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 - --- Porting note: elab_as_elim can only be global and cannot be changed on an imported decl --- attribute [local elab_as_elim] WellFounded.fix - -theorem exists_irreducible_factor {a : α} (ha : ¬IsUnit a) (ha0 : a ≠ 0) : - ∃ i, Irreducible i ∧ i ∣ a := - let ⟨b, hs, hr⟩ := wellFounded_dvdNotUnit.has_min { b | b ∣ a ∧ ¬IsUnit b } ⟨a, dvd_rfl, ha⟩ - ⟨b, - ⟨hs.2, fun c d he => - let h := dvd_trans ⟨d, he⟩ hs.1 - or_iff_not_imp_left.2 fun hc => - of_not_not fun hd => hr c ⟨h, hc⟩ ⟨ne_zero_of_dvd_ne_zero ha0 h, d, hd, he⟩⟩, - hs.1⟩ - -@[elab_as_elim] -theorem induction_on_irreducible {P : α → Prop} (a : α) (h0 : P 0) (hu : ∀ u : α, IsUnit u → P u) - (hi : ∀ a i : α, a ≠ 0 → Irreducible i → P a → P (i * a)) : P a := - haveI := Classical.dec - wellFounded_dvdNotUnit.fix - (fun a ih => - if ha0 : a = 0 then ha0.substr h0 - else - if hau : IsUnit a then hu a hau - else - let ⟨i, hii, b, hb⟩ := exists_irreducible_factor hau ha0 - let hb0 : b ≠ 0 := ne_zero_of_dvd_ne_zero ha0 ⟨i, mul_comm i b ▸ hb⟩ - hb.symm ▸ hi b i hb0 hii <| ih b ⟨hb0, i, hii.1, mul_comm i b ▸ hb⟩) - a - -theorem exists_factors (a : α) : - a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ Associated f.prod a := - induction_on_irreducible a (fun h => (h rfl).elim) - (fun _ hu _ => ⟨0, fun _ h => False.elim (Multiset.not_mem_zero _ h), hu.unit, one_mul _⟩) - fun a i ha0 hi ih _ => - let ⟨s, hs⟩ := ih ha0 - ⟨i ::ₘ s, fun b H => (Multiset.mem_cons.1 H).elim (fun h => h.symm ▸ hi) (hs.1 b), by - rw [s.prod_cons i] - exact hs.2.mul_left i⟩ - -theorem not_unit_iff_exists_factors_eq (a : α) (hn0 : a ≠ 0) : - ¬IsUnit a ↔ ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod = a ∧ f ≠ ∅ := - ⟨fun hnu => by - obtain ⟨f, hi, u, rfl⟩ := exists_factors a hn0 - obtain ⟨b, h⟩ := Multiset.exists_mem_of_ne_zero fun h : f = 0 => hnu <| by simp [h] - classical - refine ⟨(f.erase b).cons (b * u), fun a ha => ?_, ?_, Multiset.cons_ne_zero⟩ - · obtain rfl | ha := Multiset.mem_cons.1 ha - exacts [Associated.irreducible ⟨u, rfl⟩ (hi b h), hi a (Multiset.mem_of_mem_erase ha)] - · rw [Multiset.prod_cons, mul_comm b, mul_assoc, Multiset.prod_erase h, mul_comm], - fun ⟨_, hi, he, hne⟩ => - let ⟨b, h⟩ := Multiset.exists_mem_of_ne_zero hne - not_isUnit_of_not_isUnit_dvd (hi b h).not_unit <| he ▸ Multiset.dvd_prod h⟩ - -theorem isRelPrime_of_no_irreducible_factors {x y : α} (nonzero : ¬(x = 0 ∧ y = 0)) - (H : ∀ z : α, Irreducible z → z ∣ x → ¬z ∣ y) : IsRelPrime x y := - isRelPrime_of_no_nonunits_factors nonzero fun _z znu znz zx zy ↦ - have ⟨i, h1, h2⟩ := exists_irreducible_factor znu znz - H i h1 (h2.trans zx) (h2.trans zy) - -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 - ⟨by - convert h - ext - exact Associates.dvdNotUnit_iff_lt⟩ - -theorem WfDvdMonoid.iff_wellFounded_associates [CancelCommMonoidWithZero α] : - 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 - obtain ⟨a, ⟨n, rfl⟩, hm⟩ := wellFounded_dvdNotUnit.has_min - {a | ∃ n, x ^ n * a = a₀} ⟨a₀, 0, by rw [pow_zero, one_mul]⟩ - refine ⟨n, a, ?_, rfl⟩; rintro ⟨d, rfl⟩ - exact hm d ⟨n + 1, by rw [pow_succ, mul_assoc]⟩ - ⟨(right_ne_zero_of_mul <| right_ne_zero_of_mul h), x, hx, mul_comm _ _⟩ - -theorem WfDvdMonoid.max_power_factor [CommMonoidWithZero α] [WfDvdMonoid α] {a₀ x : α} - (h : a₀ ≠ 0) (hx : Irreducible x) : ∃ (n : ℕ) (a : α), ¬x ∣ a ∧ a₀ = x ^ n * a := - max_power_factor' h hx.not_unit - -theorem multiplicity.finite_of_not_isUnit [CancelCommMonoidWithZero α] [WfDvdMonoid α] - {a b : α} (ha : ¬IsUnit a) (hb : b ≠ 0) : multiplicity.Finite a b := by - obtain ⟨n, c, ndvd, rfl⟩ := WfDvdMonoid.max_power_factor' hb ha - exact ⟨n, by rwa [pow_succ, mul_dvd_mul_iff_left (left_ne_zero_of_mul hb)]⟩ - -section Prio - --- set_option default_priority 100 - --- see Note [default priority] -/-- unique factorization monoids. - -These are defined as `CancelCommMonoidWithZero`s with well-founded strict divisibility -relations, but this is equivalent to more familiar definitions: - -Each element (except zero) is uniquely represented as a multiset of irreducible factors. -Uniqueness is only up to associated elements. - -Each element (except zero) is non-uniquely represented as a multiset -of prime factors. - -To define a UFD using the definition in terms of multisets -of irreducible factors, use the definition `of_exists_unique_irreducible_factors` - -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 - IsWellFounded α DvdNotUnit : Prop where - protected irreducible_iff_prime : ∀ {a : α}, Irreducible a ↔ Prime a - -instance (priority := 100) ufm_of_decomposition_of_wfDvdMonoid - [CancelCommMonoidWithZero α] [WfDvdMonoid α] [DecompositionMonoid α] : - UniqueFactorizationMonoid α := - { ‹WfDvdMonoid α› with irreducible_iff_prime := irreducible_iff_prime } - -@[deprecated ufm_of_decomposition_of_wfDvdMonoid (since := "2024-02-12")] -theorem ufm_of_gcd_of_wfDvdMonoid [CancelCommMonoidWithZero α] [WfDvdMonoid α] - [DecompositionMonoid α] : UniqueFactorizationMonoid α := - ufm_of_decomposition_of_wfDvdMonoid - -instance Associates.ufm [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] : - UniqueFactorizationMonoid (Associates α) := - { (WfDvdMonoid.wfDvdMonoid_associates : WfDvdMonoid (Associates α)) with - irreducible_iff_prime := by - rw [← Associates.irreducible_iff_prime_iff] - apply UniqueFactorizationMonoid.irreducible_iff_prime } - -end Prio - -namespace UniqueFactorizationMonoid - -variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] - -theorem exists_prime_factors (a : α) : - a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a := by - simp_rw [← UniqueFactorizationMonoid.irreducible_iff_prime] - apply WfDvdMonoid.exists_factors a - -instance : DecompositionMonoid α where - primal a := by - obtain rfl | ha := eq_or_ne a 0; · exact isPrimal_zero - obtain ⟨f, hf, u, rfl⟩ := exists_prime_factors a ha - exact ((Submonoid.isPrimal α).multiset_prod_mem f (hf · ·|>.isPrimal)).mul u.isUnit.isPrimal - -lemma exists_prime_iff : - (∃ (p : α), Prime p) ↔ ∃ (x : α), x ≠ 0 ∧ ¬ IsUnit x := by - refine ⟨fun ⟨p, hp⟩ ↦ ⟨p, hp.ne_zero, hp.not_unit⟩, fun ⟨x, hx₀, hxu⟩ ↦ ?_⟩ - obtain ⟨f, hf, -⟩ := WfDvdMonoid.exists_irreducible_factor hxu hx₀ - exact ⟨f, UniqueFactorizationMonoid.irreducible_iff_prime.mp hf⟩ - -@[elab_as_elim] -theorem induction_on_prime {P : α → Prop} (a : α) (h₁ : P 0) (h₂ : ∀ x : α, IsUnit x → P x) - (h₃ : ∀ a p : α, a ≠ 0 → Prime p → P a → P (p * a)) : P a := by - simp_rw [← UniqueFactorizationMonoid.irreducible_iff_prime] at h₃ - exact WfDvdMonoid.induction_on_irreducible a h₁ h₂ h₃ - -end UniqueFactorizationMonoid - -theorem prime_factors_unique [CancelCommMonoidWithZero α] : - ∀ {f g : Multiset α}, - (∀ x ∈ f, Prime x) → (∀ x ∈ g, Prime x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g := by - classical - intro f - induction' f using Multiset.induction_on with p f ih - · intros g _ hg h - exact Multiset.rel_zero_left.2 <| - Multiset.eq_zero_of_forall_not_mem fun x hx => - have : IsUnit g.prod := by simpa [associated_one_iff_isUnit] using h.symm - (hg x hx).not_unit <| - isUnit_iff_dvd_one.2 <| (Multiset.dvd_prod hx).trans (isUnit_iff_dvd_one.1 this) - · intros g hf hg hfg - let ⟨b, hbg, hb⟩ := - (exists_associated_mem_of_dvd_prod (hf p (by simp)) fun q hq => hg _ hq) <| - hfg.dvd_iff_dvd_right.1 (show p ∣ (p ::ₘ f).prod by simp) - haveI := Classical.decEq α - rw [← Multiset.cons_erase hbg] - exact - Multiset.Rel.cons hb - (ih (fun q hq => hf _ (by simp [hq])) - (fun {q} (hq : q ∈ g.erase b) => hg q (Multiset.mem_of_mem_erase hq)) - (Associated.of_mul_left - (by rwa [← Multiset.prod_cons, ← Multiset.prod_cons, Multiset.cons_erase hbg]) hb - (hf p (by simp)).ne_zero)) - -namespace UniqueFactorizationMonoid - -variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] - -theorem factors_unique {f g : Multiset α} (hf : ∀ x ∈ f, Irreducible x) - (hg : ∀ x ∈ g, Irreducible x) (h : f.prod ~ᵤ g.prod) : Multiset.Rel Associated f g := - prime_factors_unique (fun x hx => UniqueFactorizationMonoid.irreducible_iff_prime.mp (hf x hx)) - (fun x hx => UniqueFactorizationMonoid.irreducible_iff_prime.mp (hg x hx)) h - -end UniqueFactorizationMonoid - -/-- If an irreducible has a prime factorization, - then it is an associate of one of its prime factors. -/ -theorem prime_factors_irreducible [CancelCommMonoidWithZero α] {a : α} {f : Multiset α} - (ha : Irreducible a) (pfa : (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a) : ∃ p, a ~ᵤ p ∧ f = {p} := by - haveI := Classical.decEq α - refine @Multiset.induction_on _ - (fun g => (g.prod ~ᵤ a) → (∀ b ∈ g, Prime b) → ∃ p, a ~ᵤ p ∧ g = {p}) f ?_ ?_ pfa.2 pfa.1 - · intro h; exact (ha.not_unit (associated_one_iff_isUnit.1 (Associated.symm h))).elim - · rintro p s _ ⟨u, hu⟩ hs - use p - have hs0 : s = 0 := by - by_contra hs0 - obtain ⟨q, hq⟩ := Multiset.exists_mem_of_ne_zero hs0 - apply (hs q (by simp [hq])).2.1 - refine (ha.isUnit_or_isUnit (?_ : _ = p * ↑u * (s.erase q).prod * _)).resolve_left ?_ - · rw [mul_right_comm _ _ q, mul_assoc, ← Multiset.prod_cons, Multiset.cons_erase hq, ← hu, - mul_comm, mul_comm p _, mul_assoc] - simp - apply mt isUnit_of_mul_isUnit_left (mt isUnit_of_mul_isUnit_left _) - apply (hs p (Multiset.mem_cons_self _ _)).2.1 - simp only [mul_one, Multiset.prod_cons, Multiset.prod_zero, hs0] at * - exact ⟨Associated.symm ⟨u, hu⟩, rfl⟩ - -section ExistsPrimeFactors - -variable [CancelCommMonoidWithZero α] -variable (pf : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a) -include pf - -theorem WfDvdMonoid.of_exists_prime_factors : WfDvdMonoid α := - ⟨by - classical - refine RelHomClass.wellFounded - (RelHom.mk ?_ ?_ : (DvdNotUnit : α → α → Prop) →r ((· < ·) : ℕ∞ → ℕ∞ → Prop)) wellFounded_lt - · intro a - by_cases h : a = 0 - · exact ⊤ - exact ↑(Multiset.card (Classical.choose (pf a h))) - rintro a b ⟨ane0, ⟨c, hc, b_eq⟩⟩ - rw [dif_neg ane0] - by_cases h : b = 0 - · simp [h, lt_top_iff_ne_top] - · rw [dif_neg h, Nat.cast_lt] - have cne0 : c ≠ 0 := by - refine mt (fun con => ?_) h - rw [b_eq, con, mul_zero] - calc - Multiset.card (Classical.choose (pf a ane0)) < - _ + Multiset.card (Classical.choose (pf c cne0)) := - lt_add_of_pos_right _ - (Multiset.card_pos.mpr fun con => hc (associated_one_iff_isUnit.mp ?_)) - _ = Multiset.card (Classical.choose (pf a ane0) + Classical.choose (pf c cne0)) := - (Multiset.card_add _ _).symm - _ = Multiset.card (Classical.choose (pf b h)) := - Multiset.card_eq_card_of_rel - (prime_factors_unique ?_ (Classical.choose_spec (pf _ h)).1 ?_) - - · convert (Classical.choose_spec (pf c cne0)).2.symm - rw [con, Multiset.prod_zero] - · intro x hadd - rw [Multiset.mem_add] at hadd - cases' hadd with h h <;> apply (Classical.choose_spec (pf _ _)).1 _ h <;> assumption - · rw [Multiset.prod_add] - trans a * c - · apply Associated.mul_mul <;> apply (Classical.choose_spec (pf _ _)).2 <;> assumption - · rw [← b_eq] - apply (Classical.choose_spec (pf _ _)).2.symm; assumption⟩ - -theorem irreducible_iff_prime_of_exists_prime_factors {p : α} : Irreducible p ↔ Prime p := by - by_cases hp0 : p = 0 - · simp [hp0] - refine ⟨fun h => ?_, Prime.irreducible⟩ - obtain ⟨f, hf⟩ := pf p hp0 - obtain ⟨q, hq, rfl⟩ := prime_factors_irreducible h hf - rw [hq.prime_iff] - exact hf.1 q (Multiset.mem_singleton_self _) - -theorem UniqueFactorizationMonoid.of_exists_prime_factors : UniqueFactorizationMonoid α := - { WfDvdMonoid.of_exists_prime_factors pf with - irreducible_iff_prime := irreducible_iff_prime_of_exists_prime_factors pf } - -end ExistsPrimeFactors - -theorem UniqueFactorizationMonoid.iff_exists_prime_factors [CancelCommMonoidWithZero α] : - UniqueFactorizationMonoid α ↔ - ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a := - ⟨fun h => @UniqueFactorizationMonoid.exists_prime_factors _ _ h, - UniqueFactorizationMonoid.of_exists_prime_factors⟩ - -section - -variable {β : Type*} [CancelCommMonoidWithZero α] [CancelCommMonoidWithZero β] - -theorem MulEquiv.uniqueFactorizationMonoid (e : α ≃* β) (hα : UniqueFactorizationMonoid α) : - UniqueFactorizationMonoid β := by - rw [UniqueFactorizationMonoid.iff_exists_prime_factors] at hα ⊢ - intro a ha - obtain ⟨w, hp, u, h⟩ := - hα (e.symm a) fun h => - ha <| by - convert← map_zero e - simp [← h] - exact - ⟨w.map e, fun b hb => - let ⟨c, hc, he⟩ := Multiset.mem_map.1 hb - he ▸ e.prime_iff.1 (hp c hc), - Units.map e.toMonoidHom u, - by - 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 β := - ⟨e.uniqueFactorizationMonoid, e.symm.uniqueFactorizationMonoid⟩ - -end - -theorem irreducible_iff_prime_of_exists_unique_irreducible_factors [CancelCommMonoidWithZero α] - (eif : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod ~ᵤ a) - (uif : - ∀ f g : Multiset α, - (∀ x ∈ f, Irreducible x) → - (∀ x ∈ g, Irreducible x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g) - (p : α) : Irreducible p ↔ Prime p := - letI := Classical.decEq α - ⟨ fun hpi => - ⟨hpi.ne_zero, hpi.1, fun a b ⟨x, hx⟩ => - if hab0 : a * b = 0 then - (eq_zero_or_eq_zero_of_mul_eq_zero hab0).elim (fun ha0 => by simp [ha0]) fun hb0 => by - simp [hb0] - else by - have hx0 : x ≠ 0 := fun hx0 => by simp_all - have ha0 : a ≠ 0 := left_ne_zero_of_mul hab0 - have hb0 : b ≠ 0 := right_ne_zero_of_mul hab0 - cases' eif x hx0 with fx hfx - cases' eif a ha0 with fa hfa - cases' eif b hb0 with fb hfb - have h : Multiset.Rel Associated (p ::ₘ fx) (fa + fb) := by - apply uif - · exact fun i hi => (Multiset.mem_cons.1 hi).elim (fun hip => hip.symm ▸ hpi) (hfx.1 _) - · exact fun i hi => (Multiset.mem_add.1 hi).elim (hfa.1 _) (hfb.1 _) - calc - Multiset.prod (p ::ₘ fx) ~ᵤ a * b := by - rw [hx, Multiset.prod_cons]; exact hfx.2.mul_left _ - _ ~ᵤ fa.prod * fb.prod := hfa.2.symm.mul_mul hfb.2.symm - _ = _ := by rw [Multiset.prod_add] - - exact - let ⟨q, hqf, hq⟩ := Multiset.exists_mem_of_rel_of_mem h (Multiset.mem_cons_self p _) - (Multiset.mem_add.1 hqf).elim - (fun hqa => - Or.inl <| hq.dvd_iff_dvd_left.2 <| hfa.2.dvd_iff_dvd_right.1 (Multiset.dvd_prod hqa)) - fun hqb => - Or.inr <| hq.dvd_iff_dvd_left.2 <| hfb.2.dvd_iff_dvd_right.1 (Multiset.dvd_prod hqb)⟩, - Prime.irreducible⟩ - -theorem UniqueFactorizationMonoid.of_exists_unique_irreducible_factors [CancelCommMonoidWithZero α] - (eif : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod ~ᵤ a) - (uif : - ∀ f g : Multiset α, - (∀ x ∈ f, Irreducible x) → - (∀ x ∈ g, Irreducible x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g) : - UniqueFactorizationMonoid α := - UniqueFactorizationMonoid.of_exists_prime_factors - (by - convert eif using 7 - simp_rw [irreducible_iff_prime_of_exists_unique_irreducible_factors eif uif]) - -namespace UniqueFactorizationMonoid - -variable [CancelCommMonoidWithZero α] -variable [UniqueFactorizationMonoid α] - -open Classical in -/-- Noncomputably determines the multiset of prime factors. -/ -noncomputable def factors (a : α) : Multiset α := - if h : a = 0 then 0 else Classical.choose (UniqueFactorizationMonoid.exists_prime_factors a h) - -theorem factors_prod {a : α} (ane0 : a ≠ 0) : Associated (factors a).prod a := by - rw [factors, dif_neg ane0] - exact (Classical.choose_spec (exists_prime_factors a ane0)).2 - -@[simp] -theorem factors_zero : factors (0 : α) = 0 := by simp [factors] - -theorem ne_zero_of_mem_factors {p a : α} (h : p ∈ factors a) : a ≠ 0 := by - rintro rfl - simp at h - -theorem dvd_of_mem_factors {p a : α} (h : p ∈ factors a) : p ∣ a := - dvd_trans (Multiset.dvd_prod h) (Associated.dvd (factors_prod (ne_zero_of_mem_factors h))) - -theorem prime_of_factor {a : α} (x : α) (hx : x ∈ factors a) : Prime x := by - have ane0 := ne_zero_of_mem_factors hx - rw [factors, dif_neg ane0] at hx - exact (Classical.choose_spec (UniqueFactorizationMonoid.exists_prime_factors a ane0)).1 x hx - -theorem irreducible_of_factor {a : α} : ∀ x : α, x ∈ factors a → Irreducible x := fun x h => - (prime_of_factor x h).irreducible - -@[simp] -theorem factors_one : factors (1 : α) = 0 := by - nontriviality α using factors - rw [← Multiset.rel_zero_right] - refine factors_unique irreducible_of_factor (fun x hx => (Multiset.not_mem_zero x hx).elim) ?_ - rw [Multiset.prod_zero] - exact factors_prod one_ne_zero - -theorem exists_mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : - p ∣ a → ∃ q ∈ factors a, p ~ᵤ q := fun ⟨b, hb⟩ => - have hb0 : b ≠ 0 := fun hb0 => by simp_all - have : Multiset.Rel Associated (p ::ₘ factors b) (factors a) := - factors_unique - (fun _ hx => (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_factor _)) - irreducible_of_factor - (Associated.symm <| - calc - Multiset.prod (factors a) ~ᵤ a := factors_prod ha0 - _ = p * b := hb - _ ~ᵤ Multiset.prod (p ::ₘ factors b) := by - rw [Multiset.prod_cons]; exact (factors_prod hb0).symm.mul_left _ - ) - Multiset.exists_mem_of_rel_of_mem this (by simp) - -theorem exists_mem_factors {x : α} (hx : x ≠ 0) (h : ¬IsUnit x) : ∃ p, p ∈ factors x := by - obtain ⟨p', hp', hp'x⟩ := WfDvdMonoid.exists_irreducible_factor h hx - obtain ⟨p, hp, _⟩ := exists_mem_factors_of_dvd hx hp' hp'x - exact ⟨p, hp⟩ - -open Classical in -theorem factors_mul {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - Multiset.Rel Associated (factors (x * y)) (factors x + factors y) := by - refine - factors_unique irreducible_of_factor - (fun a ha => - (Multiset.mem_add.mp ha).by_cases (irreducible_of_factor _) (irreducible_of_factor _)) - ((factors_prod (mul_ne_zero hx hy)).trans ?_) - rw [Multiset.prod_add] - exact (Associated.mul_mul (factors_prod hx) (factors_prod hy)).symm - -theorem factors_pow {x : α} (n : ℕ) : - Multiset.Rel Associated (factors (x ^ n)) (n • factors x) := by - match n with - | 0 => rw [zero_smul, pow_zero, factors_one, Multiset.rel_zero_right] - | n+1 => - by_cases h0 : x = 0 - · simp [h0, zero_pow n.succ_ne_zero, smul_zero] - · rw [pow_succ', succ_nsmul'] - refine Multiset.Rel.trans _ (factors_mul h0 (pow_ne_zero n h0)) ?_ - refine Multiset.Rel.add ?_ <| factors_pow n - exact Multiset.rel_refl_of_refl_on fun y _ => Associated.refl _ - -@[simp] -theorem factors_pos (x : α) (hx : x ≠ 0) : 0 < factors x ↔ ¬IsUnit x := by - constructor - · intro h hx - obtain ⟨p, hp⟩ := Multiset.exists_mem_of_ne_zero h.ne' - exact (prime_of_factor _ hp).not_unit (isUnit_of_dvd_unit (dvd_of_mem_factors hp) hx) - · intro h - obtain ⟨p, hp⟩ := exists_mem_factors hx h - exact - bot_lt_iff_ne_bot.mpr - (mt Multiset.eq_zero_iff_forall_not_mem.mp (not_forall.mpr ⟨p, not_not.mpr hp⟩)) - -open Multiset in -theorem factors_pow_count_prod [DecidableEq α] {x : α} (hx : x ≠ 0) : - (∏ p ∈ (factors x).toFinset, p ^ (factors x).count p) ~ᵤ x := - calc - _ = prod (∑ a ∈ toFinset (factors x), count a (factors x) • {a}) := by - simp only [prod_sum, prod_nsmul, prod_singleton] - _ = prod (factors x) := by rw [toFinset_sum_count_nsmul_eq (factors x)] - _ ~ᵤ x := factors_prod hx - -theorem factors_rel_of_associated {a b : α} (h : Associated a b) : - Multiset.Rel Associated (factors a) (factors b) := by - rcases iff_iff_and_or_not_and_not.mp h.eq_zero_iff with (⟨rfl, rfl⟩ | ⟨ha, hb⟩) - · simp - · refine factors_unique irreducible_of_factor irreducible_of_factor ?_ - exact ((factors_prod ha).trans h).trans (factors_prod hb).symm - -end UniqueFactorizationMonoid - -namespace UniqueFactorizationMonoid - -variable [CancelCommMonoidWithZero α] [NormalizationMonoid α] -variable [UniqueFactorizationMonoid α] - -/-- Noncomputably determines the multiset of prime factors. -/ -noncomputable def normalizedFactors (a : α) : Multiset α := - Multiset.map normalize <| factors a - -/-- An arbitrary choice of factors of `x : M` is exactly the (unique) normalized set of factors, -if `M` has a trivial group of units. -/ -@[simp] -theorem factors_eq_normalizedFactors {M : Type*} [CancelCommMonoidWithZero M] - [UniqueFactorizationMonoid M] [Subsingleton Mˣ] (x : M) : factors x = normalizedFactors x := by - unfold normalizedFactors - convert (Multiset.map_id (factors x)).symm - ext p - exact normalize_eq p - -theorem normalizedFactors_prod {a : α} (ane0 : a ≠ 0) : - Associated (normalizedFactors a).prod a := by - rw [normalizedFactors, factors, dif_neg ane0] - refine Associated.trans ?_ (Classical.choose_spec (exists_prime_factors a ane0)).2 - rw [← Associates.mk_eq_mk_iff_associated, ← Associates.prod_mk, ← Associates.prod_mk, - Multiset.map_map] - congr 2 - ext - rw [Function.comp_apply, Associates.mk_normalize] - -theorem prime_of_normalized_factor {a : α} : ∀ x : α, x ∈ normalizedFactors a → Prime x := by - rw [normalizedFactors, factors] - split_ifs with ane0; · simp - intro x hx; rcases Multiset.mem_map.1 hx with ⟨y, ⟨hy, rfl⟩⟩ - rw [(normalize_associated _).prime_iff] - exact (Classical.choose_spec (UniqueFactorizationMonoid.exists_prime_factors a ane0)).1 y hy - -theorem irreducible_of_normalized_factor {a : α} : - ∀ x : α, x ∈ normalizedFactors a → Irreducible x := fun x h => - (prime_of_normalized_factor x h).irreducible - -theorem normalize_normalized_factor {a : α} : - ∀ x : α, x ∈ normalizedFactors a → normalize x = x := by - rw [normalizedFactors, factors] - split_ifs with h; · simp - intro x hx - obtain ⟨y, _, rfl⟩ := Multiset.mem_map.1 hx - apply normalize_idem - -theorem normalizedFactors_irreducible {a : α} (ha : Irreducible a) : - normalizedFactors a = {normalize a} := by - obtain ⟨p, a_assoc, hp⟩ := - prime_factors_irreducible ha ⟨prime_of_normalized_factor, normalizedFactors_prod ha.ne_zero⟩ - have p_mem : p ∈ normalizedFactors a := by - rw [hp] - exact Multiset.mem_singleton_self _ - convert hp - rwa [← normalize_normalized_factor p p_mem, normalize_eq_normalize_iff, dvd_dvd_iff_associated] - -theorem normalizedFactors_eq_of_dvd (a : α) : - ∀ᵉ (p ∈ normalizedFactors a) (q ∈ normalizedFactors a), p ∣ q → p = q := by - intro p hp q hq hdvd - convert normalize_eq_normalize hdvd - ((prime_of_normalized_factor _ hp).irreducible.dvd_symm - (prime_of_normalized_factor _ hq).irreducible hdvd) <;> - apply (normalize_normalized_factor _ ‹_›).symm - -theorem exists_mem_normalizedFactors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : - p ∣ a → ∃ q ∈ normalizedFactors a, p ~ᵤ q := fun ⟨b, hb⟩ => - have hb0 : b ≠ 0 := fun hb0 => by simp_all - have : Multiset.Rel Associated (p ::ₘ normalizedFactors b) (normalizedFactors a) := - factors_unique - (fun _ hx => - (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_normalized_factor _)) - irreducible_of_normalized_factor - (Associated.symm <| - calc - Multiset.prod (normalizedFactors a) ~ᵤ a := normalizedFactors_prod ha0 - _ = p * b := hb - _ ~ᵤ Multiset.prod (p ::ₘ normalizedFactors b) := by - rw [Multiset.prod_cons] - exact (normalizedFactors_prod hb0).symm.mul_left _ - ) - Multiset.exists_mem_of_rel_of_mem this (by simp) - -theorem exists_mem_normalizedFactors {x : α} (hx : x ≠ 0) (h : ¬IsUnit x) : - ∃ p, p ∈ normalizedFactors x := by - obtain ⟨p', hp', hp'x⟩ := WfDvdMonoid.exists_irreducible_factor h hx - obtain ⟨p, hp, _⟩ := exists_mem_normalizedFactors_of_dvd hx hp' hp'x - exact ⟨p, hp⟩ - -@[simp] -theorem normalizedFactors_zero : normalizedFactors (0 : α) = 0 := by - simp [normalizedFactors, factors] - -@[simp] -theorem normalizedFactors_one : normalizedFactors (1 : α) = 0 := by - cases' subsingleton_or_nontrivial α with h h - · dsimp [normalizedFactors, factors] - simp [Subsingleton.elim (1 : α) 0] - · rw [← Multiset.rel_zero_right] - apply factors_unique irreducible_of_normalized_factor - · intro x hx - exfalso - apply Multiset.not_mem_zero x hx - · apply normalizedFactors_prod one_ne_zero - -@[simp] -theorem normalizedFactors_mul {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - normalizedFactors (x * y) = normalizedFactors x + normalizedFactors y := by - have h : (normalize : α → α) = Associates.out ∘ Associates.mk := by - ext - rw [Function.comp_apply, Associates.out_mk] - rw [← Multiset.map_id' (normalizedFactors (x * y)), ← Multiset.map_id' (normalizedFactors x), ← - Multiset.map_id' (normalizedFactors y), ← Multiset.map_congr rfl normalize_normalized_factor, ← - Multiset.map_congr rfl normalize_normalized_factor, ← - Multiset.map_congr rfl normalize_normalized_factor, ← Multiset.map_add, h, ← - Multiset.map_map Associates.out, eq_comm, ← Multiset.map_map Associates.out] - refine congr rfl ?_ - apply Multiset.map_mk_eq_map_mk_of_rel - apply factors_unique - · intro x hx - rcases Multiset.mem_add.1 hx with (hx | hx) <;> exact irreducible_of_normalized_factor x hx - · exact irreducible_of_normalized_factor - · rw [Multiset.prod_add] - exact - ((normalizedFactors_prod hx).mul_mul (normalizedFactors_prod hy)).trans - (normalizedFactors_prod (mul_ne_zero hx hy)).symm - -@[simp] -theorem normalizedFactors_pow {x : α} (n : ℕ) : - normalizedFactors (x ^ n) = n • normalizedFactors x := by - induction' n with n ih - · simp - by_cases h0 : x = 0 - · simp [h0, zero_pow n.succ_ne_zero, smul_zero] - rw [pow_succ', succ_nsmul', normalizedFactors_mul h0 (pow_ne_zero _ h0), ih] - -theorem _root_.Irreducible.normalizedFactors_pow {p : α} (hp : Irreducible p) (k : ℕ) : - normalizedFactors (p ^ k) = Multiset.replicate k (normalize p) := by - rw [UniqueFactorizationMonoid.normalizedFactors_pow, normalizedFactors_irreducible hp, - Multiset.nsmul_singleton] - -theorem normalizedFactors_prod_eq (s : Multiset α) (hs : ∀ a ∈ s, Irreducible a) : - normalizedFactors s.prod = s.map normalize := by - induction' s using Multiset.induction with a s ih - · rw [Multiset.prod_zero, normalizedFactors_one, Multiset.map_zero] - · have ia := hs a (Multiset.mem_cons_self a _) - have ib := fun b h => hs b (Multiset.mem_cons_of_mem h) - obtain rfl | ⟨b, hb⟩ := s.empty_or_exists_mem - · rw [Multiset.cons_zero, Multiset.prod_singleton, Multiset.map_singleton, - normalizedFactors_irreducible ia] - haveI := nontrivial_of_ne b 0 (ib b hb).ne_zero - rw [Multiset.prod_cons, Multiset.map_cons, - normalizedFactors_mul ia.ne_zero (Multiset.prod_ne_zero fun h => (ib 0 h).ne_zero rfl), - normalizedFactors_irreducible ia, ih ib, Multiset.singleton_add] - -theorem dvd_iff_normalizedFactors_le_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - x ∣ y ↔ normalizedFactors x ≤ normalizedFactors y := by - constructor - · rintro ⟨c, rfl⟩ - simp [hx, right_ne_zero_of_mul hy] - · rw [← (normalizedFactors_prod hx).dvd_iff_dvd_left, ← - (normalizedFactors_prod hy).dvd_iff_dvd_right] - apply Multiset.prod_dvd_prod_of_le - -theorem _root_.Associated.normalizedFactors_eq {a b : α} (h : Associated a b) : - normalizedFactors a = normalizedFactors b := by - unfold normalizedFactors - have h' : ⇑(normalize (α := α)) = Associates.out ∘ Associates.mk := funext Associates.out_mk - rw [h', ← Multiset.map_map, ← Multiset.map_map, - Associates.rel_associated_iff_map_eq_map.mp (factors_rel_of_associated h)] - -theorem associated_iff_normalizedFactors_eq_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - x ~ᵤ y ↔ normalizedFactors x = normalizedFactors y := - ⟨Associated.normalizedFactors_eq, fun h => - (normalizedFactors_prod hx).symm.trans (_root_.trans (by rw [h]) (normalizedFactors_prod hy))⟩ - -theorem normalizedFactors_of_irreducible_pow {p : α} (hp : Irreducible p) (k : ℕ) : - normalizedFactors (p ^ k) = Multiset.replicate k (normalize p) := by - rw [normalizedFactors_pow, normalizedFactors_irreducible hp, Multiset.nsmul_singleton] - -theorem zero_not_mem_normalizedFactors (x : α) : (0 : α) ∉ normalizedFactors x := fun h => - Prime.ne_zero (prime_of_normalized_factor _ h) rfl - -theorem dvd_of_mem_normalizedFactors {a p : α} (H : p ∈ normalizedFactors a) : p ∣ a := by - by_cases hcases : a = 0 - · rw [hcases] - exact dvd_zero p - · exact dvd_trans (Multiset.dvd_prod H) (Associated.dvd (normalizedFactors_prod hcases)) - -theorem mem_normalizedFactors_iff [Subsingleton αˣ] {p x : α} (hx : x ≠ 0) : - p ∈ normalizedFactors x ↔ Prime p ∧ p ∣ x := by - constructor - · intro h - exact ⟨prime_of_normalized_factor p h, dvd_of_mem_normalizedFactors h⟩ - · rintro ⟨hprime, hdvd⟩ - obtain ⟨q, hqmem, hqeq⟩ := exists_mem_normalizedFactors_of_dvd hx hprime.irreducible hdvd - rw [associated_iff_eq] at hqeq - exact hqeq ▸ hqmem - -theorem exists_associated_prime_pow_of_unique_normalized_factor {p r : α} - (h : ∀ {m}, m ∈ normalizedFactors r → m = p) (hr : r ≠ 0) : ∃ i : ℕ, Associated (p ^ i) r := by - use Multiset.card.toFun (normalizedFactors r) - have := UniqueFactorizationMonoid.normalizedFactors_prod hr - rwa [Multiset.eq_replicate_of_mem fun b => h, Multiset.prod_replicate] at this - -theorem normalizedFactors_prod_of_prime [Subsingleton αˣ] {m : Multiset α} - (h : ∀ p ∈ m, Prime p) : normalizedFactors m.prod = m := by - 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 - rw [← normalize_normalized_factor a ha, ← normalize_normalized_factor b hb, - normalize_eq_normalize_iff] - exact Associated.dvd_dvd h - -@[simp] -theorem normalizedFactors_pos (x : α) (hx : x ≠ 0) : 0 < normalizedFactors x ↔ ¬IsUnit x := by - constructor - · intro h hx - obtain ⟨p, hp⟩ := Multiset.exists_mem_of_ne_zero h.ne' - exact - (prime_of_normalized_factor _ hp).not_unit - (isUnit_of_dvd_unit (dvd_of_mem_normalizedFactors hp) hx) - · intro h - obtain ⟨p, hp⟩ := exists_mem_normalizedFactors hx h - exact - bot_lt_iff_ne_bot.mpr - (mt Multiset.eq_zero_iff_forall_not_mem.mp (not_forall.mpr ⟨p, not_not.mpr hp⟩)) - -theorem dvdNotUnit_iff_normalizedFactors_lt_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : - DvdNotUnit x y ↔ normalizedFactors x < normalizedFactors y := by - constructor - · rintro ⟨_, c, hc, rfl⟩ - simp only [hx, right_ne_zero_of_mul hy, normalizedFactors_mul, Ne, not_false_iff, - lt_add_iff_pos_right, normalizedFactors_pos, hc] - · intro h - exact - dvdNotUnit_of_dvd_of_not_dvd - ((dvd_iff_normalizedFactors_le_normalizedFactors hx hy).mpr h.le) - (mt (dvd_iff_normalizedFactors_le_normalizedFactors hy hx).mp h.not_le) - -theorem normalizedFactors_multiset_prod (s : Multiset α) (hs : 0 ∉ s) : - normalizedFactors (s.prod) = (s.map normalizedFactors).sum := by - cases subsingleton_or_nontrivial α - · obtain rfl : s = 0 := by - apply Multiset.eq_zero_of_forall_not_mem - intro _ - convert hs - simp - induction s using Multiset.induction with - | empty => simp - | cons _ _ IH => - rw [Multiset.prod_cons, Multiset.map_cons, Multiset.sum_cons, normalizedFactors_mul, IH] - · exact fun h ↦ hs (Multiset.mem_cons_of_mem h) - · exact fun h ↦ hs (h ▸ Multiset.mem_cons_self _ _) - · apply Multiset.prod_ne_zero - exact fun h ↦ hs (Multiset.mem_cons_of_mem h) - -end UniqueFactorizationMonoid - -namespace UniqueFactorizationMonoid - -open scoped Classical - -open Multiset Associates - -variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] - -/-- Noncomputably defines a `normalizationMonoid` structure on a `UniqueFactorizationMonoid`. -/ -protected noncomputable def normalizationMonoid : NormalizationMonoid α := - normalizationMonoidOfMonoidHomRightInverse - { toFun := fun a : Associates α => - if a = 0 then 0 - else - ((normalizedFactors a).map - (Classical.choose mk_surjective.hasRightInverse : Associates α → α)).prod - map_one' := by nontriviality α; simp - map_mul' := fun x y => by - by_cases hx : x = 0 - · simp [hx] - by_cases hy : y = 0 - · simp [hy] - simp [hx, hy] } - (by - intro x - dsimp - by_cases hx : x = 0 - · simp [hx] - have h : Associates.mkMonoidHom ∘ Classical.choose mk_surjective.hasRightInverse = - (id : Associates α → Associates α) := by - ext x - rw [Function.comp_apply, mkMonoidHom_apply, - Classical.choose_spec mk_surjective.hasRightInverse x] - rfl - rw [if_neg hx, ← mkMonoidHom_apply, MonoidHom.map_multiset_prod, map_map, h, map_id, ← - associated_iff_eq] - apply normalizedFactors_prod hx) - -end UniqueFactorizationMonoid - -namespace UniqueFactorizationMonoid - -variable {R : Type*} [CancelCommMonoidWithZero R] [UniqueFactorizationMonoid R] - -theorem isRelPrime_iff_no_prime_factors {a b : R} (ha : a ≠ 0) : - IsRelPrime a b ↔ ∀ ⦃d⦄, d ∣ a → d ∣ b → ¬Prime d := - ⟨fun h _ ha hb ↦ (·.not_unit <| h ha hb), fun h ↦ WfDvdMonoid.isRelPrime_of_no_irreducible_factors - (ha ·.1) fun _ irr ha hb ↦ h ha hb (UniqueFactorizationMonoid.irreducible_iff_prime.mp irr)⟩ - -/-- Euclid's lemma: if `a ∣ b * c` and `a` and `c` have no common prime factors, `a ∣ b`. -Compare `IsCoprime.dvd_of_dvd_mul_left`. -/ -theorem dvd_of_dvd_mul_left_of_no_prime_factors {a b c : R} (ha : a ≠ 0) - (h : ∀ ⦃d⦄, d ∣ a → d ∣ c → ¬Prime d) : a ∣ b * c → a ∣ b := - ((isRelPrime_iff_no_prime_factors ha).mpr h).dvd_of_dvd_mul_right - -/-- Euclid's lemma: if `a ∣ b * c` and `a` and `b` have no common prime factors, `a ∣ c`. -Compare `IsCoprime.dvd_of_dvd_mul_right`. -/ -theorem dvd_of_dvd_mul_right_of_no_prime_factors {a b c : R} (ha : a ≠ 0) - (no_factors : ∀ {d}, d ∣ a → d ∣ b → ¬Prime d) : a ∣ b * c → a ∣ c := by - simpa [mul_comm b c] using dvd_of_dvd_mul_left_of_no_prime_factors ha @no_factors - -/-- If `a ≠ 0, b` are elements of a unique factorization domain, then dividing -out their common factor `c'` gives `a'` and `b'` with no factors in common. -/ -theorem exists_reduced_factors : - ∀ a ≠ (0 : R), ∀ b, - ∃ a' b' c', IsRelPrime a' b' ∧ c' * a' = a ∧ c' * b' = b := by - intro a - refine induction_on_prime a ?_ ?_ ?_ - · intros - contradiction - · intro a a_unit _ b - use a, b, 1 - constructor - · intro p p_dvd_a _ - exact isUnit_of_dvd_unit p_dvd_a a_unit - · simp - · intro a p a_ne_zero p_prime ih_a pa_ne_zero b - by_cases h : p ∣ b - · rcases h with ⟨b, rfl⟩ - obtain ⟨a', b', c', no_factor, ha', hb'⟩ := ih_a a_ne_zero b - refine ⟨a', b', p * c', @no_factor, ?_, ?_⟩ - · rw [mul_assoc, ha'] - · rw [mul_assoc, hb'] - · obtain ⟨a', b', c', coprime, rfl, rfl⟩ := ih_a a_ne_zero b - refine ⟨p * a', b', c', ?_, mul_left_comm _ _ _, rfl⟩ - intro q q_dvd_pa' q_dvd_b' - cases' p_prime.left_dvd_or_dvd_right_of_dvd_mul q_dvd_pa' with p_dvd_q q_dvd_a' - · have : p ∣ c' * b' := dvd_mul_of_dvd_right (p_dvd_q.trans q_dvd_b') _ - contradiction - exact coprime q_dvd_a' q_dvd_b' - -theorem exists_reduced_factors' (a b : R) (hb : b ≠ 0) : - ∃ a' b' c', IsRelPrime a' b' ∧ c' * a' = a ∧ c' * b' = b := - 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⟩ - -@[deprecated (since := "2024-09-21")] alias pow_right_injective := pow_injective_of_not_isUnit -@[deprecated (since := "2024-09-21")] alias pow_eq_pow_iff := pow_inj_of_not_isUnit - -section multiplicity - -variable [NormalizationMonoid R] - -open Multiset - -section - -theorem le_emultiplicity_iff_replicate_le_normalizedFactors {a b : R} {n : ℕ} (ha : Irreducible a) - (hb : b ≠ 0) : - ↑n ≤ emultiplicity a b ↔ replicate n (normalize a) ≤ normalizedFactors b := by - rw [← pow_dvd_iff_le_emultiplicity] - revert b - induction' n with n ih; · simp - intro b hb - constructor - · rintro ⟨c, rfl⟩ - rw [Ne, pow_succ', mul_assoc, mul_eq_zero, not_or] at hb - rw [pow_succ', mul_assoc, normalizedFactors_mul hb.1 hb.2, replicate_succ, - normalizedFactors_irreducible ha, singleton_add, cons_le_cons_iff, ← ih hb.2] - apply Dvd.intro _ rfl - · rw [Multiset.le_iff_exists_add] - rintro ⟨u, hu⟩ - rw [← (normalizedFactors_prod hb).dvd_iff_dvd_right, hu, prod_add, prod_replicate] - exact (Associated.pow_pow <| associated_normalize a).dvd.trans (Dvd.intro u.prod rfl) - -/-- The multiplicity of an irreducible factor of a nonzero element is exactly the number of times -the normalized factor occurs in the `normalizedFactors`. - -See also `count_normalizedFactors_eq` which expands the definition of `multiplicity` -to produce a specification for `count (normalizedFactors _) _`.. --/ -theorem emultiplicity_eq_count_normalizedFactors [DecidableEq R] {a b : R} (ha : Irreducible a) - (hb : b ≠ 0) : emultiplicity a b = (normalizedFactors b).count (normalize a) := by - apply le_antisymm - · apply Order.le_of_lt_add_one - rw [← Nat.cast_one, ← Nat.cast_add, lt_iff_not_ge, ge_iff_le, - le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] - simp - rw [le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] - -end - -/-- The number of times an irreducible factor `p` appears in `normalizedFactors x` is defined by -the number of times it divides `x`. - -See also `multiplicity_eq_count_normalizedFactors` if `n` is given by `multiplicity p x`. --/ -theorem count_normalizedFactors_eq [DecidableEq R] {p x : R} (hp : Irreducible p) - (hnorm : normalize p = p) {n : ℕ} (hle : p ^ n ∣ x) (hlt : ¬p ^ (n + 1) ∣ x) : - (normalizedFactors x).count p = n := by classical - by_cases hx0 : x = 0 - · simp [hx0] at hlt - apply Nat.cast_injective (R := ℕ∞) - convert (emultiplicity_eq_count_normalizedFactors hp hx0).symm - · exact hnorm.symm - exact (emultiplicity_eq_coe.mpr ⟨hle, hlt⟩).symm - -/-- The number of times an irreducible factor `p` appears in `normalizedFactors x` is defined by -the number of times it divides `x`. This is a slightly more general version of -`UniqueFactorizationMonoid.count_normalizedFactors_eq` that allows `p = 0`. - -See also `multiplicity_eq_count_normalizedFactors` if `n` is given by `multiplicity p x`. --/ -theorem count_normalizedFactors_eq' [DecidableEq R] {p x : R} (hp : p = 0 ∨ Irreducible p) - (hnorm : normalize p = p) {n : ℕ} (hle : p ^ n ∣ x) (hlt : ¬p ^ (n + 1) ∣ x) : - (normalizedFactors x).count p = n := by - rcases hp with (rfl | hp) - · cases n - · exact count_eq_zero.2 (zero_not_mem_normalizedFactors _) - · rw [zero_pow (Nat.succ_ne_zero _)] at hle hlt - exact absurd hle hlt - · exact count_normalizedFactors_eq hp hnorm hle hlt - -end multiplicity - -/-- Deprecated. Use `WfDvdMonoid.max_power_factor` instead. -/ -@[deprecated WfDvdMonoid.max_power_factor (since := "2024-03-01")] -theorem max_power_factor {a₀ x : R} (h : a₀ ≠ 0) (hx : Irreducible x) : - ∃ n : ℕ, ∃ a : R, ¬x ∣ a ∧ a₀ = x ^ n * a := WfDvdMonoid.max_power_factor h hx - -section Multiplicative - -variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] -variable {β : Type*} [CancelCommMonoidWithZero β] - -theorem prime_pow_coprime_prod_of_coprime_insert [DecidableEq α] {s : Finset α} (i : α → ℕ) (p : α) - (hps : p ∉ s) (is_prime : ∀ q ∈ insert p s, Prime q) - (is_coprime : ∀ᵉ (q ∈ insert p s) (q' ∈ insert p s), q ∣ q' → q = q') : - IsRelPrime (p ^ i p) (∏ p' ∈ s, p' ^ i p') := by - have hp := is_prime _ (Finset.mem_insert_self _ _) - refine (isRelPrime_iff_no_prime_factors <| pow_ne_zero _ hp.ne_zero).mpr ?_ - intro d hdp hdprod hd - apply hps - replace hdp := hd.dvd_of_dvd_pow hdp - obtain ⟨q, q_mem', hdq⟩ := hd.exists_mem_multiset_dvd hdprod - 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 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] -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)) - (hcp : ∀ {x y}, IsRelPrime x y → P x → P y → P (x * y)) : - P (∏ p ∈ s, p ^ i p) := by - letI := Classical.decEq α - induction' s using Finset.induction_on with p f' hpf' ih - · simpa using h1 isUnit_one - rw [Finset.prod_insert hpf'] - exact - hcp (prime_pow_coprime_prod_of_coprime_insert i p hpf' is_prime is_coprime) - (hpr (i p) (is_prime _ (Finset.mem_insert_self _ _))) - (ih (fun q hq => is_prime _ (Finset.mem_insert_of_mem hq)) fun q hq q' hq' => - is_coprime _ (Finset.mem_insert_of_mem hq) _ (Finset.mem_insert_of_mem hq')) - -/-- If `P` holds for `0`, units and powers of primes, -and `P x ∧ P y` for coprime `x, y` implies `P (x * y)`, -then `P` holds on all `a : α`. -/ -@[elab_as_elim] -theorem induction_on_coprime {P : α → Prop} (a : α) (h0 : P 0) (h1 : ∀ {x}, IsUnit x → P x) - (hpr : ∀ {p} (i : ℕ), Prime p → P (p ^ i)) - (hcp : ∀ {x y}, IsRelPrime x y → P x → P y → P (x * y)) : P a := by - letI := Classical.decEq α - have P_of_associated : ∀ {x y}, Associated x y → P x → P y := by - rintro x y ⟨u, rfl⟩ hx - exact hcp (fun p _ hpx => isUnit_of_dvd_unit hpx u.isUnit) hx (h1 u.isUnit) - by_cases ha0 : a = 0 - · rwa [ha0] - haveI : Nontrivial α := ⟨⟨_, _, ha0⟩⟩ - letI : NormalizationMonoid α := UniqueFactorizationMonoid.normalizationMonoid - refine P_of_associated (normalizedFactors_prod ha0) ?_ - rw [← (normalizedFactors a).map_id, Finset.prod_multiset_map_count] - refine induction_on_prime_power _ _ ?_ ?_ @h1 @hpr @hcp <;> simp only [Multiset.mem_toFinset] - · apply prime_of_normalized_factor - · apply normalizedFactors_eq_of_dvd - -/-- 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. -/ -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) - (hpr : ∀ {p} (i : ℕ), Prime p → f (p ^ i) = f p ^ i) - (hcp : ∀ {x y}, IsRelPrime x y → f (x * y) = f x * f y) : - f (∏ p ∈ s, p ^ (i p + j p)) = f (∏ p ∈ s, p ^ i p) * f (∏ p ∈ s, p ^ j p) := by - letI := Classical.decEq α - induction' s using Finset.induction_on with p s hps ih - · simpa using h1 isUnit_one - have hpr_p := is_prime _ (Finset.mem_insert_self _ _) - have hpr_s : ∀ p ∈ s, Prime p := fun p hp => is_prime _ (Finset.mem_insert_of_mem hp) - have hcp_p := fun i => prime_pow_coprime_prod_of_coprime_insert i p hps is_prime is_coprime - have hcp_s : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q := fun p hp q hq => - is_coprime p (Finset.mem_insert_of_mem hp) q (Finset.mem_insert_of_mem hq) - rw [Finset.prod_insert hps, Finset.prod_insert hps, Finset.prod_insert hps, hcp (hcp_p _), - hpr _ hpr_p, hcp (hcp_p _), hpr _ hpr_p, hcp (hcp_p (fun p => i p + j p)), hpr _ hpr_p, - ih hpr_s hcp_s, pow_add, mul_assoc, mul_left_comm (f p ^ j p), mul_assoc] - -/-- If `f` maps `p ^ i` to `(f p) ^ i` for primes `p`, and `f` -is multiplicative on coprime elements, then `f` is multiplicative everywhere. -/ -theorem multiplicative_of_coprime (f : α → β) (a b : α) (h0 : f 0 = 0) - (h1 : ∀ {x y}, IsUnit y → f (x * y) = f x * f y) - (hpr : ∀ {p} (i : ℕ), Prime p → f (p ^ i) = f p ^ i) - (hcp : ∀ {x y}, IsRelPrime x y → f (x * y) = f x * f y) : - f (a * b) = f a * f b := by - letI := Classical.decEq α - by_cases ha0 : a = 0 - · rw [ha0, zero_mul, h0, zero_mul] - by_cases hb0 : b = 0 - · rw [hb0, mul_zero, h0, mul_zero] - by_cases hf1 : f 1 = 0 - · calc - f (a * b) = f (a * b * 1) := by rw [mul_one] - _ = 0 := by simp only [h1 isUnit_one, hf1, mul_zero] - _ = f a * f (b * 1) := by simp only [h1 isUnit_one, hf1, mul_zero] - _ = f a * f b := by rw [mul_one] - haveI : Nontrivial α := ⟨⟨_, _, ha0⟩⟩ - letI : NormalizationMonoid α := UniqueFactorizationMonoid.normalizationMonoid - suffices - f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, - p ^ ((normalizedFactors a).count p + (normalizedFactors b).count p)) = - f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, - p ^ (normalizedFactors a).count p) * - f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, - p ^ (normalizedFactors b).count p) by - obtain ⟨ua, a_eq⟩ := normalizedFactors_prod ha0 - obtain ⟨ub, b_eq⟩ := normalizedFactors_prod hb0 - rw [← a_eq, ← b_eq, mul_right_comm (Multiset.prod (normalizedFactors a)) ua - (Multiset.prod (normalizedFactors b) * ub), h1 ua.isUnit, h1 ub.isUnit, h1 ua.isUnit, ← - mul_assoc, h1 ub.isUnit, mul_right_comm _ (f ua), ← mul_assoc] - congr - rw [← (normalizedFactors a).map_id, ← (normalizedFactors b).map_id, - Finset.prod_multiset_map_count, Finset.prod_multiset_map_count, - Finset.prod_subset (Finset.subset_union_left (s₂ := (normalizedFactors b).toFinset)), - Finset.prod_subset (Finset.subset_union_right (s₂ := (normalizedFactors b).toFinset)), ← - Finset.prod_mul_distrib] - · simp_rw [id, ← pow_add, this] - all_goals simp only [Multiset.mem_toFinset] - · intro p _ hpb - simp [hpb] - · intro p _ hpa - simp [hpa] - refine multiplicative_prime_power _ _ _ ?_ ?_ @h1 @hpr @hcp - all_goals simp only [Multiset.mem_toFinset, Finset.mem_union] - · rintro p (hpa | hpb) <;> apply prime_of_normalized_factor <;> assumption - · rintro p (hp | hp) q (hq | hq) hdvd <;> - rw [← normalize_normalized_factor _ hp, ← normalize_normalized_factor _ hq] <;> - exact - normalize_eq_normalize hdvd - ((prime_of_normalized_factor _ hp).irreducible.dvd_symm - (prime_of_normalized_factor _ hq).irreducible hdvd) - -end Multiplicative - -end UniqueFactorizationMonoid - -namespace Associates - -open UniqueFactorizationMonoid Associated Multiset - -variable [CancelCommMonoidWithZero α] - -/-- `FactorSet α` representation elements of unique factorization domain as multisets. -`Multiset α` produced by `normalizedFactors` are only unique up to associated elements, while the -multisets in `FactorSet α` are unique by equality and restricted to irreducible elements. This -gives us a representation of each element as a unique multisets (or the added ⊤ for 0), which has a -complete lattice structure. Infimum is the greatest common divisor and supremum is the least common -multiple. --/ -abbrev FactorSet.{u} (α : Type u) [CancelCommMonoidWithZero α] : Type u := - WithTop (Multiset { a : Associates α // Irreducible a }) - -attribute [local instance] Associated.setoid - -theorem FactorSet.coe_add {a b : Multiset { a : Associates α // Irreducible a }} : - (↑(a + b) : FactorSet α) = a + b := by norm_cast - -theorem FactorSet.sup_add_inf_eq_add [DecidableEq (Associates α)] : - ∀ a b : FactorSet α, a ⊔ b + a ⊓ b = a + b - | ⊤, b => show ⊤ ⊔ b + ⊤ ⊓ b = ⊤ + b by simp - | a, ⊤ => show a ⊔ ⊤ + a ⊓ ⊤ = a + ⊤ by simp - | WithTop.some a, WithTop.some b => - show (a : FactorSet α) ⊔ b + (a : FactorSet α) ⊓ b = a + b by - rw [← WithTop.coe_sup, ← WithTop.coe_inf, ← WithTop.coe_add, ← WithTop.coe_add, - WithTop.coe_eq_coe] - exact Multiset.union_add_inter _ _ - -/-- Evaluates the product of a `FactorSet` to be the product of the corresponding multiset, - or `0` if there is none. -/ -def FactorSet.prod : FactorSet α → Associates α - | ⊤ => 0 - | WithTop.some s => (s.map (↑)).prod - -@[simp] -theorem prod_top : (⊤ : FactorSet α).prod = 0 := - rfl - -@[simp] -theorem prod_coe {s : Multiset { a : Associates α // Irreducible a }} : - FactorSet.prod (s : FactorSet α) = (s.map (↑)).prod := - rfl - -@[simp] -theorem prod_add : ∀ a b : FactorSet α, (a + b).prod = a.prod * b.prod - | ⊤, b => show (⊤ + b).prod = (⊤ : FactorSet α).prod * b.prod by simp - | a, ⊤ => show (a + ⊤).prod = a.prod * (⊤ : FactorSet α).prod by simp - | WithTop.some a, WithTop.some b => by - rw [← FactorSet.coe_add, prod_coe, prod_coe, prod_coe, Multiset.map_add, Multiset.prod_add] - -@[gcongr] -theorem prod_mono : ∀ {a b : FactorSet α}, a ≤ b → a.prod ≤ b.prod - | ⊤, b, h => by - have : b = ⊤ := top_unique h - rw [this, prod_top] - | a, ⊤, _ => show a.prod ≤ (⊤ : FactorSet α).prod by simp - | WithTop.some _, WithTop.some _, h => - prod_le_prod <| Multiset.map_le_map <| WithTop.coe_le_coe.1 <| h - -theorem FactorSet.prod_eq_zero_iff [Nontrivial α] (p : FactorSet α) : p.prod = 0 ↔ p = ⊤ := by - unfold FactorSet at p - induction p -- TODO: `induction_eliminator` doesn't work with `abbrev` - · simp only [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, not_exists] - exact fun a => not_and_of_not_right _ a.prop.ne_zero - -section count - -variable [DecidableEq (Associates α)] - -/-- `bcount p s` is the multiplicity of `p` in the FactorSet `s` (with bundled `p`)-/ -def bcount (p : { a : Associates α // Irreducible a }) : - FactorSet α → ℕ - | ⊤ => 0 - | WithTop.some s => s.count p - -variable [∀ p : Associates α, Decidable (Irreducible p)] {p : Associates α} - -/-- `count p s` is the multiplicity of the irreducible `p` in the FactorSet `s`. - -If `p` is not irreducible, `count p s` is defined to be `0`. -/ -def count (p : Associates α) : FactorSet α → ℕ := - if hp : Irreducible p then bcount ⟨p, hp⟩ else 0 - -@[simp] -theorem count_some (hp : Irreducible p) (s : Multiset _) : - count p (WithTop.some s) = s.count ⟨p, hp⟩ := by - simp only [count, dif_pos hp, bcount] - -@[simp] -theorem count_zero (hp : Irreducible p) : count p (0 : FactorSet α) = 0 := by - simp only [count, dif_pos hp, bcount, Multiset.count_zero] - -theorem count_reducible (hp : ¬Irreducible p) : count p = 0 := dif_neg hp - -end count - -section Mem - -/-- membership in a FactorSet (bundled version) -/ -def BfactorSetMem : { a : Associates α // Irreducible a } → FactorSet α → Prop - | _, ⊤ => True - | p, some l => p ∈ l - -/-- `FactorSetMem p s` is the predicate that the irreducible `p` is a member of -`s : FactorSet α`. - -If `p` is not irreducible, `p` is not a member of any `FactorSet`. -/ -def FactorSetMem (s : FactorSet α) (p : Associates α) : Prop := - letI : Decidable (Irreducible p) := Classical.dec _ - if hp : Irreducible p then BfactorSetMem ⟨p, hp⟩ s else False - -instance : Membership (Associates α) (FactorSet α) := - ⟨FactorSetMem⟩ - -@[simp] -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 - dsimp only [Membership.mem]; dsimp only [FactorSetMem]; split_ifs; exact trivial - -theorem mem_factorSet_some {p : Associates α} {hp : Irreducible p} - {l : Multiset { a : Associates α // Irreducible a }} : - p ∈ (l : FactorSet α) ↔ Subtype.mk p hp ∈ l := by - dsimp only [Membership.mem]; dsimp only [FactorSetMem]; split_ifs; rfl - -theorem reducible_not_mem_factorSet {p : Associates α} (hp : ¬Irreducible p) (s : FactorSet α) : - ¬p ∈ s := fun h ↦ by - rwa [← factorSetMem_eq_mem, FactorSetMem, dif_neg hp] at h - -theorem irreducible_of_mem_factorSet {p : Associates α} {s : FactorSet α} (h : p ∈ s) : - Irreducible p := - by_contra fun hp ↦ reducible_not_mem_factorSet hp s h - -end Mem - -variable [UniqueFactorizationMonoid α] - -theorem unique' {p q : Multiset (Associates α)} : - (∀ a ∈ p, Irreducible a) → (∀ a ∈ q, Irreducible a) → p.prod = q.prod → p = q := by - apply Multiset.induction_on_multiset_quot p - apply Multiset.induction_on_multiset_quot q - intro s t hs ht eq - refine Multiset.map_mk_eq_map_mk_of_rel (UniqueFactorizationMonoid.factors_unique ?_ ?_ ?_) - · exact fun a ha => irreducible_mk.1 <| hs _ <| Multiset.mem_map_of_mem _ ha - · exact fun a ha => irreducible_mk.1 <| ht _ <| Multiset.mem_map_of_mem _ ha - have eq' : (Quot.mk Setoid.r : α → Associates α) = Associates.mk := funext quot_mk_eq_mk - rwa [eq', prod_mk, prod_mk, mk_eq_mk_iff_associated] at eq - -theorem FactorSet.unique [Nontrivial α] {p q : FactorSet α} (h : p.prod = q.prod) : p = q := by - -- TODO: `induction_eliminator` doesn't work with `abbrev` - unfold FactorSet at p q - induction p <;> induction q - · rfl - · rw [eq_comm, ← FactorSet.prod_eq_zero_iff, ← h, Associates.prod_top] - · rw [← FactorSet.prod_eq_zero_iff, h, Associates.prod_top] - · congr 1 - rw [← Multiset.map_eq_map Subtype.coe_injective] - apply unique' _ _ h <;> - · intro a ha - obtain ⟨⟨a', irred⟩, -, rfl⟩ := Multiset.mem_map.mp ha - rwa [Subtype.coe_mk] - -theorem prod_le_prod_iff_le [Nontrivial α] {p q : Multiset (Associates α)} - (hp : ∀ a ∈ p, Irreducible a) (hq : ∀ a ∈ q, Irreducible a) : p.prod ≤ q.prod ↔ p ≤ q := by - refine ⟨?_, prod_le_prod⟩ - rintro ⟨c, eqc⟩ - refine Multiset.le_iff_exists_add.2 ⟨factors c, unique' hq (fun x hx ↦ ?_) ?_⟩ - · obtain h | h := Multiset.mem_add.1 hx - · exact hp x h - · exact irreducible_of_factor _ h - · rw [eqc, Multiset.prod_add] - congr - refine associated_iff_eq.mp (factors_prod fun hc => ?_).symm - refine not_irreducible_zero (hq _ ?_) - rw [← prod_eq_zero_iff, eqc, hc, mul_zero] - -/-- This returns the multiset of irreducible factors as a `FactorSet`, - a multiset of irreducible associates `WithTop`. -/ -noncomputable def factors' (a : α) : Multiset { a : Associates α // Irreducible a } := - (factors a).pmap (fun a ha => ⟨Associates.mk a, irreducible_mk.2 ha⟩) irreducible_of_factor - -@[simp] -theorem map_subtype_coe_factors' {a : α} : - (factors' a).map (↑) = (factors a).map Associates.mk := by - simp [factors', Multiset.map_pmap, Multiset.pmap_eq_map] - -theorem factors'_cong {a b : α} (h : a ~ᵤ b) : factors' a = factors' b := by - obtain rfl | hb := eq_or_ne b 0 - · rw [associated_zero_iff_eq_zero] at h - rw [h] - have ha : a ≠ 0 := by - contrapose! hb with ha - rw [← associated_zero_iff_eq_zero, ← ha] - exact h.symm - rw [← Multiset.map_eq_map Subtype.coe_injective, map_subtype_coe_factors', - map_subtype_coe_factors', ← rel_associated_iff_map_eq_map] - exact - factors_unique irreducible_of_factor irreducible_of_factor - ((factors_prod ha).trans <| h.trans <| (factors_prod hb).symm) - -/-- This returns the multiset of irreducible factors of an associate as a `FactorSet`, - a multiset of irreducible associates `WithTop`. -/ -noncomputable def factors (a : Associates α) : FactorSet α := by - classical refine if h : a = 0 then ⊤ else Quotient.hrecOn a (fun x _ => factors' x) ?_ h - intro a b hab - apply Function.hfunext - · have : a ~ᵤ 0 ↔ b ~ᵤ 0 := Iff.intro (fun ha0 => hab.symm.trans ha0) fun hb0 => hab.trans hb0 - simp only [associated_zero_iff_eq_zero] at this - simp only [quotient_mk_eq_mk, this, mk_eq_zero] - exact fun ha hb _ => heq_of_eq <| congr_arg some <| factors'_cong hab - -@[simp] -theorem factors_zero : (0 : Associates α).factors = ⊤ := - dif_pos rfl - -@[deprecated (since := "2024-03-16")] alias factors_0 := factors_zero - -@[simp] -theorem factors_mk (a : α) (h : a ≠ 0) : (Associates.mk a).factors = factors' a := by - classical - apply dif_neg - apply mt mk_eq_zero.1 h - -@[simp] -theorem factors_prod (a : Associates α) : a.factors.prod = a := by - rcases Associates.mk_surjective a with ⟨a, rfl⟩ - rcases eq_or_ne a 0 with rfl | ha - · simp - · simp [ha, prod_mk, mk_eq_mk_iff_associated, UniqueFactorizationMonoid.factors_prod, - -Quotient.eq] - -@[simp] -theorem prod_factors [Nontrivial α] (s : FactorSet α) : s.prod.factors = s := - FactorSet.unique <| factors_prod _ - -@[nontriviality] -theorem factors_subsingleton [Subsingleton α] {a : Associates α} : a.factors = ⊤ := by - have : Subsingleton (Associates α) := inferInstance - convert factors_zero - -theorem factors_eq_top_iff_zero {a : Associates α} : a.factors = ⊤ ↔ a = 0 := by - nontriviality α - exact ⟨fun h ↦ by rwa [← factors_prod a, FactorSet.prod_eq_zero_iff], fun h ↦ h ▸ factors_zero⟩ - -@[deprecated (since := "2024-04-16")] alias factors_eq_none_iff_zero := factors_eq_top_iff_zero - -theorem factors_eq_some_iff_ne_zero {a : Associates α} : - (∃ s : Multiset { p : Associates α // Irreducible p }, a.factors = s) ↔ a ≠ 0 := by - simp_rw [@eq_comm _ a.factors, ← WithTop.ne_top_iff_exists] - exact factors_eq_top_iff_zero.not - -theorem eq_of_factors_eq_factors {a b : Associates α} (h : a.factors = b.factors) : a = b := by - have : a.factors.prod = b.factors.prod := by rw [h] - rwa [factors_prod, factors_prod] at this - -theorem eq_of_prod_eq_prod [Nontrivial α] {a b : FactorSet α} (h : a.prod = b.prod) : a = b := by - have : a.prod.factors = b.prod.factors := by rw [h] - rwa [prod_factors, prod_factors] at this - -@[simp] -theorem factors_mul (a b : Associates α) : (a * b).factors = a.factors + b.factors := by - nontriviality α - refine eq_of_prod_eq_prod <| eq_of_factors_eq_factors ?_ - rw [prod_add, factors_prod, factors_prod, factors_prod] - -@[gcongr] -theorem factors_mono : ∀ {a b : Associates α}, a ≤ b → a.factors ≤ b.factors - | s, t, ⟨d, eq⟩ => by rw [eq, factors_mul]; exact le_add_of_nonneg_right bot_le - -@[simp] -theorem factors_le {a b : Associates α} : a.factors ≤ b.factors ↔ a ≤ b := by - refine ⟨fun h ↦ ?_, factors_mono⟩ - have : a.factors.prod ≤ b.factors.prod := prod_mono h - rwa [factors_prod, factors_prod] at this - -section count - -variable [DecidableEq (Associates α)] [∀ p : Associates α, Decidable (Irreducible p)] - -theorem eq_factors_of_eq_counts {a b : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) - (h : ∀ p : Associates α, Irreducible p → p.count a.factors = p.count b.factors) : - a.factors = b.factors := by - obtain ⟨sa, h_sa⟩ := factors_eq_some_iff_ne_zero.mpr ha - obtain ⟨sb, h_sb⟩ := factors_eq_some_iff_ne_zero.mpr hb - rw [h_sa, h_sb] at h ⊢ - rw [WithTop.coe_eq_coe] - have h_count : ∀ (p : Associates α) (hp : Irreducible p), - sa.count ⟨p, hp⟩ = sb.count ⟨p, hp⟩ := by - intro p hp - rw [← count_some, ← count_some, h p hp] - apply Multiset.toFinsupp.injective - ext ⟨p, hp⟩ - rw [Multiset.toFinsupp_apply, Multiset.toFinsupp_apply, h_count p hp] - -theorem eq_of_eq_counts {a b : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) - (h : ∀ p : Associates α, Irreducible p → p.count a.factors = p.count b.factors) : a = b := - eq_of_factors_eq_factors (eq_factors_of_eq_counts ha hb h) - -theorem count_le_count_of_factors_le {a b p : Associates α} (hb : b ≠ 0) (hp : Irreducible p) - (h : a.factors ≤ b.factors) : p.count a.factors ≤ p.count b.factors := by - by_cases ha : a = 0 - · simp_all - obtain ⟨sa, h_sa⟩ := factors_eq_some_iff_ne_zero.mpr ha - obtain ⟨sb, h_sb⟩ := factors_eq_some_iff_ne_zero.mpr hb - rw [h_sa, h_sb] at h ⊢ - rw [count_some hp, count_some hp]; rw [WithTop.coe_le_coe] at h - exact Multiset.count_le_of_le _ h - -theorem count_le_count_of_le {a b p : Associates α} (hb : b ≠ 0) (hp : Irreducible p) (h : a ≤ b) : - p.count a.factors ≤ p.count b.factors := - count_le_count_of_factors_le hb hp <| factors_mono h - -end count - -theorem prod_le [Nontrivial α] {a b : FactorSet α} : a.prod ≤ b.prod ↔ a ≤ b := by - refine ⟨fun h ↦ ?_, prod_mono⟩ - have : a.prod.factors ≤ b.prod.factors := factors_mono h - rwa [prod_factors, prod_factors] at this - -open Classical in -noncomputable instance : Max (Associates α) := - ⟨fun a b => (a.factors ⊔ b.factors).prod⟩ - -open Classical in -noncomputable instance : Min (Associates α) := - ⟨fun a b => (a.factors ⊓ b.factors).prod⟩ - -open Classical in -noncomputable instance : Lattice (Associates α) := - { Associates.instPartialOrder with - sup := (· ⊔ ·) - inf := (· ⊓ ·) - sup_le := fun _ _ c hac hbc => - factors_prod c ▸ prod_mono (sup_le (factors_mono hac) (factors_mono hbc)) - le_sup_left := fun a _ => le_trans (le_of_eq (factors_prod a).symm) <| prod_mono <| le_sup_left - le_sup_right := fun _ b => - le_trans (le_of_eq (factors_prod b).symm) <| prod_mono <| le_sup_right - le_inf := fun a _ _ hac hbc => - factors_prod a ▸ prod_mono (le_inf (factors_mono hac) (factors_mono hbc)) - inf_le_left := fun a _ => le_trans (prod_mono inf_le_left) (le_of_eq (factors_prod a)) - inf_le_right := fun _ b => le_trans (prod_mono inf_le_right) (le_of_eq (factors_prod b)) } - -open Classical in -theorem sup_mul_inf (a b : Associates α) : (a ⊔ b) * (a ⊓ b) = a * b := - show (a.factors ⊔ b.factors).prod * (a.factors ⊓ b.factors).prod = a * b by - nontriviality α - refine eq_of_factors_eq_factors ?_ - rw [← prod_add, prod_factors, factors_mul, FactorSet.sup_add_inf_eq_add] - -theorem dvd_of_mem_factors {a p : Associates α} (hm : p ∈ factors a) : - p ∣ a := by - rcases eq_or_ne a 0 with rfl | ha0 - · exact dvd_zero p - obtain ⟨a0, nza, ha'⟩ := exists_non_zero_rep ha0 - rw [← Associates.factors_prod a] - rw [← ha', factors_mk a0 nza] at hm ⊢ - rw [prod_coe] - apply Multiset.dvd_prod; apply Multiset.mem_map.mpr - exact ⟨⟨p, irreducible_of_mem_factorSet hm⟩, mem_factorSet_some.mp hm, rfl⟩ - -theorem dvd_of_mem_factors' {a : α} {p : Associates α} {hp : Irreducible p} {hz : a ≠ 0} - (h_mem : Subtype.mk p hp ∈ factors' a) : p ∣ Associates.mk a := by - haveI := Classical.decEq (Associates α) - apply dvd_of_mem_factors - rw [factors_mk _ hz] - apply mem_factorSet_some.2 h_mem - -theorem mem_factors'_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) (hd : p ∣ a) : - Subtype.mk (Associates.mk p) (irreducible_mk.2 hp) ∈ factors' a := by - obtain ⟨q, hq, hpq⟩ := exists_mem_factors_of_dvd ha0 hp hd - apply Multiset.mem_pmap.mpr; use q; use hq - exact Subtype.eq (Eq.symm (mk_eq_mk_iff_associated.mpr hpq)) - -theorem mem_factors'_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : - Subtype.mk (Associates.mk p) (irreducible_mk.2 hp) ∈ factors' a ↔ p ∣ a := by - constructor - · rw [← mk_dvd_mk] - apply dvd_of_mem_factors' - apply ha0 - · apply mem_factors'_of_dvd ha0 hp - -theorem mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) (hd : p ∣ a) : - Associates.mk p ∈ factors (Associates.mk a) := by - rw [factors_mk _ ha0] - exact mem_factorSet_some.mpr (mem_factors'_of_dvd ha0 hp hd) - -theorem mem_factors_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : - Associates.mk p ∈ factors (Associates.mk a) ↔ p ∣ a := by - constructor - · rw [← mk_dvd_mk] - apply dvd_of_mem_factors - · apply mem_factors_of_dvd ha0 hp - -open Classical in -theorem exists_prime_dvd_of_not_inf_one {a b : α} (ha : a ≠ 0) (hb : b ≠ 0) - (h : Associates.mk a ⊓ Associates.mk b ≠ 1) : ∃ p : α, Prime p ∧ p ∣ a ∧ p ∣ b := by - have hz : factors (Associates.mk a) ⊓ factors (Associates.mk b) ≠ 0 := by - contrapose! h with hf - change (factors (Associates.mk a) ⊓ factors (Associates.mk b)).prod = 1 - rw [hf] - exact Multiset.prod_zero - rw [factors_mk a ha, factors_mk b hb, ← WithTop.coe_inf] at hz - obtain ⟨⟨p0, p0_irr⟩, p0_mem⟩ := Multiset.exists_mem_of_ne_zero ((mt WithTop.coe_eq_coe.mpr) hz) - rw [Multiset.inf_eq_inter] at p0_mem - obtain ⟨p, rfl⟩ : ∃ p, Associates.mk p = p0 := Quot.exists_rep p0 - refine ⟨p, ?_, ?_, ?_⟩ - · rw [← UniqueFactorizationMonoid.irreducible_iff_prime, ← irreducible_mk] - exact p0_irr - · apply dvd_of_mk_le_mk - apply dvd_of_mem_factors' (Multiset.mem_inter.mp p0_mem).left - apply ha - · apply dvd_of_mk_le_mk - apply dvd_of_mem_factors' (Multiset.mem_inter.mp p0_mem).right - apply hb - -theorem coprime_iff_inf_one {a b : α} (ha0 : a ≠ 0) (hb0 : b ≠ 0) : - Associates.mk a ⊓ Associates.mk b = 1 ↔ ∀ {d : α}, d ∣ a → d ∣ b → ¬Prime d := by - constructor - · intro hg p ha hb hp - refine (Associates.prime_mk.mpr hp).not_unit (isUnit_of_dvd_one ?_) - rw [← hg] - exact le_inf (mk_le_mk_of_dvd ha) (mk_le_mk_of_dvd hb) - · contrapose - intro hg hc - obtain ⟨p, hp, hpa, hpb⟩ := exists_prime_dvd_of_not_inf_one ha0 hb0 hg - exact hc hpa hpb hp - -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.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.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.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 - apply eq_of_prod_eq_prod - rw [Associates.factors_prod] - exact Multiset.prod_zero - -@[simp] -theorem pow_factors [Nontrivial α] {a : Associates α} {k : ℕ} : - (a ^ k).factors = k • a.factors := by - induction' k with n h - · rw [zero_nsmul, pow_zero] - exact factors_one - · rw [pow_succ, succ_nsmul, factors_mul, h] - -section count - -variable [DecidableEq (Associates α)] [∀ p : Associates α, Decidable (Irreducible p)] - -theorem prime_pow_dvd_iff_le {m p : Associates α} (h₁ : m ≠ 0) (h₂ : Irreducible p) {k : ℕ} : - p ^ k ≤ m ↔ k ≤ count p m.factors := by - rw [count, dif_pos h₂, prime_pow_le_iff_le_bcount h₁] - -theorem le_of_count_ne_zero {m p : Associates α} (h0 : m ≠ 0) (hp : Irreducible p) : - count p m.factors ≠ 0 → p ≤ m := by - nontriviality α - rw [← pos_iff_ne_zero] - intro h - rw [← pow_one p] - apply (prime_pow_dvd_iff_le h0 hp).2 - simpa only - -theorem count_ne_zero_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : - (Associates.mk p).count (Associates.mk a).factors ≠ 0 ↔ p ∣ a := by - nontriviality α - rw [← Associates.mk_le_mk_iff_dvd] - refine - ⟨fun h => - Associates.le_of_count_ne_zero (Associates.mk_ne_zero.mpr ha0) - (Associates.irreducible_mk.mpr hp) h, - fun h => ?_⟩ - rw [← pow_one (Associates.mk p), - Associates.prime_pow_dvd_iff_le (Associates.mk_ne_zero.mpr ha0) - (Associates.irreducible_mk.mpr hp)] at h - exact (zero_lt_one.trans_le h).ne' - -theorem count_self [Nontrivial α] {p : Associates α} - (hp : Irreducible p) : p.count p.factors = 1 := by - simp [factors_self hp, Associates.count_some hp] - -theorem count_eq_zero_of_ne {p q : Associates α} (hp : Irreducible p) - (hq : Irreducible q) (h : p ≠ q) : p.count q.factors = 0 := - not_ne_iff.mp fun h' ↦ h <| associated_iff_eq.mp <| hp.associated_of_dvd hq <| - le_of_count_ne_zero hq.ne_zero hp h' - -theorem count_mul {a : Associates α} (ha : a ≠ 0) {b : Associates α} - (hb : b ≠ 0) {p : Associates α} (hp : Irreducible p) : - count p (factors (a * b)) = count p a.factors + count p b.factors := by - obtain ⟨a0, nza, rfl⟩ := exists_non_zero_rep ha - obtain ⟨b0, nzb, rfl⟩ := exists_non_zero_rep hb - rw [factors_mul, factors_mk a0 nza, factors_mk b0 nzb, ← FactorSet.coe_add, count_some hp, - Multiset.count_add, count_some hp, count_some hp] - -theorem count_of_coprime {a : Associates α} (ha : a ≠ 0) - {b : Associates α} (hb : b ≠ 0) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {p : Associates α} - (hp : Irreducible p) : count p a.factors = 0 ∨ count p b.factors = 0 := by - rw [or_iff_not_imp_left, ← Ne] - intro hca - contrapose! hab with hcb - exact ⟨p, le_of_count_ne_zero ha hp hca, le_of_count_ne_zero hb hp hcb, - UniqueFactorizationMonoid.irreducible_iff_prime.mp hp⟩ - -theorem count_mul_of_coprime {a : Associates α} {b : Associates α} - (hb : b ≠ 0) {p : Associates α} (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) : - count p a.factors = 0 ∨ count p a.factors = count p (a * b).factors := by - by_cases ha : a = 0 - · simp [ha] - cases' count_of_coprime ha hb hab hp with hz hb0; · tauto - apply Or.intro_right - rw [count_mul ha hb hp, hb0, add_zero] - -theorem count_mul_of_coprime' {a b : Associates α} {p : Associates α} - (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) : - count p (a * b).factors = count p a.factors ∨ count p (a * b).factors = count p b.factors := by - by_cases ha : a = 0 - · simp [ha] - by_cases hb : b = 0 - · simp [hb] - rw [count_mul ha hb hp] - cases' count_of_coprime ha hb hab hp with ha0 hb0 - · apply Or.intro_right - rw [ha0, zero_add] - · apply Or.intro_left - rw [hb0, add_zero] - -theorem dvd_count_of_dvd_count_mul {a b : Associates α} (hb : b ≠ 0) - {p : Associates α} (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {k : ℕ} - (habk : k ∣ count p (a * b).factors) : k ∣ count p a.factors := by - by_cases ha : a = 0 - · simpa [*] using habk - cases' count_of_coprime ha hb hab hp with hz h - · rw [hz] - exact dvd_zero k - · rw [count_mul ha hb hp, h] at habk - exact habk - -theorem count_pow [Nontrivial α] {a : Associates α} (ha : a ≠ 0) - {p : Associates α} (hp : Irreducible p) (k : ℕ) : - count p (a ^ k).factors = k * count p a.factors := by - induction' k with n h - · rw [pow_zero, factors_one, zero_mul, count_zero hp] - · rw [pow_succ', count_mul ha (pow_ne_zero _ ha) hp, h] - ring - -theorem dvd_count_pow [Nontrivial α] {a : Associates α} (ha : a ≠ 0) - {p : Associates α} (hp : Irreducible p) (k : ℕ) : k ∣ count p (a ^ k).factors := by - rw [count_pow ha hp] - apply dvd_mul_right - -theorem is_pow_of_dvd_count {a : Associates α} - (ha : a ≠ 0) {k : ℕ} (hk : ∀ p : Associates α, Irreducible p → k ∣ count p a.factors) : - ∃ b : Associates α, a = b ^ k := by - nontriviality α - obtain ⟨a0, hz, rfl⟩ := exists_non_zero_rep ha - rw [factors_mk a0 hz] at hk - have hk' : ∀ p, p ∈ factors' a0 → k ∣ (factors' a0).count p := by - rintro p - - have pp : p = ⟨p.val, p.2⟩ := by simp only [Subtype.coe_eta] - rw [pp, ← count_some p.2] - exact hk p.val p.2 - obtain ⟨u, hu⟩ := Multiset.exists_smul_of_dvd_count _ hk' - use FactorSet.prod (u : FactorSet α) - apply eq_of_factors_eq_factors - rw [pow_factors, prod_factors, factors_mk a0 hz, hu] - exact WithBot.coe_nsmul u k - -/-- The only divisors of prime powers are prime powers. See `eq_pow_find_of_dvd_irreducible_pow` -for an explicit expression as a p-power (without using `count`). -/ -theorem eq_pow_count_factors_of_dvd_pow {p a : Associates α} - (hp : Irreducible p) {n : ℕ} (h : a ∣ p ^ n) : a = p ^ p.count a.factors := by - nontriviality α - have hph := pow_ne_zero n hp.ne_zero - have ha := ne_zero_of_dvd_ne_zero hph h - apply eq_of_eq_counts ha (pow_ne_zero _ hp.ne_zero) - have eq_zero_of_ne : ∀ q : Associates α, Irreducible q → q ≠ p → _ = 0 := fun q hq h' => - Nat.eq_zero_of_le_zero <| by - convert count_le_count_of_le hph hq h - symm - rw [count_pow hp.ne_zero hq, count_eq_zero_of_ne hq hp h', mul_zero] - intro q hq - rw [count_pow hp.ne_zero hq] - by_cases h : q = p - · rw [h, count_self hp, mul_one] - · rw [count_eq_zero_of_ne hq hp h, mul_zero, eq_zero_of_ne q hq h] - -theorem count_factors_eq_find_of_dvd_pow {a p : Associates α} - (hp : Irreducible p) [∀ n : ℕ, Decidable (a ∣ p ^ n)] {n : ℕ} (h : a ∣ p ^ n) : - @Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩ = p.count a.factors := by - apply le_antisymm - · refine Nat.find_le ⟨1, ?_⟩ - rw [mul_one] - symm - exact eq_pow_count_factors_of_dvd_pow hp h - · have hph := pow_ne_zero (@Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩) hp.ne_zero - cases' subsingleton_or_nontrivial α with hα hα - · simp [eq_iff_true_of_subsingleton] at hph - convert count_le_count_of_le hph hp (@Nat.find_spec (fun n => a ∣ p ^ n) _ ⟨n, h⟩) - rw [count_pow hp.ne_zero hp, count_self hp, mul_one] - -end count - -theorem eq_pow_of_mul_eq_pow {a b c : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) - (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {k : ℕ} (h : a * b = c ^ k) : - ∃ d : Associates α, a = d ^ k := by - classical - nontriviality α - by_cases hk0 : k = 0 - · use 1 - rw [hk0, pow_zero] at h ⊢ - apply (mul_eq_one.1 h).1 - · refine is_pow_of_dvd_count ha fun p hp ↦ ?_ - apply dvd_count_of_dvd_count_mul hb hp hab - rw [h] - apply dvd_count_pow _ hp - rintro rfl - rw [zero_pow hk0] at h - cases mul_eq_zero.mp h <;> contradiction - -/-- The only divisors of prime powers are prime powers. -/ -theorem eq_pow_find_of_dvd_irreducible_pow {a p : Associates α} (hp : Irreducible p) - [∀ n : ℕ, Decidable (a ∣ p ^ n)] {n : ℕ} (h : a ∣ p ^ n) : - a = p ^ @Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩ := by - classical rw [count_factors_eq_find_of_dvd_pow hp, ← eq_pow_count_factors_of_dvd_pow hp h] - exact h - -end Associates - -section - -open Associates UniqueFactorizationMonoid - -/-- `toGCDMonoid` constructs a GCD monoid out of a unique factorization domain. -/ -noncomputable def UniqueFactorizationMonoid.toGCDMonoid (α : Type*) [CancelCommMonoidWithZero α] - [UniqueFactorizationMonoid α] : GCDMonoid α where - gcd a b := Quot.out (Associates.mk a ⊓ Associates.mk b : Associates α) - lcm a b := Quot.out (Associates.mk a ⊔ Associates.mk b : Associates α) - gcd_dvd_left a b := by - rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le] - exact inf_le_left - gcd_dvd_right a b := by - rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le] - exact inf_le_right - dvd_gcd {a b c} hac hab := by - rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le, le_inf_iff, - mk_le_mk_iff_dvd, mk_le_mk_iff_dvd] - exact ⟨hac, hab⟩ - lcm_zero_left a := by simp - lcm_zero_right a := by simp - gcd_mul_lcm a b := by - rw [← mk_eq_mk_iff_associated, ← Associates.mk_mul_mk, ← associated_iff_eq, Associates.quot_out, - Associates.quot_out, mul_comm, sup_mul_inf, Associates.mk_mul_mk] - -/-- `toNormalizedGCDMonoid` constructs a GCD monoid out of a normalization on a - unique factorization domain. -/ -noncomputable def UniqueFactorizationMonoid.toNormalizedGCDMonoid (α : Type*) - [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] [NormalizationMonoid α] : - NormalizedGCDMonoid α := - { ‹NormalizationMonoid α› with - gcd := fun a b => (Associates.mk a ⊓ Associates.mk b).out - lcm := fun a b => (Associates.mk a ⊔ Associates.mk b).out - gcd_dvd_left := fun a b => (out_dvd_iff a (Associates.mk a ⊓ Associates.mk b)).2 <| inf_le_left - gcd_dvd_right := fun a b => - (out_dvd_iff b (Associates.mk a ⊓ Associates.mk b)).2 <| inf_le_right - dvd_gcd := fun {a} {b} {c} hac hab => - show a ∣ (Associates.mk c ⊓ Associates.mk b).out by - rw [dvd_out_iff, le_inf_iff, mk_le_mk_iff_dvd, mk_le_mk_iff_dvd] - exact ⟨hac, hab⟩ - lcm_zero_left := fun a => show (⊤ ⊔ Associates.mk a).out = 0 by simp - lcm_zero_right := fun a => show (Associates.mk a ⊔ ⊤).out = 0 by simp - gcd_mul_lcm := fun a b => by - rw [← out_mul, mul_comm, sup_mul_inf, mk_mul_mk, out_mk] - exact normalize_associated (a * b) - normalize_gcd := fun a b => by apply normalize_out _ - normalize_lcm := fun a b => by apply normalize_out _ } - -instance (α) [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] : - Nonempty (NormalizedGCDMonoid α) := by - letI := UniqueFactorizationMonoid.normalizationMonoid (α := α) - classical exact ⟨UniqueFactorizationMonoid.toNormalizedGCDMonoid α⟩ - -end - -namespace UniqueFactorizationMonoid - -/-- If `y` is a nonzero element of a unique factorization monoid with finitely -many units (e.g. `ℤ`, `Ideal (ring_of_integers K)`), it has finitely many divisors. -/ -noncomputable def fintypeSubtypeDvd {M : Type*} [CancelCommMonoidWithZero M] - [UniqueFactorizationMonoid M] [Fintype Mˣ] (y : M) (hy : y ≠ 0) : Fintype { x // x ∣ y } := by - haveI : Nontrivial M := ⟨⟨y, 0, hy⟩⟩ - haveI : NormalizationMonoid M := UniqueFactorizationMonoid.normalizationMonoid - haveI := Classical.decEq M - haveI := Classical.decEq (Associates M) - -- 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, - Multiset.mem_toFinset, Multiset.mem_powerset, exists_eq_right, Multiset.mem_map] - constructor - · rintro ⟨s, hs, rfl⟩ - show (s.snd : M) * s.fst.prod ∣ y - rw [(unit_associated_one.mul_right s.fst.prod).dvd_iff_dvd_left, one_mul, - ← (normalizedFactors_prod hy).dvd_iff_dvd_right] - exact Multiset.prod_dvd_prod_of_le hs - · rintro (h : x ∣ y) - have hx : x ≠ 0 := by - refine mt (fun hx => ?_) hy - rwa [hx, zero_dvd_iff] at h - obtain ⟨u, hu⟩ := normalizedFactors_prod hx - refine ⟨⟨normalizedFactors x, u⟩, ?_, (mul_comm _ _).trans hu⟩ - exact (dvd_iff_normalizedFactors_le_normalizedFactors hx hy).mp h - -end UniqueFactorizationMonoid - -section Finsupp - -variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] -variable [NormalizationMonoid α] [DecidableEq α] - -open UniqueFactorizationMonoid - -/-- This returns the multiset of irreducible factors as a `Finsupp`. -/ -noncomputable def factorization (n : α) : α →₀ ℕ := - Multiset.toFinsupp (normalizedFactors n) - -theorem factorization_eq_count {n p : α} : - factorization n p = Multiset.count p (normalizedFactors n) := by simp [factorization] - -@[simp] -theorem factorization_zero : factorization (0 : α) = 0 := by simp [factorization] - -@[simp] -theorem factorization_one : factorization (1 : α) = 0 := by simp [factorization] - -/-- The support of `factorization n` is exactly the Finset of normalized factors -/ -@[simp] -theorem support_factorization {n : α} : - (factorization n).support = (normalizedFactors n).toFinset := by - simp [factorization, Multiset.toFinsupp_support] - -/-- For nonzero `a` and `b`, the power of `p` in `a * b` is the sum of the powers in `a` and `b` -/ -@[simp] -theorem factorization_mul {a b : α} (ha : a ≠ 0) (hb : b ≠ 0) : - factorization (a * b) = factorization a + factorization b := by - simp [factorization, normalizedFactors_mul ha hb] - -/-- For any `p`, the power of `p` in `x^n` is `n` times the power in `x` -/ -theorem factorization_pow {x : α} {n : ℕ} : factorization (x ^ n) = n • factorization x := by - ext - simp [factorization] - -theorem associated_of_factorization_eq (a b : α) (ha : a ≠ 0) (hb : b ≠ 0) - (h : factorization a = factorization b) : Associated a b := by - simp_rw [factorization, AddEquiv.apply_eq_iff_eq] at h - rwa [associated_iff_normalizedFactors_eq_normalizedFactors ha hb] - -end Finsupp - -open UniqueFactorizationMonoid in -/-- Every non-zero prime ideal in a unique factorization domain contains a prime element. -/ -theorem Ideal.IsPrime.exists_mem_prime_of_ne_bot {R : Type*} [CommSemiring R] [IsDomain R] - [UniqueFactorizationMonoid R] {I : Ideal R} (hI₂ : I.IsPrime) (hI : I ≠ ⊥) : - ∃ x ∈ I, Prime x := by - classical - obtain ⟨a : R, ha₁ : a ∈ I, ha₂ : a ≠ 0⟩ := Submodule.exists_mem_ne_zero_of_ne_bot hI - replace ha₁ : (factors a).prod ∈ I := by - obtain ⟨u : Rˣ, hu : (factors a).prod * u = a⟩ := factors_prod ha₂ - rwa [← hu, mul_unit_mem_iff_mem _ u.isUnit] at ha₁ - obtain ⟨p : R, hp₁ : p ∈ factors a, hp₂ : p ∈ I⟩ := - (hI₂.multiset_prod_mem_iff_exists_mem <| factors a).1 ha₁ - exact ⟨p, hp₂, prime_of_factor p hp₁⟩ - -namespace Nat - -instance instWfDvdMonoid : WfDvdMonoid ℕ where - wf := by - refine RelHomClass.wellFounded - (⟨fun x : ℕ => if x = 0 then (⊤ : ℕ∞) else x, ?_⟩ : DvdNotUnit →r (· < ·)) wellFounded_lt - intro a b h - cases' a with a - · exfalso - revert h - simp [DvdNotUnit] - cases b - · simpa [succ_ne_zero] using WithTop.coe_lt_top (a + 1) - cases' dvd_and_not_dvd_iff.2 h with h1 h2 - simp only [succ_ne_zero, cast_lt, if_false] - refine lt_of_le_of_ne (Nat.le_of_dvd (Nat.succ_pos _) h1) fun con => h2 ?_ - rw [con] - -instance instUniqueFactorizationMonoid : UniqueFactorizationMonoid ℕ where - irreducible_iff_prime := Nat.irreducible_iff_prime - -open UniqueFactorizationMonoid - -lemma factors_eq : ∀ n : ℕ, normalizedFactors n = n.primeFactorsList - | 0 => by simp - | n + 1 => by - rw [← Multiset.rel_eq, ← associated_eq_eq] - apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _ - · rw [Multiset.prod_coe, Nat.prod_primeFactorsList n.succ_ne_zero] - exact normalizedFactors_prod n.succ_ne_zero - · intro x hx - rw [Nat.irreducible_iff_prime, ← Nat.prime_iff] - exact Nat.prime_of_mem_primeFactorsList hx - -lemma factors_multiset_prod_of_irreducible {s : Multiset ℕ} (h : ∀ x : ℕ, x ∈ s → Irreducible x) : - normalizedFactors s.prod = s := by - rw [← Multiset.rel_eq, ← associated_eq_eq] - apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor h - (normalizedFactors_prod _) - rw [Ne, Multiset.prod_eq_zero_iff] - exact fun con ↦ not_irreducible_zero (h 0 con) - -end Nat - -section Ideal - -/-- The ascending chain condition on principal ideals holds in a `WfDvdMonoid` domain. -/ -lemma Ideal.setOf_isPrincipal_wellFoundedOn_gt [CommSemiring α] [WfDvdMonoid α] [IsDomain α] : - {I : Ideal α | I.IsPrincipal}.WellFoundedOn (· > ·) := by - have : {I : Ideal α | I.IsPrincipal} = ((fun a ↦ Ideal.span {a}) '' Set.univ) := by - ext - simp [Submodule.isPrincipal_iff, eq_comm] - rw [this, Set.wellFoundedOn_image, Set.wellFoundedOn_univ] - convert wellFounded_dvdNotUnit (α := α) - ext - exact Ideal.span_singleton_lt_span_singleton - -/-- The ascending chain condition on principal ideals in a domain is sufficient to prove that -the domain is `WfDvdMonoid`. -/ -lemma WfDvdMonoid.of_setOf_isPrincipal_wellFoundedOn_gt [CommSemiring α] [IsDomain α] - (h : {I : Ideal α | I.IsPrincipal}.WellFoundedOn (· > ·)) : - WfDvdMonoid α := by - have : WellFounded (α := {I : Ideal α // I.IsPrincipal}) (· > ·) := h - constructor - convert InvImage.wf (fun a => ⟨Ideal.span ({a} : Set α), _, rfl⟩) this - ext - exact Ideal.span_singleton_lt_span_singleton.symm - -end Ideal - -set_option linter.style.longFile 2100 diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Basic.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Basic.lean new file mode 100644 index 00000000000000..31b9b8426dbed3 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Basic.lean @@ -0,0 +1,473 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Algebra.BigOperators.Associated +import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Algebra.SMulWithZero +import Mathlib.Data.ENat.Basic +import Mathlib.Data.Multiset.OrderedMonoid +import Mathlib.RingTheory.UniqueFactorizationDomain.Defs + +/-! +# Basic results un unique factorization monoids + +## Main results +* `prime_factors_unique`: the prime factors of an element in a cancellative + commutative monoid with zero (e.g. an integral domain) are unique up to associates +* `UniqueFactorizationMonoid.factors_unique`: the irreducible factors of an element + in a unique factorization monoid (e.g. a UFD) are unique up to associates +* `UniqueFactorizationMonoid.iff_exists_prime_factors`: unique factorization exists iff each nonzero + elements factors into a product of primes +* `UniqueFactorizationMonoid.dvd_of_dvd_mul_left_of_no_prime_factors`: Euclid's lemma: + if `a ∣ b * c` and `a` and `c` have no common prime factors, `a ∣ b`. +* `UniqueFactorizationMonoid.dvd_of_dvd_mul_right_of_no_prime_factors`: Euclid's lemma: + if `a ∣ b * c` and `a` and `b` have no common prime factors, `a ∣ c`. +* `UniqueFactorizationMonoid.exists_reduced_factors`: in a UFM, we can divide out a common factor + to get relatively prime elements. +-/ + + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +namespace WfDvdMonoid + +variable [CommMonoidWithZero α] + +open Associates Nat + +theorem of_wfDvdMonoid_associates (_ : WfDvdMonoid (Associates α)) : WfDvdMonoid α := + ⟨(mk_surjective.wellFounded_iff mk_dvdNotUnit_mk_iff.symm).2 wellFounded_dvdNotUnit⟩ + +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 + +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 + ⟨by + convert h + ext + exact Associates.dvdNotUnit_iff_lt⟩ + +theorem WfDvdMonoid.iff_wellFounded_associates [CancelCommMonoidWithZero α] : + WfDvdMonoid α ↔ WellFoundedLT (Associates α) := + ⟨by apply WfDvdMonoid.wellFoundedLT_associates, WfDvdMonoid.of_wellFoundedLT_associates⟩ + +instance Associates.ufm [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] : + UniqueFactorizationMonoid (Associates α) := + { (WfDvdMonoid.wfDvdMonoid_associates : WfDvdMonoid (Associates α)) with + irreducible_iff_prime := by + rw [← Associates.irreducible_iff_prime_iff] + apply UniqueFactorizationMonoid.irreducible_iff_prime } + +theorem prime_factors_unique [CancelCommMonoidWithZero α] : + ∀ {f g : Multiset α}, + (∀ x ∈ f, Prime x) → (∀ x ∈ g, Prime x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g := by + classical + intro f + induction' f using Multiset.induction_on with p f ih + · intros g _ hg h + exact Multiset.rel_zero_left.2 <| + Multiset.eq_zero_of_forall_not_mem fun x hx => + have : IsUnit g.prod := by simpa [associated_one_iff_isUnit] using h.symm + (hg x hx).not_unit <| + isUnit_iff_dvd_one.2 <| (Multiset.dvd_prod hx).trans (isUnit_iff_dvd_one.1 this) + · intros g hf hg hfg + let ⟨b, hbg, hb⟩ := + (exists_associated_mem_of_dvd_prod (hf p (by simp)) fun q hq => hg _ hq) <| + hfg.dvd_iff_dvd_right.1 (show p ∣ (p ::ₘ f).prod by simp) + haveI := Classical.decEq α + rw [← Multiset.cons_erase hbg] + exact + Multiset.Rel.cons hb + (ih (fun q hq => hf _ (by simp [hq])) + (fun {q} (hq : q ∈ g.erase b) => hg q (Multiset.mem_of_mem_erase hq)) + (Associated.of_mul_left + (by rwa [← Multiset.prod_cons, ← Multiset.prod_cons, Multiset.cons_erase hbg]) hb + (hf p (by simp)).ne_zero)) + +namespace UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] + +theorem factors_unique {f g : Multiset α} (hf : ∀ x ∈ f, Irreducible x) + (hg : ∀ x ∈ g, Irreducible x) (h : f.prod ~ᵤ g.prod) : Multiset.Rel Associated f g := + prime_factors_unique (fun x hx => UniqueFactorizationMonoid.irreducible_iff_prime.mp (hf x hx)) + (fun x hx => UniqueFactorizationMonoid.irreducible_iff_prime.mp (hg x hx)) h + +end UniqueFactorizationMonoid + +/-- If an irreducible has a prime factorization, + then it is an associate of one of its prime factors. -/ +theorem prime_factors_irreducible [CancelCommMonoidWithZero α] {a : α} {f : Multiset α} + (ha : Irreducible a) (pfa : (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a) : ∃ p, a ~ᵤ p ∧ f = {p} := by + haveI := Classical.decEq α + refine @Multiset.induction_on _ + (fun g => (g.prod ~ᵤ a) → (∀ b ∈ g, Prime b) → ∃ p, a ~ᵤ p ∧ g = {p}) f ?_ ?_ pfa.2 pfa.1 + · intro h; exact (ha.not_unit (associated_one_iff_isUnit.1 (Associated.symm h))).elim + · rintro p s _ ⟨u, hu⟩ hs + use p + have hs0 : s = 0 := by + by_contra hs0 + obtain ⟨q, hq⟩ := Multiset.exists_mem_of_ne_zero hs0 + apply (hs q (by simp [hq])).2.1 + refine (ha.isUnit_or_isUnit (?_ : _ = p * ↑u * (s.erase q).prod * _)).resolve_left ?_ + · rw [mul_right_comm _ _ q, mul_assoc, ← Multiset.prod_cons, Multiset.cons_erase hq, ← hu, + mul_comm, mul_comm p _, mul_assoc] + simp + apply mt isUnit_of_mul_isUnit_left (mt isUnit_of_mul_isUnit_left _) + apply (hs p (Multiset.mem_cons_self _ _)).2.1 + simp only [mul_one, Multiset.prod_cons, Multiset.prod_zero, hs0] at * + exact ⟨Associated.symm ⟨u, hu⟩, rfl⟩ + +theorem irreducible_iff_prime_of_exists_unique_irreducible_factors [CancelCommMonoidWithZero α] + (eif : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod ~ᵤ a) + (uif : + ∀ f g : Multiset α, + (∀ x ∈ f, Irreducible x) → + (∀ x ∈ g, Irreducible x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g) + (p : α) : Irreducible p ↔ Prime p := + letI := Classical.decEq α + ⟨ fun hpi => + ⟨hpi.ne_zero, hpi.1, fun a b ⟨x, hx⟩ => + if hab0 : a * b = 0 then + (eq_zero_or_eq_zero_of_mul_eq_zero hab0).elim (fun ha0 => by simp [ha0]) fun hb0 => by + simp [hb0] + else by + have hx0 : x ≠ 0 := fun hx0 => by simp_all + have ha0 : a ≠ 0 := left_ne_zero_of_mul hab0 + have hb0 : b ≠ 0 := right_ne_zero_of_mul hab0 + cases' eif x hx0 with fx hfx + cases' eif a ha0 with fa hfa + cases' eif b hb0 with fb hfb + have h : Multiset.Rel Associated (p ::ₘ fx) (fa + fb) := by + apply uif + · exact fun i hi => (Multiset.mem_cons.1 hi).elim (fun hip => hip.symm ▸ hpi) (hfx.1 _) + · exact fun i hi => (Multiset.mem_add.1 hi).elim (hfa.1 _) (hfb.1 _) + calc + Multiset.prod (p ::ₘ fx) ~ᵤ a * b := by + rw [hx, Multiset.prod_cons]; exact hfx.2.mul_left _ + _ ~ᵤ fa.prod * fb.prod := hfa.2.symm.mul_mul hfb.2.symm + _ = _ := by rw [Multiset.prod_add] + + exact + let ⟨q, hqf, hq⟩ := Multiset.exists_mem_of_rel_of_mem h (Multiset.mem_cons_self p _) + (Multiset.mem_add.1 hqf).elim + (fun hqa => + Or.inl <| hq.dvd_iff_dvd_left.2 <| hfa.2.dvd_iff_dvd_right.1 (Multiset.dvd_prod hqa)) + fun hqb => + Or.inr <| hq.dvd_iff_dvd_left.2 <| hfb.2.dvd_iff_dvd_right.1 (Multiset.dvd_prod hqb)⟩, + Prime.irreducible⟩ + +namespace UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] +variable [UniqueFactorizationMonoid α] + +@[simp] +theorem factors_one : factors (1 : α) = 0 := by + nontriviality α using factors + rw [← Multiset.rel_zero_right] + refine factors_unique irreducible_of_factor (fun x hx => (Multiset.not_mem_zero x hx).elim) ?_ + rw [Multiset.prod_zero] + exact factors_prod one_ne_zero + +theorem exists_mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : + p ∣ a → ∃ q ∈ factors a, p ~ᵤ q := fun ⟨b, hb⟩ => + have hb0 : b ≠ 0 := fun hb0 => by simp_all + have : Multiset.Rel Associated (p ::ₘ factors b) (factors a) := + factors_unique + (fun _ hx => (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_factor _)) + irreducible_of_factor + (Associated.symm <| + calc + Multiset.prod (factors a) ~ᵤ a := factors_prod ha0 + _ = p * b := hb + _ ~ᵤ Multiset.prod (p ::ₘ factors b) := by + rw [Multiset.prod_cons]; exact (factors_prod hb0).symm.mul_left _ + ) + Multiset.exists_mem_of_rel_of_mem this (by simp) + +theorem exists_mem_factors {x : α} (hx : x ≠ 0) (h : ¬IsUnit x) : ∃ p, p ∈ factors x := by + obtain ⟨p', hp', hp'x⟩ := WfDvdMonoid.exists_irreducible_factor h hx + obtain ⟨p, hp, _⟩ := exists_mem_factors_of_dvd hx hp' hp'x + exact ⟨p, hp⟩ + +open Classical in +theorem factors_mul {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : + Multiset.Rel Associated (factors (x * y)) (factors x + factors y) := by + refine + factors_unique irreducible_of_factor + (fun a ha => + (Multiset.mem_add.mp ha).by_cases (irreducible_of_factor _) (irreducible_of_factor _)) + ((factors_prod (mul_ne_zero hx hy)).trans ?_) + rw [Multiset.prod_add] + exact (Associated.mul_mul (factors_prod hx) (factors_prod hy)).symm + +theorem factors_pow {x : α} (n : ℕ) : + Multiset.Rel Associated (factors (x ^ n)) (n • factors x) := by + match n with + | 0 => rw [zero_smul, pow_zero, factors_one, Multiset.rel_zero_right] + | n+1 => + by_cases h0 : x = 0 + · simp [h0, zero_pow n.succ_ne_zero, smul_zero] + · rw [pow_succ', succ_nsmul'] + refine Multiset.Rel.trans _ (factors_mul h0 (pow_ne_zero n h0)) ?_ + refine Multiset.Rel.add ?_ <| factors_pow n + exact Multiset.rel_refl_of_refl_on fun y _ => Associated.refl _ + +@[simp] +theorem factors_pos (x : α) (hx : x ≠ 0) : 0 < factors x ↔ ¬IsUnit x := by + constructor + · intro h hx + obtain ⟨p, hp⟩ := Multiset.exists_mem_of_ne_zero h.ne' + exact (prime_of_factor _ hp).not_unit (isUnit_of_dvd_unit (dvd_of_mem_factors hp) hx) + · intro h + obtain ⟨p, hp⟩ := exists_mem_factors hx h + exact + bot_lt_iff_ne_bot.mpr + (mt Multiset.eq_zero_iff_forall_not_mem.mp (not_forall.mpr ⟨p, not_not.mpr hp⟩)) + +open Multiset in +theorem factors_pow_count_prod [DecidableEq α] {x : α} (hx : x ≠ 0) : + (∏ p ∈ (factors x).toFinset, p ^ (factors x).count p) ~ᵤ x := + calc + _ = prod (∑ a ∈ toFinset (factors x), count a (factors x) • {a}) := by + simp only [prod_sum, prod_nsmul, prod_singleton] + _ = prod (factors x) := by rw [toFinset_sum_count_nsmul_eq (factors x)] + _ ~ᵤ x := factors_prod hx + +theorem factors_rel_of_associated {a b : α} (h : Associated a b) : + Multiset.Rel Associated (factors a) (factors b) := by + rcases iff_iff_and_or_not_and_not.mp h.eq_zero_iff with (⟨rfl, rfl⟩ | ⟨ha, hb⟩) + · simp + · refine factors_unique irreducible_of_factor irreducible_of_factor ?_ + exact ((factors_prod ha).trans h).trans (factors_prod hb).symm + +end UniqueFactorizationMonoid + +namespace Associates + +attribute [local instance] Associated.setoid + +open Multiset UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] + +theorem unique' {p q : Multiset (Associates α)} : + (∀ a ∈ p, Irreducible a) → (∀ a ∈ q, Irreducible a) → p.prod = q.prod → p = q := by + apply Multiset.induction_on_multiset_quot p + apply Multiset.induction_on_multiset_quot q + intro s t hs ht eq + refine Multiset.map_mk_eq_map_mk_of_rel (UniqueFactorizationMonoid.factors_unique ?_ ?_ ?_) + · exact fun a ha => irreducible_mk.1 <| hs _ <| Multiset.mem_map_of_mem _ ha + · exact fun a ha => irreducible_mk.1 <| ht _ <| Multiset.mem_map_of_mem _ ha + have eq' : (Quot.mk Setoid.r : α → Associates α) = Associates.mk := funext quot_mk_eq_mk + rwa [eq', prod_mk, prod_mk, mk_eq_mk_iff_associated] at eq + +theorem prod_le_prod_iff_le [Nontrivial α] {p q : Multiset (Associates α)} + (hp : ∀ a ∈ p, Irreducible a) (hq : ∀ a ∈ q, Irreducible a) : p.prod ≤ q.prod ↔ p ≤ q := by + refine ⟨?_, prod_le_prod⟩ + rintro ⟨c, eqc⟩ + refine Multiset.le_iff_exists_add.2 ⟨factors c, unique' hq (fun x hx ↦ ?_) ?_⟩ + · obtain h | h := Multiset.mem_add.1 hx + · exact hp x h + · exact irreducible_of_factor _ h + · rw [eqc, Multiset.prod_add] + congr + refine associated_iff_eq.mp (factors_prod fun hc => ?_).symm + refine not_irreducible_zero (hq _ ?_) + rw [← prod_eq_zero_iff, eqc, hc, mul_zero] + +end Associates + +section ExistsPrimeFactors + +variable [CancelCommMonoidWithZero α] +variable (pf : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a) +include pf + +theorem WfDvdMonoid.of_exists_prime_factors : WfDvdMonoid α := + ⟨by + classical + refine RelHomClass.wellFounded + (RelHom.mk ?_ ?_ : (DvdNotUnit : α → α → Prop) →r ((· < ·) : ℕ∞ → ℕ∞ → Prop)) wellFounded_lt + · intro a + by_cases h : a = 0 + · exact ⊤ + exact ↑(Multiset.card (Classical.choose (pf a h))) + rintro a b ⟨ane0, ⟨c, hc, b_eq⟩⟩ + rw [dif_neg ane0] + by_cases h : b = 0 + · simp [h, lt_top_iff_ne_top] + · rw [dif_neg h, Nat.cast_lt] + have cne0 : c ≠ 0 := by + refine mt (fun con => ?_) h + rw [b_eq, con, mul_zero] + calc + Multiset.card (Classical.choose (pf a ane0)) < + _ + Multiset.card (Classical.choose (pf c cne0)) := + lt_add_of_pos_right _ + (Multiset.card_pos.mpr fun con => hc (associated_one_iff_isUnit.mp ?_)) + _ = Multiset.card (Classical.choose (pf a ane0) + Classical.choose (pf c cne0)) := + (Multiset.card_add _ _).symm + _ = Multiset.card (Classical.choose (pf b h)) := + Multiset.card_eq_card_of_rel + (prime_factors_unique ?_ (Classical.choose_spec (pf _ h)).1 ?_) + + · convert (Classical.choose_spec (pf c cne0)).2.symm + rw [con, Multiset.prod_zero] + · intro x hadd + rw [Multiset.mem_add] at hadd + cases' hadd with h h <;> apply (Classical.choose_spec (pf _ _)).1 _ h <;> assumption + · rw [Multiset.prod_add] + trans a * c + · apply Associated.mul_mul <;> apply (Classical.choose_spec (pf _ _)).2 <;> assumption + · rw [← b_eq] + apply (Classical.choose_spec (pf _ _)).2.symm; assumption⟩ + +theorem irreducible_iff_prime_of_exists_prime_factors {p : α} : Irreducible p ↔ Prime p := by + by_cases hp0 : p = 0 + · simp [hp0] + refine ⟨fun h => ?_, Prime.irreducible⟩ + obtain ⟨f, hf⟩ := pf p hp0 + obtain ⟨q, hq, rfl⟩ := prime_factors_irreducible h hf + rw [hq.prime_iff] + exact hf.1 q (Multiset.mem_singleton_self _) + +theorem UniqueFactorizationMonoid.of_exists_prime_factors : UniqueFactorizationMonoid α := + { WfDvdMonoid.of_exists_prime_factors pf with + irreducible_iff_prime := irreducible_iff_prime_of_exists_prime_factors pf } + +end ExistsPrimeFactors + +theorem UniqueFactorizationMonoid.iff_exists_prime_factors [CancelCommMonoidWithZero α] : + UniqueFactorizationMonoid α ↔ + ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a := + ⟨fun h => @UniqueFactorizationMonoid.exists_prime_factors _ _ h, + UniqueFactorizationMonoid.of_exists_prime_factors⟩ + +section + +variable {β : Type*} [CancelCommMonoidWithZero α] [CancelCommMonoidWithZero β] + +theorem MulEquiv.uniqueFactorizationMonoid (e : α ≃* β) (hα : UniqueFactorizationMonoid α) : + UniqueFactorizationMonoid β := by + rw [UniqueFactorizationMonoid.iff_exists_prime_factors] at hα ⊢ + intro a ha + obtain ⟨w, hp, u, h⟩ := + hα (e.symm a) fun h => + ha <| by + convert← map_zero e + simp [← h] + exact + ⟨w.map e, fun b hb => + let ⟨c, hc, he⟩ := Multiset.mem_map.1 hb + he ▸ e.prime_iff.1 (hp c hc), + Units.map e.toMonoidHom u, + by + 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 β := + ⟨e.uniqueFactorizationMonoid, e.symm.uniqueFactorizationMonoid⟩ + +end + +namespace UniqueFactorizationMonoid + +theorem of_exists_unique_irreducible_factors [CancelCommMonoidWithZero α] + (eif : ∀ a : α, a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod ~ᵤ a) + (uif : + ∀ f g : Multiset α, + (∀ x ∈ f, Irreducible x) → + (∀ x ∈ g, Irreducible x) → f.prod ~ᵤ g.prod → Multiset.Rel Associated f g) : + UniqueFactorizationMonoid α := + UniqueFactorizationMonoid.of_exists_prime_factors + (by + convert eif using 7 + simp_rw [irreducible_iff_prime_of_exists_unique_irreducible_factors eif uif]) + +variable {R : Type*} [CancelCommMonoidWithZero R] [UniqueFactorizationMonoid R] + +theorem isRelPrime_iff_no_prime_factors {a b : R} (ha : a ≠ 0) : + IsRelPrime a b ↔ ∀ ⦃d⦄, d ∣ a → d ∣ b → ¬Prime d := + ⟨fun h _ ha hb ↦ (·.not_unit <| h ha hb), fun h ↦ WfDvdMonoid.isRelPrime_of_no_irreducible_factors + (ha ·.1) fun _ irr ha hb ↦ h ha hb (UniqueFactorizationMonoid.irreducible_iff_prime.mp irr)⟩ + +/-- Euclid's lemma: if `a ∣ b * c` and `a` and `c` have no common prime factors, `a ∣ b`. +Compare `IsCoprime.dvd_of_dvd_mul_left`. -/ +theorem dvd_of_dvd_mul_left_of_no_prime_factors {a b c : R} (ha : a ≠ 0) + (h : ∀ ⦃d⦄, d ∣ a → d ∣ c → ¬Prime d) : a ∣ b * c → a ∣ b := + ((isRelPrime_iff_no_prime_factors ha).mpr h).dvd_of_dvd_mul_right + +/-- Euclid's lemma: if `a ∣ b * c` and `a` and `b` have no common prime factors, `a ∣ c`. +Compare `IsCoprime.dvd_of_dvd_mul_right`. -/ +theorem dvd_of_dvd_mul_right_of_no_prime_factors {a b c : R} (ha : a ≠ 0) + (no_factors : ∀ {d}, d ∣ a → d ∣ b → ¬Prime d) : a ∣ b * c → a ∣ c := by + simpa [mul_comm b c] using dvd_of_dvd_mul_left_of_no_prime_factors ha @no_factors + +/-- If `a ≠ 0, b` are elements of a unique factorization domain, then dividing +out their common factor `c'` gives `a'` and `b'` with no factors in common. -/ +theorem exists_reduced_factors : + ∀ a ≠ (0 : R), ∀ b, + ∃ a' b' c', IsRelPrime a' b' ∧ c' * a' = a ∧ c' * b' = b := by + intro a + refine induction_on_prime a ?_ ?_ ?_ + · intros + contradiction + · intro a a_unit _ b + use a, b, 1 + constructor + · intro p p_dvd_a _ + exact isUnit_of_dvd_unit p_dvd_a a_unit + · simp + · intro a p a_ne_zero p_prime ih_a pa_ne_zero b + by_cases h : p ∣ b + · rcases h with ⟨b, rfl⟩ + obtain ⟨a', b', c', no_factor, ha', hb'⟩ := ih_a a_ne_zero b + refine ⟨a', b', p * c', @no_factor, ?_, ?_⟩ + · rw [mul_assoc, ha'] + · rw [mul_assoc, hb'] + · obtain ⟨a', b', c', coprime, rfl, rfl⟩ := ih_a a_ne_zero b + refine ⟨p * a', b', c', ?_, mul_left_comm _ _ _, rfl⟩ + intro q q_dvd_pa' q_dvd_b' + cases' p_prime.left_dvd_or_dvd_right_of_dvd_mul q_dvd_pa' with p_dvd_q q_dvd_a' + · have : p ∣ c' * b' := dvd_mul_of_dvd_right (p_dvd_q.trans q_dvd_b') _ + contradiction + exact coprime q_dvd_a' q_dvd_b' + +theorem exists_reduced_factors' (a b : R) (hb : b ≠ 0) : + ∃ a' b' c', IsRelPrime a' b' ∧ c' * a' = a ∧ c' * b' = b := + 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⟩ + +@[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 + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean new file mode 100644 index 00000000000000..121cf52e3a622b --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Algebra.Associated.Basic +import Mathlib.Algebra.BigOperators.Group.Multiset +import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Order.WellFounded + +/-! +# Unique factorization + +## Main Definitions +* `WfDvdMonoid` holds for `Monoid`s for which a strict divisibility relation is + well-founded. +* `UniqueFactorizationMonoid` holds for `WfDvdMonoid`s where + `Irreducible` is equivalent to `Prime` +-/ + +assert_not_exists Field +assert_not_exists Finsupp +assert_not_exists Ideal + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +/-- Well-foundedness of the strict version of ∣, which is equivalent to the descending chain +condition on divisibility and to the ascending chain condition on +principal ideals in an integral domain. + -/ +abbrev WfDvdMonoid (α : Type*) [CommMonoidWithZero α] : Prop := + IsWellFounded α DvdNotUnit + +theorem wellFounded_dvdNotUnit {α : Type*} [CommMonoidWithZero α] [h : WfDvdMonoid α] : + WellFounded (DvdNotUnit (α := α)) := + h.wf + +namespace WfDvdMonoid + +variable [CommMonoidWithZero α] + +open Associates Nat + +variable [WfDvdMonoid α] + +theorem exists_irreducible_factor {a : α} (ha : ¬IsUnit a) (ha0 : a ≠ 0) : + ∃ i, Irreducible i ∧ i ∣ a := + let ⟨b, hs, hr⟩ := wellFounded_dvdNotUnit.has_min { b | b ∣ a ∧ ¬IsUnit b } ⟨a, dvd_rfl, ha⟩ + ⟨b, + ⟨hs.2, fun c d he => + let h := dvd_trans ⟨d, he⟩ hs.1 + or_iff_not_imp_left.2 fun hc => + of_not_not fun hd => hr c ⟨h, hc⟩ ⟨ne_zero_of_dvd_ne_zero ha0 h, d, hd, he⟩⟩, + hs.1⟩ + +@[elab_as_elim] +theorem induction_on_irreducible {P : α → Prop} (a : α) (h0 : P 0) (hu : ∀ u : α, IsUnit u → P u) + (hi : ∀ a i : α, a ≠ 0 → Irreducible i → P a → P (i * a)) : P a := + haveI := Classical.dec + wellFounded_dvdNotUnit.fix + (fun a ih => + if ha0 : a = 0 then ha0.substr h0 + else + if hau : IsUnit a then hu a hau + else + let ⟨i, hii, b, hb⟩ := exists_irreducible_factor hau ha0 + let hb0 : b ≠ 0 := ne_zero_of_dvd_ne_zero ha0 ⟨i, mul_comm i b ▸ hb⟩ + hb.symm ▸ hi b i hb0 hii <| ih b ⟨hb0, i, hii.1, mul_comm i b ▸ hb⟩) + a + +theorem exists_factors (a : α) : + a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ Associated f.prod a := + induction_on_irreducible a (fun h => (h rfl).elim) + (fun _ hu _ => ⟨0, fun _ h => False.elim (Multiset.not_mem_zero _ h), hu.unit, one_mul _⟩) + fun a i ha0 hi ih _ => + let ⟨s, hs⟩ := ih ha0 + ⟨i ::ₘ s, fun b H => (Multiset.mem_cons.1 H).elim (fun h => h.symm ▸ hi) (hs.1 b), by + rw [s.prod_cons i] + exact hs.2.mul_left i⟩ + +theorem not_unit_iff_exists_factors_eq (a : α) (hn0 : a ≠ 0) : + ¬IsUnit a ↔ ∃ f : Multiset α, (∀ b ∈ f, Irreducible b) ∧ f.prod = a ∧ f ≠ ∅ := + ⟨fun hnu => by + obtain ⟨f, hi, u, rfl⟩ := exists_factors a hn0 + obtain ⟨b, h⟩ := Multiset.exists_mem_of_ne_zero fun h : f = 0 => hnu <| by simp [h] + classical + refine ⟨(f.erase b).cons (b * u), fun a ha => ?_, ?_, Multiset.cons_ne_zero⟩ + · obtain rfl | ha := Multiset.mem_cons.1 ha + exacts [Associated.irreducible ⟨u, rfl⟩ (hi b h), hi a (Multiset.mem_of_mem_erase ha)] + · rw [Multiset.prod_cons, mul_comm b, mul_assoc, Multiset.prod_erase h, mul_comm], + fun ⟨_, hi, he, hne⟩ => + let ⟨b, h⟩ := Multiset.exists_mem_of_ne_zero hne + not_isUnit_of_not_isUnit_dvd (hi b h).not_unit <| he ▸ Multiset.dvd_prod h⟩ + +theorem isRelPrime_of_no_irreducible_factors {x y : α} (nonzero : ¬(x = 0 ∧ y = 0)) + (H : ∀ z : α, Irreducible z → z ∣ x → ¬z ∣ y) : IsRelPrime x y := + isRelPrime_of_no_nonunits_factors nonzero fun _z znu znz zx zy ↦ + have ⟨i, h1, h2⟩ := exists_irreducible_factor znu znz + H i h1 (h2.trans zx) (h2.trans zy) + +end WfDvdMonoid + +section Prio + +-- set_option default_priority 100 + +-- see Note [default priority] +/-- unique factorization monoids. + +These are defined as `CancelCommMonoidWithZero`s with well-founded strict divisibility +relations, but this is equivalent to more familiar definitions: + +Each element (except zero) is uniquely represented as a multiset of irreducible factors. +Uniqueness is only up to associated elements. + +Each element (except zero) is non-uniquely represented as a multiset +of prime factors. + +To define a UFD using the definition in terms of multisets +of irreducible factors, use the definition `of_exists_unique_irreducible_factors` + +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 + IsWellFounded α DvdNotUnit : Prop where + protected irreducible_iff_prime : ∀ {a : α}, Irreducible a ↔ Prime a + +instance (priority := 100) ufm_of_decomposition_of_wfDvdMonoid + [CancelCommMonoidWithZero α] [WfDvdMonoid α] [DecompositionMonoid α] : + UniqueFactorizationMonoid α := + { ‹WfDvdMonoid α› with irreducible_iff_prime := irreducible_iff_prime } + +@[deprecated ufm_of_decomposition_of_wfDvdMonoid (since := "2024-02-12")] +theorem ufm_of_gcd_of_wfDvdMonoid [CancelCommMonoidWithZero α] [WfDvdMonoid α] + [DecompositionMonoid α] : UniqueFactorizationMonoid α := + ufm_of_decomposition_of_wfDvdMonoid + +end Prio + +namespace UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] + +theorem exists_prime_factors (a : α) : + a ≠ 0 → ∃ f : Multiset α, (∀ b ∈ f, Prime b) ∧ f.prod ~ᵤ a := by + simp_rw [← UniqueFactorizationMonoid.irreducible_iff_prime] + apply WfDvdMonoid.exists_factors a + +lemma exists_prime_iff : + (∃ (p : α), Prime p) ↔ ∃ (x : α), x ≠ 0 ∧ ¬ IsUnit x := by + refine ⟨fun ⟨p, hp⟩ ↦ ⟨p, hp.ne_zero, hp.not_unit⟩, fun ⟨x, hx₀, hxu⟩ ↦ ?_⟩ + obtain ⟨f, hf, -⟩ := WfDvdMonoid.exists_irreducible_factor hxu hx₀ + exact ⟨f, UniqueFactorizationMonoid.irreducible_iff_prime.mp hf⟩ + +@[elab_as_elim] +theorem induction_on_prime {P : α → Prop} (a : α) (h₁ : P 0) (h₂ : ∀ x : α, IsUnit x → P x) + (h₃ : ∀ a p : α, a ≠ 0 → Prime p → P a → P (p * a)) : P a := by + simp_rw [← UniqueFactorizationMonoid.irreducible_iff_prime] at h₃ + exact WfDvdMonoid.induction_on_irreducible a h₁ h₂ h₃ + +instance : DecompositionMonoid α where + primal a := by + obtain rfl | ha := eq_or_ne a 0; · exact isPrimal_zero + obtain ⟨f, hf, u, rfl⟩ := exists_prime_factors a ha + exact ((Submonoid.isPrimal α).multiset_prod_mem f (hf · ·|>.isPrimal)).mul u.isUnit.isPrimal + +end UniqueFactorizationMonoid + +namespace UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] +variable [UniqueFactorizationMonoid α] + +open Classical in +/-- Noncomputably determines the multiset of prime factors. -/ +noncomputable def factors (a : α) : Multiset α := + if h : a = 0 then 0 else Classical.choose (UniqueFactorizationMonoid.exists_prime_factors a h) + +theorem factors_prod {a : α} (ane0 : a ≠ 0) : Associated (factors a).prod a := by + rw [factors, dif_neg ane0] + exact (Classical.choose_spec (exists_prime_factors a ane0)).2 + +@[simp] +theorem factors_zero : factors (0 : α) = 0 := by simp [factors] + +theorem ne_zero_of_mem_factors {p a : α} (h : p ∈ factors a) : a ≠ 0 := by + rintro rfl + simp at h + +theorem dvd_of_mem_factors {p a : α} (h : p ∈ factors a) : p ∣ a := + dvd_trans (Multiset.dvd_prod h) (Associated.dvd (factors_prod (ne_zero_of_mem_factors h))) + +theorem prime_of_factor {a : α} (x : α) (hx : x ∈ factors a) : Prime x := by + have ane0 := ne_zero_of_mem_factors hx + rw [factors, dif_neg ane0] at hx + exact (Classical.choose_spec (UniqueFactorizationMonoid.exists_prime_factors a ane0)).1 x hx + +theorem irreducible_of_factor {a : α} : ∀ x : α, x ∈ factors a → Irreducible x := fun x h => + (prime_of_factor x h).irreducible + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/FactorSet.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/FactorSet.lean new file mode 100644 index 00000000000000..2dd1d63b54515b --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/FactorSet.lean @@ -0,0 +1,647 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Data.Finsupp.Multiset +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic +import Mathlib.Tactic.Ring + +/-! +# Set of factors + +## Main definitions +* `Associates.FactorSet`: multiset of factors of an element, unique up to propositional equality. +* `Associates.factors`: determine the `FactorSet` for a given element. + +## TODO +* set up the complete lattice structure on `FactorSet`. + +-/ + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +namespace Associates + +open UniqueFactorizationMonoid Associated Multiset + +variable [CancelCommMonoidWithZero α] + +/-- `FactorSet α` representation elements of unique factorization domain as multisets. +`Multiset α` produced by `normalizedFactors` are only unique up to associated elements, while the +multisets in `FactorSet α` are unique by equality and restricted to irreducible elements. This +gives us a representation of each element as a unique multisets (or the added ⊤ for 0), which has a +complete lattice structure. Infimum is the greatest common divisor and supremum is the least common +multiple. +-/ +abbrev FactorSet.{u} (α : Type u) [CancelCommMonoidWithZero α] : Type u := + WithTop (Multiset { a : Associates α // Irreducible a }) + +attribute [local instance] Associated.setoid + +theorem FactorSet.coe_add {a b : Multiset { a : Associates α // Irreducible a }} : + (↑(a + b) : FactorSet α) = a + b := by norm_cast + +theorem FactorSet.sup_add_inf_eq_add [DecidableEq (Associates α)] : + ∀ a b : FactorSet α, a ⊔ b + a ⊓ b = a + b + | ⊤, b => show ⊤ ⊔ b + ⊤ ⊓ b = ⊤ + b by simp + | a, ⊤ => show a ⊔ ⊤ + a ⊓ ⊤ = a + ⊤ by simp + | WithTop.some a, WithTop.some b => + show (a : FactorSet α) ⊔ b + (a : FactorSet α) ⊓ b = a + b by + rw [← WithTop.coe_sup, ← WithTop.coe_inf, ← WithTop.coe_add, ← WithTop.coe_add, + WithTop.coe_eq_coe] + exact Multiset.union_add_inter _ _ + +/-- Evaluates the product of a `FactorSet` to be the product of the corresponding multiset, + or `0` if there is none. -/ +def FactorSet.prod : FactorSet α → Associates α + | ⊤ => 0 + | WithTop.some s => (s.map (↑)).prod + +@[simp] +theorem prod_top : (⊤ : FactorSet α).prod = 0 := + rfl + +@[simp] +theorem prod_coe {s : Multiset { a : Associates α // Irreducible a }} : + FactorSet.prod (s : FactorSet α) = (s.map (↑)).prod := + rfl + +@[simp] +theorem prod_add : ∀ a b : FactorSet α, (a + b).prod = a.prod * b.prod + | ⊤, b => show (⊤ + b).prod = (⊤ : FactorSet α).prod * b.prod by simp + | a, ⊤ => show (a + ⊤).prod = a.prod * (⊤ : FactorSet α).prod by simp + | WithTop.some a, WithTop.some b => by + rw [← FactorSet.coe_add, prod_coe, prod_coe, prod_coe, Multiset.map_add, Multiset.prod_add] + +@[gcongr] +theorem prod_mono : ∀ {a b : FactorSet α}, a ≤ b → a.prod ≤ b.prod + | ⊤, b, h => by + have : b = ⊤ := top_unique h + rw [this, prod_top] + | a, ⊤, _ => show a.prod ≤ (⊤ : FactorSet α).prod by simp + | WithTop.some _, WithTop.some _, h => + prod_le_prod <| Multiset.map_le_map <| WithTop.coe_le_coe.1 <| h + +theorem FactorSet.prod_eq_zero_iff [Nontrivial α] (p : FactorSet α) : p.prod = 0 ↔ p = ⊤ := by + unfold FactorSet at p + induction p -- TODO: `induction_eliminator` doesn't work with `abbrev` + · simp only [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, not_exists] + exact fun a => not_and_of_not_right _ a.prop.ne_zero + +section count + +variable [DecidableEq (Associates α)] + +/-- `bcount p s` is the multiplicity of `p` in the FactorSet `s` (with bundled `p`)-/ +def bcount (p : { a : Associates α // Irreducible a }) : + FactorSet α → ℕ + | ⊤ => 0 + | WithTop.some s => s.count p + +variable [∀ p : Associates α, Decidable (Irreducible p)] {p : Associates α} + +/-- `count p s` is the multiplicity of the irreducible `p` in the FactorSet `s`. + +If `p` is not irreducible, `count p s` is defined to be `0`. -/ +def count (p : Associates α) : FactorSet α → ℕ := + if hp : Irreducible p then bcount ⟨p, hp⟩ else 0 + +@[simp] +theorem count_some (hp : Irreducible p) (s : Multiset _) : + count p (WithTop.some s) = s.count ⟨p, hp⟩ := by + simp only [count, dif_pos hp, bcount] + +@[simp] +theorem count_zero (hp : Irreducible p) : count p (0 : FactorSet α) = 0 := by + simp only [count, dif_pos hp, bcount, Multiset.count_zero] + +theorem count_reducible (hp : ¬Irreducible p) : count p = 0 := dif_neg hp + +end count + +section Mem + +/-- membership in a FactorSet (bundled version) -/ +def BfactorSetMem : { a : Associates α // Irreducible a } → FactorSet α → Prop + | _, ⊤ => True + | p, some l => p ∈ l + +/-- `FactorSetMem p s` is the predicate that the irreducible `p` is a member of +`s : FactorSet α`. + +If `p` is not irreducible, `p` is not a member of any `FactorSet`. -/ +def FactorSetMem (s : FactorSet α) (p : Associates α) : Prop := + letI : Decidable (Irreducible p) := Classical.dec _ + if hp : Irreducible p then BfactorSetMem ⟨p, hp⟩ s else False + +instance : Membership (Associates α) (FactorSet α) := + ⟨FactorSetMem⟩ + +@[simp] +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 + dsimp only [Membership.mem]; dsimp only [FactorSetMem]; split_ifs; exact trivial + +theorem mem_factorSet_some {p : Associates α} {hp : Irreducible p} + {l : Multiset { a : Associates α // Irreducible a }} : + p ∈ (l : FactorSet α) ↔ Subtype.mk p hp ∈ l := by + dsimp only [Membership.mem]; dsimp only [FactorSetMem]; split_ifs; rfl + +theorem reducible_not_mem_factorSet {p : Associates α} (hp : ¬Irreducible p) (s : FactorSet α) : + ¬p ∈ s := fun h ↦ by + rwa [← factorSetMem_eq_mem, FactorSetMem, dif_neg hp] at h + +theorem irreducible_of_mem_factorSet {p : Associates α} {s : FactorSet α} (h : p ∈ s) : + Irreducible p := + by_contra fun hp ↦ reducible_not_mem_factorSet hp s h + +end Mem + +variable [UniqueFactorizationMonoid α] + +theorem FactorSet.unique [Nontrivial α] {p q : FactorSet α} (h : p.prod = q.prod) : p = q := by + -- TODO: `induction_eliminator` doesn't work with `abbrev` + unfold FactorSet at p q + induction p <;> induction q + · rfl + · rw [eq_comm, ← FactorSet.prod_eq_zero_iff, ← h, Associates.prod_top] + · rw [← FactorSet.prod_eq_zero_iff, h, Associates.prod_top] + · congr 1 + rw [← Multiset.map_eq_map Subtype.coe_injective] + apply unique' _ _ h <;> + · intro a ha + obtain ⟨⟨a', irred⟩, -, rfl⟩ := Multiset.mem_map.mp ha + rwa [Subtype.coe_mk] + +/-- This returns the multiset of irreducible factors as a `FactorSet`, + a multiset of irreducible associates `WithTop`. -/ +noncomputable def factors' (a : α) : Multiset { a : Associates α // Irreducible a } := + (factors a).pmap (fun a ha => ⟨Associates.mk a, irreducible_mk.2 ha⟩) irreducible_of_factor + +@[simp] +theorem map_subtype_coe_factors' {a : α} : + (factors' a).map (↑) = (factors a).map Associates.mk := by + simp [factors', Multiset.map_pmap, Multiset.pmap_eq_map] + +theorem factors'_cong {a b : α} (h : a ~ᵤ b) : factors' a = factors' b := by + obtain rfl | hb := eq_or_ne b 0 + · rw [associated_zero_iff_eq_zero] at h + rw [h] + have ha : a ≠ 0 := by + contrapose! hb with ha + rw [← associated_zero_iff_eq_zero, ← ha] + exact h.symm + rw [← Multiset.map_eq_map Subtype.coe_injective, map_subtype_coe_factors', + map_subtype_coe_factors', ← rel_associated_iff_map_eq_map] + exact + factors_unique irreducible_of_factor irreducible_of_factor + ((factors_prod ha).trans <| h.trans <| (factors_prod hb).symm) + +/-- This returns the multiset of irreducible factors of an associate as a `FactorSet`, + a multiset of irreducible associates `WithTop`. -/ +noncomputable def factors (a : Associates α) : FactorSet α := by + classical refine if h : a = 0 then ⊤ else Quotient.hrecOn a (fun x _ => factors' x) ?_ h + intro a b hab + apply Function.hfunext + · have : a ~ᵤ 0 ↔ b ~ᵤ 0 := Iff.intro (fun ha0 => hab.symm.trans ha0) fun hb0 => hab.trans hb0 + simp only [associated_zero_iff_eq_zero] at this + simp only [quotient_mk_eq_mk, this, mk_eq_zero] + exact fun ha hb _ => heq_of_eq <| congr_arg some <| factors'_cong hab + +@[simp] +theorem factors_zero : (0 : Associates α).factors = ⊤ := + dif_pos rfl + +@[deprecated (since := "2024-03-16")] alias factors_0 := factors_zero + +@[simp] +theorem factors_mk (a : α) (h : a ≠ 0) : (Associates.mk a).factors = factors' a := by + classical + apply dif_neg + apply mt mk_eq_zero.1 h + +@[simp] +theorem factors_prod (a : Associates α) : a.factors.prod = a := by + rcases Associates.mk_surjective a with ⟨a, rfl⟩ + rcases eq_or_ne a 0 with rfl | ha + · simp + · simp [ha, prod_mk, mk_eq_mk_iff_associated, UniqueFactorizationMonoid.factors_prod, + -Quotient.eq] + +@[simp] +theorem prod_factors [Nontrivial α] (s : FactorSet α) : s.prod.factors = s := + FactorSet.unique <| factors_prod _ + +@[nontriviality] +theorem factors_subsingleton [Subsingleton α] {a : Associates α} : a.factors = ⊤ := by + have : Subsingleton (Associates α) := inferInstance + convert factors_zero + +theorem factors_eq_top_iff_zero {a : Associates α} : a.factors = ⊤ ↔ a = 0 := by + nontriviality α + exact ⟨fun h ↦ by rwa [← factors_prod a, FactorSet.prod_eq_zero_iff], fun h ↦ h ▸ factors_zero⟩ + +@[deprecated (since := "2024-04-16")] alias factors_eq_none_iff_zero := factors_eq_top_iff_zero + +theorem factors_eq_some_iff_ne_zero {a : Associates α} : + (∃ s : Multiset { p : Associates α // Irreducible p }, a.factors = s) ↔ a ≠ 0 := by + simp_rw [@eq_comm _ a.factors, ← WithTop.ne_top_iff_exists] + exact factors_eq_top_iff_zero.not + +theorem eq_of_factors_eq_factors {a b : Associates α} (h : a.factors = b.factors) : a = b := by + have : a.factors.prod = b.factors.prod := by rw [h] + rwa [factors_prod, factors_prod] at this + +theorem eq_of_prod_eq_prod [Nontrivial α] {a b : FactorSet α} (h : a.prod = b.prod) : a = b := by + have : a.prod.factors = b.prod.factors := by rw [h] + rwa [prod_factors, prod_factors] at this + +@[simp] +theorem factors_mul (a b : Associates α) : (a * b).factors = a.factors + b.factors := by + nontriviality α + refine eq_of_prod_eq_prod <| eq_of_factors_eq_factors ?_ + rw [prod_add, factors_prod, factors_prod, factors_prod] + +@[gcongr] +theorem factors_mono : ∀ {a b : Associates α}, a ≤ b → a.factors ≤ b.factors + | s, t, ⟨d, eq⟩ => by rw [eq, factors_mul]; exact le_add_of_nonneg_right bot_le + +@[simp] +theorem factors_le {a b : Associates α} : a.factors ≤ b.factors ↔ a ≤ b := by + refine ⟨fun h ↦ ?_, factors_mono⟩ + have : a.factors.prod ≤ b.factors.prod := prod_mono h + rwa [factors_prod, factors_prod] at this + +section count + +variable [DecidableEq (Associates α)] [∀ p : Associates α, Decidable (Irreducible p)] + +theorem eq_factors_of_eq_counts {a b : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) + (h : ∀ p : Associates α, Irreducible p → p.count a.factors = p.count b.factors) : + a.factors = b.factors := by + obtain ⟨sa, h_sa⟩ := factors_eq_some_iff_ne_zero.mpr ha + obtain ⟨sb, h_sb⟩ := factors_eq_some_iff_ne_zero.mpr hb + rw [h_sa, h_sb] at h ⊢ + rw [WithTop.coe_eq_coe] + have h_count : ∀ (p : Associates α) (hp : Irreducible p), + sa.count ⟨p, hp⟩ = sb.count ⟨p, hp⟩ := by + intro p hp + rw [← count_some, ← count_some, h p hp] + apply Multiset.toFinsupp.injective + ext ⟨p, hp⟩ + rw [Multiset.toFinsupp_apply, Multiset.toFinsupp_apply, h_count p hp] + +theorem eq_of_eq_counts {a b : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) + (h : ∀ p : Associates α, Irreducible p → p.count a.factors = p.count b.factors) : a = b := + eq_of_factors_eq_factors (eq_factors_of_eq_counts ha hb h) + +theorem count_le_count_of_factors_le {a b p : Associates α} (hb : b ≠ 0) (hp : Irreducible p) + (h : a.factors ≤ b.factors) : p.count a.factors ≤ p.count b.factors := by + by_cases ha : a = 0 + · simp_all + obtain ⟨sa, h_sa⟩ := factors_eq_some_iff_ne_zero.mpr ha + obtain ⟨sb, h_sb⟩ := factors_eq_some_iff_ne_zero.mpr hb + rw [h_sa, h_sb] at h ⊢ + rw [count_some hp, count_some hp]; rw [WithTop.coe_le_coe] at h + exact Multiset.count_le_of_le _ h + +theorem count_le_count_of_le {a b p : Associates α} (hb : b ≠ 0) (hp : Irreducible p) (h : a ≤ b) : + p.count a.factors ≤ p.count b.factors := + count_le_count_of_factors_le hb hp <| factors_mono h + +end count + +theorem prod_le [Nontrivial α] {a b : FactorSet α} : a.prod ≤ b.prod ↔ a ≤ b := by + refine ⟨fun h ↦ ?_, prod_mono⟩ + have : a.prod.factors ≤ b.prod.factors := factors_mono h + rwa [prod_factors, prod_factors] at this + +open Classical in +noncomputable instance : Max (Associates α) := + ⟨fun a b => (a.factors ⊔ b.factors).prod⟩ + +open Classical in +noncomputable instance : Min (Associates α) := + ⟨fun a b => (a.factors ⊓ b.factors).prod⟩ + +open Classical in +noncomputable instance : Lattice (Associates α) := + { Associates.instPartialOrder with + sup := (· ⊔ ·) + inf := (· ⊓ ·) + sup_le := fun _ _ c hac hbc => + factors_prod c ▸ prod_mono (sup_le (factors_mono hac) (factors_mono hbc)) + le_sup_left := fun a _ => le_trans (le_of_eq (factors_prod a).symm) <| prod_mono <| le_sup_left + le_sup_right := fun _ b => + le_trans (le_of_eq (factors_prod b).symm) <| prod_mono <| le_sup_right + le_inf := fun a _ _ hac hbc => + factors_prod a ▸ prod_mono (le_inf (factors_mono hac) (factors_mono hbc)) + inf_le_left := fun a _ => le_trans (prod_mono inf_le_left) (le_of_eq (factors_prod a)) + inf_le_right := fun _ b => le_trans (prod_mono inf_le_right) (le_of_eq (factors_prod b)) } + +open Classical in +theorem sup_mul_inf (a b : Associates α) : (a ⊔ b) * (a ⊓ b) = a * b := + show (a.factors ⊔ b.factors).prod * (a.factors ⊓ b.factors).prod = a * b by + nontriviality α + refine eq_of_factors_eq_factors ?_ + rw [← prod_add, prod_factors, factors_mul, FactorSet.sup_add_inf_eq_add] + +theorem dvd_of_mem_factors {a p : Associates α} (hm : p ∈ factors a) : + p ∣ a := by + rcases eq_or_ne a 0 with rfl | ha0 + · exact dvd_zero p + obtain ⟨a0, nza, ha'⟩ := exists_non_zero_rep ha0 + rw [← Associates.factors_prod a] + rw [← ha', factors_mk a0 nza] at hm ⊢ + rw [prod_coe] + apply Multiset.dvd_prod; apply Multiset.mem_map.mpr + exact ⟨⟨p, irreducible_of_mem_factorSet hm⟩, mem_factorSet_some.mp hm, rfl⟩ + +theorem dvd_of_mem_factors' {a : α} {p : Associates α} {hp : Irreducible p} {hz : a ≠ 0} + (h_mem : Subtype.mk p hp ∈ factors' a) : p ∣ Associates.mk a := by + haveI := Classical.decEq (Associates α) + apply dvd_of_mem_factors + rw [factors_mk _ hz] + apply mem_factorSet_some.2 h_mem + +theorem mem_factors'_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) (hd : p ∣ a) : + Subtype.mk (Associates.mk p) (irreducible_mk.2 hp) ∈ factors' a := by + obtain ⟨q, hq, hpq⟩ := exists_mem_factors_of_dvd ha0 hp hd + apply Multiset.mem_pmap.mpr; use q; use hq + exact Subtype.eq (Eq.symm (mk_eq_mk_iff_associated.mpr hpq)) + +theorem mem_factors'_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : + Subtype.mk (Associates.mk p) (irreducible_mk.2 hp) ∈ factors' a ↔ p ∣ a := by + constructor + · rw [← mk_dvd_mk] + apply dvd_of_mem_factors' + apply ha0 + · apply mem_factors'_of_dvd ha0 hp + +theorem mem_factors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) (hd : p ∣ a) : + Associates.mk p ∈ factors (Associates.mk a) := by + rw [factors_mk _ ha0] + exact mem_factorSet_some.mpr (mem_factors'_of_dvd ha0 hp hd) + +theorem mem_factors_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : + Associates.mk p ∈ factors (Associates.mk a) ↔ p ∣ a := by + constructor + · rw [← mk_dvd_mk] + apply dvd_of_mem_factors + · apply mem_factors_of_dvd ha0 hp + +open Classical in +theorem exists_prime_dvd_of_not_inf_one {a b : α} (ha : a ≠ 0) (hb : b ≠ 0) + (h : Associates.mk a ⊓ Associates.mk b ≠ 1) : ∃ p : α, Prime p ∧ p ∣ a ∧ p ∣ b := by + have hz : factors (Associates.mk a) ⊓ factors (Associates.mk b) ≠ 0 := by + contrapose! h with hf + change (factors (Associates.mk a) ⊓ factors (Associates.mk b)).prod = 1 + rw [hf] + exact Multiset.prod_zero + rw [factors_mk a ha, factors_mk b hb, ← WithTop.coe_inf] at hz + obtain ⟨⟨p0, p0_irr⟩, p0_mem⟩ := Multiset.exists_mem_of_ne_zero ((mt WithTop.coe_eq_coe.mpr) hz) + rw [Multiset.inf_eq_inter] at p0_mem + obtain ⟨p, rfl⟩ : ∃ p, Associates.mk p = p0 := Quot.exists_rep p0 + refine ⟨p, ?_, ?_, ?_⟩ + · rw [← UniqueFactorizationMonoid.irreducible_iff_prime, ← irreducible_mk] + exact p0_irr + · apply dvd_of_mk_le_mk + apply dvd_of_mem_factors' (Multiset.mem_inter.mp p0_mem).left + apply ha + · apply dvd_of_mk_le_mk + apply dvd_of_mem_factors' (Multiset.mem_inter.mp p0_mem).right + apply hb + +theorem coprime_iff_inf_one {a b : α} (ha0 : a ≠ 0) (hb0 : b ≠ 0) : + Associates.mk a ⊓ Associates.mk b = 1 ↔ ∀ {d : α}, d ∣ a → d ∣ b → ¬Prime d := by + constructor + · intro hg p ha hb hp + refine (Associates.prime_mk.mpr hp).not_unit (isUnit_of_dvd_one ?_) + rw [← hg] + exact le_inf (mk_le_mk_of_dvd ha) (mk_le_mk_of_dvd hb) + · contrapose + intro hg hc + obtain ⟨p, hp, hpa, hpb⟩ := exists_prime_dvd_of_not_inf_one ha0 hb0 hg + exact hc hpa hpb hp + +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.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.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.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 + apply eq_of_prod_eq_prod + rw [Associates.factors_prod] + exact Multiset.prod_zero + +@[simp] +theorem pow_factors [Nontrivial α] {a : Associates α} {k : ℕ} : + (a ^ k).factors = k • a.factors := by + induction' k with n h + · rw [zero_nsmul, pow_zero] + exact factors_one + · rw [pow_succ, succ_nsmul, factors_mul, h] + +section count + +variable [DecidableEq (Associates α)] [∀ p : Associates α, Decidable (Irreducible p)] + +theorem prime_pow_dvd_iff_le {m p : Associates α} (h₁ : m ≠ 0) (h₂ : Irreducible p) {k : ℕ} : + p ^ k ≤ m ↔ k ≤ count p m.factors := by + rw [count, dif_pos h₂, prime_pow_le_iff_le_bcount h₁] + +theorem le_of_count_ne_zero {m p : Associates α} (h0 : m ≠ 0) (hp : Irreducible p) : + count p m.factors ≠ 0 → p ≤ m := by + nontriviality α + rw [← pos_iff_ne_zero] + intro h + rw [← pow_one p] + apply (prime_pow_dvd_iff_le h0 hp).2 + simpa only + +theorem count_ne_zero_iff_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : + (Associates.mk p).count (Associates.mk a).factors ≠ 0 ↔ p ∣ a := by + nontriviality α + rw [← Associates.mk_le_mk_iff_dvd] + refine + ⟨fun h => + Associates.le_of_count_ne_zero (Associates.mk_ne_zero.mpr ha0) + (Associates.irreducible_mk.mpr hp) h, + fun h => ?_⟩ + rw [← pow_one (Associates.mk p), + Associates.prime_pow_dvd_iff_le (Associates.mk_ne_zero.mpr ha0) + (Associates.irreducible_mk.mpr hp)] at h + exact (zero_lt_one.trans_le h).ne' + +theorem count_self [Nontrivial α] {p : Associates α} + (hp : Irreducible p) : p.count p.factors = 1 := by + simp [factors_self hp, Associates.count_some hp] + +theorem count_eq_zero_of_ne {p q : Associates α} (hp : Irreducible p) + (hq : Irreducible q) (h : p ≠ q) : p.count q.factors = 0 := + not_ne_iff.mp fun h' ↦ h <| associated_iff_eq.mp <| hp.associated_of_dvd hq <| + le_of_count_ne_zero hq.ne_zero hp h' + +theorem count_mul {a : Associates α} (ha : a ≠ 0) {b : Associates α} + (hb : b ≠ 0) {p : Associates α} (hp : Irreducible p) : + count p (factors (a * b)) = count p a.factors + count p b.factors := by + obtain ⟨a0, nza, rfl⟩ := exists_non_zero_rep ha + obtain ⟨b0, nzb, rfl⟩ := exists_non_zero_rep hb + rw [factors_mul, factors_mk a0 nza, factors_mk b0 nzb, ← FactorSet.coe_add, count_some hp, + Multiset.count_add, count_some hp, count_some hp] + +theorem count_of_coprime {a : Associates α} (ha : a ≠ 0) + {b : Associates α} (hb : b ≠ 0) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {p : Associates α} + (hp : Irreducible p) : count p a.factors = 0 ∨ count p b.factors = 0 := by + rw [or_iff_not_imp_left, ← Ne] + intro hca + contrapose! hab with hcb + exact ⟨p, le_of_count_ne_zero ha hp hca, le_of_count_ne_zero hb hp hcb, + UniqueFactorizationMonoid.irreducible_iff_prime.mp hp⟩ + +theorem count_mul_of_coprime {a : Associates α} {b : Associates α} + (hb : b ≠ 0) {p : Associates α} (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) : + count p a.factors = 0 ∨ count p a.factors = count p (a * b).factors := by + by_cases ha : a = 0 + · simp [ha] + cases' count_of_coprime ha hb hab hp with hz hb0; · tauto + apply Or.intro_right + rw [count_mul ha hb hp, hb0, add_zero] + +theorem count_mul_of_coprime' {a b : Associates α} {p : Associates α} + (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) : + count p (a * b).factors = count p a.factors ∨ count p (a * b).factors = count p b.factors := by + by_cases ha : a = 0 + · simp [ha] + by_cases hb : b = 0 + · simp [hb] + rw [count_mul ha hb hp] + cases' count_of_coprime ha hb hab hp with ha0 hb0 + · apply Or.intro_right + rw [ha0, zero_add] + · apply Or.intro_left + rw [hb0, add_zero] + +theorem dvd_count_of_dvd_count_mul {a b : Associates α} (hb : b ≠ 0) + {p : Associates α} (hp : Irreducible p) (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {k : ℕ} + (habk : k ∣ count p (a * b).factors) : k ∣ count p a.factors := by + by_cases ha : a = 0 + · simpa [*] using habk + cases' count_of_coprime ha hb hab hp with hz h + · rw [hz] + exact dvd_zero k + · rw [count_mul ha hb hp, h] at habk + exact habk + +theorem count_pow [Nontrivial α] {a : Associates α} (ha : a ≠ 0) + {p : Associates α} (hp : Irreducible p) (k : ℕ) : + count p (a ^ k).factors = k * count p a.factors := by + induction' k with n h + · rw [pow_zero, factors_one, zero_mul, count_zero hp] + · rw [pow_succ', count_mul ha (pow_ne_zero _ ha) hp, h] + ring + +theorem dvd_count_pow [Nontrivial α] {a : Associates α} (ha : a ≠ 0) + {p : Associates α} (hp : Irreducible p) (k : ℕ) : k ∣ count p (a ^ k).factors := by + rw [count_pow ha hp] + apply dvd_mul_right + +theorem is_pow_of_dvd_count {a : Associates α} + (ha : a ≠ 0) {k : ℕ} (hk : ∀ p : Associates α, Irreducible p → k ∣ count p a.factors) : + ∃ b : Associates α, a = b ^ k := by + nontriviality α + obtain ⟨a0, hz, rfl⟩ := exists_non_zero_rep ha + rw [factors_mk a0 hz] at hk + have hk' : ∀ p, p ∈ factors' a0 → k ∣ (factors' a0).count p := by + rintro p - + have pp : p = ⟨p.val, p.2⟩ := by simp only [Subtype.coe_eta] + rw [pp, ← count_some p.2] + exact hk p.val p.2 + obtain ⟨u, hu⟩ := Multiset.exists_smul_of_dvd_count _ hk' + use FactorSet.prod (u : FactorSet α) + apply eq_of_factors_eq_factors + rw [pow_factors, prod_factors, factors_mk a0 hz, hu] + exact WithBot.coe_nsmul u k + +/-- The only divisors of prime powers are prime powers. See `eq_pow_find_of_dvd_irreducible_pow` +for an explicit expression as a p-power (without using `count`). -/ +theorem eq_pow_count_factors_of_dvd_pow {p a : Associates α} + (hp : Irreducible p) {n : ℕ} (h : a ∣ p ^ n) : a = p ^ p.count a.factors := by + nontriviality α + have hph := pow_ne_zero n hp.ne_zero + have ha := ne_zero_of_dvd_ne_zero hph h + apply eq_of_eq_counts ha (pow_ne_zero _ hp.ne_zero) + have eq_zero_of_ne : ∀ q : Associates α, Irreducible q → q ≠ p → _ = 0 := fun q hq h' => + Nat.eq_zero_of_le_zero <| by + convert count_le_count_of_le hph hq h + symm + rw [count_pow hp.ne_zero hq, count_eq_zero_of_ne hq hp h', mul_zero] + intro q hq + rw [count_pow hp.ne_zero hq] + by_cases h : q = p + · rw [h, count_self hp, mul_one] + · rw [count_eq_zero_of_ne hq hp h, mul_zero, eq_zero_of_ne q hq h] + +theorem count_factors_eq_find_of_dvd_pow {a p : Associates α} + (hp : Irreducible p) [∀ n : ℕ, Decidable (a ∣ p ^ n)] {n : ℕ} (h : a ∣ p ^ n) : + @Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩ = p.count a.factors := by + apply le_antisymm + · refine Nat.find_le ⟨1, ?_⟩ + rw [mul_one] + symm + exact eq_pow_count_factors_of_dvd_pow hp h + · have hph := pow_ne_zero (@Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩) hp.ne_zero + cases' subsingleton_or_nontrivial α with hα hα + · simp [eq_iff_true_of_subsingleton] at hph + convert count_le_count_of_le hph hp (@Nat.find_spec (fun n => a ∣ p ^ n) _ ⟨n, h⟩) + rw [count_pow hp.ne_zero hp, count_self hp, mul_one] + +end count + +theorem eq_pow_of_mul_eq_pow {a b c : Associates α} (ha : a ≠ 0) (hb : b ≠ 0) + (hab : ∀ d, d ∣ a → d ∣ b → ¬Prime d) {k : ℕ} (h : a * b = c ^ k) : + ∃ d : Associates α, a = d ^ k := by + classical + nontriviality α + by_cases hk0 : k = 0 + · use 1 + rw [hk0, pow_zero] at h ⊢ + apply (mul_eq_one.1 h).1 + · refine is_pow_of_dvd_count ha fun p hp ↦ ?_ + apply dvd_count_of_dvd_count_mul hb hp hab + rw [h] + apply dvd_count_pow _ hp + rintro rfl + rw [zero_pow hk0] at h + cases mul_eq_zero.mp h <;> contradiction + +/-- The only divisors of prime powers are prime powers. -/ +theorem eq_pow_find_of_dvd_irreducible_pow {a p : Associates α} (hp : Irreducible p) + [∀ n : ℕ, Decidable (a ∣ p ^ n)] {n : ℕ} (h : a ∣ p ^ n) : + a = p ^ @Nat.find (fun n => a ∣ p ^ n) _ ⟨n, h⟩ := by + classical rw [count_factors_eq_find_of_dvd_pow hp, ← eq_pow_count_factors_of_dvd_pow hp h] + exact h + +end Associates diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Finite.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Finite.lean new file mode 100644 index 00000000000000..bd5cd5c1e98194 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Finite.lean @@ -0,0 +1,53 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Finiteness of divisors + +## Main results +* `UniqueFactorizationMonoid.fintypeSubtypeDvd`: elements of a UFM with finitely many units have + finitely many divisors. +-/ + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +namespace UniqueFactorizationMonoid + +/-- If `y` is a nonzero element of a unique factorization monoid with finitely +many units (e.g. `ℤ`, `Ideal (ring_of_integers K)`), it has finitely many divisors. -/ +noncomputable def fintypeSubtypeDvd {M : Type*} [CancelCommMonoidWithZero M] + [UniqueFactorizationMonoid M] [Fintype Mˣ] (y : M) (hy : y ≠ 0) : Fintype { x // x ∣ y } := by + haveI : Nontrivial M := ⟨⟨y, 0, hy⟩⟩ + haveI : NormalizationMonoid M := UniqueFactorizationMonoid.normalizationMonoid + haveI := Classical.decEq M + haveI := Classical.decEq (Associates M) + -- 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, + Multiset.mem_toFinset, Multiset.mem_powerset, exists_eq_right, Multiset.mem_map] + constructor + · rintro ⟨s, hs, rfl⟩ + show (s.snd : M) * s.fst.prod ∣ y + rw [(unit_associated_one.mul_right s.fst.prod).dvd_iff_dvd_left, one_mul, + ← (normalizedFactors_prod hy).dvd_iff_dvd_right] + exact Multiset.prod_dvd_prod_of_le hs + · rintro (h : x ∣ y) + have hx : x ≠ 0 := by + refine mt (fun hx => ?_) hy + rwa [hx, zero_dvd_iff] at h + obtain ⟨u, hu⟩ := normalizedFactors_prod hx + refine ⟨⟨normalizedFactors x, u⟩, ?_, (mul_comm _ _).trans hu⟩ + exact (dvd_iff_normalizedFactors_le_normalizedFactors hx hy).mp h + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Finsupp.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Finsupp.lean new file mode 100644 index 00000000000000..a901b3c83b1a34 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Finsupp.lean @@ -0,0 +1,62 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Data.Finsupp.Multiset +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Factors as finsupp + +## Main definitions +* `UniqueFactorizationMonoid.factorization`: the multiset of irreducible factors as a `Finsupp`. +-/ + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +section Finsupp + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] +variable [NormalizationMonoid α] [DecidableEq α] + +open UniqueFactorizationMonoid + +/-- This returns the multiset of irreducible factors as a `Finsupp`. -/ +noncomputable def factorization (n : α) : α →₀ ℕ := + Multiset.toFinsupp (normalizedFactors n) + +theorem factorization_eq_count {n p : α} : + factorization n p = Multiset.count p (normalizedFactors n) := by simp [factorization] + +@[simp] +theorem factorization_zero : factorization (0 : α) = 0 := by simp [factorization] + +@[simp] +theorem factorization_one : factorization (1 : α) = 0 := by simp [factorization] + +/-- The support of `factorization n` is exactly the Finset of normalized factors -/ +@[simp] +theorem support_factorization {n : α} : + (factorization n).support = (normalizedFactors n).toFinset := by + simp [factorization, Multiset.toFinsupp_support] + +/-- For nonzero `a` and `b`, the power of `p` in `a * b` is the sum of the powers in `a` and `b` -/ +@[simp] +theorem factorization_mul {a b : α} (ha : a ≠ 0) (hb : b ≠ 0) : + factorization (a * b) = factorization a + factorization b := by + simp [factorization, normalizedFactors_mul ha hb] + +/-- For any `p`, the power of `p` in `x^n` is `n` times the power in `x` -/ +theorem factorization_pow {x : α} {n : ℕ} : factorization (x ^ n) = n • factorization x := by + ext + simp [factorization] + +theorem associated_of_factorization_eq (a b : α) (ha : a ≠ 0) (hb : b ≠ 0) + (h : factorization a = factorization b) : Associated a b := by + simp_rw [factorization, AddEquiv.apply_eq_iff_eq] at h + rwa [associated_iff_normalizedFactors_eq_normalizedFactors ha hb] + +end Finsupp diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/GCDMonoid.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/GCDMonoid.lean new file mode 100644 index 00000000000000..74940f8f2ed5fe --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/GCDMonoid.lean @@ -0,0 +1,73 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.RingTheory.UniqueFactorizationDomain.FactorSet +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Building GCD out of unique factorization + +## Main results +* `UniqueFactorizationMonoid.toGCDMonoid`: choose a GCD monoid structure given unique factorization. +-/ + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +section + +open Associates UniqueFactorizationMonoid + +/-- `toGCDMonoid` constructs a GCD monoid out of a unique factorization domain. -/ +noncomputable def UniqueFactorizationMonoid.toGCDMonoid (α : Type*) [CancelCommMonoidWithZero α] + [UniqueFactorizationMonoid α] : GCDMonoid α where + gcd a b := Quot.out (Associates.mk a ⊓ Associates.mk b : Associates α) + lcm a b := Quot.out (Associates.mk a ⊔ Associates.mk b : Associates α) + gcd_dvd_left a b := by + rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le] + exact inf_le_left + gcd_dvd_right a b := by + rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le] + exact inf_le_right + dvd_gcd {a b c} hac hab := by + rw [← mk_dvd_mk, Associates.quot_out, congr_fun₂ dvd_eq_le, le_inf_iff, + mk_le_mk_iff_dvd, mk_le_mk_iff_dvd] + exact ⟨hac, hab⟩ + lcm_zero_left a := by simp + lcm_zero_right a := by simp + gcd_mul_lcm a b := by + rw [← mk_eq_mk_iff_associated, ← Associates.mk_mul_mk, ← associated_iff_eq, Associates.quot_out, + Associates.quot_out, mul_comm, sup_mul_inf, Associates.mk_mul_mk] + +/-- `toNormalizedGCDMonoid` constructs a GCD monoid out of a normalization on a + unique factorization domain. -/ +noncomputable def UniqueFactorizationMonoid.toNormalizedGCDMonoid (α : Type*) + [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] [NormalizationMonoid α] : + NormalizedGCDMonoid α := + { ‹NormalizationMonoid α› with + gcd := fun a b => (Associates.mk a ⊓ Associates.mk b).out + lcm := fun a b => (Associates.mk a ⊔ Associates.mk b).out + gcd_dvd_left := fun a b => (out_dvd_iff a (Associates.mk a ⊓ Associates.mk b)).2 <| inf_le_left + gcd_dvd_right := fun a b => + (out_dvd_iff b (Associates.mk a ⊓ Associates.mk b)).2 <| inf_le_right + dvd_gcd := fun {a} {b} {c} hac hab => + show a ∣ (Associates.mk c ⊓ Associates.mk b).out by + rw [dvd_out_iff, le_inf_iff, mk_le_mk_iff_dvd, mk_le_mk_iff_dvd] + exact ⟨hac, hab⟩ + lcm_zero_left := fun a => show (⊤ ⊔ Associates.mk a).out = 0 by simp + lcm_zero_right := fun a => show (Associates.mk a ⊔ ⊤).out = 0 by simp + gcd_mul_lcm := fun a b => by + rw [← out_mul, mul_comm, sup_mul_inf, mk_mul_mk, out_mk] + exact normalize_associated (a * b) + normalize_gcd := fun a b => by apply normalize_out _ + normalize_lcm := fun a b => by apply normalize_out _ } + +instance (α) [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] : + Nonempty (NormalizedGCDMonoid α) := by + letI := UniqueFactorizationMonoid.normalizationMonoid (α := α) + classical exact ⟨UniqueFactorizationMonoid.toNormalizedGCDMonoid α⟩ + +end diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Ideal.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Ideal.lean new file mode 100644 index 00000000000000..76a9fb5c099410 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Ideal.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.RingTheory.Ideal.Operations +import Mathlib.RingTheory.UniqueFactorizationDomain.Defs + +/-! +# Unique factorization and ascending chain condition on ideals + +## Main results +* `Ideal.setOf_isPrincipal_wellFoundedOn_gt`, `WfDvdMonoid.of_setOf_isPrincipal_wellFoundedOn_gt` + in a domain, well-foundedness of the strict version of ∣ is equivalent to the ascending + chain condition on principal ideals. +-/ + +variable {α : Type*} + +open UniqueFactorizationMonoid in +/-- Every non-zero prime ideal in a unique factorization domain contains a prime element. -/ +theorem Ideal.IsPrime.exists_mem_prime_of_ne_bot {R : Type*} [CommSemiring R] [IsDomain R] + [UniqueFactorizationMonoid R] {I : Ideal R} (hI₂ : I.IsPrime) (hI : I ≠ ⊥) : + ∃ x ∈ I, Prime x := by + classical + obtain ⟨a : R, ha₁ : a ∈ I, ha₂ : a ≠ 0⟩ := Submodule.exists_mem_ne_zero_of_ne_bot hI + replace ha₁ : (factors a).prod ∈ I := by + obtain ⟨u : Rˣ, hu : (factors a).prod * u = a⟩ := factors_prod ha₂ + rwa [← hu, mul_unit_mem_iff_mem _ u.isUnit] at ha₁ + obtain ⟨p : R, hp₁ : p ∈ factors a, hp₂ : p ∈ I⟩ := + (hI₂.multiset_prod_mem_iff_exists_mem <| factors a).1 ha₁ + exact ⟨p, hp₂, prime_of_factor p hp₁⟩ + +section Ideal + +/-- The ascending chain condition on principal ideals holds in a `WfDvdMonoid` domain. -/ +lemma Ideal.setOf_isPrincipal_wellFoundedOn_gt [CommSemiring α] [WfDvdMonoid α] [IsDomain α] : + {I : Ideal α | I.IsPrincipal}.WellFoundedOn (· > ·) := by + have : {I : Ideal α | I.IsPrincipal} = ((fun a ↦ Ideal.span {a}) '' Set.univ) := by + ext + simp [Submodule.isPrincipal_iff, eq_comm] + rw [this, Set.wellFoundedOn_image, Set.wellFoundedOn_univ] + convert wellFounded_dvdNotUnit (α := α) + ext + exact Ideal.span_singleton_lt_span_singleton + +/-- The ascending chain condition on principal ideals in a domain is sufficient to prove that +the domain is `WfDvdMonoid`. -/ +lemma WfDvdMonoid.of_setOf_isPrincipal_wellFoundedOn_gt [CommSemiring α] [IsDomain α] + (h : {I : Ideal α | I.IsPrincipal}.WellFoundedOn (· > ·)) : + WfDvdMonoid α := by + have : WellFounded (α := {I : Ideal α // I.IsPrincipal}) (· > ·) := h + constructor + convert InvImage.wf (fun a => ⟨Ideal.span ({a} : Set α), _, rfl⟩) this + ext + exact Ideal.span_singleton_lt_span_singleton.symm + +end Ideal diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicative.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicative.lean new file mode 100644 index 00000000000000..a8a04d3a9ad0f0 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicative.lean @@ -0,0 +1,163 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Multiplicative maps on unique factorization domains + +## Main results +* `UniqueFactorizationMonoid.induction_on_coprime`: if `P` holds for `0`, units and powers of + primes, and `P x ∧ P y` for coprime `x, y` implies `P (x * y)`, then `P` holds on all `a : α`. +* `UniqueFactorizationMonoid.multiplicative_of_coprime`: if `f` maps `p ^ i` to `(f p) ^ i` for + primes `p`, and `f` is multiplicative on coprime elements, then `f` is multiplicative everywhere. +-/ + + +variable {α : Type*} + +namespace UniqueFactorizationMonoid + +variable {R : Type*} [CancelCommMonoidWithZero R] [UniqueFactorizationMonoid R] + +section Multiplicative + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] +variable {β : Type*} [CancelCommMonoidWithZero β] + +theorem prime_pow_coprime_prod_of_coprime_insert [DecidableEq α] {s : Finset α} (i : α → ℕ) (p : α) + (hps : p ∉ s) (is_prime : ∀ q ∈ insert p s, Prime q) + (is_coprime : ∀ᵉ (q ∈ insert p s) (q' ∈ insert p s), q ∣ q' → q = q') : + IsRelPrime (p ^ i p) (∏ p' ∈ s, p' ^ i p') := by + have hp := is_prime _ (Finset.mem_insert_self _ _) + refine (isRelPrime_iff_no_prime_factors <| pow_ne_zero _ hp.ne_zero).mpr ?_ + intro d hdp hdprod hd + apply hps + replace hdp := hd.dvd_of_dvd_pow hdp + obtain ⟨q, q_mem', hdq⟩ := hd.exists_mem_multiset_dvd hdprod + 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 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] +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)) + (hcp : ∀ {x y}, IsRelPrime x y → P x → P y → P (x * y)) : + P (∏ p ∈ s, p ^ i p) := by + letI := Classical.decEq α + induction' s using Finset.induction_on with p f' hpf' ih + · simpa using h1 isUnit_one + rw [Finset.prod_insert hpf'] + exact + hcp (prime_pow_coprime_prod_of_coprime_insert i p hpf' is_prime is_coprime) + (hpr (i p) (is_prime _ (Finset.mem_insert_self _ _))) + (ih (fun q hq => is_prime _ (Finset.mem_insert_of_mem hq)) fun q hq q' hq' => + is_coprime _ (Finset.mem_insert_of_mem hq) _ (Finset.mem_insert_of_mem hq')) + +/-- If `P` holds for `0`, units and powers of primes, +and `P x ∧ P y` for coprime `x, y` implies `P (x * y)`, +then `P` holds on all `a : α`. -/ +@[elab_as_elim] +theorem induction_on_coprime {P : α → Prop} (a : α) (h0 : P 0) (h1 : ∀ {x}, IsUnit x → P x) + (hpr : ∀ {p} (i : ℕ), Prime p → P (p ^ i)) + (hcp : ∀ {x y}, IsRelPrime x y → P x → P y → P (x * y)) : P a := by + letI := Classical.decEq α + have P_of_associated : ∀ {x y}, Associated x y → P x → P y := by + rintro x y ⟨u, rfl⟩ hx + exact hcp (fun p _ hpx => isUnit_of_dvd_unit hpx u.isUnit) hx (h1 u.isUnit) + by_cases ha0 : a = 0 + · rwa [ha0] + haveI : Nontrivial α := ⟨⟨_, _, ha0⟩⟩ + letI : NormalizationMonoid α := UniqueFactorizationMonoid.normalizationMonoid + refine P_of_associated (normalizedFactors_prod ha0) ?_ + rw [← (normalizedFactors a).map_id, Finset.prod_multiset_map_count] + refine induction_on_prime_power _ _ ?_ ?_ @h1 @hpr @hcp <;> simp only [Multiset.mem_toFinset] + · apply prime_of_normalized_factor + · apply normalizedFactors_eq_of_dvd + +/-- 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. -/ +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) + (hpr : ∀ {p} (i : ℕ), Prime p → f (p ^ i) = f p ^ i) + (hcp : ∀ {x y}, IsRelPrime x y → f (x * y) = f x * f y) : + f (∏ p ∈ s, p ^ (i p + j p)) = f (∏ p ∈ s, p ^ i p) * f (∏ p ∈ s, p ^ j p) := by + letI := Classical.decEq α + induction' s using Finset.induction_on with p s hps ih + · simpa using h1 isUnit_one + have hpr_p := is_prime _ (Finset.mem_insert_self _ _) + have hpr_s : ∀ p ∈ s, Prime p := fun p hp => is_prime _ (Finset.mem_insert_of_mem hp) + have hcp_p := fun i => prime_pow_coprime_prod_of_coprime_insert i p hps is_prime is_coprime + have hcp_s : ∀ᵉ (p ∈ s) (q ∈ s), p ∣ q → p = q := fun p hp q hq => + is_coprime p (Finset.mem_insert_of_mem hp) q (Finset.mem_insert_of_mem hq) + rw [Finset.prod_insert hps, Finset.prod_insert hps, Finset.prod_insert hps, hcp (hcp_p _), + hpr _ hpr_p, hcp (hcp_p _), hpr _ hpr_p, hcp (hcp_p (fun p => i p + j p)), hpr _ hpr_p, + ih hpr_s hcp_s, pow_add, mul_assoc, mul_left_comm (f p ^ j p), mul_assoc] + +/-- If `f` maps `p ^ i` to `(f p) ^ i` for primes `p`, and `f` +is multiplicative on coprime elements, then `f` is multiplicative everywhere. -/ +theorem multiplicative_of_coprime (f : α → β) (a b : α) (h0 : f 0 = 0) + (h1 : ∀ {x y}, IsUnit y → f (x * y) = f x * f y) + (hpr : ∀ {p} (i : ℕ), Prime p → f (p ^ i) = f p ^ i) + (hcp : ∀ {x y}, IsRelPrime x y → f (x * y) = f x * f y) : + f (a * b) = f a * f b := by + letI := Classical.decEq α + by_cases ha0 : a = 0 + · rw [ha0, zero_mul, h0, zero_mul] + by_cases hb0 : b = 0 + · rw [hb0, mul_zero, h0, mul_zero] + by_cases hf1 : f 1 = 0 + · calc + f (a * b) = f (a * b * 1) := by rw [mul_one] + _ = 0 := by simp only [h1 isUnit_one, hf1, mul_zero] + _ = f a * f (b * 1) := by simp only [h1 isUnit_one, hf1, mul_zero] + _ = f a * f b := by rw [mul_one] + haveI : Nontrivial α := ⟨⟨_, _, ha0⟩⟩ + letI : NormalizationMonoid α := UniqueFactorizationMonoid.normalizationMonoid + suffices + f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, + p ^ ((normalizedFactors a).count p + (normalizedFactors b).count p)) = + f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, + p ^ (normalizedFactors a).count p) * + f (∏ p ∈ (normalizedFactors a).toFinset ∪ (normalizedFactors b).toFinset, + p ^ (normalizedFactors b).count p) by + obtain ⟨ua, a_eq⟩ := normalizedFactors_prod ha0 + obtain ⟨ub, b_eq⟩ := normalizedFactors_prod hb0 + rw [← a_eq, ← b_eq, mul_right_comm (Multiset.prod (normalizedFactors a)) ua + (Multiset.prod (normalizedFactors b) * ub), h1 ua.isUnit, h1 ub.isUnit, h1 ua.isUnit, ← + mul_assoc, h1 ub.isUnit, mul_right_comm _ (f ua), ← mul_assoc] + congr + rw [← (normalizedFactors a).map_id, ← (normalizedFactors b).map_id, + Finset.prod_multiset_map_count, Finset.prod_multiset_map_count, + Finset.prod_subset (Finset.subset_union_left (s₂ := (normalizedFactors b).toFinset)), + Finset.prod_subset (Finset.subset_union_right (s₂ := (normalizedFactors b).toFinset)), ← + Finset.prod_mul_distrib] + · simp_rw [id, ← pow_add, this] + all_goals simp only [Multiset.mem_toFinset] + · intro p _ hpb + simp [hpb] + · intro p _ hpa + simp [hpa] + refine multiplicative_prime_power _ _ _ ?_ ?_ @h1 @hpr @hcp + all_goals simp only [Multiset.mem_toFinset, Finset.mem_union] + · rintro p (hpa | hpb) <;> apply prime_of_normalized_factor <;> assumption + · rintro p (hp | hp) q (hq | hq) hdvd <;> + rw [← normalize_normalized_factor _ hp, ← normalize_normalized_factor _ hq] <;> + exact + normalize_eq_normalize hdvd + ((prime_of_normalized_factor _ hp).irreducible.dvd_symm + (prime_of_normalized_factor _ hq).irreducible hdvd) + +end Multiplicative + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean new file mode 100644 index 00000000000000..dbc52cb56fad12 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean @@ -0,0 +1,126 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.RingTheory.Multiplicity +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Unique factorization and multiplicity + +## Main results + +* `UniqueFactorizationMonoid.emultiplicity_eq_count_normalizedFactors`: The multiplicity of an + irreducible factor of a nonzero element is exactly the number of times the normalized factor + occurs in the `normalizedFactors`. +-/ + + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +theorem WfDvdMonoid.max_power_factor' [CommMonoidWithZero α] [WfDvdMonoid α] {a₀ x : α} + (h : a₀ ≠ 0) (hx : ¬IsUnit x) : ∃ (n : ℕ) (a : α), ¬x ∣ a ∧ a₀ = x ^ n * a := by + obtain ⟨a, ⟨n, rfl⟩, hm⟩ := wellFounded_dvdNotUnit.has_min + {a | ∃ n, x ^ n * a = a₀} ⟨a₀, 0, by rw [pow_zero, one_mul]⟩ + refine ⟨n, a, ?_, rfl⟩; rintro ⟨d, rfl⟩ + exact hm d ⟨n + 1, by rw [pow_succ, mul_assoc]⟩ + ⟨(right_ne_zero_of_mul <| right_ne_zero_of_mul h), x, hx, mul_comm _ _⟩ + +theorem WfDvdMonoid.max_power_factor [CommMonoidWithZero α] [WfDvdMonoid α] {a₀ x : α} + (h : a₀ ≠ 0) (hx : Irreducible x) : ∃ (n : ℕ) (a : α), ¬x ∣ a ∧ a₀ = x ^ n * a := + max_power_factor' h hx.not_unit + +theorem multiplicity.finite_of_not_isUnit [CancelCommMonoidWithZero α] [WfDvdMonoid α] + {a b : α} (ha : ¬IsUnit a) (hb : b ≠ 0) : multiplicity.Finite a b := by + obtain ⟨n, c, ndvd, rfl⟩ := WfDvdMonoid.max_power_factor' hb ha + exact ⟨n, by rwa [pow_succ, mul_dvd_mul_iff_left (left_ne_zero_of_mul hb)]⟩ + +namespace UniqueFactorizationMonoid + +variable {R : Type*} [CancelCommMonoidWithZero R] [UniqueFactorizationMonoid R] + +section multiplicity + +variable [NormalizationMonoid R] + +open Multiset + +section + +theorem le_emultiplicity_iff_replicate_le_normalizedFactors {a b : R} {n : ℕ} (ha : Irreducible a) + (hb : b ≠ 0) : + ↑n ≤ emultiplicity a b ↔ replicate n (normalize a) ≤ normalizedFactors b := by + rw [← pow_dvd_iff_le_emultiplicity] + revert b + induction' n with n ih; · simp + intro b hb + constructor + · rintro ⟨c, rfl⟩ + rw [Ne, pow_succ', mul_assoc, mul_eq_zero, not_or] at hb + rw [pow_succ', mul_assoc, normalizedFactors_mul hb.1 hb.2, replicate_succ, + normalizedFactors_irreducible ha, singleton_add, cons_le_cons_iff, ← ih hb.2] + apply Dvd.intro _ rfl + · rw [Multiset.le_iff_exists_add] + rintro ⟨u, hu⟩ + rw [← (normalizedFactors_prod hb).dvd_iff_dvd_right, hu, prod_add, prod_replicate] + exact (Associated.pow_pow <| associated_normalize a).dvd.trans (Dvd.intro u.prod rfl) + +/-- The multiplicity of an irreducible factor of a nonzero element is exactly the number of times +the normalized factor occurs in the `normalizedFactors`. + +See also `count_normalizedFactors_eq` which expands the definition of `multiplicity` +to produce a specification for `count (normalizedFactors _) _`.. +-/ +theorem emultiplicity_eq_count_normalizedFactors [DecidableEq R] {a b : R} (ha : Irreducible a) + (hb : b ≠ 0) : emultiplicity a b = (normalizedFactors b).count (normalize a) := by + apply le_antisymm + · apply Order.le_of_lt_add_one + rw [← Nat.cast_one, ← Nat.cast_add, lt_iff_not_ge, ge_iff_le, + le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] + simp + rw [le_emultiplicity_iff_replicate_le_normalizedFactors ha hb, ← le_count_iff_replicate_le] + +end + +/-- The number of times an irreducible factor `p` appears in `normalizedFactors x` is defined by +the number of times it divides `x`. + +See also `multiplicity_eq_count_normalizedFactors` if `n` is given by `multiplicity p x`. +-/ +theorem count_normalizedFactors_eq [DecidableEq R] {p x : R} (hp : Irreducible p) + (hnorm : normalize p = p) {n : ℕ} (hle : p ^ n ∣ x) (hlt : ¬p ^ (n + 1) ∣ x) : + (normalizedFactors x).count p = n := by classical + by_cases hx0 : x = 0 + · simp [hx0] at hlt + apply Nat.cast_injective (R := ℕ∞) + convert (emultiplicity_eq_count_normalizedFactors hp hx0).symm + · exact hnorm.symm + exact (emultiplicity_eq_coe.mpr ⟨hle, hlt⟩).symm + +/-- The number of times an irreducible factor `p` appears in `normalizedFactors x` is defined by +the number of times it divides `x`. This is a slightly more general version of +`UniqueFactorizationMonoid.count_normalizedFactors_eq` that allows `p = 0`. + +See also `multiplicity_eq_count_normalizedFactors` if `n` is given by `multiplicity p x`. +-/ +theorem count_normalizedFactors_eq' [DecidableEq R] {p x : R} (hp : p = 0 ∨ Irreducible p) + (hnorm : normalize p = p) {n : ℕ} (hle : p ^ n ∣ x) (hlt : ¬p ^ (n + 1) ∣ x) : + (normalizedFactors x).count p = n := by + rcases hp with (rfl | hp) + · cases n + · exact count_eq_zero.2 (zero_not_mem_normalizedFactors _) + · rw [zero_pow (Nat.succ_ne_zero _)] at hle hlt + exact absurd hle hlt + · exact count_normalizedFactors_eq hp hnorm hle hlt + +end multiplicity + +/-- Deprecated. Use `WfDvdMonoid.max_power_factor` instead. -/ +@[deprecated WfDvdMonoid.max_power_factor (since := "2024-03-01")] +theorem max_power_factor {a₀ x : R} (h : a₀ ≠ 0) (hx : Irreducible x) : + ∃ n : ℕ, ∃ a : R, ¬x ∣ a ∧ a₀ = x ^ n * a := WfDvdMonoid.max_power_factor h hx + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean new file mode 100644 index 00000000000000..4c69bfb655b75c --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean @@ -0,0 +1,60 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Data.ENat.Basic +import Mathlib.Data.Nat.Factors +import Mathlib.RingTheory.UniqueFactorizationDomain.NormalizedFactors + +/-! +# Unique factorization of natural numbers + +## Main definitions + +* `Nat.instUniqueFactorizationMonoid`: the natural numbers have unique factorization +-/ + +namespace Nat + +instance instWfDvdMonoid : WfDvdMonoid ℕ where + wf := by + refine RelHomClass.wellFounded + (⟨fun x : ℕ => if x = 0 then (⊤ : ℕ∞) else x, ?_⟩ : DvdNotUnit →r (· < ·)) wellFounded_lt + intro a b h + cases' a with a + · exfalso + revert h + simp [DvdNotUnit] + cases b + · simpa [succ_ne_zero] using WithTop.coe_lt_top (a + 1) + cases' dvd_and_not_dvd_iff.2 h with h1 h2 + simp only [succ_ne_zero, cast_lt, if_false] + refine lt_of_le_of_ne (Nat.le_of_dvd (Nat.succ_pos _) h1) fun con => h2 ?_ + rw [con] + +instance instUniqueFactorizationMonoid : UniqueFactorizationMonoid ℕ where + irreducible_iff_prime := Nat.irreducible_iff_prime + +open UniqueFactorizationMonoid + +lemma factors_eq : ∀ n : ℕ, normalizedFactors n = n.primeFactorsList + | 0 => by simp + | n + 1 => by + rw [← Multiset.rel_eq, ← associated_eq_eq] + apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor _ + · rw [Multiset.prod_coe, Nat.prod_primeFactorsList n.succ_ne_zero] + exact normalizedFactors_prod n.succ_ne_zero + · intro x hx + rw [Nat.irreducible_iff_prime, ← Nat.prime_iff] + exact Nat.prime_of_mem_primeFactorsList hx + +lemma factors_multiset_prod_of_irreducible {s : Multiset ℕ} (h : ∀ x : ℕ, x ∈ s → Irreducible x) : + normalizedFactors s.prod = s := by + rw [← Multiset.rel_eq, ← associated_eq_eq] + apply UniqueFactorizationMonoid.factors_unique irreducible_of_normalized_factor h + (normalizedFactors_prod _) + rw [Ne, Multiset.prod_eq_zero_iff] + exact fun con ↦ not_irreducible_zero (h 0 con) + +end Nat diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean new file mode 100644 index 00000000000000..3d30df0c3b8137 --- /dev/null +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean @@ -0,0 +1,329 @@ +/- +Copyright (c) 2018 Johannes Hölzl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson +-/ +import Mathlib.Algebra.GCDMonoid.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic + +/-! +# Unique factorization and normalization + +## Main definitions +* `UniqueFactorizationMonoid.normalizedFactors`: choose a multiset of prime factors that are unique + by normalizing them. +* `UniqueFactorizationMonoid.normalizationMonoid`: choose a way of normalizing the elements of a UFM +-/ + + +variable {α : Type*} + +local infixl:50 " ~ᵤ " => Associated + +namespace UniqueFactorizationMonoid + +variable [CancelCommMonoidWithZero α] [NormalizationMonoid α] +variable [UniqueFactorizationMonoid α] + +/-- Noncomputably determines the multiset of prime factors. -/ +noncomputable def normalizedFactors (a : α) : Multiset α := + Multiset.map normalize <| factors a + +/-- An arbitrary choice of factors of `x : M` is exactly the (unique) normalized set of factors, +if `M` has a trivial group of units. -/ +@[simp] +theorem factors_eq_normalizedFactors {M : Type*} [CancelCommMonoidWithZero M] + [UniqueFactorizationMonoid M] [Subsingleton Mˣ] (x : M) : factors x = normalizedFactors x := by + unfold normalizedFactors + convert (Multiset.map_id (factors x)).symm + ext p + exact normalize_eq p + +theorem normalizedFactors_prod {a : α} (ane0 : a ≠ 0) : + Associated (normalizedFactors a).prod a := by + rw [normalizedFactors, factors, dif_neg ane0] + refine Associated.trans ?_ (Classical.choose_spec (exists_prime_factors a ane0)).2 + rw [← Associates.mk_eq_mk_iff_associated, ← Associates.prod_mk, ← Associates.prod_mk, + Multiset.map_map] + congr 2 + ext + rw [Function.comp_apply, Associates.mk_normalize] + +theorem prime_of_normalized_factor {a : α} : ∀ x : α, x ∈ normalizedFactors a → Prime x := by + rw [normalizedFactors, factors] + split_ifs with ane0; · simp + intro x hx; rcases Multiset.mem_map.1 hx with ⟨y, ⟨hy, rfl⟩⟩ + rw [(normalize_associated _).prime_iff] + exact (Classical.choose_spec (UniqueFactorizationMonoid.exists_prime_factors a ane0)).1 y hy + +theorem irreducible_of_normalized_factor {a : α} : + ∀ x : α, x ∈ normalizedFactors a → Irreducible x := fun x h => + (prime_of_normalized_factor x h).irreducible + +theorem normalize_normalized_factor {a : α} : + ∀ x : α, x ∈ normalizedFactors a → normalize x = x := by + rw [normalizedFactors, factors] + split_ifs with h; · simp + intro x hx + obtain ⟨y, _, rfl⟩ := Multiset.mem_map.1 hx + apply normalize_idem + +theorem normalizedFactors_irreducible {a : α} (ha : Irreducible a) : + normalizedFactors a = {normalize a} := by + obtain ⟨p, a_assoc, hp⟩ := + prime_factors_irreducible ha ⟨prime_of_normalized_factor, normalizedFactors_prod ha.ne_zero⟩ + have p_mem : p ∈ normalizedFactors a := by + rw [hp] + exact Multiset.mem_singleton_self _ + convert hp + rwa [← normalize_normalized_factor p p_mem, normalize_eq_normalize_iff, dvd_dvd_iff_associated] + +theorem normalizedFactors_eq_of_dvd (a : α) : + ∀ᵉ (p ∈ normalizedFactors a) (q ∈ normalizedFactors a), p ∣ q → p = q := by + intro p hp q hq hdvd + convert normalize_eq_normalize hdvd + ((prime_of_normalized_factor _ hp).irreducible.dvd_symm + (prime_of_normalized_factor _ hq).irreducible hdvd) <;> + apply (normalize_normalized_factor _ ‹_›).symm + +theorem exists_mem_normalizedFactors_of_dvd {a p : α} (ha0 : a ≠ 0) (hp : Irreducible p) : + p ∣ a → ∃ q ∈ normalizedFactors a, p ~ᵤ q := fun ⟨b, hb⟩ => + have hb0 : b ≠ 0 := fun hb0 => by simp_all + have : Multiset.Rel Associated (p ::ₘ normalizedFactors b) (normalizedFactors a) := + factors_unique + (fun _ hx => + (Multiset.mem_cons.1 hx).elim (fun h => h.symm ▸ hp) (irreducible_of_normalized_factor _)) + irreducible_of_normalized_factor + (Associated.symm <| + calc + Multiset.prod (normalizedFactors a) ~ᵤ a := normalizedFactors_prod ha0 + _ = p * b := hb + _ ~ᵤ Multiset.prod (p ::ₘ normalizedFactors b) := by + rw [Multiset.prod_cons] + exact (normalizedFactors_prod hb0).symm.mul_left _ + ) + Multiset.exists_mem_of_rel_of_mem this (by simp) + +theorem exists_mem_normalizedFactors {x : α} (hx : x ≠ 0) (h : ¬IsUnit x) : + ∃ p, p ∈ normalizedFactors x := by + obtain ⟨p', hp', hp'x⟩ := WfDvdMonoid.exists_irreducible_factor h hx + obtain ⟨p, hp, _⟩ := exists_mem_normalizedFactors_of_dvd hx hp' hp'x + exact ⟨p, hp⟩ + +@[simp] +theorem normalizedFactors_zero : normalizedFactors (0 : α) = 0 := by + simp [normalizedFactors, factors] + +@[simp] +theorem normalizedFactors_one : normalizedFactors (1 : α) = 0 := by + cases' subsingleton_or_nontrivial α with h h + · dsimp [normalizedFactors, factors] + simp [Subsingleton.elim (1 : α) 0] + · rw [← Multiset.rel_zero_right] + apply factors_unique irreducible_of_normalized_factor + · intro x hx + exfalso + apply Multiset.not_mem_zero x hx + · apply normalizedFactors_prod one_ne_zero + +@[simp] +theorem normalizedFactors_mul {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : + normalizedFactors (x * y) = normalizedFactors x + normalizedFactors y := by + have h : (normalize : α → α) = Associates.out ∘ Associates.mk := by + ext + rw [Function.comp_apply, Associates.out_mk] + rw [← Multiset.map_id' (normalizedFactors (x * y)), ← Multiset.map_id' (normalizedFactors x), ← + Multiset.map_id' (normalizedFactors y), ← Multiset.map_congr rfl normalize_normalized_factor, ← + Multiset.map_congr rfl normalize_normalized_factor, ← + Multiset.map_congr rfl normalize_normalized_factor, ← Multiset.map_add, h, ← + Multiset.map_map Associates.out, eq_comm, ← Multiset.map_map Associates.out] + refine congr rfl ?_ + apply Multiset.map_mk_eq_map_mk_of_rel + apply factors_unique + · intro x hx + rcases Multiset.mem_add.1 hx with (hx | hx) <;> exact irreducible_of_normalized_factor x hx + · exact irreducible_of_normalized_factor + · rw [Multiset.prod_add] + exact + ((normalizedFactors_prod hx).mul_mul (normalizedFactors_prod hy)).trans + (normalizedFactors_prod (mul_ne_zero hx hy)).symm + +@[simp] +theorem normalizedFactors_pow {x : α} (n : ℕ) : + normalizedFactors (x ^ n) = n • normalizedFactors x := by + induction' n with n ih + · simp + by_cases h0 : x = 0 + · simp [h0, zero_pow n.succ_ne_zero, smul_zero] + rw [pow_succ', succ_nsmul', normalizedFactors_mul h0 (pow_ne_zero _ h0), ih] + +theorem _root_.Irreducible.normalizedFactors_pow {p : α} (hp : Irreducible p) (k : ℕ) : + normalizedFactors (p ^ k) = Multiset.replicate k (normalize p) := by + rw [UniqueFactorizationMonoid.normalizedFactors_pow, normalizedFactors_irreducible hp, + Multiset.nsmul_singleton] + +theorem normalizedFactors_prod_eq (s : Multiset α) (hs : ∀ a ∈ s, Irreducible a) : + normalizedFactors s.prod = s.map normalize := by + induction' s using Multiset.induction with a s ih + · rw [Multiset.prod_zero, normalizedFactors_one, Multiset.map_zero] + · have ia := hs a (Multiset.mem_cons_self a _) + have ib := fun b h => hs b (Multiset.mem_cons_of_mem h) + obtain rfl | ⟨b, hb⟩ := s.empty_or_exists_mem + · rw [Multiset.cons_zero, Multiset.prod_singleton, Multiset.map_singleton, + normalizedFactors_irreducible ia] + haveI := nontrivial_of_ne b 0 (ib b hb).ne_zero + rw [Multiset.prod_cons, Multiset.map_cons, + normalizedFactors_mul ia.ne_zero (Multiset.prod_ne_zero fun h => (ib 0 h).ne_zero rfl), + normalizedFactors_irreducible ia, ih ib, Multiset.singleton_add] + +theorem dvd_iff_normalizedFactors_le_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : + x ∣ y ↔ normalizedFactors x ≤ normalizedFactors y := by + constructor + · rintro ⟨c, rfl⟩ + simp [hx, right_ne_zero_of_mul hy] + · rw [← (normalizedFactors_prod hx).dvd_iff_dvd_left, ← + (normalizedFactors_prod hy).dvd_iff_dvd_right] + apply Multiset.prod_dvd_prod_of_le + +theorem _root_.Associated.normalizedFactors_eq {a b : α} (h : Associated a b) : + normalizedFactors a = normalizedFactors b := by + unfold normalizedFactors + have h' : ⇑(normalize (α := α)) = Associates.out ∘ Associates.mk := funext Associates.out_mk + rw [h', ← Multiset.map_map, ← Multiset.map_map, + Associates.rel_associated_iff_map_eq_map.mp (factors_rel_of_associated h)] + +theorem associated_iff_normalizedFactors_eq_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : + x ~ᵤ y ↔ normalizedFactors x = normalizedFactors y := + ⟨Associated.normalizedFactors_eq, fun h => + (normalizedFactors_prod hx).symm.trans (_root_.trans (by rw [h]) (normalizedFactors_prod hy))⟩ + +theorem normalizedFactors_of_irreducible_pow {p : α} (hp : Irreducible p) (k : ℕ) : + normalizedFactors (p ^ k) = Multiset.replicate k (normalize p) := by + rw [normalizedFactors_pow, normalizedFactors_irreducible hp, Multiset.nsmul_singleton] + +theorem zero_not_mem_normalizedFactors (x : α) : (0 : α) ∉ normalizedFactors x := fun h => + Prime.ne_zero (prime_of_normalized_factor _ h) rfl + +theorem dvd_of_mem_normalizedFactors {a p : α} (H : p ∈ normalizedFactors a) : p ∣ a := by + by_cases hcases : a = 0 + · rw [hcases] + exact dvd_zero p + · exact dvd_trans (Multiset.dvd_prod H) (Associated.dvd (normalizedFactors_prod hcases)) + +theorem mem_normalizedFactors_iff [Subsingleton αˣ] {p x : α} (hx : x ≠ 0) : + p ∈ normalizedFactors x ↔ Prime p ∧ p ∣ x := by + constructor + · intro h + exact ⟨prime_of_normalized_factor p h, dvd_of_mem_normalizedFactors h⟩ + · rintro ⟨hprime, hdvd⟩ + obtain ⟨q, hqmem, hqeq⟩ := exists_mem_normalizedFactors_of_dvd hx hprime.irreducible hdvd + rw [associated_iff_eq] at hqeq + exact hqeq ▸ hqmem + +theorem exists_associated_prime_pow_of_unique_normalized_factor {p r : α} + (h : ∀ {m}, m ∈ normalizedFactors r → m = p) (hr : r ≠ 0) : ∃ i : ℕ, Associated (p ^ i) r := by + use Multiset.card.toFun (normalizedFactors r) + have := UniqueFactorizationMonoid.normalizedFactors_prod hr + rwa [Multiset.eq_replicate_of_mem fun b => h, Multiset.prod_replicate] at this + +theorem normalizedFactors_prod_of_prime [Subsingleton αˣ] {m : Multiset α} + (h : ∀ p ∈ m, Prime p) : normalizedFactors m.prod = m := by + 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 + rw [← normalize_normalized_factor a ha, ← normalize_normalized_factor b hb, + normalize_eq_normalize_iff] + exact Associated.dvd_dvd h + +@[simp] +theorem normalizedFactors_pos (x : α) (hx : x ≠ 0) : 0 < normalizedFactors x ↔ ¬IsUnit x := by + constructor + · intro h hx + obtain ⟨p, hp⟩ := Multiset.exists_mem_of_ne_zero h.ne' + exact + (prime_of_normalized_factor _ hp).not_unit + (isUnit_of_dvd_unit (dvd_of_mem_normalizedFactors hp) hx) + · intro h + obtain ⟨p, hp⟩ := exists_mem_normalizedFactors hx h + exact + bot_lt_iff_ne_bot.mpr + (mt Multiset.eq_zero_iff_forall_not_mem.mp (not_forall.mpr ⟨p, not_not.mpr hp⟩)) + +theorem dvdNotUnit_iff_normalizedFactors_lt_normalizedFactors {x y : α} (hx : x ≠ 0) (hy : y ≠ 0) : + DvdNotUnit x y ↔ normalizedFactors x < normalizedFactors y := by + constructor + · rintro ⟨_, c, hc, rfl⟩ + simp only [hx, right_ne_zero_of_mul hy, normalizedFactors_mul, Ne, not_false_iff, + lt_add_iff_pos_right, normalizedFactors_pos, hc] + · intro h + exact + dvdNotUnit_of_dvd_of_not_dvd + ((dvd_iff_normalizedFactors_le_normalizedFactors hx hy).mpr h.le) + (mt (dvd_iff_normalizedFactors_le_normalizedFactors hy hx).mp h.not_le) + +theorem normalizedFactors_multiset_prod (s : Multiset α) (hs : 0 ∉ s) : + normalizedFactors (s.prod) = (s.map normalizedFactors).sum := by + cases subsingleton_or_nontrivial α + · obtain rfl : s = 0 := by + apply Multiset.eq_zero_of_forall_not_mem + intro _ + convert hs + simp + induction s using Multiset.induction with + | empty => simp + | cons _ _ IH => + rw [Multiset.prod_cons, Multiset.map_cons, Multiset.sum_cons, normalizedFactors_mul, IH] + · exact fun h ↦ hs (Multiset.mem_cons_of_mem h) + · exact fun h ↦ hs (h ▸ Multiset.mem_cons_self _ _) + · apply Multiset.prod_ne_zero + exact fun h ↦ hs (Multiset.mem_cons_of_mem h) + +end UniqueFactorizationMonoid + +namespace UniqueFactorizationMonoid + +open scoped Classical + +open Multiset Associates + +variable [CancelCommMonoidWithZero α] [UniqueFactorizationMonoid α] + +/-- Noncomputably defines a `normalizationMonoid` structure on a `UniqueFactorizationMonoid`. -/ +protected noncomputable def normalizationMonoid : NormalizationMonoid α := + normalizationMonoidOfMonoidHomRightInverse + { toFun := fun a : Associates α => + if a = 0 then 0 + else + ((normalizedFactors a).map + (Classical.choose mk_surjective.hasRightInverse : Associates α → α)).prod + map_one' := by nontriviality α; simp + map_mul' := fun x y => by + by_cases hx : x = 0 + · simp [hx] + by_cases hy : y = 0 + · simp [hy] + simp [hx, hy] } + (by + intro x + dsimp + by_cases hx : x = 0 + · simp [hx] + have h : Associates.mkMonoidHom ∘ Classical.choose mk_surjective.hasRightInverse = + (id : Associates α → Associates α) := by + ext x + rw [Function.comp_apply, mkMonoidHom_apply, + Classical.choose_spec mk_surjective.hasRightInverse x] + rfl + rw [if_neg hx, ← mkMonoidHom_apply, MonoidHom.map_multiset_prod, map_map, h, map_id, ← + associated_iff_eq] + apply normalizedFactors_prod hx) + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/Valuation/Basic.lean b/Mathlib/RingTheory/Valuation/Basic.lean index e4f462f1385001..fe79b5797d6c9b 100644 --- a/Mathlib/RingTheory/Valuation/Basic.lean +++ b/Mathlib/RingTheory/Valuation/Basic.lean @@ -128,7 +128,7 @@ theorem coe_mk (f : R →*₀ Γ₀) (h) : ⇑(Valuation.mk f h) = f := rfl theorem toFun_eq_coe (v : Valuation R Γ₀) : v.toFun = v := rfl -@[simp] -- Porting note: requested by simpNF as toFun_eq_coe LHS simplifies +@[simp] theorem toMonoidWithZeroHom_coe_eq_coe (v : Valuation R Γ₀) : (v.toMonoidWithZeroHom : R → Γ₀) = v := rfl diff --git a/Mathlib/RingTheory/Valuation/Integral.lean b/Mathlib/RingTheory/Valuation/Integral.lean index c8e1a11e3d9703..515de9eca405b5 100644 --- a/Mathlib/RingTheory/Valuation/Integral.lean +++ b/Mathlib/RingTheory/Valuation/Integral.lean @@ -37,7 +37,7 @@ theorem mem_of_integral {x : R} (hx : IsIntegral O x) : x ∈ v.integer := rw [eval₂_mul, eval₂_pow, eval₂_C, eval₂_X, v.map_mul, v.map_pow, ← one_mul (v x ^ p.natDegree)] cases' (hv.2 <| p.coeff i).lt_or_eq with hvpi hvpi - · exact mul_lt_mul₀ hvpi (pow_lt_pow_right₀ hvx <| Finset.mem_range.1 hi) + · exact mul_lt_mul'' hvpi (pow_lt_pow_right₀ hvx <| Finset.mem_range.1 hi) zero_le' zero_le' · rw [hvpi, one_mul, one_mul]; exact pow_lt_pow_right₀ hvx (Finset.mem_range.1 hi) protected theorem integralClosure : integralClosure O R = ⊥ := diff --git a/Mathlib/RingTheory/Valuation/ValuationSubring.lean b/Mathlib/RingTheory/Valuation/ValuationSubring.lean index a5ea654a7ca327..813f07bdbde315 100644 --- a/Mathlib/RingTheory/Valuation/ValuationSubring.lean +++ b/Mathlib/RingTheory/Valuation/ValuationSubring.lean @@ -50,9 +50,6 @@ instance : SetLike (ValuationSubring K) K where replace h := SetLike.coe_injective' h congr --- Porting note https://github.com/leanprover-community/mathlib4/issues/10959 --- simp cannot prove this -@[simp, nolint simpNF] theorem mem_carrier (x : K) : x ∈ A.carrier ↔ x ∈ A := Iff.refl _ @[simp] @@ -480,7 +477,8 @@ section nonunits def nonunits : Subsemigroup K where carrier := {x | A.valuation x < 1} -- Porting note: added `Set.mem_setOf.mp` - mul_mem' ha hb := (mul_lt_mul₀ (Set.mem_setOf.mp ha) (Set.mem_setOf.mp hb)).trans_eq <| mul_one _ + mul_mem' ha hb := (mul_lt_mul'' (Set.mem_setOf.mp ha) (Set.mem_setOf.mp hb) + zero_le' zero_le').trans_eq <| mul_one _ theorem mem_nonunits_iff {x : K} : x ∈ A.nonunits ↔ A.valuation x < 1 := Iff.rfl @@ -667,9 +665,9 @@ def unitsModPrincipalUnitsEquivResidueFieldUnits : local instance : MulOneClass ({ x // x ∈ unitGroup A } ⧸ Subgroup.comap (Subgroup.subtype (unitGroup A)) (principalUnitGroup A)) := inferInstance --- @[simp] -- Porting note: not in simpNF theorem unitsModPrincipalUnitsEquivResidueFieldUnits_comp_quotientGroup_mk : - A.unitsModPrincipalUnitsEquivResidueFieldUnits.toMonoidHom.comp (QuotientGroup.mk' _) = + (A.unitsModPrincipalUnitsEquivResidueFieldUnits : _ ⧸ Subgroup.comap _ _ →* _).comp + (QuotientGroup.mk' (A.principalUnitGroup.subgroupOf A.unitGroup)) = A.unitGroupToResidueFieldUnits := rfl theorem unitsModPrincipalUnitsEquivResidueFieldUnits_comp_quotientGroup_mk_apply @@ -792,7 +790,6 @@ namespace Valuation variable {Γ : Type*} [LinearOrderedCommGroupWithZero Γ] (v : Valuation K Γ) (x : Kˣ) --- @[simp] -- Porting note: not in simpNF theorem mem_unitGroup_iff : x ∈ v.valuationSubring.unitGroup ↔ v x = 1 := IsEquiv.eq_one_iff_eq_one (Valuation.isEquiv_valuation_valuationSubring _).symm diff --git a/Mathlib/SetTheory/Cardinal/Aleph.lean b/Mathlib/SetTheory/Cardinal/Aleph.lean index 3970c6fc6cb576..ca79284dac29a0 100644 --- a/Mathlib/SetTheory/Cardinal/Aleph.lean +++ b/Mathlib/SetTheory/Cardinal/Aleph.lean @@ -541,7 +541,7 @@ def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := def alephIdx : Cardinal → Ordinal := aleph'.symm -@[deprecated (since := "2024-08-28")] +@[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephIdx := rfl @@ -555,7 +555,7 @@ theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephId def Aleph'.relIso := aleph' -@[deprecated (since := "2024-08-28")] +@[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' := rfl @@ -571,11 +571,11 @@ theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ theorem aleph'_max (o₁ o₂ : Ordinal) : aleph' (max o₁ o₂) = max (aleph' o₁) (aleph' o₂) := aleph'.monotone.map_max -@[deprecated (since := "2024-08-28")] +@[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem aleph'_alephIdx (c : Cardinal) : aleph' c.alephIdx = c := Cardinal.alephIdx.relIso.toEquiv.symm_apply_apply c -@[deprecated (since := "2024-08-28")] +@[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o := Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o @@ -608,7 +608,7 @@ theorem aleph'_limit {o : Ordinal} (ho : o.IsLimit) : aleph' o = ⨆ a : Iio o, theorem aleph'_omega0 : aleph' ω = ℵ₀ := preAleph_omega0 -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias aleph'_omega := aleph'_omega0 /-- `aleph'` and `aleph_idx` form an equivalence between `Ordinal` and `Cardinal` -/ @@ -616,6 +616,7 @@ alias aleph'_omega := aleph'_omega0 def aleph'Equiv : Ordinal ≃ Cardinal := ⟨aleph', alephIdx, alephIdx_aleph', aleph'_alephIdx⟩ +@[deprecated aleph_eq_preAleph (since := "2024-10-22")] theorem aleph_eq_aleph' (o : Ordinal) : ℵ_ o = preAleph (ω + o) := rfl @@ -637,7 +638,7 @@ theorem aleph'_isNormal : IsNormal (ord ∘ aleph') := -- They should also use `¬ BddAbove` instead of `Unbounded (· < ·)`. /-- Ordinals that are cardinals are unbounded. -/ -@[deprecated (since := "2024-09-24")] +@[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b } := unbounded_lt_iff.2 fun a => ⟨_, @@ -645,16 +646,16 @@ theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b dsimp rw [card_ord], (lt_ord_succ_card a).le⟩⟩ -@[deprecated (since := "2024-09-24")] +@[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem eq_aleph'_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) : ∃ a, (aleph' a).ord = o := ⟨aleph'.symm o.card, by simpa using ho⟩ /-- Infinite ordinals that are cardinals are unbounded. -/ -@[deprecated (since := "2024-09-24")] +@[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := (unbounded_lt_inter_le ω).2 ord_card_unbounded -@[deprecated (since := "2024-09-24")] +@[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem eq_aleph_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) (ho' : ω ≤ o) : ∃ a, (ℵ_ a).ord = o := by cases' eq_aleph'_of_eq_card_ord ho with a ha diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index 18f50f95db1cbd..e0105b35878923 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -145,7 +145,7 @@ protected theorem eq : #α = #β ↔ Nonempty (α ≃ β) := Quotient.eq' /-- Avoid using `Quotient.mk` to construct a `Cardinal` directly -/ -@[deprecated (since := "2024-10-24")] +@[deprecated "No deprecation message was provided." (since := "2024-10-24")] theorem mk'_def (α : Type u) : @Eq Cardinal ⟦α⟧ #α := rfl diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index 4024caa0c1f7a6..9a8363e186c9ac 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality.lean @@ -114,7 +114,7 @@ def StrictOrder.cof (r : α → α → Prop) : Cardinal := Order.cof (swap rᶜ) /-- The set in the definition of `Order.StrictOrder.cof` is nonempty. -/ -@[deprecated (since := "2024-10-22")] +@[deprecated "No deprecation message was provided." (since := "2024-10-22")] theorem StrictOrder.cof_nonempty (r : α → α → Prop) [IsIrrefl α r] : { c | ∃ S : Set α, Unbounded r S ∧ #S = c }.Nonempty := @Order.cof_nonempty α _ (IsRefl.swap rᶜ) @@ -287,7 +287,6 @@ 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 * diff --git a/Mathlib/SetTheory/Cardinal/CountableCover.lean b/Mathlib/SetTheory/Cardinal/CountableCover.lean index 16eb4b46b329ca..b3a0fe7e59ed23 100644 --- a/Mathlib/SetTheory/Cardinal/CountableCover.lean +++ b/Mathlib/SetTheory/Cardinal/CountableCover.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.SetTheory.Cardinal.Arithmetic -import Mathlib.Order.Filter.Basic +import Mathlib.Order.Filter.Finite /-! # Cardinality of a set with a countable cover diff --git a/Mathlib/SetTheory/Cardinal/Divisibility.lean b/Mathlib/SetTheory/Cardinal/Divisibility.lean index 6a176f3246b65f..a82232c834d801 100644 --- a/Mathlib/SetTheory/Cardinal/Divisibility.lean +++ b/Mathlib/SetTheory/Cardinal/Divisibility.lean @@ -31,8 +31,6 @@ Note furthermore that no infinite cardinal is irreducible namespace Cardinal -open Cardinal - universe u variable {a b : Cardinal.{u}} {n m : ℕ} diff --git a/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean b/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean index a5c9f5c0186295..02acdbd1461b6c 100644 --- a/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean +++ b/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean @@ -49,8 +49,7 @@ theorem schroeder_bernstein {f : α → β} {g : β → α} (hf : Function.Injec { toFun := fun s => (g '' (f '' s)ᶜ)ᶜ monotone' := fun s t hst => compl_subset_compl.mpr <| image_subset _ <| compl_subset_compl.mpr <| image_subset _ hst } - -- Porting note: dot notation `F.lfp` doesn't work here - set s : Set α := OrderHom.lfp F + set s : Set α := F.lfp have hs : (g '' (f '' s)ᶜ)ᶜ = s := F.map_lfp have hns : g '' (f '' s)ᶜ = sᶜ := compl_injective (by simp [hs]) set g' := invFun g diff --git a/Mathlib/SetTheory/Cardinal/Subfield.lean b/Mathlib/SetTheory/Cardinal/Subfield.lean index 604447735f1cc1..37f45168df1dd9 100644 --- a/Mathlib/SetTheory/Cardinal/Subfield.lean +++ b/Mathlib/SetTheory/Cardinal/Subfield.lean @@ -76,7 +76,7 @@ lemma cardinalMk_closure_le_max : #(closure s) ≤ max #s ℵ₀ := exact (add_lt_aleph0 this h).le · rw [max_eq_left h, add_eq_right h (this.le.trans h), max_eq_left h] rintro (n|_) - · fin_cases n <;> infer_instance + · fin_cases n <;> (dsimp only [id_eq]; infer_instance) infer_instance @[deprecated (since := "2024-11-10")] alias cardinal_mk_closure_le_max := cardinalMk_closure_le_max diff --git a/Mathlib/SetTheory/Game/Ordinal.lean b/Mathlib/SetTheory/Game/Ordinal.lean index d281b72b36a02c..cf5a7e8f4cf976 100644 --- a/Mathlib/SetTheory/Game/Ordinal.lean +++ b/Mathlib/SetTheory/Game/Ordinal.lean @@ -35,7 +35,7 @@ noncomputable def toPGame (o : Ordinal.{u}) : PGame.{u} := termination_by o decreasing_by exact ((enumIsoToType o).symm x).prop -@[deprecated (since := "2024-09-22")] +@[deprecated "No deprecation message was provided." (since := "2024-09-22")] theorem toPGame_def (o : Ordinal) : o.toPGame = ⟨o.toType, PEmpty, fun x => ((enumIsoToType o).symm x).val.toPGame, PEmpty.elim⟩ := by rw [toPGame] diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index 6cc7dfe51df9e8..3563908538d096 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -605,14 +605,14 @@ theorem one_add_omega0 : 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")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias one_add_omega := one_add_omega0 @[simp] theorem one_add_of_omega0_le {o} (h : ω ≤ o) : 1 + o = o := by rw [← Ordinal.add_sub_cancel_of_le h, ← add_assoc, one_add_omega0] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias one_add_of_omega_le := one_add_of_omega0_le /-! ### Multiplication of ordinals -/ @@ -1185,7 +1185,7 @@ def sup {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal.{max u v} := iSup f set_option linter.deprecated false in -@[deprecated (since := "2024-08-27")] +@[deprecated "No deprecation message was provided." (since := "2024-08-27")] theorem sSup_eq_sup {ι : Type u} (f : ι → Ordinal.{max u v}) : sSup (Set.range f) = sup.{_, v} f := rfl @@ -1252,14 +1252,15 @@ protected theorem lt_iSup_iff {ι} {f : ι → Ordinal.{u}} {a : Ordinal.{u}} [S a < iSup f ↔ ∃ i, a < f i := lt_ciSup_iff' (bddAbove_of_small _) -@[deprecated (since := "2024-11-12")] alias lt_iSup := lt_iSup_iff +@[deprecated "No deprecation message was provided." (since := "2024-11-12")] +alias lt_iSup := lt_iSup_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")] +@[deprecated "No deprecation message was provided." (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 @@ -1377,7 +1378,7 @@ theorem unbounded_range_of_sup_ge {α β : Type u} (r : α → α → Prop) [IsW unbounded_range_of_le_iSup r f h set_option linter.deprecated false in -@[deprecated (since := "2024-08-27")] +@[deprecated "No deprecation message was provided." (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⟩) @@ -1422,7 +1423,7 @@ theorem IsNormal.apply_of_isLimit {f : Ordinal.{u} → Ordinal.{v}} (H : IsNorma rw [← H.map_iSup, ho.iSup_Iio] set_option linter.deprecated false in -@[deprecated (since := "2024-08-27")] +@[deprecated "No deprecation message was provided." (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 @@ -1986,12 +1987,12 @@ theorem IsNormal.eq_iff_zero_and_succ {f g : Ordinal.{u} → Ordinal.{u}} (hf : Deprecated. If you need this value explicitly, write it in terms of `iSup`. If you just want an upper bound for the image of `op`, use that `Iio a ×ˢ Iio b` is a small set. -/ -@[deprecated (since := "2024-10-11")] +@[deprecated "No deprecation message was provided." (since := "2024-10-11")] def blsub₂ (o₁ o₂ : Ordinal) (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) : Ordinal := lsub (fun x : o₁.toType × o₂.toType => op (typein_lt_self x.1) (typein_lt_self x.2)) -@[deprecated (since := "2024-10-11")] +@[deprecated "No deprecation message was provided." (since := "2024-10-11")] theorem lt_blsub₂ {o₁ o₂ : Ordinal} (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) {a b : Ordinal} (ha : a < o₁) (hb : b < o₂) : op ha hb < blsub₂ o₁ o₂ op := by @@ -2012,34 +2013,34 @@ set_option linter.deprecated false def mex {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal := sInf (Set.range f)ᶜ -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_not_mem_range {ι : Type u} (f : ι → Ordinal.{max u v}) : mex.{_, v} f ∉ Set.range f := csInf_mem (nonempty_compl_range.{_, v} f) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem le_mex_of_forall {ι : Type u} {f : ι → Ordinal.{max u v}} {a : Ordinal} (H : ∀ b < a, ∃ i, f i = b) : a ≤ mex.{_, v} f := by by_contra! h exact mex_not_mem_range f (H _ h) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem ne_mex {ι : Type u} (f : ι → Ordinal.{max u v}) : ∀ i, f i ≠ mex.{_, v} f := by simpa using mex_not_mem_range.{_, v} f -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_le_of_ne {ι} {f : ι → Ordinal} {a} (ha : ∀ i, f i ≠ a) : mex f ≤ a := csInf_le' (by simp [ha]) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem exists_of_lt_mex {ι} {f : ι → Ordinal} {a} (ha : a < mex f) : ∃ i, f i = a := by by_contra! ha' exact ha.not_le (mex_le_of_ne ha') -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_le_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : mex.{_, v} f ≤ lsub.{_, v} f := csInf_le' (lsub_not_mem_range f) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_monotone {α β : Type u} {f : α → Ordinal.{max u v}} {g : β → Ordinal.{max u v}} (h : Set.range f ⊆ Set.range g) : mex.{_, v} f ≤ mex.{_, v} g := by refine mex_le_of_ne fun i hi => ?_ @@ -2072,18 +2073,18 @@ theorem mex_lt_ord_succ_mk {ι : Type u} (f : ι → Ordinal.{u}) : def bmex (o : Ordinal) (f : ∀ a < o, Ordinal) : Ordinal := mex (familyOfBFamily o f) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_not_mem_brange {o : Ordinal} (f : ∀ a < o, Ordinal) : bmex o f ∉ brange o f := by rw [← range_familyOfBFamily] apply mex_not_mem_range -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem le_bmex_of_forall {o : Ordinal} (f : ∀ a < o, Ordinal) {a : Ordinal} (H : ∀ b < a, ∃ i hi, f i hi = b) : a ≤ bmex o f := by by_contra! h exact bmex_not_mem_brange f (H _ h) -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem ne_bmex {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {i} (hi) : f i hi ≠ bmex.{_, v} o f := by convert (config := {transparency := .default}) @@ -2091,23 +2092,23 @@ theorem ne_bmex {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {i} (hi) : -- Porting note: `familyOfBFamily_enum` → `typein_enum` rw [typein_enum] -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_le_of_ne {o : Ordinal} {f : ∀ a < o, Ordinal} {a} (ha : ∀ i hi, f i hi ≠ a) : bmex o f ≤ a := mex_le_of_ne fun _i => ha _ _ -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem exists_of_lt_bmex {o : Ordinal} {f : ∀ a < o, Ordinal} {a} (ha : a < bmex o f) : ∃ i hi, f i hi = a := by cases' exists_of_lt_mex ha with i hi exact ⟨_, typein_lt_self i, hi⟩ -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_le_blsub {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) : bmex.{_, v} o f ≤ blsub.{_, v} o f := mex_le_lsub _ -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_monotone {o o' : Ordinal.{u}} {f : ∀ a < o, Ordinal.{max u v}} {g : ∀ a < o', Ordinal.{max u v}} (h : brange o f ⊆ brange o' g) : bmex.{_, v} o f ≤ bmex.{_, v} o' g := @@ -2165,7 +2166,7 @@ theorem one_add_natCast (m : ℕ) : 1 + (m : Ordinal) = succ m := by rw [← Nat.cast_one, ← Nat.cast_add, add_comm] rfl -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias one_add_nat_cast := one_add_natCast -- See note [no_index around OfNat.ofNat] @@ -2179,43 +2180,43 @@ theorem natCast_mul (m : ℕ) : ∀ n : ℕ, ((m * n : ℕ) : Ordinal) = m * n | 0 => by simp | n + 1 => by rw [Nat.mul_succ, Nat.cast_add, natCast_mul m n, Nat.cast_succ, mul_add_one] -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_mul := natCast_mul @[deprecated Nat.cast_le (since := "2024-10-17")] theorem natCast_le {m n : ℕ} : (m : Ordinal) ≤ n ↔ m ≤ n := Nat.cast_le -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_le := natCast_le @[deprecated Nat.cast_inj (since := "2024-10-17")] theorem natCast_inj {m n : ℕ} : (m : Ordinal) = n ↔ m = n := Nat.cast_inj -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_inj := natCast_inj @[deprecated Nat.cast_lt (since := "2024-10-17")] theorem natCast_lt {m n : ℕ} : (m : Ordinal) < n ↔ m < n := Nat.cast_lt -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_lt := natCast_lt @[deprecated Nat.cast_eq_zero (since := "2024-10-17")] theorem natCast_eq_zero {n : ℕ} : (n : Ordinal) = 0 ↔ n = 0 := Nat.cast_eq_zero -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_eq_zero := natCast_eq_zero @[deprecated Nat.cast_ne_zero (since := "2024-10-17")] theorem natCast_ne_zero {n : ℕ} : (n : Ordinal) ≠ 0 ↔ n ≠ 0 := Nat.cast_ne_zero -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_ne_zero := natCast_ne_zero @[deprecated Nat.cast_pos' (since := "2024-10-17")] theorem natCast_pos {n : ℕ} : (0 : Ordinal) < n ↔ 0 < n := Nat.cast_pos' -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_pos := natCast_pos @[simp, norm_cast] @@ -2226,7 +2227,7 @@ theorem natCast_sub (m n : ℕ) : ((m - n : ℕ) : Ordinal) = m - n := by · apply (add_left_cancel n).1 rw [← Nat.cast_add, add_tsub_cancel_of_le h, Ordinal.add_sub_cancel_of_le (Nat.cast_le.2 h)] -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_sub := natCast_sub @[simp, norm_cast] @@ -2241,7 +2242,7 @@ theorem natCast_div (m n : ℕ) : ((m / n : ℕ) : Ordinal) = m / n := by ← Nat.div_lt_iff_lt_mul (Nat.pos_of_ne_zero hn)] apply Nat.lt_succ_self -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_div := natCast_div @[simp, norm_cast] @@ -2249,7 +2250,7 @@ theorem natCast_mod (m n : ℕ) : ((m % n : ℕ) : Ordinal) = m % n := by rw [← add_left_cancel, div_add_mod, ← natCast_div, ← natCast_mul, ← Nat.cast_add, Nat.div_add_mod] -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_mod := natCast_mod @[simp] @@ -2257,7 +2258,7 @@ theorem lift_natCast : ∀ n : ℕ, lift.{u, v} n = n | 0 => by simp | n + 1 => by simp [lift_natCast n] -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias lift_nat_cast := lift_natCast -- See note [no_index around OfNat.ofNat] @@ -2292,13 +2293,13 @@ theorem lt_add_of_limit {a b c : Ordinal.{u}} (h : IsLimit c) : theorem lt_omega0 {o : Ordinal} : o < ω ↔ ∃ n : ℕ, o = n := by simp_rw [← Cardinal.ord_aleph0, Cardinal.lt_ord, lt_aleph0, card_eq_nat] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias lt_omega := lt_omega0 theorem nat_lt_omega0 (n : ℕ) : ↑n < ω := lt_omega0.2 ⟨_, rfl⟩ -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias nat_lt_omega := nat_lt_omega0 theorem omega0_pos : 0 < ω := @@ -2307,12 +2308,12 @@ theorem omega0_pos : 0 < ω := theorem omega0_ne_zero : ω ≠ 0 := omega0_pos.ne' -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias omega_ne_zero := omega0_ne_zero theorem one_lt_omega0 : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omega0 1 -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias one_lt_omega := one_lt_omega0 theorem isLimit_omega0 : IsLimit ω := @@ -2320,10 +2321,10 @@ theorem isLimit_omega0 : IsLimit ω := let ⟨n, e⟩ := lt_omega0.1 h rw [e]; exact nat_lt_omega0 (n + 1)⟩ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] alias omega0_isLimit := isLimit_omega0 -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias omega_isLimit := isLimit_omega0 theorem omega0_le {o : Ordinal} : ω ≤ o ↔ ∀ n : ℕ, ↑n ≤ o := @@ -2332,7 +2333,7 @@ theorem omega0_le {o : Ordinal} : ω ≤ o ↔ ∀ n : ℕ, ↑n ≤ o := let ⟨n, e⟩ := lt_omega0.1 h rw [e, ← succ_le_iff]; exact H (n + 1)⟩ -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias omega_le := omega0_le @[simp] @@ -2344,7 +2345,7 @@ set_option linter.deprecated false in theorem sup_natCast : sup Nat.cast = ω := iSup_natCast -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias sup_nat_cast := sup_natCast theorem nat_lt_limit {o} (h : IsLimit o) : ∀ n : ℕ, ↑n < o @@ -2354,7 +2355,7 @@ theorem nat_lt_limit {o} (h : IsLimit o) : ∀ n : ℕ, ↑n < o 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")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias omega_le_of_isLimit := omega0_le_of_isLimit theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ a := by @@ -2372,7 +2373,7 @@ theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ intro e simp only [e, mul_zero] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias isLimit_iff_omega_dvd := isLimit_iff_omega0_dvd theorem add_mul_limit_aux {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c) @@ -2416,7 +2417,7 @@ theorem add_le_of_forall_add_lt {a b c : Ordinal} (hb : 0 < b) (h : ∀ d < b, a 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")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias IsNormal.apply_omega := IsNormal.apply_omega0 @[simp] @@ -2460,7 +2461,7 @@ theorem isLimit_ord {c} (co : ℵ₀ ≤ c) : (ord c).IsLimit := by · rw [ord_aleph0] exact Ordinal.isLimit_omega0 -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] alias ord_isLimit := isLimit_ord theorem noMaxOrder {c} (h : ℵ₀ ≤ c) : NoMaxOrder c.ord.toType := diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean index 5a31bfe919ee9a..ec9a34419fbf4c 100644 --- a/Mathlib/SetTheory/Ordinal/Basic.lean +++ b/Mathlib/SetTheory/Ordinal/Basic.lean @@ -387,7 +387,7 @@ def typein (r : α → α → Prop) [IsWellOrder α r] : @PrincipalSeg α Ordina alias typein.principalSeg := typein set_option linter.deprecated false in -@[deprecated (since := "2024-10-09")] +@[deprecated "No deprecation message was provided." (since := "2024-10-09")] theorem typein.principalSeg_coe (r : α → α → Prop) [IsWellOrder α r] : (typein.principalSeg r : α → Ordinal) = typein r := rfl @@ -513,7 +513,7 @@ noncomputable def enumIsoToType (o : Ordinal) : Set.Iio o ≃o o.toType where right_inv _ := enum_typein _ _ map_rel_iff' := enum_le_enum' _ -@[deprecated (since := "2024-08-26")] +@[deprecated "No deprecation message was provided." (since := "2024-08-26")] alias enumIsoOut := enumIsoToType instance small_Iio (o : Ordinal.{u}) : Small.{u} (Iio o) := @@ -925,7 +925,7 @@ theorem card_succ (o : Ordinal) : card (succ o) = card o + 1 := by theorem natCast_succ (n : ℕ) : ↑n.succ = succ (n : Ordinal) := rfl -@[deprecated (since := "2024-04-17")] +@[deprecated "No deprecation message was provided." (since := "2024-04-17")] alias nat_cast_succ := natCast_succ instance uniqueIioOne : Unique (Iio (1 : Ordinal)) where @@ -1213,7 +1213,7 @@ 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")] +@[deprecated "No deprecation message was provided." (since := "2024-08-26")] alias mk_Iio_ord_out_α := mk_Iio_ord_toType theorem ord_injective : Injective ord := by diff --git a/Mathlib/SetTheory/Ordinal/Enum.lean b/Mathlib/SetTheory/Ordinal/Enum.lean index 4e5d4d38a7cf6b..e8b3bb9314bc5a 100644 --- a/Mathlib/SetTheory/Ordinal/Enum.lean +++ b/Mathlib/SetTheory/Ordinal/Enum.lean @@ -33,7 +33,7 @@ termination_by o variable {s : Set Ordinal.{u}} -@[deprecated (since := "2024-09-20")] +@[deprecated "No deprecation message was provided." (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] diff --git a/Mathlib/SetTheory/Ordinal/FixedPoint.lean b/Mathlib/SetTheory/Ordinal/FixedPoint.lean index 36b50a052b83da..84f2f8db36b0da 100644 --- a/Mathlib/SetTheory/Ordinal/FixedPoint.lean +++ b/Mathlib/SetTheory/Ordinal/FixedPoint.lean @@ -52,7 +52,7 @@ least `a`, and `Ordinal.nfpFamily_le_fp` shows this is the least ordinal with th def nfpFamily (f : ι → Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) : Ordinal := ⨆ i, List.foldr f a i -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpFamily_eq_sup (f : ι → Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) : nfpFamily f a = ⨆ i, List.foldr f a i := rfl @@ -238,48 +238,48 @@ def nfpBFamily (o : Ordinal.{u}) (f : ∀ b < o, Ordinal.{max u v} → Ordinal.{ Ordinal.{max u v} → Ordinal.{max u v} := nfpFamily (familyOfBFamily o f) -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_eq_nfpFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : nfpBFamily.{u, v} o f = nfpFamily (familyOfBFamily o f) := rfl -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem foldr_le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a l) : List.foldr (familyOfBFamily o f) a l ≤ nfpBFamily.{u, v} o f a := Ordinal.le_iSup _ _ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a) : a ≤ nfpBFamily.{u, v} o f a := Ordinal.le_iSup (fun _ ↦ List.foldr _ a _) [] -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem lt_nfpBFamily {a b} : a < nfpBFamily.{u, v} o f b ↔ ∃ l, a < List.foldr (familyOfBFamily o f) b l := Ordinal.lt_iSup_iff -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_iff {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a b} : nfpBFamily.{u, v} o f a ≤ b ↔ ∀ l, List.foldr (familyOfBFamily o f) a l ≤ b := Ordinal.iSup_le_iff -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a b} : (∀ l, List.foldr (familyOfBFamily o f) a l ≤ b) → nfpBFamily.{u, v} o f a ≤ b := Ordinal.iSup_le -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_monotone (hf : ∀ i hi, Monotone (f i hi)) : Monotone (nfpBFamily.{u, v} o f) := nfpFamily_monotone fun _ => hf _ _ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_lt_nfpBFamily (H : ∀ i hi, IsNormal (f i hi)) {a b} (hb : b < nfpBFamily.{u, v} o f a) (i hi) : f i hi b < nfpBFamily.{u, v} o f a := by rw [← familyOfBFamily_enum o f] apply apply_lt_nfpFamily (fun _ => H _ _) hb -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_lt_nfpBFamily_iff (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∀ i hi, f i hi b < nfpBFamily.{u, v} o f a) ↔ b < nfpBFamily.{u, v} o f a := ⟨fun h => by @@ -287,19 +287,19 @@ theorem apply_lt_nfpBFamily_iff (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) refine (apply_lt_nfpFamily_iff ?_).1 fun _ => h _ _ exact fun _ => H _ _, apply_lt_nfpBFamily H⟩ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_apply (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∃ i hi, nfpBFamily.{u, v} o f a ≤ f i hi b) ↔ nfpBFamily.{u, v} o f a ≤ b := by rw [← not_iff_not] push_neg exact apply_lt_nfpBFamily_iff.{u, v} ho H -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_fp (H : ∀ i hi, Monotone (f i hi)) {a b} (ab : a ≤ b) (h : ∀ i hi, f i hi b ≤ b) : nfpBFamily.{u, v} o f a ≤ b := nfpFamily_le_fp (fun _ => H _ _) ab fun _ => h _ _ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_fp {i hi} (H : IsNormal (f i hi)) (a) : f i hi (nfpBFamily.{u, v} o f a) = nfpBFamily.{u, v} o f a := by rw [← familyOfBFamily_enum o f] @@ -307,7 +307,7 @@ theorem nfpBFamily_fp {i hi} (H : IsNormal (f i hi)) (a) : rw [familyOfBFamily_enum] exact H -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_le_nfpBFamily (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∀ i hi, f i hi b ≤ nfpBFamily.{u, v} o f a) ↔ b ≤ nfpBFamily.{u, v} o f a := by refine ⟨fun h => ?_, fun h i hi => ?_⟩ @@ -316,13 +316,13 @@ theorem apply_le_nfpBFamily (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a · rw [← nfpBFamily_fp (H i hi)] exact (H i hi).monotone h -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_eq_self {a} (h : ∀ i hi, f i hi a = a) : nfpBFamily.{u, v} o f a = a := nfpFamily_eq_self fun _ => h _ _ /-- A generalization of the fixed point lemma for normal functions: any family of normal functions has an unbounded set of common fixed points. -/ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] 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] @@ -347,12 +347,12 @@ def derivBFamily (o : Ordinal.{u}) (f : ∀ b < o, Ordinal.{max u v} → Ordinal Ordinal.{max u v} → Ordinal.{max u v} := derivFamily (familyOfBFamily o f) -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem derivBFamily_eq_derivFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : derivBFamily.{u, v} o f = derivFamily (familyOfBFamily o f) := rfl -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem isNormal_derivBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : IsNormal (derivBFamily o f) := isNormal_derivFamily _ @@ -360,7 +360,7 @@ theorem isNormal_derivBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) @[deprecated isNormal_derivBFamily (since := "2024-10-11")] alias derivBFamily_isNormal := isNormal_derivBFamily -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem derivBFamily_fp {i hi} (H : IsNormal (f i hi)) (a : Ordinal) : f i hi (derivBFamily.{u, v} o f a) = derivBFamily.{u, v} o f a := by rw [← familyOfBFamily_enum o f] @@ -368,7 +368,7 @@ theorem derivBFamily_fp {i hi} (H : IsNormal (f i hi)) (a : Ordinal) : rw [familyOfBFamily_enum] exact H -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem le_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : (∀ i hi, f i hi a ≤ a) ↔ ∃ b, derivBFamily.{u, v} o f b = a := by unfold derivBFamily @@ -378,7 +378,7 @@ theorem le_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : apply h · exact fun _ => H _ _ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem fp_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : (∀ i hi, f i hi a = a) ↔ ∃ b, derivBFamily.{u, v} o f b = a := by rw [← le_iff_derivBFamily H] @@ -387,7 +387,7 @@ theorem fp_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : exact h i hi /-- For a family of normal functions, `Ordinal.derivBFamily` enumerates the common fixed points. -/ -@[deprecated (since := "2024-10-14")] +@[deprecated "No deprecation message was provided." (since := "2024-10-14")] 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_comm, eq_enumOrd _ (not_bddAbove_fp_bfamily H)] @@ -428,7 +428,7 @@ theorem iSup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) (a : Ordinal.{u}) exact Ordinal.le_iSup _ _ set_option linter.deprecated false in -@[deprecated (since := "2024-08-27")] +@[deprecated "No deprecation message was provided." (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 => ?_) @@ -580,7 +580,7 @@ theorem nfp_add_eq_mul_omega0 {a b} (hba : b ≤ a * ω) : nfp (a + ·) b = a * exact nfp_monotone (isNormal_add_right a).monotone (Ordinal.zero_le b) · dsimp; rw [← mul_one_add, one_add_omega0] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias nfp_add_eq_mul_omega := nfp_add_eq_mul_omega0 theorem add_eq_right_iff_mul_omega0_le {a b : Ordinal} : a + b = b ↔ a * ω ≤ b := by @@ -593,14 +593,14 @@ theorem add_eq_right_iff_mul_omega0_le {a b : Ordinal} : a + b = b ↔ a * ω nth_rw 1 [← this] rwa [← add_assoc, ← mul_one_add, one_add_omega0] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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 (isNormal_add_right a).le_iff_eq -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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 @@ -612,7 +612,7 @@ theorem deriv_add_eq_mul_omega0_add (a b : Ordinal.{u}) : deriv (a + ·) b = a * · rw [deriv_succ, h, add_succ] exact nfp_eq_self (add_eq_right_iff_mul_omega0_le.2 ((le_add_right _ _).trans (le_succ _))) -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias deriv_add_eq_mul_omega_add := deriv_add_eq_mul_omega0_add /-! ### Fixed points of multiplication -/ @@ -645,7 +645,7 @@ theorem nfp_mul_eq_opow_omega0 {a b : Ordinal} (hb : 0 < b) (hba : b ≤ a ^ ω) rw [← nfp_mul_one ha] exact nfp_monotone (isNormal_mul_right ha).monotone (one_le_iff_pos.2 hb) -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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) : @@ -659,7 +659,7 @@ theorem eq_zero_or_opow_omega0_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = rw [← Ne, ← one_le_iff_ne_zero] at hb exact nfp_le_fp (isNormal_mul_right ha).monotone hb (le_of_eq hab) -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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 @@ -677,7 +677,7 @@ theorem mul_eq_right_iff_opow_omega0_dvd {a b : Ordinal} : a * b = b ↔ a ^ ω cases' h with c hc rw [hc, ← mul_assoc, ← opow_one_add, one_add_omega0] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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_omega0_dvd {a b : Ordinal} (ha : 0 < a) : @@ -685,7 +685,7 @@ theorem mul_le_right_iff_opow_omega0_dvd {a b : Ordinal} (ha : 0 < a) : rw [← mul_eq_right_iff_opow_omega0_dvd] exact (isNormal_mul_right ha).le_iff_eq -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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) @@ -705,7 +705,7 @@ theorem nfp_mul_opow_omega0_add {a c : Ordinal} (b) (ha : 0 < a) (hc : 0 < c) rw [add_zero, mul_lt_mul_iff_left (opow_pos ω ha)] at this rwa [succ_le_iff] -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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) : @@ -718,7 +718,7 @@ theorem deriv_mul_eq_opow_omega0_mul {a : Ordinal.{u}} (ha : 0 < a) (b) : · rw [deriv_succ, h] exact nfp_mul_opow_omega0_add c ha zero_lt_one (one_le_iff_pos.2 (opow_pos _ ha)) -@[deprecated (since := "2024-09-30")] +@[deprecated "No deprecation message was provided." (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 97272de665f4f9..4d1e937f10243a 100644 --- a/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean +++ b/Mathlib/SetTheory/Ordinal/FixedPointApproximants.lean @@ -226,9 +226,9 @@ theorem lfpApprox_le_of_mem_fixedPoints {a : α} /-- 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 +theorem lfpApprox_ord_eq_lfp : lfpApprox f ⊥ (ord <| succ #α) = f.lfp := by apply le_antisymm - · have h_lfp : ∃ y : fixedPoints f, lfp f = y := by use ⊥; exact rfl + · have h_lfp : ∃ y : fixedPoints f, f.lfp = y := by use ⊥; exact rfl let ⟨y, h_y⟩ := h_lfp; rw [h_y] exact lfpApprox_le_of_mem_fixedPoints f ⊥ y.2 bot_le (ord <| succ #α) · have h_fix : ∃ y : fixedPoints f, lfpApprox f ⊥ (ord <| succ #α) = y := by @@ -238,7 +238,7 @@ theorem lfpApprox_ord_eq_lfp : lfpApprox f ⊥ (ord <| succ #α) = lfp f := by exact lfp_le_fixed f x.prop /-- 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 +theorem lfp_mem_range_lfpApprox : f.lfp ∈ Set.range (lfpApprox f ⊥) := by use ord <| succ #α exact lfpApprox_ord_eq_lfp f @@ -256,52 +256,52 @@ decreasing_by exact h unseal gfpApprox lfpApprox theorem gfpApprox_antitone : Antitone (gfpApprox f x) := - lfpApprox_monotone (OrderHom.dual f) x + lfpApprox_monotone f.dual x theorem gfpApprox_le {a : Ordinal} : gfpApprox f x a ≤ x := - le_lfpApprox (OrderHom.dual f) x + le_lfpApprox f.dual x 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 + lfpApprox_add_one f.dual x h a theorem gfpApprox_mono_left : Monotone (gfpApprox : (α →o α) → _) := by intro f g h - have : OrderHom.dual g ≤ OrderHom.dual f := h + have : g.dual ≤ f.dual := h exact lfpApprox_mono_left this theorem gfpApprox_mono_mid : Monotone (gfpApprox f) := - fun _ _ h => lfpApprox_mono_mid (OrderHom.dual f) h + fun _ _ h => lfpApprox_mono_mid f.dual 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 + lfpApprox_eq_of_mem_fixedPoints f.dual x h_init h_ab h /-- 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 + exists_lfpApprox_eq_lfpApprox f.dual x /-- 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 + lfpApprox_ord_mem_fixedPoint f.dual x h_init /-- 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 + lfpApprox_le_of_mem_fixedPoints f.dual x h_a h_le_init i /-- 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) +theorem gfpApprox_ord_eq_gfp : gfpApprox f ⊤ (ord <| succ #α) = f.gfp := + lfpApprox_ord_eq_lfp f.dual /-- 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) +theorem gfp_mem_range_gfpApprox : f.gfp ∈ Set.range (gfpApprox f ⊤) := + lfp_mem_range_lfpApprox f.dual end OrdinalApprox diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index f5a5db19acb409..02806888024ebe 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.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 Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.Ordering.Lemmas import Mathlib.Data.PNat.Basic import Mathlib.SetTheory.Ordinal.Principal diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index 5d6417f1740426..194abeabc7c50a 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -129,7 +129,7 @@ theorem not_bddAbove_principal (op : Ordinal → Ordinal → Ordinal) : exact ((le_nfp _ _).trans (ha (principal_nfp_iSup op (succ a)))).not_lt (lt_succ a) set_option linter.deprecated false in -@[deprecated (since := "2024-10-11")] +@[deprecated "No deprecation message was provided." (since := "2024-10-11")] theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Principal op (nfp (fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b)) o) := by intro a b ha hb @@ -147,7 +147,7 @@ theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordin exact lt_blsub₂ (@fun a _ b _ => op a b) hm (hn.trans_le h) set_option linter.deprecated false in -@[deprecated (since := "2024-10-11")] +@[deprecated "No deprecation message was provided." (since := "2024-10-11")] theorem unbounded_principal (op : Ordinal → Ordinal → Ordinal) : Set.Unbounded (· < ·) { o | Principal op o } := fun o => ⟨_, principal_nfp_blsub₂ op o, (le_nfp _ o).not_lt⟩ diff --git a/Mathlib/SetTheory/Surreal/Dyadic.lean b/Mathlib/SetTheory/Surreal/Dyadic.lean index 66e64a35705b57..b1dc9275095fb2 100644 --- a/Mathlib/SetTheory/Surreal/Dyadic.lean +++ b/Mathlib/SetTheory/Surreal/Dyadic.lean @@ -5,12 +5,12 @@ Authors: Apurva Nakade -/ import Mathlib.Algebra.Algebra.Defs import Mathlib.Algebra.Order.Group.Basic +import Mathlib.Algebra.Ring.Regular import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.RingTheory.Localization.Defs import Mathlib.SetTheory.Game.Birthday import Mathlib.SetTheory.Surreal.Multiplication import Mathlib.Tactic.Linarith -import Mathlib.Algebra.Ring.Regular /-! # Dyadic numbers diff --git a/Mathlib/SetTheory/ZFC/Basic.lean b/Mathlib/SetTheory/ZFC/Basic.lean index c7a0c35cdfcef1..a2b3354096bf06 100644 --- a/Mathlib/SetTheory/ZFC/Basic.lean +++ b/Mathlib/SetTheory/ZFC/Basic.lean @@ -447,12 +447,12 @@ set_option linter.deprecated false /-- Function equivalence is defined so that `f ~ g` iff `∀ x y, x ~ y → f x ~ g y`. This extends to equivalence of `n`-ary functions. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Arity.Equiv : ∀ {n}, OfArity PSet.{u} PSet.{u} n → OfArity PSet.{u} PSet.{u} n → Prop | 0, a, b => PSet.Equiv a b | _ + 1, a, b => ∀ x y : PSet, PSet.Equiv x y → Arity.Equiv (a x) (b y) -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem Arity.equiv_const {a : PSet.{u}} : ∀ n, Arity.Equiv (OfArity.const PSet.{u} a n) (OfArity.const PSet.{u} a n) | 0 => Equiv.rfl @@ -460,46 +460,46 @@ theorem Arity.equiv_const {a : PSet.{u}} : /-- `resp n` is the collection of n-ary functions on `PSet` that respect equivalence, i.e. when the inputs are equivalent the output is as well. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp (n) := { x : OfArity PSet.{u} PSet.{u} n // Arity.Equiv x x } -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] instance Resp.inhabited {n} : Inhabited (Resp n) := ⟨⟨OfArity.const _ default _, Arity.equiv_const _⟩⟩ /-- The `n`-ary image of a `(n + 1)`-ary function respecting equivalence as a function respecting equivalence. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp.f {n} (f : Resp (n + 1)) (x : PSet) : Resp n := ⟨f.1 x, f.2 _ _ <| Equiv.refl x⟩ /-- Function equivalence for functions respecting equivalence. See `PSet.Arity.Equiv`. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp.Equiv {n} (a b : Resp n) : Prop := Arity.Equiv a.1 b.1 -@[deprecated (since := "2024-09-02"), refl] +@[deprecated "No deprecation message was provided." (since := "2024-09-02"), refl] protected theorem Resp.Equiv.refl {n} (a : Resp n) : Resp.Equiv a a := a.2 -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] protected theorem Resp.Equiv.euc : ∀ {n} {a b c : Resp n}, Resp.Equiv a b → Resp.Equiv c b → Resp.Equiv a c | 0, _, _, _, hab, hcb => PSet.Equiv.euc hab hcb | n + 1, a, b, c, hab, hcb => fun x y h => @Resp.Equiv.euc n (a.f x) (b.f y) (c.f y) (hab _ _ h) (hcb _ _ <| PSet.Equiv.refl y) -@[deprecated (since := "2024-09-02"), symm] +@[deprecated "No deprecation message was provided." (since := "2024-09-02"), symm] protected theorem Resp.Equiv.symm {n} {a b : Resp n} : Resp.Equiv a b → Resp.Equiv b a := (Resp.Equiv.refl b).euc -@[deprecated (since := "2024-09-02"), trans] +@[deprecated "No deprecation message was provided." (since := "2024-09-02"), trans] protected theorem Resp.Equiv.trans {n} {x y z : Resp n} (h1 : Resp.Equiv x y) (h2 : Resp.Equiv y z) : Resp.Equiv x z := h1.euc h2.symm -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] instance Resp.setoid {n} : Setoid (Resp n) := ⟨Resp.Equiv, Resp.Equiv.refl, Resp.Equiv.symm, Resp.Equiv.trans⟩ @@ -611,7 +611,7 @@ set_option linter.deprecated false namespace Resp /-- Helper function for `PSet.eval`. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def evalAux : ∀ {n}, { f : Resp n → OfArity ZFSet.{u} ZFSet.{u} n // ∀ a b : Resp n, Resp.Equiv a b → f a = f b } @@ -626,11 +626,11 @@ def evalAux : evalAux.2 (Resp.f b z) (Resp.f c z) (h _ _ (PSet.Equiv.refl z))⟩ /-- An equivalence-respecting function yields an n-ary ZFC set function. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def eval (n) : Resp n → OfArity ZFSet.{u} ZFSet.{u} n := evalAux.1 -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem eval_val {n f x} : (@eval (n + 1) f : ZFSet → OfArity ZFSet ZFSet n) ⟦x⟧ = eval n (Resp.f f x) := rfl @@ -640,24 +640,25 @@ end Resp /-- A set function is "definable" if it is the image of some n-ary pre-set function. This isn't exactly definability, but is useful as a sufficient condition for functions that have a computable image. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] class inductive Definable (n) : OfArity ZFSet.{u} ZFSet.{u} n → Type (u + 1) | mk (f) : Definable n (Resp.eval n f) -attribute [deprecated (since := "2024-09-02"), instance] Definable.mk +attribute [deprecated "No deprecation message was provided." (since := "2024-09-02"), instance] + Definable.mk /-- The evaluation of a function respecting equivalence is definable, by that same function. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Definable.EqMk {n} (f) : ∀ {s : OfArity ZFSet.{u} ZFSet.{u} n} (_ : Resp.eval _ f = s), Definable n s | _, rfl => ⟨f⟩ /-- Turns a definable function into a function that respects equivalence. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Definable.Resp {n} : ∀ (s : OfArity ZFSet.{u} ZFSet.{u} n) [Definable n s], Resp n | _, ⟨f⟩ => f -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem Definable.eq {n} : ∀ (s : OfArity ZFSet.{u} ZFSet.{u} n) [H : Definable n s], (@Definable.Resp n s H).eval _ = s | _, ⟨_⟩ => rfl @@ -670,7 +671,7 @@ open PSet ZFSet set_option linter.deprecated false in /-- All functions are classically definable. -/ -@[deprecated (since := "2024-09-02")] +@[deprecated "No deprecation message was provided." (since := "2024-09-02")] noncomputable def allDefinable : ∀ {n} (F : OfArity ZFSet ZFSet n), Definable n F | 0, F => let p := @Quotient.exists_rep PSet _ F @@ -706,7 +707,7 @@ theorem exact {x y : PSet} : mk x = mk y → PSet.Equiv x y := Quotient.exact set_option linter.deprecated false in -@[deprecated (since := "2024-09-02"), simp] +@[deprecated "No deprecation message was provided." (since := "2024-09-02"), simp] theorem eval_mk {n f x} : (@Resp.eval (n + 1) f : ZFSet → OfArity ZFSet ZFSet n) (mk x) = Resp.eval n (Resp.f f x) := rfl diff --git a/Mathlib/SetTheory/ZFC/Ordinal.lean b/Mathlib/SetTheory/ZFC/Ordinal.lean index 56dbcfb274d7a0..bd816b21e5dacb 100644 --- a/Mathlib/SetTheory/ZFC/Ordinal.lean +++ b/Mathlib/SetTheory/ZFC/Ordinal.lean @@ -3,26 +3,27 @@ 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.RelIso.Set import Mathlib.SetTheory.ZFC.Basic /-! # Von Neumann ordinals This file works towards the development of von Neumann ordinals, i.e. transitive sets, well-ordered -under `∈`. We currently only have an initial development of transitive sets. +under `∈`. -Further development can be found on the branch `von_neumann_v2`. +We currently only have an initial development of transitive sets and ordinals. Further development +can be found on the Mathlib 3 branch `von_neumann_v2`. ## Definitions - `ZFSet.IsTransitive` means that every element of a set is a subset. +- `ZFSet.IsOrdinal` means that the set is transitive and well-ordered under `∈`. ## TODO -- Define von Neumann ordinals. -- Define the basic arithmetic operations on ordinals from a purely set-theoretic perspective. -- Prove the equivalences between these definitions and those provided in - `SetTheory/Ordinal/Arithmetic.lean`. +- Define von Neumann ordinals and the von Neumann hierarchy. +- Build correspondences between these notions and those of the standard `Ordinal` type. -/ @@ -38,10 +39,12 @@ def IsTransitive (x : ZFSet) : Prop := ∀ y ∈ x, y ⊆ x @[simp] -theorem empty_isTransitive : IsTransitive ∅ := fun y hy => (not_mem_empty y hy).elim +theorem isTransitive_empty : IsTransitive ∅ := fun y hy => (not_mem_empty y hy).elim -theorem IsTransitive.subset_of_mem (h : x.IsTransitive) : y ∈ x → y ⊆ x := - h y +@[deprecated isTransitive_empty (since := "2024-09-21")] +alias empty_isTransitive := isTransitive_empty + +theorem IsTransitive.subset_of_mem (h : x.IsTransitive) : y ∈ x → y ⊆ x := h y theorem isTransitive_iff_mem_trans : z.IsTransitive ↔ ∀ {x y : ZFSet}, x ∈ y → y ∈ z → x ∈ z := ⟨fun h _ _ hx hy => h.subset_of_mem hy hx, fun H _ hx _ hy => H hy hx⟩ @@ -66,7 +69,7 @@ theorem IsTransitive.sUnion' (H : ∀ y ∈ x, IsTransitive y) : protected theorem IsTransitive.union (hx : x.IsTransitive) (hy : y.IsTransitive) : (x ∪ y).IsTransitive := by rw [← sUnion_pair] - apply IsTransitive.sUnion' fun z => _ + apply IsTransitive.sUnion' intro rw [mem_pair] rintro (rfl | rfl) @@ -77,10 +80,12 @@ protected theorem IsTransitive.powerset (h : x.IsTransitive) : (powerset x).IsTr rw [mem_powerset] at hy ⊢ exact h.subset_of_mem (hy hz) -theorem isTransitive_iff_sUnion_subset : x.IsTransitive ↔ (⋃₀ x : ZFSet) ⊆ x := - ⟨fun h y hy => by - rcases mem_sUnion.1 hy with ⟨z, hz, hz'⟩ - exact h.mem_trans hz' hz, fun H _ hy _ hz => H <| mem_sUnion_of_mem hz hy⟩ +theorem isTransitive_iff_sUnion_subset : x.IsTransitive ↔ (⋃₀ x : ZFSet) ⊆ x := by + constructor <;> + intro h y hy + · obtain ⟨z, hz, hz'⟩ := mem_sUnion.1 hy + exact h.mem_trans hz' hz + · exact fun z hz ↦ h <| mem_sUnion_of_mem hz hy alias ⟨IsTransitive.sUnion_subset, _⟩ := isTransitive_iff_sUnion_subset @@ -89,4 +94,39 @@ theorem isTransitive_iff_subset_powerset : x.IsTransitive ↔ x ⊆ powerset x : alias ⟨IsTransitive.subset_powerset, _⟩ := isTransitive_iff_subset_powerset +/-- A set `x` is a von Neumann ordinal when it's a transitive set, that's transitive under `∈`. We +will prove that this further implies that `x` is well-ordered under `∈`. + +The transitivity condition `a ∈ b → b ∈ c → a ∈ c` can be written without assuming `a ∈ x` and +`b ∈ x`. The lemma `isOrdinal_iff_isTrans` shows this condition is equivalent to the usual one. -/ +structure IsOrdinal (x : ZFSet) : Prop where + /-- An ordinal is a transitive set. -/ + isTransitive : x.IsTransitive + /-- The membership operation within an ordinal is transitive. -/ + mem_trans' {y z w : ZFSet} : y ∈ z → z ∈ w → w ∈ x → y ∈ w + +namespace IsOrdinal + +theorem subset_of_mem (h : x.IsOrdinal) : y ∈ x → y ⊆ x := + h.isTransitive.subset_of_mem + +theorem mem_trans (h : z.IsOrdinal) : x ∈ y → y ∈ z → x ∈ z := + h.isTransitive.mem_trans + +protected theorem isTrans (h : x.IsOrdinal) : IsTrans x.toSet (Subrel (· ∈ ·) _) := + ⟨fun _ _ c hab hbc => h.mem_trans' hab hbc c.2⟩ + +end IsOrdinal + +/-- The simplified form of transitivity used within `IsOrdinal` yields an equivalent definition to +the standard one. -/ +theorem isOrdinal_iff_isTrans : + x.IsOrdinal ↔ x.IsTransitive ∧ IsTrans x.toSet (Subrel (· ∈ ·) _) := by + use fun h => ⟨h.isTransitive, h.isTrans⟩ + rintro ⟨h₁, ⟨h₂⟩⟩ + use h₁ + intro y z w hyz hzw hwx + have hzx := h₁.mem_trans hzw hwx + exact h₂ ⟨y, h₁.mem_trans hyz hzx⟩ ⟨z, hzx⟩ ⟨w, hwx⟩ hyz hzw + end ZFSet diff --git a/Mathlib/Tactic/Abel.lean b/Mathlib/Tactic/Abel.lean index dafcc98e2ffe07..4002862603dbc1 100644 --- a/Mathlib/Tactic/Abel.lean +++ b/Mathlib/Tactic/Abel.lean @@ -247,11 +247,11 @@ theorem term_atom_pfg {α} [AddCommGroup α] (x x' : α) (h : x = x') : x = term /-- Interpret an expression as an atom for `abel`'s normal form. -/ def evalAtom (e : Expr) : M (NormalExpr × Expr) := do let { expr := e', proof?, .. } ← (← readThe AtomM.Context).evalAtom e - let i ← AtomM.addAtom e' + let (i, a) ← AtomM.addAtom e' let p ← match proof? with | none => iapp ``term_atom #[e] - | some p => iapp ``term_atom_pf #[e, e', p] - return (← term' (← intToExpr 1, 1) (i, e') (← zero'), p) + | some p => iapp ``term_atom_pf #[e, a, p] + return (← term' (← intToExpr 1, 1) (i, a) (← zero'), p) theorem unfold_sub {α} [SubtractionMonoid α] (a b c : α) (h : a + -b = c) : a - b = c := by rw [sub_eq_add_neg, h] diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean index 90340cd10a34ee..3c61c4a8849120 100644 --- a/Mathlib/Tactic/Common.lean +++ b/Mathlib/Tactic/Common.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ --- First import Aesop and Qq +-- First import Aesop, Qq, and Plausible import Aesop import Qq +import Plausible -- Tools for analysing imports, like `#find_home`, `#minimize_imports`, ... import ImportGraph.Imports diff --git a/Mathlib/Tactic/FunProp/Core.lean b/Mathlib/Tactic/FunProp/Core.lean index 7cfc38fde4b738..9f84b5b2c1371d 100644 --- a/Mathlib/Tactic/FunProp/Core.lean +++ b/Mathlib/Tactic/FunProp/Core.lean @@ -507,20 +507,18 @@ def tryTheorems (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) if let .some r ← tryTheorem? e thm.thmOrigin funProp then return r | .some (.some (f,g)) => - trace[Debug.Meta.Tactic.fun_prop] - s!"decomposing to later use {←ppOrigin' thm.thmOrigin}" - trace[Debug.Meta.Tactic.fun_prop] - s!"decomposition: {← ppExpr f} ∘ {← ppExpr g}" + trace[Meta.Tactic.fun_prop] + s!"decomposing to later use {←ppOrigin' thm.thmOrigin} as: + ({← ppExpr f}) ∘ ({← ppExpr g})" if let .some r ← applyCompRule funPropDecl e f g funProp then return r | _ => continue else - trace[Debug.Meta.Tactic.fun_prop] - s!"decomposing in args {thm.mainArgs} to later use {←ppOrigin' thm.thmOrigin}" let .some (f,g) ← fData.decompositionOverArgs thm.mainArgs | continue - trace[Debug.Meta.Tactic.fun_prop] - s!"decomposition: {← ppExpr f} ∘ {← ppExpr g}" + trace[Meta.Tactic.fun_prop] + s!"decomposing to later use {←ppOrigin' thm.thmOrigin} as: + ({← ppExpr f}) ∘ ({← ppExpr g})" if let .some r ← applyCompRule funPropDecl e f g funProp then return r -- todo: decompose if uncurried and arguments do not match exactly @@ -594,9 +592,17 @@ def constAppCase (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) return r if let .some (f,g) ← fData.nontrivialDecomposition then + trace[Meta.Tactic.fun_prop] + s!"failed applying `{funPropDecl.funPropName}` theorems for `{funName}` + trying again after decomposing function as: `({← ppExpr f}) ∘ ({← ppExpr g})`" + if let .some r ← applyCompRule funPropDecl e f g funProp then return r else + trace[Meta.Tactic.fun_prop] + s!"failed applying `{funPropDecl.funPropName}` theorems for `{funName}` + now trying to prove `{funPropDecl.funPropName}` from another function property" + if let .some r ← applyTransitionRules e funProp then return r @@ -609,15 +615,27 @@ def cacheResult (e : Expr) (r : Result) : FunPropM Result := do -- return proof? modify (fun s => { s with cache := s.cache.insert e { expr := q(True), proof? := r.proof} }) return r +/-- Cache for failed goals such that `fun_prop` can fail fast next time. -/ +def cacheFailure (e : Expr) : FunPropM Unit := do -- return proof? + modify (fun s => { s with failureCache := s.failureCache.insert e }) + + mutual /-- Main `funProp` function. Returns proof of `e`. -/ partial def funProp (e : Expr) : FunPropM (Option Result) := do let e ← instantiateMVars e - -- check cache + + withTraceNode `Meta.Tactic.fun_prop + (fun r => do pure s!"[{ExceptToEmoji.toEmoji r}] {← ppExpr e}") do + + -- check cache for succesfull goals if let .some { expr := _, proof? := .some proof } := (← get).cache.find? e then - trace[Debug.Meta.Tactic.fun_prop] "cached result for {e}" + trace[Meta.Tactic.fun_prop] "reusing previously found proof for {e}" return .some { proof := proof } + else if (← get).failureCache.contains e then + trace[Meta.Tactic.fun_prop] "skipping proof search, proving {e} was tried already and failed" + return .none else -- take care of forall and let binders and run main match e with @@ -633,9 +651,12 @@ mutual cacheResult e {proof := ← mkLambdaFVars xs r.proof } | .mdata _ e' => funProp e' | _ => - let .some r ← main e - | return none - cacheResult e r + if let .some r ← main e then + cacheResult e r + else + cacheFailure e + return none + /-- Main `funProp` function. Returns proof of `e`. -/ private partial def main (e : Expr) : FunPropM (Option Result) := do @@ -645,9 +666,6 @@ mutual increaseSteps - withTraceNode `Meta.Tactic.fun_prop - (fun r => do pure s!"[{ExceptToEmoji.toEmoji r}] {← ppExpr e}") do - -- if function starts with let bindings move them the top of `e` and try again if f.isLet then return ← letTelescope f fun xs b => do diff --git a/Mathlib/Tactic/FunProp/Elab.lean b/Mathlib/Tactic/FunProp/Elab.lean index 94afec84e91770..6761d53f837c6d 100644 --- a/Mathlib/Tactic/FunProp/Elab.lean +++ b/Mathlib/Tactic/FunProp/Elab.lean @@ -83,6 +83,59 @@ def funPropTac : Tactic | _ => throwUnsupportedSyntax + + +/-- Command that printins all function properties attached to a function. + +For example +``` +#print_fun_prop_theorems HAdd.hAdd +``` +might print out +``` +Continuous + continuous_add, args: [4,5], priority: 1000 + continuous_add_left, args: [5], priority: 1000 + continuous_add_right, args [4], priority: 1000 + ... +Diferentiable + Differentiable.add, args: [4,5], priority: 1000 + Differentiable.add_const, args: [4], priority: 1000 + Differentiable.const_add, args: [5], priority: 1000 + ... +``` + +You can also see only theorems about a concrete function property +``` +#print_fun_prop_theorems HAdd.hAdd Continuous +``` +-/ +elab "#print_fun_prop_theorems " funIdent:ident funProp:(ident)? : command => do + + let funName ← ensureNonAmbiguous funIdent (← resolveGlobalConst funIdent) + let funProp? ← funProp.mapM (fun stx => do + ensureNonAmbiguous stx (← resolveGlobalConst stx)) + + let theorems := (functionTheoremsExt.getState (← getEnv)).theorems.findD funName {} + + let logTheorems (funProp : Name) (thms : Array FunctionTheorem) : Command.CommandElabM Unit := do + let mut msg : MessageData := "" + msg := msg ++ m!"{← Meta.ppOrigin (.decl funProp)}" + for thm in thms do + msg := msg ++ m!"\n {← Meta.ppOrigin (.decl thm.thmOrigin.name)}, \ + args: {thm.mainArgs}, form: {thm.form}" + pure () + logInfo msg + + + match funProp? with + | none => + for (funProp,thms) in theorems do + logTheorems funProp thms + | some funProp => + logTheorems funProp (theorems.findD funProp #[]) + + end Meta.FunProp end Mathlib diff --git a/Mathlib/Tactic/FunProp/Theorems.lean b/Mathlib/Tactic/FunProp/Theorems.lean index 1ab9b3850fec50..b0c184aedc988b 100644 --- a/Mathlib/Tactic/FunProp/Theorems.lean +++ b/Mathlib/Tactic/FunProp/Theorems.lean @@ -145,7 +145,7 @@ inductive TheoremForm where /-- TheoremForm to string -/ instance : ToString TheoremForm := - ⟨fun x => match x with | .uncurried => "uncurried" | .comp => "compositional"⟩ + ⟨fun x => match x with | .uncurried => "simple" | .comp => "compositional"⟩ /-- theorem about specific function (either declared constant or free variable) -/ structure FunctionTheorem where diff --git a/Mathlib/Tactic/FunProp/Types.lean b/Mathlib/Tactic/FunProp/Types.lean index 6f12b788e1928a..a8af67ac13b915 100644 --- a/Mathlib/Tactic/FunProp/Types.lean +++ b/Mathlib/Tactic/FunProp/Types.lean @@ -97,8 +97,10 @@ structure Context where /-- `fun_prop` state -/ structure State where /-- Simp's cache is used as the `fun_prop` tactic is designed to be used inside of simp and - utilize its cache -/ + utilize its cache. It holds successful goals. -/ cache : Simp.Cache := {} + /-- Cache storing failed goals such that they are not tried again. -/ + failureCache : ExprSet := {} /-- Count the number of steps and stop when maxSteps is reached. -/ numSteps := 0 /-- Log progress and failures messages that should be displayed to the user at the end. -/ diff --git a/Mathlib/Tactic/GCongr/Core.lean b/Mathlib/Tactic/GCongr/Core.lean index a47257466df275..90aeed7ba38159 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -367,7 +367,7 @@ partial def _root_.Lean.MVarId.gcongr 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) + Except.ok <$> withReducibleAndInstances (g.apply (← mkConstWithFreshMVarLevels lem.declName)) catch e => pure (Except.error e) match gs with | .error e => diff --git a/Mathlib/Tactic/ITauto.lean b/Mathlib/Tactic/ITauto.lean index f0449d9828b14d..f87cbcddd6ec36 100644 --- a/Mathlib/Tactic/ITauto.lean +++ b/Mathlib/Tactic/ITauto.lean @@ -486,7 +486,7 @@ partial def reify (e : Q(Prop)) : AtomM IProp := | ~q(@Ne Prop $a $b) => return .not (.eq (← reify a) (← reify b)) | e => if e.isArrow then return .imp (← reify e.bindingDomain!) (← reify e.bindingBody!) - else return .var (← AtomM.addAtom e) + else return .var (← AtomM.addAtom e).1 /-- Once we have a proof object, we have to apply it to the goal. -/ partial def applyProof (g : MVarId) (Γ : NameMap Expr) (p : Proof) : MetaM Unit := diff --git a/Mathlib/Tactic/Linarith/Preprocessing.lean b/Mathlib/Tactic/Linarith/Preprocessing.lean index eca9903c6a74d4..eda221c8c33d16 100644 --- a/Mathlib/Tactic/Linarith/Preprocessing.lean +++ b/Mathlib/Tactic/Linarith/Preprocessing.lean @@ -274,12 +274,12 @@ partial def findSquares (s : RBSet (Nat × Bool) lexOrd.compare) (e : Expr) : | (``HPow.hPow, #[_, _, _, _, a, b]) => match b.numeral? with | some 2 => do let s ← findSquares s a - let ai ← AtomM.addAtom a + let (ai, _) ← AtomM.addAtom a return (s.insert (ai, true)) | _ => e.foldlM findSquares s | (``HMul.hMul, #[_, _, _, _, a, b]) => do - let ai ← AtomM.addAtom a - let bi ← AtomM.addAtom b + let (ai, _) ← AtomM.addAtom a + let (bi, _) ← AtomM.addAtom b if ai = bi then do let s ← findSquares s a return (s.insert (ai, false)) diff --git a/Mathlib/Tactic/LinearCombination.lean b/Mathlib/Tactic/LinearCombination.lean index f1c65e78a805b8..5c891e021eae95 100644 --- a/Mathlib/Tactic/LinearCombination.lean +++ b/Mathlib/Tactic/LinearCombination.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Abby J. Goldberg, Mario Carneiro, Heather Macbeth -/ import Mathlib.Tactic.LinearCombination.Lemmas +import Mathlib.Tactic.Positivity.Core import Mathlib.Tactic.Ring import Mathlib.Tactic.Ring.Compare diff --git a/Mathlib/Tactic/LinearCombination/Lemmas.lean b/Mathlib/Tactic/LinearCombination/Lemmas.lean index 2d93dbab832175..e22bec542ae8b9 100644 --- a/Mathlib/Tactic/LinearCombination/Lemmas.lean +++ b/Mathlib/Tactic/LinearCombination/Lemmas.lean @@ -3,8 +3,8 @@ 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, Heather Macbeth -/ +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Data.Ineq -import Mathlib.Algebra.Order.Field.Basic /-! # Lemmas for the linear_combination tactic diff --git a/Mathlib/Tactic/Linter/DocPrime.lean b/Mathlib/Tactic/Linter/DocPrime.lean index 7221a12e1ad7fb..c2a8a38fbcdcf2 100644 --- a/Mathlib/Tactic/Linter/DocPrime.lean +++ b/Mathlib/Tactic/Linter/DocPrime.lean @@ -26,7 +26,7 @@ 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. +The file `scripts/nolints_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 := { @@ -63,8 +63,8 @@ def docPrimeLinter : Linter where run := withSetOptionIn fun stx ↦ do 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 + if ← System.FilePath.pathExists "scripts/nolints_prime_decls.txt" then + if (← IO.FS.lines "scripts/nolints_prime_decls.txt").contains declName.toString then return else Linter.logLint linter.docPrime declId msg diff --git a/Mathlib/Tactic/Linter/Header.lean b/Mathlib/Tactic/Linter/Header.lean index 3e2a44a3d836f3..19b353da35598d 100644 --- a/Mathlib/Tactic/Linter/Header.lean +++ b/Mathlib/Tactic/Linter/Header.lean @@ -218,6 +218,15 @@ def isInMathlib (modName : Name) : IO Bool := do return (ml.map (·.module == modName)).any (·) else return false +/-- `inMathlibRef` is +* `none` at initialization time; +* `some true` if the `header` linter has already discovered that the current file + is imported in `Mathlib.lean`; +* `some false` if the `header` linter has already discovered that the current file + is *not* imported in `Mathlib.lean`. +-/ +initialize inMathlibRef : IO.Ref (Option Bool) ← IO.mkRef none + /-- The "header" style linter checks that a file starts with ``` @@ -290,7 +299,18 @@ def duplicateImportsCheck (imports : Array Syntax) : CommandElabM Unit := do @[inherit_doc Mathlib.Linter.linter.style.header] def headerLinter : Linter where run := withSetOptionIn fun stx ↦ do let mainModule ← getMainModule - unless Linter.getLinterValue linter.style.header (← getOptions) || (← isInMathlib mainModule) do + let inMathlib? := ← match ← inMathlibRef.get with + | some d => return d + | none => do + let val ← isInMathlib mainModule + -- We store the answer to the question "is this file in `Mathlib.lean`?" in `inMathlibRef` + -- to avoid recomputing its value on every command. This is a performance optimisation. + inMathlibRef.set (some val) + return val + -- The linter skips files not imported in `Mathlib.lean`, to avoid linting "scratch files". + -- It is however active in the test file `MathlibTest.Header` for the linter itself. + unless inMathlib? || mainModule == `MathlibTest.Header do return + unless Linter.getLinterValue linter.style.header (← getOptions) do return if (← get).messages.hasErrors then return diff --git a/Mathlib/Tactic/Linter/TextBased.lean b/Mathlib/Tactic/Linter/TextBased.lean index a1d3a9955b489e..aa2c455269b43f 100644 --- a/Mathlib/Tactic/Linter/TextBased.lean +++ b/Mathlib/Tactic/Linter/TextBased.lean @@ -56,6 +56,8 @@ inductive StyleError where | adaptationNote /-- A line ends with windows line endings (\r\n) instead of unix ones (\n). -/ | windowsLineEnding + /-- A line contains trailing whitespace. -/ + | trailingWhitespace deriving BEq /-- How to format style errors -/ @@ -76,6 +78,7 @@ def StyleError.errorMessage (err : StyleError) : String := match err with "Found the string \"Adaptation note:\", please use the #adaptation_note command instead" | windowsLineEnding => "This line ends with a windows line ending (\r\n): please use Unix line\ endings (\n) instead" + | trailingWhitespace => "This line ends with some whitespace: please remove this" /-- 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; @@ -83,6 +86,7 @@ def StyleError.errorMessage (err : StyleError) : String := match err with def StyleError.errorCode (err : StyleError) : String := match err with | StyleError.adaptationNote => "ERR_ADN" | StyleError.windowsLineEnding => "ERR_WIN" + | StyleError.trailingWhitespace => "ERR_TWS" /-- Context for a style error: the actual error, the line number in the file we're reading and the path to the file. -/ @@ -160,6 +164,7 @@ 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_ADN" => some (StyleError.adaptationNote) + | "ERR_TWS" => some (StyleError.trailingWhitespace) | "ERR_WIN" => some (StyleError.windowsLineEnding) | _ => none match String.toNat? lineNumber with @@ -196,14 +201,24 @@ section /-- Lint on any occurrences of the string "Adaptation note:" or variants thereof. -/ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do let mut errors := Array.mkEmpty 0 - let mut lineNumber := 1 - for line in lines do + for (line, idx) in lines.zipWithIndex do -- We make this shorter to catch "Adaptation note", "adaptation note" and a missing colon. if line.containsSubstr "daptation note" then - errors := errors.push (StyleError.adaptationNote, lineNumber) - lineNumber := lineNumber + 1 + errors := errors.push (StyleError.adaptationNote, idx + 1) return (errors, none) + +/-- Lint a collection of input strings if one of them contains trailing whitespace. -/ +def trailingWhitespaceLinter : TextbasedLinter := fun lines ↦ Id.run do + let mut errors := Array.mkEmpty 0 + let mut fixedLines := lines + for (line, idx) in lines.zipWithIndex do + if line.back == ' ' then + errors := errors.push (StyleError.trailingWhitespace, idx + 1) + fixedLines := fixedLines.set! idx line.trimRight + return (errors, if errors.size > 0 then some fixedLines else none) + + /-- 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. -/ def isImportsOnlyFile (lines : Array String) : Bool := @@ -215,7 +230,7 @@ end /-- All text-based linters registered in this file. -/ def allLinters : Array TextbasedLinter := #[ - adaptationNoteLinter + adaptationNoteLinter, trailingWhitespaceLinter ] @@ -257,7 +272,6 @@ def lintFile (path : FilePath) (exceptions : Array ErrorContext) : (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; correct automatically fixable style errors if configured so. diff --git a/Mathlib/Tactic/Linter/UpstreamableDecl.lean b/Mathlib/Tactic/Linter/UpstreamableDecl.lean index 86f55dc84e8bd8..59beda016bc47d 100644 --- a/Mathlib/Tactic/Linter/UpstreamableDecl.lean +++ b/Mathlib/Tactic/Linter/UpstreamableDecl.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa, Anne Baanen -/ import ImportGraph.Imports -import Mathlib.Lean.Expr.Basic import Mathlib.Tactic.MinImports /-! # The `upstreamableDecl` linter @@ -21,8 +20,12 @@ def Lean.Name.isLocal (env : Environment) (decl : Name) : Bool := open Mathlib.Command.MinImports -/-- Does the declaration with this name depend on `def`s in the current file? -/ -def Lean.Environment.localDefDependencies (env : Environment) (stx id : Syntax) : +/-- Does the declaration with this name depend on definitions in the current file? + +Here, "definition" means everything that is not a theorem, and so includes `def`, +`structure`, `inductive`, etc. +-/ +def Lean.Environment.localDefinitionDependencies (env : Environment) (stx id : Syntax) : CommandElabM Bool := do let declName : NameSet ← try NameSet.ofList <$> resolveGlobalConst id @@ -37,7 +40,14 @@ def Lean.Environment.localDefDependencies (env : Environment) (stx id : Syntax) let deps ← liftCoreM <| immediateDeps.transitivelyUsedConstants let constInfos := deps.toList.filterMap env.find? - let defs := constInfos.filter (·.isDef) + -- We allow depending on theorems and constructors. + -- We explicitly allow constructors since `inductive` declarations are reported to depend on their + -- own constructors, and we want inductives to behave the same as definitions, so place one + -- warning on the inductive itself but nothing on its downstream uses. + -- (There does not seem to be an easy way to determine, given `Syntax` and `ConstInfo`, + -- whether the `ConstInfo` is a constructor declared in this piece of `Syntax`.) + let defs := constInfos.filter (fun constInfo => !(constInfo.isTheorem || constInfo.isCtor)) + return defs.any fun constInfo => !(declName.contains constInfo.name) && constInfo.name.isLocal env namespace Mathlib.Linter @@ -72,7 +82,7 @@ def upstreamableDeclLinter : Linter where run := withSetOptionIn fun stx ↦ do let minImports := getIrredundantImports env (← getAllImports stx id) match minImports with | ⟨(RBNode.node _ .leaf upstream _ .leaf), _⟩ => do - if !(← env.localDefDependencies stx id) then + if !(← env.localDefinitionDependencies stx id) then let p : GoToModuleLinkProps := { modName := upstream } let widget : MessageData := .ofWidget (← liftCoreM <| Widget.WidgetInstance.ofHash diff --git a/Mathlib/Tactic/Module.lean b/Mathlib/Tactic/Module.lean index 4df4c398c9ef42..e06d5ce2088c2d 100644 --- a/Mathlib/Tactic/Module.lean +++ b/Mathlib/Tactic/Module.lean @@ -464,9 +464,9 @@ partial def parse (iM : Q(AddCommMonoid $M)) (x : Q($M)) : 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)⟩ + let (k, ⟨x', _⟩) ← AtomM.addAtomQ 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 diff --git a/Mathlib/Tactic/NormNum/GCD.lean b/Mathlib/Tactic/NormNum/GCD.lean index 1e3b522bdd15a0..cf43344d0f6e3f 100644 --- a/Mathlib/Tactic/NormNum/GCD.lean +++ b/Mathlib/Tactic/NormNum/GCD.lean @@ -1,8 +1,9 @@ /- 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 +Authors: Mario Carneiro, Kyle Miller, Eric Wieser -/ +import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.Int.GCD import Mathlib.Tactic.NormNum @@ -210,6 +211,48 @@ def evalIntLCM : NormNumExt where eval {u α} e := do let ⟨ed, pf⟩ := proveIntLCM ex ey return .isNat _ ed q(isInt_lcm $p $q $pf) +theorem isInt_ratNum : ∀ {q : ℚ} {n : ℤ} {n' : ℕ} {d : ℕ}, + IsRat q n d → n.natAbs = n' → n'.gcd d = 1 → IsInt q.num n + | _, n, _, d, ⟨hi, rfl⟩, rfl, h => by + constructor + have : 0 < d := Nat.pos_iff_ne_zero.mpr <| by simpa using hi.ne_zero + simp_rw [Rat.mul_num, Rat.intCast_den, invOf_eq_inv, + Rat.inv_natCast_den_of_pos this, Rat.inv_natCast_num_of_pos this, + Rat.intCast_num, one_mul, mul_one, h, Nat.cast_one, Int.ediv_one, Int.cast_id] + +theorem isNat_ratDen : ∀ {q : ℚ} {n : ℤ} {n' : ℕ} {d : ℕ}, + IsRat q n d → n.natAbs = n' → n'.gcd d = 1 → IsNat q.den d + | _, n, _, d, ⟨hi, rfl⟩, rfl, h => by + constructor + have : 0 < d := Nat.pos_iff_ne_zero.mpr <| by simpa using hi.ne_zero + simp_rw [Rat.mul_den, Rat.intCast_den, invOf_eq_inv, + Rat.inv_natCast_den_of_pos this, Rat.inv_natCast_num_of_pos this, + Rat.intCast_num, one_mul, mul_one, Nat.cast_id, h, Nat.div_one] + +/-- Evaluates the `Rat.num` function. -/ +@[nolint unusedHavesSuffices, norm_num Rat.num _] +def evalRatNum : NormNumExt where eval {u α} e := do + let .proj _ _ (q : Q(ℚ)) ← Meta.whnfR e | failure + have : u =QL 0 := ⟨⟩; have : $α =Q ℤ := ⟨⟩; have : $e =Q Rat.num $q := ⟨⟩ + let ⟨q', n, d, eq⟩ ← deriveRat q (_inst := q(inferInstance)) + let ⟨n', hn⟩ := rawIntLitNatAbs n + -- deriveRat ensures these are coprime, so the gcd will be 1 + let ⟨gcd, pf⟩ := proveNatGCD q($n') q($d) + have : $gcd =Q nat_lit 1 := ⟨⟩ + return .isInt _ n q'.num q(isInt_ratNum $eq $hn $pf) + +/-- Evaluates the `Rat.den` function. -/ +@[nolint unusedHavesSuffices, norm_num Rat.den _] +def evalRatDen : NormNumExt where eval {u α} e := do + let .proj _ _ (q : Q(ℚ)) ← Meta.whnfR e | failure + have : u =QL 0 := ⟨⟩; have : $α =Q ℕ := ⟨⟩; have : $e =Q Rat.den $q := ⟨⟩ + let ⟨q', n, d, eq⟩ ← deriveRat q (_inst := q(inferInstance)) + let ⟨n', hn⟩ := rawIntLitNatAbs n + -- deriveRat ensures these are coprime, so the gcd will be 1 + let ⟨gcd, pf⟩ := proveNatGCD q($n') q($d) + have : $gcd =Q nat_lit 1 := ⟨⟩ + return .isNat _ d q(isNat_ratDen $eq $hn $pf) + end NormNum end Tactic diff --git a/Mathlib/Tactic/Polyrith.lean b/Mathlib/Tactic/Polyrith.lean index 57ef95ad04cbb4..50e42c8eecbd17 100644 --- a/Mathlib/Tactic/Polyrith.lean +++ b/Mathlib/Tactic/Polyrith.lean @@ -133,7 +133,7 @@ partial def parse {u : Level} {α : Q(Type u)} (sα : Q(CommSemiring $α)) (c : Ring.Cache sα) (e : Q($α)) : AtomM Poly := do let els := do try pure <| Poly.const (← (← NormNum.derive e).toRat) - catch _ => pure <| Poly.var (← addAtom e) + catch _ => pure <| Poly.var (← addAtom e).1 let .const n _ := (← withReducible <| whnf e).getAppFn | els match n, c.rα with | ``HAdd.hAdd, _ | ``Add.add, _ => match e with diff --git a/Mathlib/Tactic/Positivity.lean b/Mathlib/Tactic/Positivity.lean index 8d76b597bcf25a..7b2a24e70ec160 100644 --- a/Mathlib/Tactic/Positivity.lean +++ b/Mathlib/Tactic/Positivity.lean @@ -1,3 +1,4 @@ import Mathlib.Tactic.Positivity.Basic +import Mathlib.Tactic.Positivity.Finset import Mathlib.Tactic.NormNum.Basic import Mathlib.Data.Int.Order.Basic diff --git a/Mathlib/Tactic/Ring/Basic.lean b/Mathlib/Tactic/Ring/Basic.lean index 84faee3f1a0d4c..b5dacb13e9ab5c 100644 --- a/Mathlib/Tactic/Ring/Basic.lean +++ b/Mathlib/Tactic/Ring/Basic.lean @@ -512,9 +512,8 @@ mutual partial def ExBase.evalNatCast {a : Q(ℕ)} (va : ExBase sℕ a) : AtomM (Result (ExBase sα) q($a)) := match va with | .atom _ => do - let a' : Q($α) := q($a) - let i ← addAtom a' - pure ⟨a', ExBase.atom i, (q(Eq.refl $a') : Expr)⟩ + let (i, ⟨b', _⟩) ← addAtomQ q($a) + pure ⟨b', ExBase.atom i, q(Eq.refl $b')⟩ | .sum va => do let ⟨_, vc, p⟩ ← va.evalNatCast pure ⟨_, .sum vc, p⟩ @@ -952,11 +951,11 @@ Evaluates an atom, an expression where `ring` can find no additional structure. def evalAtom (e : Q($α)) : AtomM (Result (ExSum sα) e) := do let r ← (← read).evalAtom e have e' : Q($α) := r.expr - let i ← addAtom e' - let ve' := (ExBase.atom i (e := e')).toProd (ExProd.mkNat sℕ 1).2 |>.toSum + let (i, ⟨a', _⟩) ← addAtomQ e' + let ve' := (ExBase.atom i (e := a')).toProd (ExProd.mkNat sℕ 1).2 |>.toSum pure ⟨_, ve', match r.proof? with | none => (q(atom_pf $e) : Expr) - | some (p : Q($e = $e')) => (q(atom_pf' $p) : Expr)⟩ + | some (p : Q($e = $a')) => (q(atom_pf' $p) : Expr)⟩ theorem inv_mul {R} [DivisionRing R] {a₁ a₂ a₃ b₁ b₃ c} (_ : (a₁⁻¹ : R) = b₁) (_ : (a₃⁻¹ : R) = b₃) @@ -977,9 +976,8 @@ variable (dα : Q(DivisionRing $α)) /-- Applies `⁻¹` to a polynomial to get an atom. -/ def evalInvAtom (a : Q($α)) : AtomM (Result (ExBase sα) q($a⁻¹)) := do - let a' : Q($α) := q($a⁻¹) - let i ← addAtom a' - pure ⟨a', ExBase.atom i, (q(Eq.refl $a') : Expr)⟩ + let (i, ⟨b', _⟩) ← addAtomQ q($a⁻¹) + pure ⟨b', ExBase.atom i, q(Eq.refl $b')⟩ /-- Inverts a polynomial `va` to get a normalized result polynomial. diff --git a/Mathlib/Tactic/Sat/FromLRAT.lean b/Mathlib/Tactic/Sat/FromLRAT.lean index c1962b10c84a84..db7f18cb54a913 100644 --- a/Mathlib/Tactic/Sat/FromLRAT.lean +++ b/Mathlib/Tactic/Sat/FromLRAT.lean @@ -3,7 +3,8 @@ Copyright (c) 2022 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic +import Mathlib.Tactic.ByContra /-! # `lrat_proof` command diff --git a/Mathlib/Tactic/TFAE.lean b/Mathlib/Tactic/TFAE.lean index 45405bfe5ad585..ac5f1114a8529b 100644 --- a/Mathlib/Tactic/TFAE.lean +++ b/Mathlib/Tactic/TFAE.lean @@ -298,18 +298,18 @@ elab_rules : tactic goal.withContext do let (tfaeListQ, tfaeList) ← getTFAEList (← goal.getType) closeMainGoal `tfae_finish <|← AtomM.run .reducible do - let is ← tfaeList.mapM AtomM.addAtom + let is ← tfaeList.mapM (fun e ↦ Prod.fst <$> AtomM.addAtom e) let mut hyps := #[] for hyp in ← getLocalHyps do let ty ← whnfR <|← instantiateMVars <|← inferType hyp if let (``Iff, #[p1, p2]) := ty.getAppFnArgs then - let q1 ← AtomM.addAtom p1 - let q2 ← AtomM.addAtom p2 + let (q1, _) ← AtomM.addAtom p1 + let (q2, _) ← AtomM.addAtom p2 hyps := hyps.push (q1, q2, ← mkAppM ``Iff.mp #[hyp]) hyps := hyps.push (q2, q1, ← mkAppM ``Iff.mpr #[hyp]) else if ty.isArrow then - let q1 ← AtomM.addAtom ty.bindingDomain! - let q2 ← AtomM.addAtom ty.bindingBody! + let (q1, _) ← AtomM.addAtom ty.bindingDomain! + let (q2, _) ← AtomM.addAtom ty.bindingBody! hyps := hyps.push (q1, q2, hyp) proveTFAE hyps (← get).atoms is tfaeListQ diff --git a/Mathlib/Tactic/ToAdditive/Frontend.lean b/Mathlib/Tactic/ToAdditive/Frontend.lean index c7a97764f023a1..25e3af975e0bf8 100644 --- a/Mathlib/Tactic/ToAdditive/Frontend.lean +++ b/Mathlib/Tactic/ToAdditive/Frontend.lean @@ -964,6 +964,7 @@ def nameDict : String → List String | "powers" => ["multiples"] | "multipliable"=> ["summable"] | "gpfree" => ["apfree"] + | "quantale" => ["add", "Quantale"] | x => [x] /-- diff --git a/Mathlib/Testing/Plausible/Functions.lean b/Mathlib/Testing/Plausible/Functions.lean index 9a83323198f476..a9bdf24d8ccb4a 100644 --- a/Mathlib/Testing/Plausible/Functions.lean +++ b/Mathlib/Testing/Plausible/Functions.lean @@ -40,9 +40,9 @@ their defining property is invariant through shrinking. Injective functions are an example of how complicated it can get. -/ -universe u v w +universe u v -variable {α : Type u} {β : Type v} {γ : Sort w} +variable {α : Type u} {β : Type v} namespace Plausible diff --git a/Mathlib/Topology/Algebra/ClosedSubgroup.lean b/Mathlib/Topology/Algebra/ClosedSubgroup.lean index 543b8793ad0fa0..f3cf42ab0809fc 100644 --- a/Mathlib/Topology/Algebra/ClosedSubgroup.lean +++ b/Mathlib/Topology/Algebra/ClosedSubgroup.lean @@ -102,7 +102,7 @@ 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) + ↦ IsClosed.smul h (Quotient.out x.1) ext x refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · have : QuotientGroup.mk 1 ≠ QuotientGroup.mk (s := H) x := by @@ -110,7 +110,7 @@ lemma isOpen_of_isClosed_of_finiteIndex (H : Subgroup G) [H.FiniteIndex] 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 + (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⟩ diff --git a/Mathlib/Topology/Algebra/ConstMulAction.lean b/Mathlib/Topology/Algebra/ConstMulAction.lean index 1da40dadc219d3..10007257a47c57 100644 --- a/Mathlib/Topology/Algebra/ConstMulAction.lean +++ b/Mathlib/Topology/Algebra/ConstMulAction.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex Kontorovich, Heather Macbeth -/ import Mathlib.Algebra.Module.ULift +import Mathlib.Algebra.Order.Group.Synonym import Mathlib.Data.Set.Pointwise.SMul import Mathlib.GroupTheory.GroupAction.Defs import Mathlib.Topology.Algebra.Constructions @@ -266,7 +267,7 @@ theorem smul_mem_nhds_smul_iff {t : Set α} (g : G) {a : α} : g • t ∈ 𝓝 @[to_additive] alias ⟨_, smul_mem_nhds_smul⟩ := smul_mem_nhds_smul_iff -@[to_additive (attr := deprecated (since := "2024-08-06"))] +@[to_additive (attr := deprecated "No deprecation message was provided." (since := "2024-08-06"))] alias smul_mem_nhds := smul_mem_nhds_smul @[to_additive (attr := simp)] diff --git a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean index 91b1a4ca3bcd43..f7373a1da6da01 100644 --- a/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean +++ b/Mathlib/Topology/Algebra/ContinuousMonoidHom.lean @@ -65,7 +65,8 @@ homomorphisms. 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"))] +@[to_additive (attr := deprecated "Use `[MonoidHomClass F A B] [ContinuousMapClass F A B]` instead." + (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, ContinuousMapClass F A B : Prop diff --git a/Mathlib/Topology/Algebra/Field.lean b/Mathlib/Topology/Algebra/Field.lean index 48b1183bc9f014..cc34c6223561e6 100644 --- a/Mathlib/Topology/Algebra/Field.lean +++ b/Mathlib/Topology/Algebra/Field.lean @@ -5,6 +5,7 @@ Authors: Patrick Massot, Kim Morrison -/ import Mathlib.Algebra.Field.Subfield.Basic import Mathlib.Algebra.GroupWithZero.Divisibility +import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.Topology.Algebra.GroupWithZero import Mathlib.Topology.Algebra.Ring.Basic import Mathlib.Topology.Order.LocalExtr @@ -91,6 +92,26 @@ def affineHomeomorph (a b : 𝕜) (h : a ≠ 0) : 𝕜 ≃ₜ 𝕜 where exact mul_div_cancel_left₀ x h right_inv y := by simp [mul_div_cancel₀ _ h] +theorem affineHomeomorph_image_Icc {𝕜 : Type*} [LinearOrderedField 𝕜] [TopologicalSpace 𝕜] + [TopologicalRing 𝕜] (a b c d : 𝕜) (h : 0 < a) : + affineHomeomorph a b h.ne' '' Set.Icc c d = Set.Icc (a * c + b) (a * d + b) := by + simp [h] + +theorem affineHomeomorph_image_Ico {𝕜 : Type*} [LinearOrderedField 𝕜] [TopologicalSpace 𝕜] + [TopologicalRing 𝕜] (a b c d : 𝕜) (h : 0 < a) : + affineHomeomorph a b h.ne' '' Set.Ico c d = Set.Ico (a * c + b) (a * d + b) := by + simp [h] + +theorem affineHomeomorph_image_Ioc {𝕜 : Type*} [LinearOrderedField 𝕜] [TopologicalSpace 𝕜] + [TopologicalRing 𝕜] (a b c d : 𝕜) (h : 0 < a) : + affineHomeomorph a b h.ne' '' Set.Ioc c d = Set.Ioc (a * c + b) (a * d + b) := by + simp [h] + +theorem affineHomeomorph_image_Ioo {𝕜 : Type*} [LinearOrderedField 𝕜] [TopologicalSpace 𝕜] + [TopologicalRing 𝕜] (a b c d : 𝕜) (h : 0 < a) : + affineHomeomorph a b h.ne' '' Set.Ioo c d = Set.Ioo (a * c + b) (a * d + b) := by + simp [h] + end affineHomeomorph section LocalExtr diff --git a/Mathlib/Topology/Algebra/Group/Quotient.lean b/Mathlib/Topology/Algebra/Group/Quotient.lean index 4a2b490786409e..e46af523bf2cae 100644 --- a/Mathlib/Topology/Algebra/Group/Quotient.lean +++ b/Mathlib/Topology/Algebra/Group/Quotient.lean @@ -76,7 +76,7 @@ instance instLocallyCompactSpace [LocallyCompactSpace G] (N : Subgroup G) : LocallyCompactSpace (G ⧸ N) := QuotientGroup.isOpenQuotientMap_mk.locallyCompactSpace -@[to_additive (attr := deprecated (since := "2024-10-05"))] +@[to_additive (attr := deprecated "No deprecation message was provided." (since := "2024-10-05"))] theorem continuous_smul₁ (x : G ⧸ N) : Continuous fun g : G => g • x := continuous_id.smul continuous_const @@ -101,7 +101,7 @@ instance instSecondCountableTopology [SecondCountableTopology G] : SecondCountableTopology (G ⧸ N) := ContinuousConstSMul.secondCountableTopology -@[to_additive (attr := deprecated (since := "2024-08-05"))] +@[to_additive (attr := deprecated "No deprecation message was provided." (since := "2024-08-05"))] theorem nhds_one_isCountablyGenerated [FirstCountableTopology G] [N.Normal] : (𝓝 (1 : G ⧸ N)).IsCountablyGenerated := inferInstance @@ -117,7 +117,7 @@ instance instTopologicalGroup [N.Normal] : TopologicalGroup (G ⧸ N) where exact continuous_mk.comp continuous_mul continuous_inv := continuous_inv.quotient_map' _ -@[to_additive (attr := deprecated (since := "2024-08-05"))] +@[to_additive (attr := deprecated "No deprecation message was provided." (since := "2024-08-05"))] theorem _root_.topologicalGroup_quotient [N.Normal] : TopologicalGroup (G ⧸ N) := instTopologicalGroup N diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index 74529c1335d72f..ba49c204bab72a 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -21,12 +21,12 @@ noncomputable section open Filter Finset Function Topology -variable {α β γ δ : Type*} +variable {α β γ : Type*} section HasProd variable [CommMonoid α] [TopologicalSpace α] -variable {f g : β → α} {a b : α} {s : Finset β} +variable {f g : β → α} {a b : α} /-- Constant one function has product `1` -/ @[to_additive "Constant zero function has sum `0`"] @@ -355,7 +355,7 @@ end HasProd section tprod -variable [CommMonoid α] [TopologicalSpace α] {f g : β → α} {a a₁ a₂ : α} +variable [CommMonoid α] [TopologicalSpace α] {f g : β → α} @[to_additive] theorem tprod_congr_set_coe (f : β → α) {s t : Set β} (h : s = t) : diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean index 47d09ed95c689d..4386fe90f6bd14 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean @@ -20,7 +20,7 @@ open Filter Finset Function open scoped Topology -variable {α β γ δ : Type*} +variable {α β γ : Type*} /-! ## Product, Sigma and Pi types -/ @@ -192,6 +192,11 @@ theorem Multipliable.prod_factor {f : β × γ → α} (h : Multipliable f) (b : Multipliable fun c ↦ f (b, c) := h.comp_injective fun _ _ h ↦ (Prod.ext_iff.1 h).2 +@[to_additive Summable.prod] +lemma Multipliable.prod {f : β × γ → α} (h : Multipliable f) : + Multipliable fun b ↦ ∏' c, f (b, c) := + ((Equiv.sigmaEquivProd β γ).multipliable_iff.mpr h).sigma + @[to_additive] lemma HasProd.tprod_fiberwise [T2Space α] {f : β → α} {a : α} (hf : HasProd f a) (g : β → γ) : HasProd (fun c : γ ↦ ∏' b : g ⁻¹' {c}, f b) a := diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean index 2bf685cd201e10..cc835074878097 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Defs.lean @@ -111,7 +111,7 @@ notation3 "∏' "(...)", "r:67:(scoped f => tprod f) => r @[inherit_doc tsum] notation3 "∑' "(...)", "r:67:(scoped f => tsum f) => r -variable {f g : β → α} {a b : α} {s : Finset β} +variable {f : β → α} {a : α} {s : Finset β} @[to_additive] theorem HasProd.multipliable (h : HasProd f a) : Multipliable f := diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean index 4c5353916aae3a..937a415544928b 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean @@ -20,7 +20,7 @@ open Filter Finset Function open scoped Topology -variable {α β γ δ : Type*} +variable {α β γ : Type*} section TopologicalGroup @@ -197,7 +197,7 @@ theorem multipliable_iff_cauchySeq_finset [CompleteSpace α] {f : β → α} : Multipliable f ↔ CauchySeq fun s : Finset β ↦ ∏ b ∈ s, f b := by classical exact cauchy_map_iff_exists_tendsto.symm -variable [UniformGroup α] {f g : β → α} {a a₁ a₂ : α} +variable [UniformGroup α] {f g : β → α} @[to_additive] theorem cauchySeq_finset_iff_prod_vanishing : diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean b/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean index ea55550f547438..aa0cdf8f9a57d1 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean @@ -19,12 +19,12 @@ This file provides lemmas about the interaction between infinite sums and multip open Filter Finset Function -variable {ι κ R α : Type*} +variable {ι κ α : Type*} section NonUnitalNonAssocSemiring -variable [NonUnitalNonAssocSemiring α] [TopologicalSpace α] [TopologicalSemiring α] {f g : ι → α} - {a a₁ a₂ : α} +variable [NonUnitalNonAssocSemiring α] [TopologicalSpace α] [TopologicalSemiring α] {f : ι → α} + {a₁ : α} theorem HasSum.mul_left (a₂) (h : HasSum f a₁) : HasSum (fun i ↦ a₂ * f i) (a₂ * a₁) := by simpa only using h.map (AddMonoidHom.mulLeft a₂) (continuous_const.mul continuous_id) @@ -63,8 +63,7 @@ end NonUnitalNonAssocSemiring section DivisionSemiring -variable [DivisionSemiring α] [TopologicalSpace α] [TopologicalSemiring α] {f g : ι → α} - {a a₁ a₂ : α} +variable [DivisionSemiring α] [TopologicalSpace α] [TopologicalSemiring α] {f : ι → α} {a a₁ a₂ : α} theorem HasSum.div_const (h : HasSum f a) (b : α) : HasSum (fun i ↦ f i / b) (a / b) := by simp only [div_eq_mul_inv, h.mul_right b⁻¹] diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean index 4f3a24fdd08bce..d339eba913c788 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean @@ -105,8 +105,6 @@ end NonarchimedeanGroup namespace NonarchimedeanRing -open NonarchimedeanRing - open NonarchimedeanAddGroup variable {R S : Type*} diff --git a/Mathlib/Topology/Algebra/Order/Field.lean b/Mathlib/Topology/Algebra/Order/Field.lean index 51f7585e7e00c8..29f1d4890fd66c 100644 --- a/Mathlib/Topology/Algebra/Order/Field.lean +++ b/Mathlib/Topology/Algebra/Order/Field.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Benjamin Davidson. All rights reserved. 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.Algebra.Order.Group.Pointwise.Interval import Mathlib.Order.Filter.AtTopBot.Field import Mathlib.Topology.Algebra.Field import Mathlib.Topology.Algebra.Order.Group @@ -114,7 +114,7 @@ theorem Filter.Tendsto.neg_mul_atBot {C : 𝕜} (hC : C < 0) (hf : Tendsto f l ( @[simp] lemma inv_atTop₀ : (atTop : Filter 𝕜)⁻¹ = 𝓝[>] 0 := (((atTop_basis_Ioi' (0 : 𝕜)).map _).comp_surjective inv_surjective).eq_of_same_basis <| - (nhdsWithin_Ioi_basis _).congr (by simp) fun a ha ↦ by simp [inv_Ioi (inv_pos.2 ha)] + (nhdsWithin_Ioi_basis _).congr (by simp) fun a ha ↦ by simp [inv_Ioi₀ (inv_pos.2 ha)] @[simp] lemma inv_nhdsWithin_Ioi_zero : (𝓝[>] (0 : 𝕜))⁻¹ = atTop := by rw [← inv_atTop₀, inv_inv] diff --git a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean index 44fe760b02479f..9f2b202d567893 100644 --- a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean +++ b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean @@ -130,20 +130,18 @@ instance (priority := 100) OrderTop.to_BoundedLENhdsClass [OrderTop α] : Bounde instance (priority := 100) OrderBot.to_BoundedGENhdsClass [OrderBot α] : BoundedGENhdsClass α := ⟨fun _a ↦ isBounded_ge_of_bot⟩ --- See note [lower instance priority] -instance (priority := 100) OrderTopology.to_BoundedLENhdsClass [IsDirected α (· ≤ ·)] - [OrderTopology α] : BoundedLENhdsClass α := - ⟨fun a ↦ - ((isTop_or_exists_gt a).elim fun h ↦ ⟨a, Eventually.of_forall h⟩) <| - Exists.imp fun _b ↦ ge_mem_nhds⟩ +end Preorder -- 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⟩) <| - Exists.imp fun _b ↦ le_mem_nhds⟩ +instance (priority := 100) BoundedLENhdsClass.of_closedIciTopology [LinearOrder α] + [TopologicalSpace α] [ClosedIciTopology α] : BoundedLENhdsClass α := + ⟨fun a ↦ ((isTop_or_exists_gt a).elim fun h ↦ ⟨a, Eventually.of_forall h⟩) <| + Exists.imp fun _b ↦ eventually_le_nhds⟩ -end Preorder +-- See note [lower instance priority] +instance (priority := 100) BoundedGENhdsClass.of_closedIicTopology [LinearOrder α] + [TopologicalSpace α] [ClosedIicTopology α] : BoundedGENhdsClass α := + inferInstanceAs <| BoundedGENhdsClass αᵒᵈᵒᵈ section LiminfLimsup @@ -411,43 +409,6 @@ theorem Monotone.map_liminf_of_continuousAt {f : R → S} (f_incr : Monotone f) end Monotone -section InfiAndSupr - -open Topology - -open Filter Set - -variable [CompleteLinearOrder R] [TopologicalSpace R] [OrderTopology R] - -theorem iInf_eq_of_forall_le_of_tendsto {x : R} {as : ι → R} (x_le : ∀ i, x ≤ as i) {F : Filter ι} - [Filter.NeBot F] (as_lim : Filter.Tendsto as F (𝓝 x)) : ⨅ i, as i = x := by - refine iInf_eq_of_forall_ge_of_forall_gt_exists_lt (fun i ↦ x_le i) ?_ - apply fun w x_lt_w ↦ ‹Filter.NeBot F›.nonempty_of_mem (eventually_lt_of_tendsto_lt x_lt_w as_lim) - -theorem iSup_eq_of_forall_le_of_tendsto {x : R} {as : ι → R} (le_x : ∀ i, as i ≤ x) {F : Filter ι} - [Filter.NeBot F] (as_lim : Filter.Tendsto as F (𝓝 x)) : ⨆ i, as i = x := - iInf_eq_of_forall_le_of_tendsto (R := Rᵒᵈ) le_x as_lim - -theorem iUnion_Ici_eq_Ioi_of_lt_of_tendsto (x : R) {as : ι → R} (x_lt : ∀ i, x < as i) - {F : Filter ι} [Filter.NeBot F] (as_lim : Filter.Tendsto as F (𝓝 x)) : - ⋃ i : ι, Ici (as i) = Ioi x := by - have obs : x ∉ range as := by - intro maybe_x_is - rcases mem_range.mp maybe_x_is with ⟨i, hi⟩ - simpa only [hi, lt_self_iff_false] using x_lt i - -- Porting note: `rw at *` was too destructive. Let's only rewrite `obs` and the goal. - have := iInf_eq_of_forall_le_of_tendsto (fun i ↦ (x_lt i).le) as_lim - rw [← this] at obs - rw [← this] - exact iUnion_Ici_eq_Ioi_iInf obs - -theorem iUnion_Iic_eq_Iio_of_lt_of_tendsto (x : R) {as : ι → R} (lt_x : ∀ i, as i < x) - {F : Filter ι} [Filter.NeBot F] (as_lim : Filter.Tendsto as F (𝓝 x)) : - ⋃ i : ι, Iic (as i) = Iio x := - iUnion_Ici_eq_Ioi_of_lt_of_tendsto (R := Rᵒᵈ) x lt_x as_lim - -end InfiAndSupr - section Indicator theorem limsup_eq_tendsto_sum_indicator_nat_atTop (s : ℕ → Set α) : diff --git a/Mathlib/Topology/Algebra/Polynomial.lean b/Mathlib/Topology/Algebra/Polynomial.lean index 663b8bd81dc208..cda8bf62a44a17 100644 --- a/Mathlib/Topology/Algebra/Polynomial.lean +++ b/Mathlib/Topology/Algebra/Polynomial.lean @@ -37,8 +37,6 @@ open IsAbsoluteValue Filter namespace Polynomial -open Polynomial - section TopologicalSemiring variable {R S : Type*} [Semiring R] [TopologicalSpace R] [TopologicalSemiring R] (p : R[X]) diff --git a/Mathlib/Topology/Algebra/UniformGroup/Basic.lean b/Mathlib/Topology/Algebra/UniformGroup/Basic.lean index 8fd7dd61a29d27..4baeea0bda780c 100644 --- a/Mathlib/Topology/Algebra/UniformGroup/Basic.lean +++ b/Mathlib/Topology/Algebra/UniformGroup/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Topology.UniformSpace.UniformConvergence import Mathlib.Topology.UniformSpace.UniformEmbedding import Mathlib.Topology.UniformSpace.CompleteSeparated import Mathlib.Topology.UniformSpace.Compact +import Mathlib.Topology.UniformSpace.HeineCantor import Mathlib.Topology.Algebra.UniformGroup.Defs import Mathlib.Topology.Algebra.Group.Quotient import Mathlib.Topology.DiscreteSubset diff --git a/Mathlib/Topology/Algebra/UniformGroup/Defs.lean b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean index 1ebc4e5aa7b0d0..3455d9f14d056a 100644 --- a/Mathlib/Topology/Algebra/UniformGroup/Defs.lean +++ b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean @@ -3,8 +3,8 @@ Copyright (c) 2018 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Johannes Hölzl -/ -import Mathlib.Topology.UniformSpace.Basic import Mathlib.Topology.Algebra.Group.Basic +import Mathlib.Topology.UniformSpace.Basic /-! # Uniform structure on topological groups @@ -324,7 +324,7 @@ theorem MonoidHom.uniformContinuous_of_continuousAt_one [UniformSpace β] [Group its kernel is open. -/ @[to_additive "A homomorphism from a uniform additive group to a discrete uniform additive group is continuous if and only if its kernel is open."] -theorem UniformGroup.uniformContinuous_iff_open_ker {hom : Type*} [UniformSpace β] +theorem UniformGroup.uniformContinuous_iff_isOpen_ker {hom : Type*} [UniformSpace β] [DiscreteTopology β] [Group β] [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} : UniformContinuous f ↔ IsOpen ((f : α →* β).ker : Set α) := by @@ -334,6 +334,11 @@ theorem UniformGroup.uniformContinuous_iff_open_ker {hom : Type*} [UniformSpace rw [ContinuousAt, nhds_discrete β, map_one, tendsto_pure] exact hf.mem_nhds (map_one f) +@[deprecated (since := "2024-11-18")] alias UniformGroup.uniformContinuous_iff_open_ker := + UniformGroup.uniformContinuous_iff_isOpen_ker +@[deprecated (since := "2024-11-18")] alias UniformAddGroup.uniformContinuous_iff_open_ker := + UniformAddGroup.uniformContinuous_iff_isOpen_ker + @[to_additive] theorem uniformContinuous_monoidHom_of_continuous {hom : Type*} [UniformSpace β] [Group β] [UniformGroup β] [FunLike hom α β] [MonoidHomClass hom α β] {f : hom} (h : Continuous f) : diff --git a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean index 8cdff99b6d7feb..621c4dd2159b28 100644 --- a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean +++ b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean @@ -42,9 +42,10 @@ theorem subgroups_basis : RingSubgroupsBasis fun γ : Γ₀ˣ => (v.ltAddSubgrou cases' exists_square_le γ with γ₀ h use γ₀ rintro - ⟨r, r_in, s, s_in, rfl⟩ + simp only [ltAddSubgroup, AddSubgroup.coe_set_mk, mem_setOf_eq] at r_in s_in calc (v (r * s) : Γ₀) = v r * v s := Valuation.map_mul _ _ _ - _ < γ₀ * γ₀ := mul_lt_mul₀ r_in s_in + _ < γ₀ * γ₀ := by gcongr <;> exact zero_le' _ ≤ γ := mod_cast h leftMul := by rintro x γ diff --git a/Mathlib/Topology/Algebra/WithZeroTopology.lean b/Mathlib/Topology/Algebra/WithZeroTopology.lean index c115bccac22484..cd47b1c9d0f8fa 100644 --- a/Mathlib/Topology/Algebra/WithZeroTopology.lean +++ b/Mathlib/Topology/Algebra/WithZeroTopology.lean @@ -166,7 +166,7 @@ scoped instance (priority := 100) : ContinuousMul Γ₀ where refine ((hasBasis_nhds_zero.prod_nhds hasBasis_nhds_zero).tendsto_iff hasBasis_nhds_zero).2 fun γ hγ => ⟨(γ, 1), ⟨hγ, one_ne_zero⟩, ?_⟩ rintro ⟨x, y⟩ ⟨hx : x < γ, hy : y < 1⟩ - exact (mul_lt_mul₀ hx hy).trans_eq (mul_one γ) + exact (mul_lt_mul'' hx hy zero_le' zero_le').trans_eq (mul_one γ) · 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 => ?_⟩ diff --git a/Mathlib/Topology/Bornology/Basic.lean b/Mathlib/Topology/Bornology/Basic.lean index 6b8a44d2bdedf8..e8de59a17b3692 100644 --- a/Mathlib/Topology/Bornology/Basic.lean +++ b/Mathlib/Topology/Bornology/Basic.lean @@ -261,7 +261,7 @@ open Bornology theorem Filter.HasBasis.disjoint_cobounded_iff [Bornology α] {ι : Sort*} {p : ι → Prop} {s : ι → Set α} {l : Filter α} (h : l.HasBasis p s) : - Disjoint l (cobounded α) ↔ ∃ i, p i ∧ IsBounded (s i) := + Disjoint l (cobounded α) ↔ ∃ i, p i ∧ Bornology.IsBounded (s i) := h.disjoint_iff_left theorem Set.Finite.isBounded [Bornology α] {s : Set α} (hs : s.Finite) : IsBounded s := diff --git a/Mathlib/Topology/Category/LightProfinite/Basic.lean b/Mathlib/Topology/Category/LightProfinite/Basic.lean index 362a23b4df0545..bd67bbffa19eab 100644 --- a/Mathlib/Topology/Category/LightProfinite/Basic.lean +++ b/Mathlib/Topology/Category/LightProfinite/Basic.lean @@ -297,10 +297,11 @@ instance instCountableDiscreteQuotient (S : LightProfinite) : /-- A profinite space which is light gives rise to a light profinite space. -/ noncomputable def toLightDiagram (S : LightProfinite.{u}) : LightDiagram.{u} where - diagram := sequentialFunctor _ ⋙ (lightToProfinite.obj S).fintypeDiagram - cone := (Functor.Initial.limitConeComp (sequentialFunctor _) (lightToProfinite.obj S).lim).cone - isLimit := - (Functor.Initial.limitConeComp (sequentialFunctor _) (lightToProfinite.obj S).lim).isLimit + diagram := IsCofiltered.sequentialFunctor _ ⋙ (lightToProfinite.obj S).fintypeDiagram + cone := (Functor.Initial.limitConeComp (IsCofiltered.sequentialFunctor _) + (lightToProfinite.obj S).lim).cone + isLimit := (Functor.Initial.limitConeComp (IsCofiltered.sequentialFunctor _) + (lightToProfinite.obj S).lim).isLimit end LightProfinite diff --git a/Mathlib/Topology/Connected/LocallyConnected.lean b/Mathlib/Topology/Connected/LocallyConnected.lean index ff3a0ebf666189..2e690ee0fbb2d0 100644 --- a/Mathlib/Topology/Connected/LocallyConnected.lean +++ b/Mathlib/Topology/Connected/LocallyConnected.lean @@ -31,15 +31,18 @@ class LocallyConnectedSpace (α : Type*) [TopologicalSpace α] : Prop where /-- Open connected neighborhoods form a basis of the neighborhoods filter. -/ open_connected_basis : ∀ x, (𝓝 x).HasBasis (fun s : Set α => IsOpen s ∧ x ∈ s ∧ IsConnected s) id -theorem locallyConnectedSpace_iff_open_connected_basis : +theorem locallyConnectedSpace_iff_hasBasis_isOpen_isConnected : LocallyConnectedSpace α ↔ ∀ x, (𝓝 x).HasBasis (fun s : Set α => IsOpen s ∧ x ∈ s ∧ IsConnected s) id := ⟨@LocallyConnectedSpace.open_connected_basis _ _, LocallyConnectedSpace.mk⟩ -theorem locallyConnectedSpace_iff_open_connected_subsets : +@[deprecated (since := "2024-11-18")] alias locallyConnectedSpace_iff_open_connected_basis := + locallyConnectedSpace_iff_hasBasis_isOpen_isConnected + +theorem locallyConnectedSpace_iff_subsets_isOpen_isConnected : LocallyConnectedSpace α ↔ ∀ x, ∀ U ∈ 𝓝 x, ∃ V : Set α, V ⊆ U ∧ IsOpen V ∧ x ∈ V ∧ IsConnected V := by - simp_rw [locallyConnectedSpace_iff_open_connected_basis] + simp_rw [locallyConnectedSpace_iff_hasBasis_isOpen_isConnected] refine forall_congr' fun _ => ?_ constructor · intro h U hU @@ -49,10 +52,13 @@ theorem locallyConnectedSpace_iff_open_connected_subsets : let ⟨V, hVU, hV⟩ := h U hU ⟨V, hV, hVU⟩, fun ⟨V, ⟨hV, hxV, _⟩, hVU⟩ => mem_nhds_iff.mpr ⟨V, hVU, hV, hxV⟩⟩⟩ +@[deprecated (since := "2024-11-18")] alias locallyConnectedSpace_iff_open_connected_subsets := + locallyConnectedSpace_iff_subsets_isOpen_isConnected + /-- A space with discrete topology is a locally connected space. -/ instance (priority := 100) DiscreteTopology.toLocallyConnectedSpace (α) [TopologicalSpace α] [DiscreteTopology α] : LocallyConnectedSpace α := - locallyConnectedSpace_iff_open_connected_subsets.2 fun x _U hU => + locallyConnectedSpace_iff_subsets_isOpen_isConnected.2 fun x _U hU => ⟨{x}, singleton_subset_iff.2 <| mem_of_mem_nhds hU, isOpen_discrete _, rfl, isConnected_singleton⟩ @@ -85,7 +91,7 @@ theorem locallyConnectedSpace_iff_connectedComponentIn_open : · intro h exact fun F hF x _ => hF.connectedComponentIn · intro h - rw [locallyConnectedSpace_iff_open_connected_subsets] + rw [locallyConnectedSpace_iff_subsets_isOpen_isConnected] refine fun x U hU => ⟨connectedComponentIn (interior U) x, (connectedComponentIn_subset _ _).trans interior_subset, h _ isOpen_interior x ?_, @@ -95,7 +101,7 @@ theorem locallyConnectedSpace_iff_connectedComponentIn_open : theorem locallyConnectedSpace_iff_connected_subsets : LocallyConnectedSpace α ↔ ∀ (x : α), ∀ U ∈ 𝓝 x, ∃ V ∈ 𝓝 x, IsPreconnected V ∧ V ⊆ U := by constructor - · rw [locallyConnectedSpace_iff_open_connected_subsets] + · rw [locallyConnectedSpace_iff_subsets_isOpen_isConnected] intro h x U hxU rcases h x U hxU with ⟨V, hVU, hV₁, hxV, hV₂⟩ exact ⟨V, hV₁.mem_nhds hxV, hV₂.isPreconnected, hVU⟩ diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index 07f52c0cebe24c..c5d94601f96f7a 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -330,7 +330,7 @@ theorem trans_range {a b c : X} (γ₁ : Path a b) (γ₂ : Path b c) : rwa [coe_mk_mk, Function.comp_apply, if_neg h] at hxt · rintro x (⟨⟨t, ht0, ht1⟩, hxt⟩ | ⟨⟨t, ht0, ht1⟩, hxt⟩) · use ⟨t / 2, ⟨by linarith, by linarith⟩⟩ - have : t / 2 ≤ 1 / 2 := (div_le_div_right (zero_lt_two : (0 : ℝ) < 2)).mpr ht1 + have : t / 2 ≤ 1 / 2 := (div_le_div_iff_of_pos_right (zero_lt_two : (0 : ℝ) < 2)).mpr ht1 rw [coe_mk_mk, Function.comp_apply, if_pos this, Subtype.coe_mk] ring_nf rwa [γ₁.extend_extends] @@ -1160,13 +1160,18 @@ alias locPathConnected_of_bases := LocPathConnectedSpace.of_bases variable [LocPathConnectedSpace X] +protected theorem IsOpen.pathComponentIn (x : X) (hF : IsOpen F) : + IsOpen (pathComponentIn x F) := by + rw [isOpen_iff_mem_nhds] + intro y hy + let ⟨s, hs⟩ := (path_connected_basis y).mem_iff.mp (hF.mem_nhds (pathComponentIn_subset hy)) + exact mem_of_superset hs.1.1 <| pathComponentIn_congr hy ▸ + hs.1.2.subset_pathComponentIn (mem_of_mem_nhds hs.1.1) hs.2 + /-- In a locally path connected space, each path component is an open set. -/ protected theorem IsOpen.pathComponent (x : X) : IsOpen (pathComponent x) := by - rw [isOpen_iff_mem_nhds] - intro y hxy - rcases (path_connected_basis y).ex_mem with ⟨V, hVy, hVc⟩ - filter_upwards [hVy] with z hz - exact hxy.out.trans (hVc.joinedIn _ (mem_of_mem_nhds hVy) _ hz).joined + rw [← pathComponentIn_univ] + exact isOpen_univ.pathComponentIn _ /-- In a locally path connected space, each path component is a closed set. -/ protected theorem IsClosed.pathComponent (x : X) : IsClosed (pathComponent x) := by @@ -1192,6 +1197,13 @@ theorem pathConnected_subset_basis {U : Set X} (h : IsOpen U) (hx : x ∈ U) : (𝓝 x).HasBasis (fun s : Set X => s ∈ 𝓝 x ∧ IsPathConnected s ∧ s ⊆ U) id := (path_connected_basis x).hasBasis_self_subset (IsOpen.mem_nhds h hx) +theorem isOpen_isPathConnected_basis (x : X) : + (𝓝 x).HasBasis (fun s : Set X ↦ IsOpen s ∧ x ∈ s ∧ IsPathConnected s) id := by + refine ⟨fun s ↦ ⟨fun hs ↦ ?_, fun ⟨u, hu⟩ ↦ mem_nhds_iff.mpr ⟨u, hu.2, hu.1.1, hu.1.2.1⟩⟩⟩ + have ⟨u, hus, hu, hxu⟩ := mem_nhds_iff.mp hs + exact ⟨pathComponentIn x u, ⟨hu.pathComponentIn _, ⟨mem_pathComponentIn_self hxu, + isPathConnected_pathComponentIn hxu⟩⟩, pathComponentIn_subset.trans hus⟩ + theorem Topology.IsOpenEmbedding.locPathConnectedSpace {e : Y → X} (he : IsOpenEmbedding e) : LocPathConnectedSpace Y := have (y : Y) : @@ -1215,4 +1227,94 @@ theorem IsOpen.isConnected_iff_isPathConnected {U : Set X} (U_op : IsOpen U) : haveI := U_op.locPathConnectedSpace exact pathConnectedSpace_iff_connectedSpace.symm +/-- Locally path-connected spaces are locally connected. -/ +instance : LocallyConnectedSpace X := by + refine ⟨forall_imp (fun x h ↦ ⟨fun s ↦ ?_⟩) isOpen_isPathConnected_basis⟩ + refine ⟨fun hs ↦ ?_, fun ⟨u, ⟨hu, hxu, _⟩, hus⟩ ↦ mem_nhds_iff.mpr ⟨u, hus, hu, hxu⟩⟩ + let ⟨u, ⟨hu, hxu, hu'⟩, hus⟩ := (h.mem_iff' s).mp hs + exact ⟨u, ⟨hu, hxu, hu'.isConnected⟩, hus⟩ + +/-- A space is locally path-connected iff all path components of open subsets are open. -/ +lemma locPathConnectedSpace_iff_isOpen_pathComponentIn {X : Type*} [TopologicalSpace X] : + LocPathConnectedSpace X ↔ ∀ (x : X) (u : Set X), IsOpen u → IsOpen (pathComponentIn x u) := + ⟨fun _ _ _ hu ↦ hu.pathComponentIn _, fun h ↦ ⟨fun x ↦ ⟨fun s ↦ by + refine ⟨fun hs ↦ ?_, fun ⟨_, ht⟩ ↦ Filter.mem_of_superset ht.1.1 ht.2⟩ + let ⟨u, hu⟩ := mem_nhds_iff.mp hs + exact ⟨pathComponentIn x u, ⟨(h x u hu.2.1).mem_nhds (mem_pathComponentIn_self hu.2.2), + isPathConnected_pathComponentIn hu.2.2⟩, pathComponentIn_subset.trans hu.1⟩⟩⟩⟩ + +/-- A space is locally path-connected iff all path components of open subsets are neighbourhoods. -/ +lemma locPathConnectedSpace_iff_pathComponentIn_mem_nhds {X : Type*} [TopologicalSpace X] : + LocPathConnectedSpace X ↔ + ∀ x : X, ∀ u : Set X, IsOpen u → x ∈ u → pathComponentIn x u ∈ nhds x := by + rw [locPathConnectedSpace_iff_isOpen_pathComponentIn] + simp_rw [forall_comm (β := Set X), ← imp_forall_iff] + refine forall_congr' fun u ↦ imp_congr_right fun _ ↦ ?_ + exact ⟨fun h x hxu ↦ (h x).mem_nhds (mem_pathComponentIn_self hxu), + fun h x ↦ isOpen_iff_mem_nhds.mpr fun y hy ↦ + pathComponentIn_congr hy ▸ h y <| pathComponentIn_subset hy⟩ + +/-- Any topology coinduced by a locally path-connected topology is locally path-connected. -/ +lemma LocPathConnectedSpace.coinduced {Y : Type*} (f : X → Y) : + @LocPathConnectedSpace Y (.coinduced f ‹_›) := by + let _ := TopologicalSpace.coinduced f ‹_›; have hf : Continuous f := continuous_coinduced_rng + refine locPathConnectedSpace_iff_isOpen_pathComponentIn.mpr fun y u hu ↦ + isOpen_coinduced.mpr <| isOpen_iff_mem_nhds.mpr fun x hx ↦ ?_ + have hx' := preimage_mono pathComponentIn_subset hx + refine mem_nhds_iff.mpr ⟨pathComponentIn x (f ⁻¹' u), ?_, + (hu.preimage hf).pathComponentIn _, mem_pathComponentIn_self hx'⟩ + rw [← image_subset_iff, ← pathComponentIn_congr hx] + exact ((isPathConnected_pathComponentIn hx').image hf).subset_pathComponentIn + ⟨x, mem_pathComponentIn_self hx', rfl⟩ <| + (image_mono pathComponentIn_subset).trans <| u.image_preimage_subset f + +/-- Quotients of locally path-connected spaces are locally path-connected. -/ +lemma Topology.IsQuotientMap.locPathConnectedSpace {f : X → Y} (h : IsQuotientMap f) : + LocPathConnectedSpace Y := + h.2 ▸ LocPathConnectedSpace.coinduced f + +/-- Quotients of locally path-connected spaces are locally path-connected. -/ +instance Quot.locPathConnectedSpace {r : X → X → Prop} : LocPathConnectedSpace (Quot r) := + isQuotientMap_quot_mk.locPathConnectedSpace + +/-- Quotients of locally path-connected spaces are locally path-connected. -/ +instance Quotient.locPathConnectedSpace {s : Setoid X} : LocPathConnectedSpace (Quotient s) := + isQuotientMap_quotient_mk'.locPathConnectedSpace + + +/-- Disjoint unions of locally path-connected spaces are locally path-connected. -/ +instance Sum.locPathConnectedSpace.{u} {X Y : Type u} [TopologicalSpace X] [TopologicalSpace Y] + [LocPathConnectedSpace X] [LocPathConnectedSpace Y] : + LocPathConnectedSpace (X ⊕ Y) := by + rw [locPathConnectedSpace_iff_pathComponentIn_mem_nhds]; intro x u hu hxu; rw [mem_nhds_iff] + obtain x | y := x + · refine ⟨Sum.inl '' (pathComponentIn x (Sum.inl ⁻¹' u)), ?_, ?_, ?_⟩ + · apply IsPathConnected.subset_pathComponentIn + · exact (isPathConnected_pathComponentIn (by exact hxu)).image continuous_inl + · exact ⟨x, mem_pathComponentIn_self hxu, rfl⟩ + · exact (image_mono pathComponentIn_subset).trans (u.image_preimage_subset _) + · exact isOpenMap_inl _ <| (hu.preimage continuous_inl).pathComponentIn _ + · exact ⟨x, mem_pathComponentIn_self hxu, rfl⟩ + · refine ⟨Sum.inr '' (pathComponentIn y (Sum.inr ⁻¹' u)), ?_, ?_, ?_⟩ + · apply IsPathConnected.subset_pathComponentIn + · exact (isPathConnected_pathComponentIn (by exact hxu)).image continuous_inr + · exact ⟨y, mem_pathComponentIn_self hxu, rfl⟩ + · exact (image_mono pathComponentIn_subset).trans (u.image_preimage_subset _) + · exact isOpenMap_inr _ <| (hu.preimage continuous_inr).pathComponentIn _ + · exact ⟨y, mem_pathComponentIn_self hxu, rfl⟩ + + +/-- Disjoint unions of locally path-connected spaces are locally path-connected. -/ +instance Sigma.locPathConnectedSpace {X : ι → Type*} + [(i : ι) → TopologicalSpace (X i)] [(i : ι) → LocPathConnectedSpace (X i)] : + LocPathConnectedSpace ((i : ι) × X i) := by + rw [locPathConnectedSpace_iff_pathComponentIn_mem_nhds]; intro x u hu hxu; rw [mem_nhds_iff] + refine ⟨(Sigma.mk x.1) '' (pathComponentIn x.2 ((Sigma.mk x.1) ⁻¹' u)), ?_, ?_, ?_⟩ + · apply IsPathConnected.subset_pathComponentIn + · exact (isPathConnected_pathComponentIn (by exact hxu)).image continuous_sigmaMk + · exact ⟨x.2, mem_pathComponentIn_self hxu, rfl⟩ + · exact (image_mono pathComponentIn_subset).trans (u.image_preimage_subset _) + · exact isOpenMap_sigmaMk _ <| (hu.preimage continuous_sigmaMk).pathComponentIn _ + · exact ⟨x.2, mem_pathComponentIn_self hxu, rfl⟩ + end LocPathConnectedSpace diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 7d92b1e682ec53..280967dfdc29d1 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -115,9 +115,9 @@ theorem nhds_ofMul (x : X) : 𝓝 (ofMul x) = map ofMul (𝓝 x) := rfl theorem nhds_ofAdd (x : X) : 𝓝 (ofAdd x) = map ofAdd (𝓝 x) := rfl -theorem nhds_toMul (x : Additive X) : 𝓝 (toMul x) = map toMul (𝓝 x) := rfl +theorem nhds_toMul (x : Additive X) : 𝓝 x.toMul = map toMul (𝓝 x) := rfl -theorem nhds_toAdd (x : Multiplicative X) : 𝓝 (toAdd x) = map toAdd (𝓝 x) := rfl +theorem nhds_toAdd (x : Multiplicative X) : 𝓝 x.toAdd = map toAdd (𝓝 x) := rfl end diff --git a/Mathlib/Topology/ContinuousMap/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean index 2cefc72b970be5..42a37d593e9a0c 100644 --- a/Mathlib/Topology/ContinuousMap/Algebra.lean +++ b/Mathlib/Topology/ContinuousMap/Algebra.lean @@ -351,20 +351,20 @@ instance [CommGroup β] [TopologicalGroup β] : TopologicalGroup C(α, β) where have : UniformGroup β := comm_topologicalGroup_is_uniform rw [continuous_iff_continuousAt] rintro ⟨f, g⟩ - rw [ContinuousAt, tendsto_iff_forall_compact_tendstoUniformlyOn, nhds_prod_eq] + rw [ContinuousAt, tendsto_iff_forall_isCompact_tendstoUniformlyOn, nhds_prod_eq] exact fun K hK => uniformContinuous_mul.comp_tendstoUniformlyOn - ((tendsto_iff_forall_compact_tendstoUniformlyOn.mp Filter.tendsto_id K hK).prod - (tendsto_iff_forall_compact_tendstoUniformlyOn.mp Filter.tendsto_id K hK)) + ((tendsto_iff_forall_isCompact_tendstoUniformlyOn.mp Filter.tendsto_id K hK).prod + (tendsto_iff_forall_isCompact_tendstoUniformlyOn.mp Filter.tendsto_id K hK)) continuous_inv := by letI : UniformSpace β := TopologicalGroup.toUniformSpace β have : UniformGroup β := comm_topologicalGroup_is_uniform rw [continuous_iff_continuousAt] intro f - rw [ContinuousAt, tendsto_iff_forall_compact_tendstoUniformlyOn] + rw [ContinuousAt, tendsto_iff_forall_isCompact_tendstoUniformlyOn] exact fun K hK => uniformContinuous_inv.comp_tendstoUniformlyOn - (tendsto_iff_forall_compact_tendstoUniformlyOn.mp Filter.tendsto_id K hK) + (tendsto_iff_forall_isCompact_tendstoUniformlyOn.mp Filter.tendsto_id K hK) /-- If an infinite product of functions in `C(α, β)` converges to `g` (for the compact-open topology), then the pointwise product converges to `g x` for all `x ∈ α`. -/ diff --git a/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean b/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean index 40d279aec7e3ab..81b40ea72345ab 100644 --- a/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean +++ b/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean @@ -18,7 +18,7 @@ the uniform distance. -/ -assert_not_exists CStarAlgebra.star +assert_not_exists CStarRing noncomputable section diff --git a/Mathlib/Topology/ContinuousMap/Ordered.lean b/Mathlib/Topology/ContinuousMap/Ordered.lean index 5ef9876bb5f8c9..7677b1c20ea565 100644 --- a/Mathlib/Topology/ContinuousMap/Ordered.lean +++ b/Mathlib/Topology/ContinuousMap/Ordered.lean @@ -13,8 +13,7 @@ import Mathlib.Topology.ContinuousMap.Defs -/ -variable {α : Type*} {β : Type*} {γ : Type*} -variable [TopologicalSpace α] [TopologicalSpace β] [TopologicalSpace γ] +variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] namespace ContinuousMap diff --git a/Mathlib/Topology/Defs/Filter.lean b/Mathlib/Topology/Defs/Filter.lean index 462aaeabab0572..340ed360bb1da9 100644 --- a/Mathlib/Topology/Defs/Filter.lean +++ b/Mathlib/Topology/Defs/Filter.lean @@ -202,8 +202,8 @@ infixl:300 " ⤳ " => Specializes equivalent properties hold: - `𝓝 x = 𝓝 y`; we use this property as the definition; -- for any open set `s`, `x ∈ s ↔ y ∈ s`, see `inseparable_iff_open`; -- for any closed set `s`, `x ∈ s ↔ y ∈ s`, see `inseparable_iff_closed`; +- for any open set `s`, `x ∈ s ↔ y ∈ s`, see `inseparable_iff_forall_isOpen`; +- for any closed set `s`, `x ∈ s ↔ y ∈ s`, see `inseparable_iff_forall_isClosed`; - `x ∈ closure {y}` and `y ∈ closure {x}`, see `inseparable_iff_mem_closure`; - `closure {x} = closure {y}`, see `inseparable_iff_closure_eq`. -/ diff --git a/Mathlib/Topology/EMetricSpace/Defs.lean b/Mathlib/Topology/EMetricSpace/Defs.lean index 1c005ea7118645..b791062fbf6508 100644 --- a/Mathlib/Topology/EMetricSpace/Defs.lean +++ b/Mathlib/Topology/EMetricSpace/Defs.lean @@ -5,6 +5,7 @@ Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébas -/ import Mathlib.Data.ENNReal.Inv import Mathlib.Topology.UniformSpace.OfFun +import Mathlib.Topology.Bases /-! # Extended metric spaces @@ -656,11 +657,11 @@ 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 := +theorem edist_toMul (a b : Additive X) : edist a.toMul b.toMul = edist a b := rfl @[simp] -theorem edist_toAdd (a b : Multiplicative X) : edist (toAdd a) (toAdd b) = edist a b := +theorem edist_toAdd (a b : Multiplicative X) : edist a.toAdd b.toAdd = edist a b := rfl end diff --git a/Mathlib/Topology/GDelta/UniformSpace.lean b/Mathlib/Topology/GDelta/UniformSpace.lean index 46bdc36f2fdabc..3aab2f9dd00c06 100644 --- a/Mathlib/Topology/GDelta/UniformSpace.lean +++ b/Mathlib/Topology/GDelta/UniformSpace.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Yury Kudryashov -/ import Mathlib.Topology.GDelta.Basic -import Mathlib.Topology.UniformSpace.Basic import Mathlib.Order.Filter.CountableInter +import Mathlib.Topology.UniformSpace.Basic /-! # `Gδ` sets and uniform spaces diff --git a/Mathlib/Topology/Inseparable.lean b/Mathlib/Topology/Inseparable.lean index 2c7156a1d00f3f..7b0bf5a54bf81a 100644 --- a/Mathlib/Topology/Inseparable.lean +++ b/Mathlib/Topology/Inseparable.lean @@ -433,17 +433,22 @@ theorem Inseparable.specializes' (h : x ~ᵢ y) : y ⤳ x := h.ge theorem Specializes.antisymm (h₁ : x ⤳ y) (h₂ : y ⤳ x) : x ~ᵢ y := le_antisymm h₁ h₂ -theorem inseparable_iff_forall_open : (x ~ᵢ y) ↔ ∀ s : Set X, IsOpen s → (x ∈ s ↔ y ∈ s) := by +theorem inseparable_iff_forall_isOpen : (x ~ᵢ y) ↔ ∀ s : Set X, IsOpen s → (x ∈ s ↔ y ∈ s) := by simp only [inseparable_iff_specializes_and, specializes_iff_forall_open, ← forall_and, ← iff_def, Iff.comm] +@[deprecated (since := "2024-11-18")] alias +inseparable_iff_forall_open := inseparable_iff_forall_isOpen + theorem not_inseparable_iff_exists_open : ¬(x ~ᵢ y) ↔ ∃ s : Set X, IsOpen s ∧ Xor' (x ∈ s) (y ∈ s) := by - simp [inseparable_iff_forall_open, ← xor_iff_not_iff] + simp [inseparable_iff_forall_isOpen, ← xor_iff_not_iff] -theorem inseparable_iff_forall_closed : (x ~ᵢ y) ↔ ∀ s : Set X, IsClosed s → (x ∈ s ↔ y ∈ s) := by +theorem inseparable_iff_forall_isClosed : (x ~ᵢ y) ↔ ∀ s : Set X, IsClosed s → (x ∈ s ↔ y ∈ s) := by simp only [inseparable_iff_specializes_and, specializes_iff_forall_closed, ← forall_and, ← iff_def] +@[deprecated (since := "2024-11-18")] alias +inseparable_iff_forall_closed := inseparable_iff_forall_isClosed theorem inseparable_iff_mem_closure : (x ~ᵢ y) ↔ x ∈ closure ({y} : Set X) ∧ y ∈ closure ({x} : Set X) := @@ -497,10 +502,10 @@ nonrec theorem trans (h₁ : x ~ᵢ y) (h₂ : y ~ᵢ z) : x ~ᵢ z := h₁.tran theorem nhds_eq (h : x ~ᵢ y) : 𝓝 x = 𝓝 y := h theorem mem_open_iff (h : x ~ᵢ y) (hs : IsOpen s) : x ∈ s ↔ y ∈ s := - inseparable_iff_forall_open.1 h s hs + inseparable_iff_forall_isOpen.1 h s hs theorem mem_closed_iff (h : x ~ᵢ y) (hs : IsClosed s) : x ∈ s ↔ y ∈ s := - inseparable_iff_forall_closed.1 h s hs + inseparable_iff_forall_isClosed.1 h s hs theorem map_of_continuousAt (h : x ~ᵢ y) (hx : ContinuousAt f x) (hy : ContinuousAt f y) : f x ~ᵢ f y := diff --git a/Mathlib/Topology/Instances/ENNReal.lean b/Mathlib/Topology/Instances/ENNReal.lean index 94b73607b7f71b..029ada7f6a78a6 100644 --- a/Mathlib/Topology/Instances/ENNReal.lean +++ b/Mathlib/Topology/Instances/ENNReal.lean @@ -25,7 +25,7 @@ variable {α : Type*} {β : Type*} {γ : Type*} namespace ENNReal -variable {a b c d : ℝ≥0∞} {r p q : ℝ≥0} {x y z : ℝ≥0∞} {ε ε₁ ε₂ : ℝ≥0∞} {s : Set ℝ≥0∞} +variable {a b : ℝ≥0∞} {r : ℝ≥0} {x : ℝ≥0∞} {ε : ℝ≥0∞} section TopologicalSpace diff --git a/Mathlib/Topology/Instances/EReal.lean b/Mathlib/Topology/Instances/EReal.lean index cedc98e15dfa01..746c9fd365e5b9 100644 --- a/Mathlib/Topology/Instances/EReal.lean +++ b/Mathlib/Topology/Instances/EReal.lean @@ -214,65 +214,56 @@ 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 ↦ ?_ +lemma le_liminf_add : (liminf u f) + (liminf v f) ≤ liminf (u + v) f := by + refine add_le_of_forall_lt fun a a_u b b_v ↦ (le_liminf_iff).2 fun c c_ab ↦ ?_ filter_upwards [eventually_lt_of_lt_liminf a_u, eventually_lt_of_lt_liminf b_v] with x a_x b_x - exact lt_trans c_ab (add_lt_add a_x b_x) + exact c_ab.trans (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 ≠ ⊥) : +lemma limsup_add_le (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 ↦ ?_ + refine le_add_of_forall_gt 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_u _ b_v ↦ (le_limsup_iff).2 fun _ c_ab ↦ - Frequently.mono (Frequently.and_eventually ((frequently_lt_of_lt_limsup) a_u) - ((eventually_lt_of_lt_liminf) b_v)) fun _ ab_x ↦ c_ab.trans (add_lt_add ab_x.1 ab_x.2) +lemma le_limsup_add : (limsup u f) + (liminf v f) ≤ limsup (u + v) f := + add_le_of_forall_lt fun _ a_u _ b_v ↦ (le_limsup_iff).2 fun _ c_ab ↦ + (((frequently_lt_of_lt_limsup) a_u).and_eventually ((eventually_lt_of_lt_liminf) b_v)).mono + 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 ≠ ⊥) : +lemma liminf_add_le (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_u _ b_v ↦ (liminf_le_iff).2 fun _ c_ab ↦ - Frequently.mono (Frequently.and_eventually ((frequently_lt_of_liminf_lt) b_v) - ((eventually_lt_of_limsup_lt) a_u)) fun _ ab_x ↦ (add_lt_add ab_x.2 ab_x.1).trans c_ab + le_add_of_forall_gt h h' fun _ a_u _ b_v ↦ (liminf_le_iff).2 fun _ c_ab ↦ + (((frequently_lt_of_liminf_lt) b_v).and_eventually ((eventually_lt_of_limsup_lt) a_u)).mono + fun _ ab_x ↦ (add_lt_add ab_x.2 ab_x.1).trans c_ab + +@[deprecated (since := "2024-11-11")] alias add_liminf_le_liminf_add := le_liminf_add +@[deprecated (since := "2024-11-11")] alias limsup_add_le_add_limsup := limsup_add_le +@[deprecated (since := "2024-11-11")] alias limsup_add_liminf_le_limsup_add := le_limsup_add +@[deprecated (since := "2024-11-11")] alias liminf_add_le_limsup_add_liminf := liminf_add_le 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 + apply le_bot_iff.1 ((limsup_add_le (.inr h') _).trans _) + · rw [h]; exact .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) + 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) + · exact (limsup_add_le (.inr (hb.trans_lt h).ne) (.inl ha.ne_top)).trans (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 := - lt_of_lt_of_le (add_lt_add ha hb) add_liminf_le_liminf_add + (add_lt_add ha hb).trans_le 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 (le_trans _ (add_liminf_le_liminf_add)) + apply top_le_iff.1 (le_trans _ 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_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 _ h' ↦ h'.le - · rcases eq_or_neBot f with rfl | _ - · simp only [limsup_bot, bot_le] - · exact (limsup_le_of_le) (h c b_c) - end LimInfSup /-! ### Continuity of addition -/ diff --git a/Mathlib/Topology/Irreducible.lean b/Mathlib/Topology/Irreducible.lean index c5c1339a53ef9a..5d383423319f0e 100644 --- a/Mathlib/Topology/Irreducible.lean +++ b/Mathlib/Topology/Irreducible.lean @@ -240,7 +240,7 @@ theorem isIrreducible_iff_sInter : /-- A set is preirreducible if and only if for every cover by two closed sets, it is contained in one of the two covering sets. -/ -theorem isPreirreducible_iff_closed_union_closed : +theorem isPreirreducible_iff_isClosed_union_isClosed : IsPreirreducible s ↔ ∀ z₁ z₂ : Set X, IsClosed z₁ → IsClosed z₂ → s ⊆ z₁ ∪ z₂ → s ⊆ z₁ ∨ s ⊆ z₂ := by refine compl_surjective.forall.trans <| forall_congr' fun z₁ => compl_surjective.forall.trans <| @@ -248,10 +248,12 @@ theorem isPreirreducible_iff_closed_union_closed : simp only [isOpen_compl_iff, ← compl_union, inter_compl_nonempty_iff] refine forall₂_congr fun _ _ => ?_ rw [← and_imp, ← not_or, not_imp_not] +@[deprecated (since := "2024-11-19")] alias +isPreirreducible_iff_closed_union_closed := isPreirreducible_iff_isClosed_union_isClosed /-- A set is irreducible if and only if for every cover by a finite collection of closed sets, it is contained in one of the members of the collection. -/ -theorem isIrreducible_iff_sUnion_closed : +theorem isIrreducible_iff_sUnion_isClosed : IsIrreducible s ↔ ∀ t : Finset (Set X), (∀ z ∈ t, IsClosed z) → (s ⊆ ⋃₀ ↑t) → ∃ z ∈ t, s ⊆ z := by simp only [isIrreducible_iff_sInter] @@ -263,6 +265,9 @@ theorem isIrreducible_iff_sUnion_closed : simp only [not_exists, not_and, ← compl_iInter₂, ← sInter_eq_biInter, subset_compl_iff_disjoint_right, not_disjoint_iff_nonempty_inter] +@[deprecated (since := "2024-11-19")] alias +isIrreducible_iff_sUnion_closed := isIrreducible_iff_sUnion_isClosed + /-- A nonempty open subset of a preirreducible subspace is dense in the subspace. -/ theorem subset_closure_inter_of_isPreirreducible_of_isOpen {S U : Set X} (hS : IsPreirreducible S) (hU : IsOpen U) (h : (S ∩ U).Nonempty) : S ⊆ closure (S ∩ U) := by diff --git a/Mathlib/Topology/LocalAtTarget.lean b/Mathlib/Topology/LocalAtTarget.lean index 9d801889f8176e..af16705f2ce510 100644 --- a/Mathlib/Topology/LocalAtTarget.lean +++ b/Mathlib/Topology/LocalAtTarget.lean @@ -82,7 +82,7 @@ theorem IsClosedMap.restrictPreimage (H : IsClosedMap f) (s : Set β) : simpa [isClosed_induced_iff] exact fun u hu e => ⟨f '' u, H u hu, by simp [← e, image_restrictPreimage]⟩ -@[deprecated (since := "2024-04-02")] +@[deprecated "No deprecation message was provided." (since := "2024-04-02")] theorem Set.restrictPreimage_isClosedMap (s : Set β) (H : IsClosedMap f) : IsClosedMap (s.restrictPreimage f) := H.restrictPreimage s @@ -94,7 +94,7 @@ theorem IsOpenMap.restrictPreimage (H : IsOpenMap f) (s : Set β) : simpa [isOpen_induced_iff] exact fun u hu e => ⟨f '' u, H u hu, by simp [← e, image_restrictPreimage]⟩ -@[deprecated (since := "2024-04-02")] +@[deprecated "No deprecation message was provided." (since := "2024-04-02")] theorem Set.restrictPreimage_isOpenMap (s : Set β) (H : IsOpenMap f) : IsOpenMap (s.restrictPreimage f) := H.restrictPreimage s @@ -185,6 +185,47 @@ theorem isEmbedding_iff_of_iSup_eq_top (h : Continuous f) : convert congr_arg SetLike.coe hU simp +omit hU in +/-- +Given a continuous map `f : X → Y` between topological spaces. +Suppose we have an open cover `V i` of the range of `f`, and an open cover `U i` of `X` that is +coarser than the pullback of `V` under `f`. +To check that `f` is an embedding it suffices to check that `U i → Y` is an embedding for all `i`. +-/ +theorem isEmbedding_of_iSup_eq_top_of_preimage_subset_range + {X Y} [TopologicalSpace X] [TopologicalSpace Y] + (f : X → Y) (h : Continuous f) {ι : Type*} + (U : ι → Opens Y) (hU : Set.range f ⊆ (iSup U : _)) + (V : ι → Type*) [∀ i, TopologicalSpace (V i)] + (iV : ∀ i, V i → X) (hiV : ∀ i, Continuous (iV i)) (hV : ∀ i, f ⁻¹' U i ⊆ Set.range (iV i)) + (hV' : ∀ i, IsEmbedding (f ∘ iV i)) : IsEmbedding f := by + wlog hU' : iSup U = ⊤ + · let f₀ : X → Set.range f := fun x ↦ ⟨f x, ⟨x, rfl⟩⟩ + suffices IsEmbedding f₀ from IsEmbedding.subtypeVal.comp this + have hU'' : (⨆ i, (U i).comap ⟨Subtype.val, continuous_subtype_val⟩ : + Opens (Set.range f)) = ⊤ := by + rw [← top_le_iff] + simpa [Set.range_subset_iff, SetLike.le_def] using hU + refine this _ ?_ _ ?_ V iV hiV ?_ ?_ hU'' + · fun_prop + · rw [hU'']; simp + · exact hV + · exact fun i ↦ IsEmbedding.of_comp (by fun_prop) continuous_subtype_val (hV' i) + rw [isEmbedding_iff_of_iSup_eq_top hU' h] + intro i + let f' := (Subtype.val ∘ (f ⁻¹' U i).restrictPreimage (iV i)) + have : IsEmbedding f' := + IsEmbedding.subtypeVal.comp ((IsEmbedding.of_comp (hiV i) h (hV' _)).restrictPreimage _) + have hf' : Set.range f' = f ⁻¹' U i := by + simpa [f', Set.range_comp, Set.range_restrictPreimage] using hV i + let e := (Homeomorph.ofIsEmbedding _ this).trans (Homeomorph.setCongr hf') + refine IsEmbedding.of_comp (by fun_prop) continuous_subtype_val ?_ + convert ((hV' i).comp IsEmbedding.subtypeVal).comp e.symm.isEmbedding + ext x + obtain ⟨x, rfl⟩ := e.surjective x + simp + rfl + @[deprecated (since := "2024-10-26")] alias embedding_iff_embedding_of_iSup_eq_top := isEmbedding_iff_of_iSup_eq_top diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index b71fbe5d98fd9e..077466f86f8776 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -286,13 +286,15 @@ lemma isQuotientMap_iff : IsQuotientMap f ↔ Surjective f ∧ ∀ s, IsOpen s @[deprecated (since := "2024-10-22")] alias quotientMap_iff := isQuotientMap_iff -theorem isQuotientMap_iff_closed : +theorem isQuotientMap_iff_isClosed : IsQuotientMap f ↔ Surjective f ∧ ∀ s : Set Y, IsClosed s ↔ IsClosed (f ⁻¹' s) := isQuotientMap_iff.trans <| Iff.rfl.and <| compl_surjective.forall.trans <| by simp only [isOpen_compl_iff, preimage_compl] @[deprecated (since := "2024-10-22")] -alias quotientMap_iff_closed := isQuotientMap_iff_closed +alias quotientMap_iff_closed := isQuotientMap_iff_isClosed +@[deprecated (since := "2024-11-19")] +alias isQuotientMap_iff_closed := isQuotientMap_iff_isClosed namespace IsQuotientMap @@ -326,7 +328,7 @@ protected lemma isOpen_preimage (hf : IsQuotientMap f) {s : Set Y} : IsOpen (f protected theorem isClosed_preimage (hf : IsQuotientMap f) {s : Set Y} : IsClosed (f ⁻¹' s) ↔ IsClosed s := - ((isQuotientMap_iff_closed.1 hf).2 s).symm + ((isQuotientMap_iff_isClosed.1 hf).2 s).symm end IsQuotientMap @@ -489,7 +491,7 @@ theorem isClosed_range (hf : IsClosedMap f) : IsClosed (range f) := theorem isQuotientMap (hcl : IsClosedMap f) (hcont : Continuous f) (hsurj : Surjective f) : IsQuotientMap f := - isQuotientMap_iff_closed.2 ⟨hsurj, fun s => + isQuotientMap_iff_isClosed.2 ⟨hsurj, fun s => ⟨fun hs => hs.preimage hcont, fun hs => hsurj.image_preimage s ▸ hcl _ hs⟩⟩ @[deprecated (since := "2024-10-22")] diff --git a/Mathlib/Topology/MetricSpace/Contracting.lean b/Mathlib/Topology/MetricSpace/Contracting.lean index e70e951d652945..a4c5c2b74235d2 100644 --- a/Mathlib/Topology/MetricSpace/Contracting.lean +++ b/Mathlib/Topology/MetricSpace/Contracting.lean @@ -266,7 +266,7 @@ theorem dist_fixedPoint_fixedPoint_of_dist_le' (g : α → α) {x y} (hx : IsFix dist x y = dist y x := dist_comm x y _ ≤ dist y (f y) / (1 - K) := hf.dist_le_of_fixedPoint y hx _ = dist (f y) (g y) / (1 - K) := by rw [hy.eq, dist_comm] - _ ≤ C / (1 - K) := (div_le_div_right hf.one_sub_K_pos).2 (hfg y) + _ ≤ C / (1 - K) := (div_le_div_iff_of_pos_right hf.one_sub_K_pos).2 (hfg y) variable [Nonempty α] [CompleteSpace α] variable (f) diff --git a/Mathlib/Topology/MetricSpace/Defs.lean b/Mathlib/Topology/MetricSpace/Defs.lean index 93866859fadb0b..e678bdcfedb6b9 100644 --- a/Mathlib/Topology/MetricSpace/Defs.lean +++ b/Mathlib/Topology/MetricSpace/Defs.lean @@ -197,9 +197,9 @@ instance : Dist (Multiplicative X) := ‹Dist X› @[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_toMul (a b : Additive X) : dist a.toMul b.toMul = dist a b := rfl -@[simp] theorem dist_toAdd (a b : Multiplicative X) : dist (toAdd a) (toAdd b) = dist a b := rfl +@[simp] theorem dist_toAdd (a b : Multiplicative X) : dist a.toAdd b.toAdd = dist a b := rfl end @@ -211,10 +211,10 @@ variable [PseudoMetricSpace X] @[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_toMul (a b : Additive X) : nndist a.toMul b.toMul = nndist a b := rfl @[simp] -theorem nndist_toAdd (a b : Multiplicative X) : nndist (toAdd a) (toAdd b) = nndist a b := rfl +theorem nndist_toAdd (a b : Multiplicative X) : nndist a.toAdd b.toAdd = nndist a b := rfl end diff --git a/Mathlib/Topology/MetricSpace/Dilation.lean b/Mathlib/Topology/MetricSpace/Dilation.lean index 201c0e06799e39..6ab93147d696be 100644 --- a/Mathlib/Topology/MetricSpace/Dilation.lean +++ b/Mathlib/Topology/MetricSpace/Dilation.lean @@ -74,7 +74,7 @@ end Defs namespace Dilation -variable {α : Type*} {β : Type*} {γ : Type*} {F : Type*} {G : Type*} +variable {α : Type*} {β : Type*} {γ : Type*} {F : Type*} section Setup @@ -229,8 +229,8 @@ end Setup section PseudoEmetricDilation variable [PseudoEMetricSpace α] [PseudoEMetricSpace β] [PseudoEMetricSpace γ] -variable [FunLike F α β] [DilationClass F α β] [FunLike G β γ] [DilationClass G β γ] -variable (f : F) (g : G) {x y z : α} {s : Set α} +variable [FunLike F α β] [DilationClass F α β] +variable (f : F) /-- Every isometry is a dilation of ratio `1`. -/ @[simps] diff --git a/Mathlib/Topology/MetricSpace/IsometricSMul.lean b/Mathlib/Topology/MetricSpace/IsometricSMul.lean index 8bbc25f34f0aba..7af5ce1593cca4 100644 --- a/Mathlib/Topology/MetricSpace/IsometricSMul.lean +++ b/Mathlib/Topology/MetricSpace/IsometricSMul.lean @@ -420,26 +420,26 @@ instance Pi.isometricSMul'' {ι} {M : ι → Type*} [Fintype ι] [∀ i, Mul (M ⟨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)⟩ + ⟨fun c => isometry_smul X c.toMul⟩ instance Additive.isometricVAdd' [Mul M] [PseudoEMetricSpace M] [IsometricSMul M M] : IsometricVAdd (Additive M) (Additive M) := - ⟨fun c x y => edist_smul_left (toMul c) (toMul x) (toMul y)⟩ + ⟨fun c x y => edist_smul_left c.toMul x.toMul y.toMul⟩ instance Additive.isometricVAdd'' [Mul M] [PseudoEMetricSpace M] [IsometricSMul Mᵐᵒᵖ M] : IsometricVAdd (Additive M)ᵃᵒᵖ (Additive M) := - ⟨fun c x y => edist_smul_left (MulOpposite.op (toMul c.unop)) (toMul x) (toMul y)⟩ + ⟨fun c x y => edist_smul_left (MulOpposite.op c.unop.toMul) x.toMul y.toMul⟩ instance Multiplicative.isometricSMul {M X} [VAdd M X] [PseudoEMetricSpace X] [IsometricVAdd M X] : IsometricSMul (Multiplicative M) X := - ⟨fun c => isometry_vadd X (toAdd c)⟩ + ⟨fun c => isometry_vadd X c.toAdd⟩ instance Multiplicative.isometricSMul' [Add M] [PseudoEMetricSpace M] [IsometricVAdd M M] : IsometricSMul (Multiplicative M) (Multiplicative M) := - ⟨fun c x y => edist_vadd_left (toAdd c) (toAdd x) (toAdd y)⟩ + ⟨fun c x y => edist_vadd_left c.toAdd x.toAdd y.toAdd⟩ instance Multiplicative.isometricVAdd'' [Add M] [PseudoEMetricSpace M] [IsometricVAdd Mᵃᵒᵖ M] : IsometricSMul (Multiplicative M)ᵐᵒᵖ (Multiplicative M) := - ⟨fun c x y => edist_vadd_left (AddOpposite.op (toAdd c.unop)) (toAdd x) (toAdd y)⟩ + ⟨fun c x y => edist_vadd_left (AddOpposite.op c.unop.toAdd) x.toAdd y.toAdd⟩ end Instances diff --git a/Mathlib/Topology/MetricSpace/Isometry.lean b/Mathlib/Topology/MetricSpace/Isometry.lean index 5e434b37434df4..a987f5c09f2845 100644 --- a/Mathlib/Topology/MetricSpace/Isometry.lean +++ b/Mathlib/Topology/MetricSpace/Isometry.lean @@ -62,7 +62,7 @@ namespace Isometry section PseudoEmetricIsometry variable [PseudoEMetricSpace α] [PseudoEMetricSpace β] [PseudoEMetricSpace γ] -variable {f : α → β} {x y z : α} {s : Set α} +variable {f : α → β} {x : α} /-- An isometry preserves edistances. -/ theorem edist_eq (hf : Isometry f) (x y : α) : edist (f x) (f y) = edist x y := diff --git a/Mathlib/Topology/MetricSpace/Kuratowski.lean b/Mathlib/Topology/MetricSpace/Kuratowski.lean index 5a21609d09845d..a0fa5566df6e33 100644 --- a/Mathlib/Topology/MetricSpace/Kuratowski.lean +++ b/Mathlib/Topology/MetricSpace/Kuratowski.lean @@ -68,15 +68,12 @@ theorem embeddingOfSubset_isometry (H : DenseRange x) : Isometry (embeddingOfSub apply_rules [add_le_add_left, le_abs_self] _ ≤ 2 * (e / 2) + |embeddingOfSubset x b n - embeddingOfSubset x a n| := by rw [C] - apply_rules [add_le_add, mul_le_mul_of_nonneg_left, hn.le, le_refl] - norm_num + gcongr _ ≤ 2 * (e / 2) + dist (embeddingOfSubset x b) (embeddingOfSubset x a) := by - have : |embeddingOfSubset x b n - embeddingOfSubset x a n| ≤ - dist (embeddingOfSubset x b) (embeddingOfSubset x a) := by - simp only [dist_eq_norm] - exact lp.norm_apply_le_norm ENNReal.top_ne_zero - (embeddingOfSubset x b - embeddingOfSubset x a) n - nlinarith + gcongr + simp only [dist_eq_norm] + exact lp.norm_apply_le_norm ENNReal.top_ne_zero + (embeddingOfSubset x b - embeddingOfSubset x a) n _ = dist (embeddingOfSubset x b) (embeddingOfSubset x a) + e := by ring simpa [dist_comm] using this diff --git a/Mathlib/Topology/MetricSpace/Polish.lean b/Mathlib/Topology/MetricSpace/Polish.lean index d1e851e3c7d446..93c053adc16d7d 100644 --- a/Mathlib/Topology/MetricSpace/Polish.lean +++ b/Mathlib/Topology/MetricSpace/Polish.lean @@ -102,7 +102,7 @@ instance (priority := 100) instMetrizableSpace (α : Type*) [TopologicalSpace α letI := upgradePolishSpace α infer_instance -@[deprecated (since := "2024-02-23")] +@[deprecated "No deprecation message was provided." (since := "2024-02-23")] theorem t2Space (α : Type*) [TopologicalSpace α] [PolishSpace α] : T2Space α := inferInstance /-- A countable product of Polish spaces is Polish. -/ diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean index 19689b2f5cdf65..6f5392e44495c5 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean @@ -6,6 +6,7 @@ Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébas import Mathlib.Data.ENNReal.Real import Mathlib.Tactic.Bound.Attribute import Mathlib.Topology.EMetricSpace.Defs +import Mathlib.Topology.UniformSpace.Compact /-! ## Pseudo-metric spaces @@ -1079,6 +1080,10 @@ theorem tendsto_iff_of_dist {f₁ f₂ : ι → α} {p : Filter ι} {a : α} end Real +theorem PseudoMetricSpace.dist_eq_of_dist_zero (x : α) {y z : α} (h : dist y z = 0) : + dist x y = dist x z := + dist_comm y x ▸ dist_comm z x ▸ sub_eq_zero.1 (abs_nonpos_iff.1 (h ▸ abs_dist_sub_le y z x)) + -- Porting note: 3 new lemmas theorem dist_dist_dist_le_left (x y z : α) : dist (dist x z) (dist y z) ≤ dist x y := abs_dist_sub_le .. @@ -1126,6 +1131,10 @@ theorem dense_iff {s : Set α} : Dense s ↔ ∀ x, ∀ r > 0, (ball x r ∩ s). forall_congr' fun x => by simp only [mem_closure_iff, Set.Nonempty, exists_prop, mem_inter_iff, mem_ball', and_comm] +theorem dense_iff_iUnion_ball (s : Set α) : Dense s ↔ ∀ r > 0, ⋃ c ∈ s, ball c r = univ := by + simp_rw [eq_univ_iff_forall, mem_iUnion, exists_prop, mem_ball, Dense, mem_closure_iff, + forall_comm (α := α)] + 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] diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Real.lean b/Mathlib/Topology/MetricSpace/Pseudo/Real.lean index ae477178577c56..6183ec868a947a 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Real.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Real.lean @@ -3,7 +3,7 @@ Copyright (c) 2015, 2017 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébastien Gouëzel -/ -import Mathlib.Data.Set.Pointwise.Interval +import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.Topology.MetricSpace.Pseudo.Pi /-! @@ -15,7 +15,7 @@ open scoped NNReal Topology namespace Real -variable {ι α : Type*} [PseudoMetricSpace α] +variable {ι : Type*} 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 @@ -35,7 +35,7 @@ lemma dist_le_of_mem_Icc {x y x' y' : ℝ} (hx : x ∈ Icc x' y') (hy : y ∈ Ic 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' : ι → ℝ} +variable [Fintype ι] {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 => diff --git a/Mathlib/Topology/NoetherianSpace.lean b/Mathlib/Topology/NoetherianSpace.lean index 4008eacfe3e3f2..931e8748cbfcef 100644 --- a/Mathlib/Topology/NoetherianSpace.lean +++ b/Mathlib/Topology/NoetherianSpace.lean @@ -98,7 +98,7 @@ theorem noetherianSpace_iff_isCompact : NoetherianSpace α ↔ ∀ s : Set α, I instance [NoetherianSpace α] : WellFoundedLT (Closeds α) := Iff.mp ((noetherianSpace_TFAE α).out 0 1) ‹_› -@[deprecated (since := "2024-10-07")] +@[deprecated "No deprecation message was provided." (since := "2024-10-07")] theorem NoetherianSpace.wellFounded_closeds [NoetherianSpace α] : WellFounded fun s t : Closeds α => s < t := wellFounded_lt @@ -165,7 +165,7 @@ theorem NoetherianSpace.exists_finite_set_closeds_irreducible [NoetherianSpace · by_cases h₁ : IsPreirreducible (s : Set α) · replace h₁ : IsIrreducible (s : Set α) := ⟨Closeds.coe_nonempty.2 h₀, h₁⟩ use {s}; simp [h₁] - · simp only [isPreirreducible_iff_closed_union_closed, not_forall, not_or] at h₁ + · simp only [isPreirreducible_iff_isClosed_union_isClosed, not_forall, not_or] at h₁ obtain ⟨z₁, z₂, hz₁, hz₂, h, hz₁', hz₂'⟩ := h₁ lift z₁ to Closeds α using hz₁ lift z₂ to Closeds α using hz₂ @@ -198,7 +198,7 @@ theorem NoetherianSpace.finite_irreducibleComponents [NoetherianSpace α] : NoetherianSpace.exists_finite_set_isClosed_irreducible isClosed_univ (α := α) refine hSf.subset fun s hs => ?_ lift S to Finset (Set α) using hSf - rcases isIrreducible_iff_sUnion_closed.1 hs.1 S hSc (hSU ▸ Set.subset_univ _) with ⟨t, htS, ht⟩ + rcases isIrreducible_iff_sUnion_isClosed.1 hs.1 S hSc (hSU ▸ Set.subset_univ _) with ⟨t, htS, ht⟩ rwa [ht.antisymm (hs.2 (hSi _ htS) ht)] /-- [Stacks: Lemma 0052 (3)](https://stacks.math.columbia.edu/tag/0052) -/ @@ -213,7 +213,7 @@ theorem NoetherianSpace.exists_open_ne_empty_le_irreducibleComponent [Noetherian let U := Z \ ⋃ (x : ι), x have hU0 : U ≠ ∅ := fun r ↦ by - obtain ⟨Z', hZ'⟩ := isIrreducible_iff_sUnion_closed.mp H.1 hι.toFinset + obtain ⟨Z', hZ'⟩ := isIrreducible_iff_sUnion_isClosed.mp H.1 hι.toFinset (fun z hz ↦ by simp only [Set.Finite.mem_toFinset, Set.mem_diff, Set.mem_singleton_iff] at hz exact isClosed_of_mem_irreducibleComponents _ hz.1) diff --git a/Mathlib/Topology/Order.lean b/Mathlib/Topology/Order.lean index 789c64a0b05111..168716335f5dcb 100644 --- a/Mathlib/Topology/Order.lean +++ b/Mathlib/Topology/Order.lean @@ -305,6 +305,11 @@ theorem singletons_open_iff_discrete {X : Type*} [TopologicalSpace X] : (∀ a : X, IsOpen ({a} : Set X)) ↔ DiscreteTopology X := ⟨fun h => ⟨eq_bot_of_singletons_open h⟩, fun a _ => @isOpen_discrete _ _ a _⟩ +theorem DiscreteTopology.of_finite_of_isClosed_singleton [TopologicalSpace α] [Finite α] + (h : ∀ a : α, IsClosed {a}) : DiscreteTopology α := + discreteTopology_iff_forall_isClosed.mpr fun s ↦ + s.iUnion_of_singleton_coe ▸ isClosed_iUnion_of_finite fun _ ↦ h _ + theorem discreteTopology_iff_singleton_mem_nhds [TopologicalSpace α] : DiscreteTopology α ↔ ∀ x : α, {x} ∈ 𝓝 x := by simp only [← singletons_open_iff_discrete, isOpen_iff_mem_nhds, mem_singleton_iff, forall_eq] diff --git a/Mathlib/Topology/Order/ExtrClosure.lean b/Mathlib/Topology/Order/ExtrClosure.lean index d1b2049789057a..31b06abf781bda 100644 --- a/Mathlib/Topology/Order/ExtrClosure.lean +++ b/Mathlib/Topology/Order/ExtrClosure.lean @@ -20,7 +20,7 @@ open Filter Set open Topology variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] [Preorder Y] - [OrderClosedTopology Y] {f g : X → Y} {s : Set X} {a : X} + [OrderClosedTopology Y] {f : X → Y} {s : Set X} {a : X} protected theorem IsMaxOn.closure (h : IsMaxOn f s a) (hc : ContinuousOn f (closure s)) : IsMaxOn f (closure s) a := fun x hx => diff --git a/Mathlib/Topology/Order/IntermediateValue.lean b/Mathlib/Topology/Order/IntermediateValue.lean index 81446ea8fdf08e..ef73d422348e15 100644 --- a/Mathlib/Topology/Order/IntermediateValue.lean +++ b/Mathlib/Topology/Order/IntermediateValue.lean @@ -122,21 +122,20 @@ theorem IsPreconnected.intermediate_value {s : Set X} (hs : IsPreconnected s) {a theorem IsPreconnected.intermediate_value_Ico {s : Set X} (hs : IsPreconnected s) {a : X} {l : Filter X} (ha : a ∈ s) [NeBot l] (hl : l ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) {v : α} (ht : Tendsto f l (𝓝 v)) : Ico (f a) v ⊆ f '' s := fun _ h => - hs.intermediate_value₂_eventually₁ ha hl hf continuousOn_const h.1 - (eventually_ge_of_tendsto_gt h.2 ht) + hs.intermediate_value₂_eventually₁ ha hl hf continuousOn_const h.1 (ht.eventually_const_le h.2) theorem IsPreconnected.intermediate_value_Ioc {s : Set X} (hs : IsPreconnected s) {a : X} {l : Filter X} (ha : a ∈ s) [NeBot l] (hl : l ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) {v : α} (ht : Tendsto f l (𝓝 v)) : Ioc v (f a) ⊆ f '' s := fun _ h => (hs.intermediate_value₂_eventually₁ ha hl continuousOn_const hf h.2 - (eventually_le_of_tendsto_lt h.1 ht)).imp fun _ h => h.imp_right Eq.symm + (ht.eventually_le_const h.1)).imp fun _ h => h.imp_right Eq.symm theorem IsPreconnected.intermediate_value_Ioo {s : Set X} (hs : IsPreconnected s) {l₁ l₂ : Filter X} [NeBot l₁] [NeBot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) {v₁ v₂ : α} (ht₁ : Tendsto f l₁ (𝓝 v₁)) (ht₂ : Tendsto f l₂ (𝓝 v₂)) : Ioo v₁ v₂ ⊆ f '' s := fun _ h => hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const - (eventually_le_of_tendsto_lt h.1 ht₁) (eventually_ge_of_tendsto_gt h.2 ht₂) + (ht₁.eventually_le_const h.1) (ht₂.eventually_const_le h.2) theorem IsPreconnected.intermediate_value_Ici {s : Set X} (hs : IsPreconnected s) {a : X} {l : Filter X} (ha : a ∈ s) [NeBot l] (hl : l ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) @@ -153,19 +152,19 @@ theorem IsPreconnected.intermediate_value_Ioi {s : Set X} (hs : IsPreconnected s [NeBot l₁] [NeBot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) {v : α} (ht₁ : Tendsto f l₁ (𝓝 v)) (ht₂ : Tendsto f l₂ atTop) : Ioi v ⊆ f '' s := fun y h => hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const - (eventually_le_of_tendsto_lt h ht₁) (tendsto_atTop.1 ht₂ y) + (ht₁.eventually_le_const h) (ht₂.eventually_ge_atTop y) theorem IsPreconnected.intermediate_value_Iio {s : Set X} (hs : IsPreconnected s) {l₁ l₂ : Filter X} [NeBot l₁] [NeBot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) {v : α} (ht₁ : Tendsto f l₁ atBot) (ht₂ : Tendsto f l₂ (𝓝 v)) : Iio v ⊆ f '' s := fun y h => - hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const (tendsto_atBot.1 ht₁ y) - (eventually_ge_of_tendsto_gt h ht₂) + hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const (ht₁.eventually_le_atBot y) + (ht₂.eventually_const_le h) theorem IsPreconnected.intermediate_value_Iii {s : Set X} (hs : IsPreconnected s) {l₁ l₂ : Filter X} [NeBot l₁] [NeBot l₂] (hl₁ : l₁ ≤ 𝓟 s) (hl₂ : l₂ ≤ 𝓟 s) {f : X → α} (hf : ContinuousOn f s) (ht₁ : Tendsto f l₁ atBot) (ht₂ : Tendsto f l₂ atTop) : univ ⊆ f '' s := fun y _ => - hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const (tendsto_atBot.1 ht₁ y) - (tendsto_atTop.1 ht₂ y) + hs.intermediate_value₂_eventually₂ hl₁ hl₂ hf continuousOn_const (ht₁.eventually_le_atBot y) + (ht₂.eventually_ge_atTop y) /-- **Intermediate Value Theorem** for continuous functions on connected spaces. -/ theorem intermediate_value_univ [PreconnectedSpace X] (a b : X) {f : X → α} (hf : Continuous f) : diff --git a/Mathlib/Topology/Order/MonotoneConvergence.lean b/Mathlib/Topology/Order/MonotoneConvergence.lean index bad7ee58b291e2..7936b81bae9f37 100644 --- a/Mathlib/Topology/Order/MonotoneConvergence.lean +++ b/Mathlib/Topology/Order/MonotoneConvergence.lean @@ -107,7 +107,7 @@ end IsGLB section CiSup -variable [ConditionallyCompleteLattice α] [SupConvergenceClass α] {f : ι → α} {a : α} +variable [ConditionallyCompleteLattice α] [SupConvergenceClass α] {f : ι → α} theorem tendsto_atTop_ciSup (h_mono : Monotone f) (hbdd : BddAbove <| range f) : Tendsto f atTop (𝓝 (⨆ i, f i)) := by @@ -121,7 +121,7 @@ end CiSup section CiInf -variable [ConditionallyCompleteLattice α] [InfConvergenceClass α] {f : ι → α} {a : α} +variable [ConditionallyCompleteLattice α] [InfConvergenceClass α] {f : ι → α} theorem tendsto_atBot_ciInf (h_mono : Monotone f) (hbdd : BddBelow <| range f) : Tendsto f atBot (𝓝 (⨅ i, f i)) := by convert tendsto_atTop_ciSup h_mono.dual hbdd.dual using 1 @@ -133,7 +133,7 @@ end CiInf section iSup -variable [CompleteLattice α] [SupConvergenceClass α] {f : ι → α} {a : α} +variable [CompleteLattice α] [SupConvergenceClass α] {f : ι → α} theorem tendsto_atTop_iSup (h_mono : Monotone f) : Tendsto f atTop (𝓝 (⨆ i, f i)) := tendsto_atTop_ciSup h_mono (OrderTop.bddAbove _) @@ -145,7 +145,7 @@ end iSup section iInf -variable [CompleteLattice α] [InfConvergenceClass α] {f : ι → α} {a : α} +variable [CompleteLattice α] [InfConvergenceClass α] {f : ι → α} theorem tendsto_atBot_iInf (h_mono : Monotone f) : Tendsto f atBot (𝓝 (⨅ i, f i)) := tendsto_atBot_ciInf h_mono (OrderBot.bddBelow _) diff --git a/Mathlib/Topology/Order/OrderClosed.lean b/Mathlib/Topology/Order/OrderClosed.lean index 07a4ecd8f0010e..46e8626f54295a 100644 --- a/Mathlib/Topology/Order/OrderClosed.lean +++ b/Mathlib/Topology/Order/OrderClosed.lean @@ -150,6 +150,10 @@ theorem disjoint_nhds_atBot_iff : Disjoint (𝓝 a) atBot ↔ ¬IsBot a := by refine disjoint_of_disjoint_of_mem disjoint_compl_left ?_ (Iic_mem_atBot b) exact isClosed_Iic.isOpen_compl.mem_nhds hb +theorem IsLUB.range_of_tendsto {F : Filter β} [F.NeBot] (hle : ∀ i, f i ≤ a) + (hlim : Tendsto f F (𝓝 a)) : IsLUB (range f) a := + ⟨forall_mem_range.mpr hle, fun _c hc ↦ le_of_tendsto' hlim fun i ↦ hc <| mem_range_self i⟩ + end Preorder section NoBotOrder @@ -170,6 +174,23 @@ theorem not_tendsto_atBot_of_tendsto_nhds (hf : Tendsto f l (𝓝 a)) : ¬Tendst end NoBotOrder +theorem iSup_eq_of_forall_le_of_tendsto {ι : Type*} {F : Filter ι} [Filter.NeBot F] + [ConditionallyCompleteLattice α] [TopologicalSpace α] [ClosedIicTopology α] + {a : α} {f : ι → α} (hle : ∀ i, f i ≤ a) (hlim : Filter.Tendsto f F (𝓝 a)) : + ⨆ i, f i = a := + have := F.nonempty_of_neBot + (IsLUB.range_of_tendsto hle hlim).ciSup_eq + +theorem iUnion_Iic_eq_Iio_of_lt_of_tendsto {ι : Type*} {F : Filter ι} [F.NeBot] + [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [ClosedIicTopology α] + {a : α} {f : ι → α} (hlt : ∀ i, f i < a) (hlim : Tendsto f F (𝓝 a)) : + ⋃ i : ι, Iic (f i) = Iio a := by + have obs : a ∉ range f := by + rw [mem_range] + rintro ⟨i, rfl⟩ + exact (hlt i).false + rw [← biUnion_range, (IsLUB.range_of_tendsto (le_of_lt <| hlt ·) hlim).biUnion_Iic_eq_Iio obs] + section LinearOrder variable [TopologicalSpace α] [LinearOrder α] [ClosedIicTopology α] [TopologicalSpace β] @@ -192,14 +213,20 @@ theorem Ici_mem_nhds (h : a < b) : Ici a ∈ 𝓝 b := theorem eventually_ge_nhds (hab : b < a) : ∀ᶠ x in 𝓝 a, b ≤ x := Ici_mem_nhds hab -theorem eventually_gt_of_tendsto_gt {l : Filter γ} {f : γ → α} {u v : α} (hv : u < v) +theorem Filter.Tendsto.eventually_const_lt {l : Filter γ} {f : γ → α} {u v : α} (hv : u < v) (h : Filter.Tendsto f l (𝓝 v)) : ∀ᶠ a in l, u < f a := h.eventually <| eventually_gt_nhds hv -theorem eventually_ge_of_tendsto_gt {l : Filter γ} {f : γ → α} {u v : α} (hv : u < v) +@[deprecated (since := "2024-11-17")] +alias eventually_gt_of_tendsto_gt := Filter.Tendsto.eventually_const_lt + +theorem Filter.Tendsto.eventually_const_le {l : Filter γ} {f : γ → α} {u v : α} (hv : u < v) (h : Tendsto f l (𝓝 v)) : ∀ᶠ a in l, u ≤ f a := h.eventually <| eventually_ge_nhds hv +@[deprecated (since := "2024-11-17")] +alias eventually_ge_of_tendsto_gt := Filter.Tendsto.eventually_const_le + protected theorem Dense.exists_gt [NoMaxOrder α] {s : Set α} (hs : Dense s) (x : α) : ∃ y ∈ s, x < y := hs.exists_mem_open isOpen_Ioi (exists_gt x) @@ -341,7 +368,7 @@ variable [TopologicalSpace α] [Preorder α] [ClosedIciTopology α] {f : β → theorem isClosed_Ici {a : α} : IsClosed (Ici a) := ClosedIciTopology.isClosed_Ici a -@[deprecated (since := "2024-02-15")] +@[deprecated "No deprecation message was provided." (since := "2024-02-15")] lemma ClosedIciTopology.isClosed_ge' (a : α) : IsClosed {x | a ≤ x} := isClosed_Ici a export ClosedIciTopology (isClosed_ge') @@ -376,6 +403,10 @@ protected alias ⟨_, BddBelow.closure⟩ := bddBelow_closure theorem disjoint_nhds_atTop_iff : Disjoint (𝓝 a) atTop ↔ ¬IsTop a := disjoint_nhds_atBot_iff (α := αᵒᵈ) +theorem IsGLB.range_of_tendsto {F : Filter β} [F.NeBot] (hle : ∀ i, a ≤ f i) + (hlim : Tendsto f F (𝓝 a)) : IsGLB (range f) a := + IsLUB.range_of_tendsto (α := αᵒᵈ) hle hlim + end Preorder section NoTopOrder @@ -396,6 +427,18 @@ theorem not_tendsto_atTop_of_tendsto_nhds (hf : Tendsto f l (𝓝 a)) : ¬Tendst end NoTopOrder +theorem iInf_eq_of_forall_le_of_tendsto {ι : Type*} {F : Filter ι} [F.NeBot] + [ConditionallyCompleteLattice α] [TopologicalSpace α] [ClosedIciTopology α] + {a : α} {f : ι → α} (hle : ∀ i, a ≤ f i) (hlim : Tendsto f F (𝓝 a)) : + ⨅ i, f i = a := + iSup_eq_of_forall_le_of_tendsto (α := αᵒᵈ) hle hlim + +theorem iUnion_Ici_eq_Ioi_of_lt_of_tendsto {ι : Type*} {F : Filter ι} [F.NeBot] + [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [ClosedIciTopology α] + {a : α} {f : ι → α} (hlt : ∀ i, a < f i) (hlim : Tendsto f F (𝓝 a)) : + ⋃ i : ι, Ici (f i) = Ioi a := + iUnion_Iic_eq_Iio_of_lt_of_tendsto (α := αᵒᵈ) hlt hlim + section LinearOrder variable [TopologicalSpace α] [LinearOrder α] [ClosedIciTopology α] [TopologicalSpace β] @@ -414,14 +457,20 @@ theorem Iic_mem_nhds (h : a < b) : Iic b ∈ 𝓝 a := theorem eventually_le_nhds (hab : a < b) : ∀ᶠ x in 𝓝 a, x ≤ b := Iic_mem_nhds hab -theorem eventually_lt_of_tendsto_lt {l : Filter γ} {f : γ → α} {u v : α} (hv : v < u) +theorem Filter.Tendsto.eventually_lt_const {l : Filter γ} {f : γ → α} {u v : α} (hv : v < u) (h : Filter.Tendsto f l (𝓝 v)) : ∀ᶠ a in l, f a < u := h.eventually <| eventually_lt_nhds hv -theorem eventually_le_of_tendsto_lt {l : Filter γ} {f : γ → α} {u v : α} (hv : v < u) +@[deprecated (since := "2024-11-17")] +alias eventually_lt_of_tendsto_lt := Filter.Tendsto.eventually_lt_const + +theorem Filter.Tendsto.eventually_le_const {l : Filter γ} {f : γ → α} {u v : α} (hv : v < u) (h : Tendsto f l (𝓝 v)) : ∀ᶠ a in l, f a ≤ u := h.eventually <| eventually_le_nhds hv +@[deprecated (since := "2024-11-17")] +alias eventually_le_of_tendsto_lt := Filter.Tendsto.eventually_le_const + protected theorem Dense.exists_lt [NoMinOrder α] {s : Set α} (hs : Dense s) (x : α) : ∃ y ∈ s, y < x := hs.orderDual.exists_gt x diff --git a/Mathlib/Topology/Order/T5.lean b/Mathlib/Topology/Order/T5.lean index 39e0d08dc9b0a0..597085db3f1096 100644 --- a/Mathlib/Topology/Order/T5.lean +++ b/Mathlib/Topology/Order/T5.lean @@ -16,8 +16,7 @@ topological space. open Filter Set Function OrderDual Topology Interval -variable {X : Type*} [LinearOrder X] [TopologicalSpace X] [OrderTopology X] {a b c : X} - {s t : Set X} +variable {X : Type*} [LinearOrder X] [TopologicalSpace X] [OrderTopology X] {a : X} {s t : Set X} namespace Set diff --git a/Mathlib/Topology/Separation/Basic.lean b/Mathlib/Topology/Separation/Basic.lean index 7698efb12ea4db..b56a3a27aa9a92 100644 --- a/Mathlib/Topology/Separation/Basic.lean +++ b/Mathlib/Topology/Separation/Basic.lean @@ -316,7 +316,7 @@ theorem inseparable_eq_eq [T0Space X] : Inseparable = @Eq X := theorem TopologicalSpace.IsTopologicalBasis.inseparable_iff {b : Set (Set X)} (hb : IsTopologicalBasis b) {x y : X} : Inseparable x y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) := - ⟨fun h _ hs ↦ inseparable_iff_forall_open.1 h _ (hb.isOpen hs), + ⟨fun h _ hs ↦ inseparable_iff_forall_isOpen.1 h _ (hb.isOpen hs), fun h ↦ hb.nhds_hasBasis.eq_of_same_basis <| by convert hb.nhds_hasBasis using 2 exact and_congr_right (h _)⟩ @@ -328,7 +328,7 @@ theorem TopologicalSpace.IsTopologicalBasis.eq_iff [T0Space X] {b : Set (Set X)} theorem t0Space_iff_exists_isOpen_xor'_mem (X : Type u) [TopologicalSpace X] : T0Space X ↔ Pairwise fun x y => ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := by simp only [t0Space_iff_not_inseparable, xor_iff_not_iff, not_forall, exists_prop, - inseparable_iff_forall_open, Pairwise] + inseparable_iff_forall_isOpen, Pairwise] theorem exists_isOpen_xor'_mem [T0Space X] {x y : X} (h : x ≠ y) : ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := diff --git a/Mathlib/Topology/Sets/Opens.lean b/Mathlib/Topology/Sets/Opens.lean index 574a884fa980a0..452c6d12ef50e9 100644 --- a/Mathlib/Topology/Sets/Opens.lean +++ b/Mathlib/Topology/Sets/Opens.lean @@ -378,7 +378,7 @@ theorem comap_injective [T0Space β] : Injective (comap : C(α, β) → FrameHom fun f g h => ContinuousMap.ext fun a => Inseparable.eq <| - inseparable_iff_forall_open.2 fun s hs => + inseparable_iff_forall_isOpen.2 fun s hs => have : comap f ⟨s, hs⟩ = comap g ⟨s, hs⟩ := DFunLike.congr_fun h ⟨_, hs⟩ show a ∈ f ⁻¹' s ↔ a ∈ g ⁻¹' s from Set.ext_iff.1 (coe_inj.2 this) a diff --git a/Mathlib/Topology/ShrinkingLemma.lean b/Mathlib/Topology/ShrinkingLemma.lean index 8f03eeab6a0688..65f6b728897309 100644 --- a/Mathlib/Topology/ShrinkingLemma.lean +++ b/Mathlib/Topology/ShrinkingLemma.lean @@ -206,7 +206,7 @@ section NormalSpace open ShrinkingLemma -variable {u : ι → Set X} {s : Set X} {p : Set X → Prop} [NormalSpace X] +variable {u : ι → Set X} {s : Set X} [NormalSpace X] /-- **Shrinking lemma**. A point-finite open cover of a closed subset of a normal space can be "shrunk" to a new open cover so that the closure of each new open set is contained in the diff --git a/Mathlib/Topology/TietzeExtension.lean b/Mathlib/Topology/TietzeExtension.lean index 37c54d6ae46aeb..84b683fbeb2feb 100644 --- a/Mathlib/Topology/TietzeExtension.lean +++ b/Mathlib/Topology/TietzeExtension.lean @@ -181,7 +181,7 @@ theorem tietze_extension_step (f : X →ᵇ ℝ) (e : C(X, Y)) (he : IsClosedEmb are disjoint, hence by Urysohn's lemma there exists a function `g` that is equal to `-‖f‖ / 3` on the former set and is equal to `‖f‖ / 3` on the latter set. This function `g` satisfies the assertions of the lemma. -/ - have hf3 : -‖f‖ / 3 < ‖f‖ / 3 := (div_lt_div_right h3).2 (Left.neg_lt_self hf) + have hf3 : -‖f‖ / 3 < ‖f‖ / 3 := (div_lt_div_iff_of_pos_right h3).2 (Left.neg_lt_self hf) have hc₁ : IsClosed (e '' (f ⁻¹' Iic (-‖f‖ / 3))) := he.isClosedMap _ (isClosed_Iic.preimage f.continuous) have hc₂ : IsClosed (e '' (f ⁻¹' Ici (‖f‖ / 3))) := diff --git a/Mathlib/Topology/UniformSpace/Basic.lean b/Mathlib/Topology/UniformSpace/Basic.lean index 9bfe9b67a53a3a..5534b8ebfe86d8 100644 --- a/Mathlib/Topology/UniformSpace/Basic.lean +++ b/Mathlib/Topology/UniformSpace/Basic.lean @@ -5,9 +5,10 @@ Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ import Mathlib.Order.Filter.SmallSets import Mathlib.Tactic.Monotonicity.Basic -import Mathlib.Topology.Compactness.Compact +import Mathlib.Order.Filter.Tendsto import Mathlib.Topology.NhdsSet import Mathlib.Algebra.Group.Defs +import Mathlib.Topology.ContinuousOn /-! # Uniform spaces @@ -651,7 +652,7 @@ theorem nhdsWithin_eq_comap_uniformity {x : α} (S : Set α) : 𝓝[S] x = (𝓤 α ⊓ 𝓟 (univ ×ˢ S)).comap (Prod.mk x) := nhdsWithin_eq_comap_uniformity_of_mem (mem_univ _) S -/-- See also `isOpen_iff_open_ball_subset`. -/ +/-- See also `isOpen_iff_isOpen_ball_subset`. -/ theorem isOpen_iff_ball_subset {s : Set α} : IsOpen s ↔ ∀ x ∈ s, ∃ V ∈ 𝓤 α, ball x V ⊆ s := by simp_rw [isOpen_iff_mem_nhds, nhds_eq_comap_uniformity, mem_comap, ball] @@ -863,7 +864,7 @@ theorem mem_uniformity_isClosed {s : Set (α × α)} (h : s ∈ 𝓤 α) : ∃ t let ⟨t, ⟨ht_mem, htc⟩, hts⟩ := uniformity_hasBasis_closed.mem_iff.1 h ⟨t, ht_mem, htc, hts⟩ -theorem isOpen_iff_open_ball_subset {s : Set α} : +theorem isOpen_iff_isOpen_ball_subset {s : Set α} : IsOpen s ↔ ∀ x ∈ s, ∃ V ∈ 𝓤 α, IsOpen V ∧ ball x V ⊆ s := by rw [isOpen_iff_ball_subset] constructor <;> intro h x hx @@ -874,6 +875,9 @@ theorem isOpen_iff_open_ball_subset {s : Set α} : · obtain ⟨V, hV, -, hV'⟩ := h x hx exact ⟨V, hV, hV'⟩ +@[deprecated (since := "2024-11-18")] alias +isOpen_iff_open_ball_subset := isOpen_iff_isOpen_ball_subset + /-- The uniform neighborhoods of all points of a dense set cover the whole space. -/ theorem Dense.biUnion_uniformity_ball {s : Set α} {U : Set (α × α)} (hs : Dense s) (hU : U ∈ 𝓤 α) : ⋃ x ∈ s, ball x U = univ := by @@ -1605,102 +1609,6 @@ end Sum end Constructions -/-! -### Compact sets in uniform spaces --/ - -section Compact - -open UniformSpace -variable [UniformSpace α] {K : Set α} - -/-- Let `c : ι → Set α` be an open cover of a compact set `s`. Then there exists an entourage -`n` such that for each `x ∈ s` its `n`-neighborhood is contained in some `c i`. -/ -theorem lebesgue_number_lemma {ι : Sort*} {U : ι → Set α} (hK : IsCompact K) - (hopen : ∀ i, IsOpen (U i)) (hcover : K ⊆ ⋃ i, U i) : - ∃ V ∈ 𝓤 α, ∀ x ∈ K, ∃ i, ball x V ⊆ U i := by - have : ∀ x ∈ K, ∃ i, ∃ V ∈ 𝓤 α, ball x (V ○ V) ⊆ U i := fun x hx ↦ by - obtain ⟨i, hi⟩ := mem_iUnion.1 (hcover hx) - rw [← (hopen i).mem_nhds_iff, nhds_eq_comap_uniformity, ← lift'_comp_uniformity] at hi - exact ⟨i, (((basis_sets _).lift' <| monotone_id.compRel monotone_id).comap _).mem_iff.1 hi⟩ - choose ind W hW hWU using this - rcases hK.elim_nhds_subcover' (fun x hx ↦ ball x (W x hx)) (fun x hx ↦ ball_mem_nhds _ (hW x hx)) - with ⟨t, ht⟩ - refine ⟨⋂ x ∈ t, W x x.2, (biInter_finset_mem _).2 fun x _ ↦ hW x x.2, fun x hx ↦ ?_⟩ - rcases mem_iUnion₂.1 (ht hx) with ⟨y, hyt, hxy⟩ - exact ⟨ind y y.2, fun z hz ↦ hWU _ _ ⟨x, hxy, mem_iInter₂.1 hz _ hyt⟩⟩ - -/-- Let `U : ι → Set α` be an open cover of a compact set `K`. -Then there exists an entourage `V` -such that for each `x ∈ K` its `V`-neighborhood is included in some `U i`. - -Moreover, one can choose an entourage from a given basis. -/ -protected theorem Filter.HasBasis.lebesgue_number_lemma {ι' ι : Sort*} {p : ι' → Prop} - {V : ι' → Set (α × α)} {U : ι → Set α} (hbasis : (𝓤 α).HasBasis p V) (hK : IsCompact K) - (hopen : ∀ j, IsOpen (U j)) (hcover : K ⊆ ⋃ j, U j) : - ∃ i, p i ∧ ∀ x ∈ K, ∃ j, ball x (V i) ⊆ U j := by - refine (hbasis.exists_iff ?_).1 (lebesgue_number_lemma hK hopen hcover) - exact fun s t hst ht x hx ↦ (ht x hx).imp fun i hi ↦ Subset.trans (ball_mono hst _) hi - -/-- Let `c : Set (Set α)` be an open cover of a compact set `s`. Then there exists an entourage -`n` such that for each `x ∈ s` its `n`-neighborhood is contained in some `t ∈ c`. -/ -theorem lebesgue_number_lemma_sUnion {S : Set (Set α)} - (hK : IsCompact K) (hopen : ∀ s ∈ S, IsOpen s) (hcover : K ⊆ ⋃₀ S) : - ∃ V ∈ 𝓤 α, ∀ x ∈ K, ∃ s ∈ S, ball x V ⊆ s := by - rw [sUnion_eq_iUnion] at hcover - simpa using lebesgue_number_lemma hK (by simpa) hcover - -/-- If `K` is a compact set in a uniform space and `{V i | p i}` is a basis of entourages, -then `{⋃ x ∈ K, UniformSpace.ball x (V i) | p i}` is a basis of `𝓝ˢ K`. - -Here "`{s i | p i}` is a basis of a filter `l`" means `Filter.HasBasis l p s`. -/ -theorem IsCompact.nhdsSet_basis_uniformity {p : ι → Prop} {V : ι → Set (α × α)} - (hbasis : (𝓤 α).HasBasis p V) (hK : IsCompact K) : - (𝓝ˢ K).HasBasis p fun i => ⋃ x ∈ K, ball x (V i) where - mem_iff' U := by - constructor - · intro H - have HKU : K ⊆ ⋃ _ : Unit, interior U := by - simpa only [iUnion_const, subset_interior_iff_mem_nhdsSet] using H - obtain ⟨i, hpi, hi⟩ : ∃ i, p i ∧ ⋃ x ∈ K, ball x (V i) ⊆ interior U := by - simpa using hbasis.lebesgue_number_lemma hK (fun _ ↦ isOpen_interior) HKU - exact ⟨i, hpi, hi.trans interior_subset⟩ - · rintro ⟨i, hpi, hi⟩ - refine mem_of_superset (bUnion_mem_nhdsSet fun x _ ↦ ?_) hi - exact ball_mem_nhds _ <| hbasis.mem_of_mem hpi - --- TODO: move to a separate file, golf using the regularity of a uniform space. -theorem Disjoint.exists_uniform_thickening {A B : Set α} (hA : IsCompact A) (hB : IsClosed B) - (h : Disjoint A B) : ∃ V ∈ 𝓤 α, Disjoint (⋃ x ∈ A, ball x V) (⋃ x ∈ B, ball x V) := by - have : Bᶜ ∈ 𝓝ˢ A := hB.isOpen_compl.mem_nhdsSet.mpr h.le_compl_right - rw [(hA.nhdsSet_basis_uniformity (Filter.basis_sets _)).mem_iff] at this - rcases this with ⟨U, hU, hUAB⟩ - rcases comp_symm_mem_uniformity_sets hU with ⟨V, hV, hVsymm, hVU⟩ - refine ⟨V, hV, Set.disjoint_left.mpr fun x => ?_⟩ - simp only [mem_iUnion₂] - rintro ⟨a, ha, hxa⟩ ⟨b, hb, hxb⟩ - rw [mem_ball_symmetry hVsymm] at hxa hxb - exact hUAB (mem_iUnion₂_of_mem ha <| hVU <| mem_comp_of_mem_ball hVsymm hxa hxb) hb - -theorem Disjoint.exists_uniform_thickening_of_basis {p : ι → Prop} {s : ι → Set (α × α)} - (hU : (𝓤 α).HasBasis p s) {A B : Set α} (hA : IsCompact A) (hB : IsClosed B) - (h : Disjoint A B) : ∃ i, p i ∧ Disjoint (⋃ x ∈ A, ball x (s i)) (⋃ x ∈ B, ball x (s i)) := by - rcases h.exists_uniform_thickening hA hB with ⟨V, hV, hVAB⟩ - rcases hU.mem_iff.1 hV with ⟨i, hi, hiV⟩ - exact ⟨i, hi, hVAB.mono (iUnion₂_mono fun a _ => ball_mono hiV a) - (iUnion₂_mono fun b _ => ball_mono hiV b)⟩ - -/-- A useful consequence of the Lebesgue number lemma: given any compact set `K` contained in an -open set `U`, we can find an (open) entourage `V` such that the ball of size `V` about any point of -`K` is contained in `U`. -/ -theorem lebesgue_number_of_compact_open {K U : Set α} (hK : IsCompact K) - (hU : IsOpen U) (hKU : K ⊆ U) : ∃ V ∈ 𝓤 α, IsOpen V ∧ ∀ x ∈ K, UniformSpace.ball x V ⊆ U := - let ⟨V, ⟨hV, hVo⟩, hVU⟩ := - (hK.nhdsSet_basis_uniformity uniformity_hasBasis_open).mem_iff.1 (hU.mem_nhdsSet.2 hKU) - ⟨V, hV, hVo, iUnion₂_subset_iff.1 hVU⟩ - -end Compact - /-! ### Expressing continuity properties in uniform spaces diff --git a/Mathlib/Topology/UniformSpace/Cauchy.lean b/Mathlib/Topology/UniformSpace/Cauchy.lean index 9962bbe2a00d6b..b8ae4225ddef4b 100644 --- a/Mathlib/Topology/UniformSpace/Cauchy.lean +++ b/Mathlib/Topology/UniformSpace/Cauchy.lean @@ -5,8 +5,8 @@ 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 +import Mathlib.Topology.UniformSpace.Basic /-! # Theory of Cauchy filters in uniform spaces. Complete uniform spaces. Totally bounded subsets. diff --git a/Mathlib/Topology/UniformSpace/Compact.lean b/Mathlib/Topology/UniformSpace/Compact.lean index f8308127388e00..ed4c24be25ac24 100644 --- a/Mathlib/Topology/UniformSpace/Compact.lean +++ b/Mathlib/Topology/UniformSpace/Compact.lean @@ -1,44 +1,115 @@ /- -Copyright (c) 2020 Patrick Massot. All rights reserved. +Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Patrick Massot, Yury Kudryashov +Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ -import Mathlib.Topology.UniformSpace.UniformConvergence -import Mathlib.Topology.UniformSpace.Equicontinuity -import Mathlib.Topology.Support +import Mathlib.Topology.UniformSpace.Basic +import Mathlib.Topology.Compactness.Compact /-! -# Compact separated uniform spaces - -## Main statements +# Compact sets in uniform spaces * `compactSpace_uniformity`: On a compact uniform space, the topology determines the uniform structure, entourages are exactly the neighborhoods of the diagonal. -* `uniformSpace_of_compact_t2`: every compact T2 topological structure is induced by a uniform - structure. This uniform structure is described in the previous item. - -* **Heine-Cantor** theorem: continuous functions on compact uniform spaces with values in uniform - spaces are automatically uniformly continuous. There are several variations, the main one is - `CompactSpace.uniformContinuous_of_continuous`. - -## Implementation notes - -The construction `uniformSpace_of_compact_t2` is not declared as an instance, as it would badly -loop. - -## Tags - -uniform space, uniform continuity, compact space -/ -open Uniformity Topology Filter UniformSpace Set +universe u v ua ub uc ud + +variable {α : Type ua} {β : Type ub} {γ : Type uc} {δ : Type ud} {ι : Sort*} + +section Compact + +open Uniformity Set Filter UniformSpace +open scoped Topology + +variable [UniformSpace α] {K : Set α} + +/-- Let `c : ι → Set α` be an open cover of a compact set `s`. Then there exists an entourage +`n` such that for each `x ∈ s` its `n`-neighborhood is contained in some `c i`. -/ +theorem lebesgue_number_lemma {ι : Sort*} {U : ι → Set α} (hK : IsCompact K) + (hopen : ∀ i, IsOpen (U i)) (hcover : K ⊆ ⋃ i, U i) : + ∃ V ∈ 𝓤 α, ∀ x ∈ K, ∃ i, ball x V ⊆ U i := by + have : ∀ x ∈ K, ∃ i, ∃ V ∈ 𝓤 α, ball x (V ○ V) ⊆ U i := fun x hx ↦ by + obtain ⟨i, hi⟩ := mem_iUnion.1 (hcover hx) + rw [← (hopen i).mem_nhds_iff, nhds_eq_comap_uniformity, ← lift'_comp_uniformity] at hi + exact ⟨i, (((basis_sets _).lift' <| monotone_id.compRel monotone_id).comap _).mem_iff.1 hi⟩ + choose ind W hW hWU using this + rcases hK.elim_nhds_subcover' (fun x hx ↦ ball x (W x hx)) (fun x hx ↦ ball_mem_nhds _ (hW x hx)) + with ⟨t, ht⟩ + refine ⟨⋂ x ∈ t, W x x.2, (biInter_finset_mem _).2 fun x _ ↦ hW x x.2, fun x hx ↦ ?_⟩ + rcases mem_iUnion₂.1 (ht hx) with ⟨y, hyt, hxy⟩ + exact ⟨ind y y.2, fun z hz ↦ hWU _ _ ⟨x, hxy, mem_iInter₂.1 hz _ hyt⟩⟩ + +/-- Let `U : ι → Set α` be an open cover of a compact set `K`. +Then there exists an entourage `V` +such that for each `x ∈ K` its `V`-neighborhood is included in some `U i`. + +Moreover, one can choose an entourage from a given basis. -/ +protected theorem Filter.HasBasis.lebesgue_number_lemma {ι' ι : Sort*} {p : ι' → Prop} + {V : ι' → Set (α × α)} {U : ι → Set α} (hbasis : (𝓤 α).HasBasis p V) (hK : IsCompact K) + (hopen : ∀ j, IsOpen (U j)) (hcover : K ⊆ ⋃ j, U j) : + ∃ i, p i ∧ ∀ x ∈ K, ∃ j, ball x (V i) ⊆ U j := by + refine (hbasis.exists_iff ?_).1 (lebesgue_number_lemma hK hopen hcover) + exact fun s t hst ht x hx ↦ (ht x hx).imp fun i hi ↦ Subset.trans (ball_mono hst _) hi + +/-- Let `c : Set (Set α)` be an open cover of a compact set `s`. Then there exists an entourage +`n` such that for each `x ∈ s` its `n`-neighborhood is contained in some `t ∈ c`. -/ +theorem lebesgue_number_lemma_sUnion {S : Set (Set α)} + (hK : IsCompact K) (hopen : ∀ s ∈ S, IsOpen s) (hcover : K ⊆ ⋃₀ S) : + ∃ V ∈ 𝓤 α, ∀ x ∈ K, ∃ s ∈ S, ball x V ⊆ s := by + rw [sUnion_eq_iUnion] at hcover + simpa using lebesgue_number_lemma hK (by simpa) hcover + +/-- If `K` is a compact set in a uniform space and `{V i | p i}` is a basis of entourages, +then `{⋃ x ∈ K, UniformSpace.ball x (V i) | p i}` is a basis of `𝓝ˢ K`. + +Here "`{s i | p i}` is a basis of a filter `l`" means `Filter.HasBasis l p s`. -/ +theorem IsCompact.nhdsSet_basis_uniformity {p : ι → Prop} {V : ι → Set (α × α)} + (hbasis : (𝓤 α).HasBasis p V) (hK : IsCompact K) : + (𝓝ˢ K).HasBasis p fun i => ⋃ x ∈ K, ball x (V i) where + mem_iff' U := by + constructor + · intro H + have HKU : K ⊆ ⋃ _ : Unit, interior U := by + simpa only [iUnion_const, subset_interior_iff_mem_nhdsSet] using H + obtain ⟨i, hpi, hi⟩ : ∃ i, p i ∧ ⋃ x ∈ K, ball x (V i) ⊆ interior U := by + simpa using hbasis.lebesgue_number_lemma hK (fun _ ↦ isOpen_interior) HKU + exact ⟨i, hpi, hi.trans interior_subset⟩ + · rintro ⟨i, hpi, hi⟩ + refine mem_of_superset (bUnion_mem_nhdsSet fun x _ ↦ ?_) hi + exact ball_mem_nhds _ <| hbasis.mem_of_mem hpi + +-- TODO: move to a separate file, golf using the regularity of a uniform space. +theorem Disjoint.exists_uniform_thickening {A B : Set α} (hA : IsCompact A) (hB : IsClosed B) + (h : Disjoint A B) : ∃ V ∈ 𝓤 α, Disjoint (⋃ x ∈ A, ball x V) (⋃ x ∈ B, ball x V) := by + have : Bᶜ ∈ 𝓝ˢ A := hB.isOpen_compl.mem_nhdsSet.mpr h.le_compl_right + rw [(hA.nhdsSet_basis_uniformity (Filter.basis_sets _)).mem_iff] at this + rcases this with ⟨U, hU, hUAB⟩ + rcases comp_symm_mem_uniformity_sets hU with ⟨V, hV, hVsymm, hVU⟩ + refine ⟨V, hV, Set.disjoint_left.mpr fun x => ?_⟩ + simp only [mem_iUnion₂] + rintro ⟨a, ha, hxa⟩ ⟨b, hb, hxb⟩ + rw [mem_ball_symmetry hVsymm] at hxa hxb + exact hUAB (mem_iUnion₂_of_mem ha <| hVU <| mem_comp_of_mem_ball hVsymm hxa hxb) hb + +theorem Disjoint.exists_uniform_thickening_of_basis {p : ι → Prop} {s : ι → Set (α × α)} + (hU : (𝓤 α).HasBasis p s) {A B : Set α} (hA : IsCompact A) (hB : IsClosed B) + (h : Disjoint A B) : ∃ i, p i ∧ Disjoint (⋃ x ∈ A, ball x (s i)) (⋃ x ∈ B, ball x (s i)) := by + rcases h.exists_uniform_thickening hA hB with ⟨V, hV, hVAB⟩ + rcases hU.mem_iff.1 hV with ⟨i, hi, hiV⟩ + exact ⟨i, hi, hVAB.mono (iUnion₂_mono fun a _ => ball_mono hiV a) + (iUnion₂_mono fun b _ => ball_mono hiV b)⟩ + +/-- A useful consequence of the Lebesgue number lemma: given any compact set `K` contained in an +open set `U`, we can find an (open) entourage `V` such that the ball of size `V` about any point of +`K` is contained in `U`. -/ +theorem lebesgue_number_of_compact_open {K U : Set α} (hK : IsCompact K) + (hU : IsOpen U) (hKU : K ⊆ U) : ∃ V ∈ 𝓤 α, IsOpen V ∧ ∀ x ∈ K, UniformSpace.ball x V ⊆ U := + let ⟨V, ⟨hV, hVo⟩, hVU⟩ := + (hK.nhdsSet_basis_uniformity uniformity_hasBasis_open).mem_iff.1 (hU.mem_nhdsSet.2 hKU) + ⟨V, hV, hVo, iUnion₂_subset_iff.1 hVU⟩ -variable {α β γ : Type*} [UniformSpace α] [UniformSpace β] - -/-! -### Uniformity on compact spaces --/ /-- On a compact uniform space, the topology determines the uniform structure, entourages are exactly the neighborhoods of the diagonal. -/ @@ -66,196 +137,4 @@ theorem unique_uniformity_of_compact [t : TopologicalSpace γ] [CompactSpace γ] have : @CompactSpace γ u'.toTopologicalSpace := by rwa [h'] rw [@compactSpace_uniformity _ u, compactSpace_uniformity, h, h'] -/-- The unique uniform structure inducing a given compact topological structure. -/ -def uniformSpaceOfCompactT2 [TopologicalSpace γ] [CompactSpace γ] [T2Space γ] : UniformSpace γ where - uniformity := 𝓝ˢ (diagonal γ) - symm := continuous_swap.tendsto_nhdsSet fun _ => Eq.symm - comp := by - /- This is the difficult part of the proof. We need to prove that, for each neighborhood `W` - of the diagonal `Δ`, there exists a smaller neighborhood `V` such that `V ○ V ⊆ W`. - -/ - set 𝓝Δ := 𝓝ˢ (diagonal γ) - -- The filter of neighborhoods of Δ - set F := 𝓝Δ.lift' fun s : Set (γ × γ) => s ○ s - -- Compositions of neighborhoods of Δ - -- If this weren't true, then there would be V ∈ 𝓝Δ such that F ⊓ 𝓟 Vᶜ ≠ ⊥ - rw [le_iff_forall_inf_principal_compl] - intro V V_in - by_contra H - haveI : NeBot (F ⊓ 𝓟 Vᶜ) := ⟨H⟩ - -- Hence compactness would give us a cluster point (x, y) for F ⊓ 𝓟 Vᶜ - obtain ⟨⟨x, y⟩, hxy⟩ : ∃ p : γ × γ, ClusterPt p (F ⊓ 𝓟 Vᶜ) := exists_clusterPt_of_compactSpace _ - -- In particular (x, y) is a cluster point of 𝓟 Vᶜ, hence is not in the interior of V, - -- and a fortiori not in Δ, so x ≠ y - have clV : ClusterPt (x, y) (𝓟 <| Vᶜ) := hxy.of_inf_right - have : (x, y) ∉ interior V := by - have : (x, y) ∈ closure Vᶜ := by rwa [mem_closure_iff_clusterPt] - rwa [closure_compl] at this - have diag_subset : diagonal γ ⊆ interior V := subset_interior_iff_mem_nhdsSet.2 V_in - have x_ne_y : x ≠ y := mt (@diag_subset (x, y)) this - -- Since γ is compact and Hausdorff, it is T₄, hence T₃. - -- So there are closed neighborhoods V₁ and V₂ of x and y contained in - -- disjoint open neighborhoods U₁ and U₂. - obtain - ⟨U₁, _, V₁, V₁_in, U₂, _, V₂, V₂_in, V₁_cl, V₂_cl, U₁_op, U₂_op, VU₁, VU₂, hU₁₂⟩ := - disjoint_nested_nhds x_ne_y - -- We set U₃ := (V₁ ∪ V₂)ᶜ so that W := U₁ ×ˢ U₁ ∪ U₂ ×ˢ U₂ ∪ U₃ ×ˢ U₃ is an open - -- neighborhood of Δ. - let U₃ := (V₁ ∪ V₂)ᶜ - have U₃_op : IsOpen U₃ := (V₁_cl.union V₂_cl).isOpen_compl - let W := U₁ ×ˢ U₁ ∪ U₂ ×ˢ U₂ ∪ U₃ ×ˢ U₃ - have W_in : W ∈ 𝓝Δ := by - rw [mem_nhdsSet_iff_forall] - rintro ⟨z, z'⟩ (rfl : z = z') - refine IsOpen.mem_nhds ?_ ?_ - · apply_rules [IsOpen.union, IsOpen.prod] - · simp only [W, mem_union, mem_prod, and_self_iff] - exact (_root_.em _).imp_left fun h => union_subset_union VU₁ VU₂ h - -- So W ○ W ∈ F by definition of F - have : W ○ W ∈ F := @mem_lift' _ _ _ (fun s => s ○ s) _ W_in - -- Porting note: was `by simpa only using mem_lift' W_in` - -- And V₁ ×ˢ V₂ ∈ 𝓝 (x, y) - have hV₁₂ : V₁ ×ˢ V₂ ∈ 𝓝 (x, y) := prod_mem_nhds V₁_in V₂_in - -- But (x, y) is also a cluster point of F so (V₁ ×ˢ V₂) ∩ (W ○ W) ≠ ∅ - -- However the construction of W implies (V₁ ×ˢ V₂) ∩ (W ○ W) = ∅. - -- Indeed assume for contradiction there is some (u, v) in the intersection. - obtain ⟨⟨u, v⟩, ⟨u_in, v_in⟩, w, huw, hwv⟩ := clusterPt_iff.mp hxy.of_inf_left hV₁₂ this - -- So u ∈ V₁, v ∈ V₂, and there exists some w such that (u, w) ∈ W and (w ,v) ∈ W. - -- Because u is in V₁ which is disjoint from U₂ and U₃, (u, w) ∈ W forces (u, w) ∈ U₁ ×ˢ U₁. - have uw_in : (u, w) ∈ U₁ ×ˢ U₁ := - (huw.resolve_right fun h => h.1 <| Or.inl u_in).resolve_right fun h => - hU₁₂.le_bot ⟨VU₁ u_in, h.1⟩ - -- Similarly, because v ∈ V₂, (w ,v) ∈ W forces (w, v) ∈ U₂ ×ˢ U₂. - have wv_in : (w, v) ∈ U₂ ×ˢ U₂ := - (hwv.resolve_right fun h => h.2 <| Or.inr v_in).resolve_left fun h => - hU₁₂.le_bot ⟨h.2, VU₂ v_in⟩ - -- Hence w ∈ U₁ ∩ U₂ which is empty. - -- 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, 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: a continuous function on a compact uniform space is uniformly -continuous. -/ -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.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 -continuous. -/ -theorem IsCompact.uniformContinuousOn_of_continuous {s : Set α} {f : α → β} (hs : IsCompact s) - (hf : ContinuousOn f s) : UniformContinuousOn f s := by - rw [uniformContinuousOn_iff_restrict] - rw [isCompact_iff_compactSpace] at hs - rw [continuousOn_iff_continuous_restrict] at hf - exact CompactSpace.uniformContinuous_of_continuous hf - -/-- If `s` is compact and `f` is continuous at all points of `s`, then `f` is -"uniformly continuous at the set `s`", i.e. `f x` is close to `f y` whenever `x ∈ s` and `y` is -close to `x` (even if `y` is not itself in `s`, so this is a stronger assertion than -`UniformContinuousOn s`). -/ -theorem IsCompact.uniformContinuousAt_of_continuousAt {r : Set (β × β)} {s : Set α} - (hs : IsCompact s) (f : α → β) (hf : ∀ a ∈ s, ContinuousAt f a) (hr : r ∈ 𝓤 β) : - { x : α × α | x.1 ∈ s → (f x.1, f x.2) ∈ r } ∈ 𝓤 α := by - obtain ⟨t, ht, htsymm, htr⟩ := comp_symm_mem_uniformity_sets hr - choose U hU T hT hb using fun a ha => - exists_mem_nhds_ball_subset_of_mem_nhds ((hf a ha).preimage_mem_nhds <| mem_nhds_left _ ht) - obtain ⟨fs, hsU⟩ := hs.elim_nhds_subcover' U hU - apply mem_of_superset ((biInter_finset_mem fs).2 fun a _ => hT a a.2) - rintro ⟨a₁, a₂⟩ h h₁ - obtain ⟨a, ha, haU⟩ := Set.mem_iUnion₂.1 (hsU h₁) - apply htr - refine ⟨f a, htsymm.mk_mem_comm.1 (hb _ _ _ haU ?_), hb _ _ _ haU ?_⟩ - exacts [mem_ball_self _ (hT a a.2), mem_iInter₂.1 h a ha] - -theorem Continuous.uniformContinuous_of_tendsto_cocompact {f : α → β} {x : β} - (h_cont : Continuous f) (hx : Tendsto f (cocompact α) (𝓝 x)) : UniformContinuous f := - uniformContinuous_def.2 fun r hr => by - obtain ⟨t, ht, htsymm, htr⟩ := comp_symm_mem_uniformity_sets hr - obtain ⟨s, hs, hst⟩ := mem_cocompact.1 (hx <| mem_nhds_left _ ht) - apply - mem_of_superset - (symmetrize_mem_uniformity <| - (hs.uniformContinuousAt_of_continuousAt f fun _ _ => h_cont.continuousAt) <| - symmetrize_mem_uniformity hr) - rintro ⟨b₁, b₂⟩ h - by_cases h₁ : b₁ ∈ s; · exact (h.1 h₁).1 - by_cases h₂ : b₂ ∈ s; · exact (h.2 h₂).2 - apply htr - exact ⟨x, htsymm.mk_mem_comm.1 (hst h₁), hst h₂⟩ - -@[to_additive] -theorem HasCompactMulSupport.uniformContinuous_of_continuous {f : α → β} [One β] - (h1 : HasCompactMulSupport f) (h2 : Continuous f) : UniformContinuous f := - h2.uniformContinuous_of_tendsto_cocompact h1.is_one_at_infty - -/-- A family of functions `α → β → γ` tends uniformly to its value at `x` if `α` is locally compact, -`β` is compact and `f` is continuous on `U × (univ : Set β)` for some neighborhood `U` of `x`. -/ -theorem ContinuousOn.tendstoUniformly [LocallyCompactSpace α] [CompactSpace β] [UniformSpace γ] - {f : α → β → γ} {x : α} {U : Set α} (hxU : U ∈ 𝓝 x) (h : ContinuousOn (↿f) (U ×ˢ univ)) : - TendstoUniformly f (f x) (𝓝 x) := by - rcases LocallyCompactSpace.local_compact_nhds _ _ hxU with ⟨K, hxK, hKU, hK⟩ - have : UniformContinuousOn (↿f) (K ×ˢ univ) := - IsCompact.uniformContinuousOn_of_continuous (hK.prod isCompact_univ) - (h.mono <| prod_mono hKU Subset.rfl) - exact this.tendstoUniformly hxK - -/-- A continuous family of functions `α → β → γ` tends uniformly to its value at `x` -if `α` is weakly locally compact and `β` is compact. -/ -theorem Continuous.tendstoUniformly [WeaklyLocallyCompactSpace α] [CompactSpace β] [UniformSpace γ] - (f : α → β → γ) (h : Continuous ↿f) (x : α) : TendstoUniformly f (f x) (𝓝 x) := - let ⟨K, hK, hxK⟩ := exists_compact_mem_nhds x - have : UniformContinuousOn (↿f) (K ×ˢ univ) := - IsCompact.uniformContinuousOn_of_continuous (hK.prod isCompact_univ) h.continuousOn - this.tendstoUniformly hxK - -/-- In a product space `α × β`, assume that a function `f` is continuous on `s × k` where `k` is -compact. Then, along the fiber above any `q ∈ s`, `f` is transversely uniformly continuous, i.e., -if `p ∈ s` is close enough to `q`, then `f p x` is uniformly close to `f q x` for all `x ∈ k`. -/ -lemma IsCompact.mem_uniformity_of_prod - {α β E : Type*} [TopologicalSpace α] [TopologicalSpace β] [UniformSpace E] - {f : α → β → E} {s : Set α} {k : Set β} {q : α} {u : Set (E × E)} - (hk : IsCompact k) (hf : ContinuousOn f.uncurry (s ×ˢ k)) (hq : q ∈ s) (hu : u ∈ 𝓤 E) : - ∃ v ∈ 𝓝[s] q, ∀ p ∈ v, ∀ x ∈ k, (f p x, f q x) ∈ u := by - apply hk.induction_on (p := fun t ↦ ∃ v ∈ 𝓝[s] q, ∀ p ∈ v, ∀ x ∈ t, (f p x, f q x) ∈ u) - · exact ⟨univ, univ_mem, by simp⟩ - · intro t' t ht't ⟨v, v_mem, hv⟩ - exact ⟨v, v_mem, fun p hp x hx ↦ hv p hp x (ht't hx)⟩ - · intro t t' ⟨v, v_mem, hv⟩ ⟨v', v'_mem, hv'⟩ - refine ⟨v ∩ v', inter_mem v_mem v'_mem, fun p hp x hx ↦ ?_⟩ - rcases hx with h'x|h'x - · exact hv p hp.1 x h'x - · exact hv' p hp.2 x h'x - · rcases comp_symm_of_uniformity hu with ⟨u', u'_mem, u'_symm, hu'⟩ - intro x hx - obtain ⟨v, hv, w, hw, hvw⟩ : - ∃ v ∈ 𝓝[s] q, ∃ w ∈ 𝓝[k] x, v ×ˢ w ⊆ f.uncurry ⁻¹' {z | (f q x, z) ∈ u'} := - mem_nhdsWithin_prod_iff.1 (hf (q, x) ⟨hq, hx⟩ (mem_nhds_left (f q x) u'_mem)) - refine ⟨w, hw, v, hv, fun p hp y hy ↦ ?_⟩ - have A : (f q x, f p y) ∈ u' := hvw (⟨hp, hy⟩ : (p, y) ∈ v ×ˢ w) - have B : (f q x, f q y) ∈ u' := hvw (⟨mem_of_mem_nhdsWithin hq hv, hy⟩ : (q, y) ∈ v ×ˢ w) - exact hu' (prod_mk_mem_compRel (u'_symm A) B) - -section UniformConvergence - -/-- An equicontinuous family of functions defined on a compact uniform space is automatically -uniformly equicontinuous. -/ -theorem CompactSpace.uniformEquicontinuous_of_equicontinuous {ι : Type*} {F : ι → β → α} - [CompactSpace β] (h : Equicontinuous F) : UniformEquicontinuous F := by - rw [equicontinuous_iff_continuous] at h - rw [uniformEquicontinuous_iff_uniformContinuous] - exact CompactSpace.uniformContinuous_of_continuous h - -end UniformConvergence +end Compact diff --git a/Mathlib/Topology/UniformSpace/CompactConvergence.lean b/Mathlib/Topology/UniformSpace/CompactConvergence.lean index 0a9a0c7520df83..d5e4df759ebef9 100644 --- a/Mathlib/Topology/UniformSpace/CompactConvergence.lean +++ b/Mathlib/Topology/UniformSpace/CompactConvergence.lean @@ -7,6 +7,7 @@ import Mathlib.Topology.CompactOpen import Mathlib.Topology.LocallyFinite import Mathlib.Topology.Maps.Proper.Basic import Mathlib.Topology.UniformSpace.UniformConvergenceTopology +import Mathlib.Topology.UniformSpace.Compact /-! # Compact convergence (uniform convergence on compact sets) @@ -48,12 +49,12 @@ and also prove its basic properties. a similar statement that uses a basis of entourages of `β` instead of all entourages. It is useful, e.g., if `β` is a metric space. -* `ContinuousMap.tendsto_iff_forall_compact_tendstoUniformlyOn`: +* `ContinuousMap.tendsto_iff_forall_isCompact_tendstoUniformlyOn`: a sequence of functions `Fₙ` in `C(α, β)` converges in the compact-open topology to some `f` iff `Fₙ` converges to `f` uniformly on each compact subset `K` of `α`. * Topology induced by the uniformity described above agrees with the compact-open topology. - This is essentially the same as `ContinuousMap.tendsto_iff_forall_compact_tendstoUniformlyOn`. + This is essentially the same as `ContinuousMap.tendsto_iff_forall_isCompact_tendstoUniformlyOn`. This fact is not available as a separate theorem. Instead, we override the projection of `ContinuousMap.compactConvergenceUniformity` @@ -95,7 +96,7 @@ namespace ContinuousMap /-- Compact-open topology on `C(α, β)` agrees with the topology of uniform convergence on compacts: a family of continuous functions `F i` tends to `f` in the compact-open topology if and only if the `F i` tends to `f` uniformly on all compact sets. -/ -theorem tendsto_iff_forall_compact_tendstoUniformlyOn +theorem tendsto_iff_forall_isCompact_tendstoUniformlyOn {ι : Type u₃} {p : Filter ι} {F : ι → C(α, β)} {f} : Tendsto F p (𝓝 f) ↔ ∀ K, IsCompact K → TendstoUniformlyOn (fun i a => F i a) f p K := by rw [tendsto_nhds_compactOpen] @@ -138,6 +139,9 @@ theorem tendsto_iff_forall_compact_tendstoUniformlyOn -- maps `K` to `U` as well filter_upwards [h K hK V hV] with g hg x hx using hVf _ (mem_image_of_mem f hx) (hg x hx) +@[deprecated (since := "2024-11-19")] alias +tendsto_iff_forall_compact_tendstoUniformlyOn := tendsto_iff_forall_isCompact_tendstoUniformlyOn + /-- Interpret a bundled continuous map as an element of `α →ᵤ[{K | IsCompact K}] β`. We use this map to induce the `UniformSpace` structure on `C(α, β)`. -/ @@ -157,14 +161,14 @@ open UniformSpace in The uniformity comes from `α →ᵤ[{K | IsCompact K}] β` (i.e., `UniformOnFun α β {K | IsCompact K}`) which defines topology of uniform convergence on compact sets. -We use `ContinuousMap.tendsto_iff_forall_compact_tendstoUniformlyOn` +We use `ContinuousMap.tendsto_iff_forall_isCompact_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]. -/ instance compactConvergenceUniformSpace : UniformSpace C(α, β) := .replaceTopology (.comap toUniformOnFunIsCompact inferInstance) <| by refine TopologicalSpace.ext_nhds fun f ↦ eq_of_forall_le_iff fun l ↦ ?_ - simp_rw [← tendsto_id', tendsto_iff_forall_compact_tendstoUniformlyOn, + simp_rw [← tendsto_id', tendsto_iff_forall_isCompact_tendstoUniformlyOn, nhds_induced, tendsto_comap_iff, UniformOnFun.tendsto_iff_tendstoUniformlyOn] rfl @@ -232,7 +236,7 @@ variable {ι : Type u₃} {p : Filter ι} {F : ι → C(α, β)} {f} /-- Locally uniform convergence implies convergence in the compact-open topology. -/ theorem tendsto_of_tendstoLocallyUniformly (h : TendstoLocallyUniformly (fun i a => F i a) f p) : Tendsto F p (𝓝 f) := by - rw [tendsto_iff_forall_compact_tendstoUniformlyOn] + rw [tendsto_iff_forall_isCompact_tendstoUniformlyOn] intro K hK rw [← tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hK] exact h.tendstoLocallyUniformlyOn @@ -245,7 +249,7 @@ see `ContinuousMap.tendsto_of_tendstoLocallyUniformly`. -/ theorem tendsto_iff_tendstoLocallyUniformly [WeaklyLocallyCompactSpace α] : Tendsto F p (𝓝 f) ↔ TendstoLocallyUniformly (fun i a => F i a) f p := by refine ⟨fun h V hV x ↦ ?_, tendsto_of_tendstoLocallyUniformly⟩ - rw [tendsto_iff_forall_compact_tendstoUniformlyOn] at h + rw [tendsto_iff_forall_isCompact_tendstoUniformlyOn] at h obtain ⟨n, hn₁, hn₂⟩ := exists_compact_mem_nhds x exact ⟨n, hn₂, h n hn₁ V hV⟩ @@ -313,7 +317,7 @@ theorem hasBasis_compactConvergenceUniformity_of_compact : continuous functions on a compact space. -/ theorem tendsto_iff_tendstoUniformly : Tendsto F p (𝓝 f) ↔ TendstoUniformly (fun i a => F i a) f p := by - rw [tendsto_iff_forall_compact_tendstoUniformlyOn, ← tendstoUniformlyOn_univ] + rw [tendsto_iff_forall_isCompact_tendstoUniformlyOn, ← tendstoUniformlyOn_univ] exact ⟨fun h => h univ isCompact_univ, fun h K _hK => h.mono (subset_univ K)⟩ end CompactDomain diff --git a/Mathlib/Topology/UniformSpace/HeineCantor.lean b/Mathlib/Topology/UniformSpace/HeineCantor.lean new file mode 100644 index 00000000000000..d97593eba0566a --- /dev/null +++ b/Mathlib/Topology/UniformSpace/HeineCantor.lean @@ -0,0 +1,146 @@ +/- +Copyright (c) 2020 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Yury Kudryashov +-/ +import Mathlib.Topology.UniformSpace.Equicontinuity +import Mathlib.Topology.UniformSpace.Compact +import Mathlib.Topology.Support + +/-! +# Compact separated uniform spaces + +## Main statement + +* **Heine-Cantor** theorem: continuous functions on compact uniform spaces with values in uniform + spaces are automatically uniformly continuous. There are several variations, the main one is + `CompactSpace.uniformContinuous_of_continuous`. + +## Tags + +uniform space, uniform continuity, compact space +-/ + +open Uniformity Topology Filter UniformSpace Set + +variable {α β γ : Type*} [UniformSpace α] [UniformSpace β] + +/-! +### Heine-Cantor theorem +-/ + +/-- Heine-Cantor: a continuous function on a compact uniform space is uniformly +continuous. -/ +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.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 +continuous. -/ +theorem IsCompact.uniformContinuousOn_of_continuous {s : Set α} {f : α → β} (hs : IsCompact s) + (hf : ContinuousOn f s) : UniformContinuousOn f s := by + rw [uniformContinuousOn_iff_restrict] + rw [isCompact_iff_compactSpace] at hs + rw [continuousOn_iff_continuous_restrict] at hf + exact CompactSpace.uniformContinuous_of_continuous hf + +/-- If `s` is compact and `f` is continuous at all points of `s`, then `f` is +"uniformly continuous at the set `s`", i.e. `f x` is close to `f y` whenever `x ∈ s` and `y` is +close to `x` (even if `y` is not itself in `s`, so this is a stronger assertion than +`UniformContinuousOn s`). -/ +theorem IsCompact.uniformContinuousAt_of_continuousAt {r : Set (β × β)} {s : Set α} + (hs : IsCompact s) (f : α → β) (hf : ∀ a ∈ s, ContinuousAt f a) (hr : r ∈ 𝓤 β) : + { x : α × α | x.1 ∈ s → (f x.1, f x.2) ∈ r } ∈ 𝓤 α := by + obtain ⟨t, ht, htsymm, htr⟩ := comp_symm_mem_uniformity_sets hr + choose U hU T hT hb using fun a ha => + exists_mem_nhds_ball_subset_of_mem_nhds ((hf a ha).preimage_mem_nhds <| mem_nhds_left _ ht) + obtain ⟨fs, hsU⟩ := hs.elim_nhds_subcover' U hU + apply mem_of_superset ((biInter_finset_mem fs).2 fun a _ => hT a a.2) + rintro ⟨a₁, a₂⟩ h h₁ + obtain ⟨a, ha, haU⟩ := Set.mem_iUnion₂.1 (hsU h₁) + apply htr + refine ⟨f a, htsymm.mk_mem_comm.1 (hb _ _ _ haU ?_), hb _ _ _ haU ?_⟩ + exacts [mem_ball_self _ (hT a a.2), mem_iInter₂.1 h a ha] + +theorem Continuous.uniformContinuous_of_tendsto_cocompact {f : α → β} {x : β} + (h_cont : Continuous f) (hx : Tendsto f (cocompact α) (𝓝 x)) : UniformContinuous f := + uniformContinuous_def.2 fun r hr => by + obtain ⟨t, ht, htsymm, htr⟩ := comp_symm_mem_uniformity_sets hr + obtain ⟨s, hs, hst⟩ := mem_cocompact.1 (hx <| mem_nhds_left _ ht) + apply + mem_of_superset + (symmetrize_mem_uniformity <| + (hs.uniformContinuousAt_of_continuousAt f fun _ _ => h_cont.continuousAt) <| + symmetrize_mem_uniformity hr) + rintro ⟨b₁, b₂⟩ h + by_cases h₁ : b₁ ∈ s; · exact (h.1 h₁).1 + by_cases h₂ : b₂ ∈ s; · exact (h.2 h₂).2 + apply htr + exact ⟨x, htsymm.mk_mem_comm.1 (hst h₁), hst h₂⟩ + +@[to_additive] +theorem HasCompactMulSupport.uniformContinuous_of_continuous {f : α → β} [One β] + (h1 : HasCompactMulSupport f) (h2 : Continuous f) : UniformContinuous f := + h2.uniformContinuous_of_tendsto_cocompact h1.is_one_at_infty + +/-- A family of functions `α → β → γ` tends uniformly to its value at `x` if `α` is locally compact, +`β` is compact and `f` is continuous on `U × (univ : Set β)` for some neighborhood `U` of `x`. -/ +theorem ContinuousOn.tendstoUniformly [LocallyCompactSpace α] [CompactSpace β] [UniformSpace γ] + {f : α → β → γ} {x : α} {U : Set α} (hxU : U ∈ 𝓝 x) (h : ContinuousOn (↿f) (U ×ˢ univ)) : + TendstoUniformly f (f x) (𝓝 x) := by + rcases LocallyCompactSpace.local_compact_nhds _ _ hxU with ⟨K, hxK, hKU, hK⟩ + have : UniformContinuousOn (↿f) (K ×ˢ univ) := + IsCompact.uniformContinuousOn_of_continuous (hK.prod isCompact_univ) + (h.mono <| prod_mono hKU Subset.rfl) + exact this.tendstoUniformly hxK + +/-- A continuous family of functions `α → β → γ` tends uniformly to its value at `x` +if `α` is weakly locally compact and `β` is compact. -/ +theorem Continuous.tendstoUniformly [WeaklyLocallyCompactSpace α] [CompactSpace β] [UniformSpace γ] + (f : α → β → γ) (h : Continuous ↿f) (x : α) : TendstoUniformly f (f x) (𝓝 x) := + let ⟨K, hK, hxK⟩ := exists_compact_mem_nhds x + have : UniformContinuousOn (↿f) (K ×ˢ univ) := + IsCompact.uniformContinuousOn_of_continuous (hK.prod isCompact_univ) h.continuousOn + this.tendstoUniformly hxK + +/-- In a product space `α × β`, assume that a function `f` is continuous on `s × k` where `k` is +compact. Then, along the fiber above any `q ∈ s`, `f` is transversely uniformly continuous, i.e., +if `p ∈ s` is close enough to `q`, then `f p x` is uniformly close to `f q x` for all `x ∈ k`. -/ +lemma IsCompact.mem_uniformity_of_prod + {α β E : Type*} [TopologicalSpace α] [TopologicalSpace β] [UniformSpace E] + {f : α → β → E} {s : Set α} {k : Set β} {q : α} {u : Set (E × E)} + (hk : IsCompact k) (hf : ContinuousOn f.uncurry (s ×ˢ k)) (hq : q ∈ s) (hu : u ∈ 𝓤 E) : + ∃ v ∈ 𝓝[s] q, ∀ p ∈ v, ∀ x ∈ k, (f p x, f q x) ∈ u := by + apply hk.induction_on (p := fun t ↦ ∃ v ∈ 𝓝[s] q, ∀ p ∈ v, ∀ x ∈ t, (f p x, f q x) ∈ u) + · exact ⟨univ, univ_mem, by simp⟩ + · intro t' t ht't ⟨v, v_mem, hv⟩ + exact ⟨v, v_mem, fun p hp x hx ↦ hv p hp x (ht't hx)⟩ + · intro t t' ⟨v, v_mem, hv⟩ ⟨v', v'_mem, hv'⟩ + refine ⟨v ∩ v', inter_mem v_mem v'_mem, fun p hp x hx ↦ ?_⟩ + rcases hx with h'x|h'x + · exact hv p hp.1 x h'x + · exact hv' p hp.2 x h'x + · rcases comp_symm_of_uniformity hu with ⟨u', u'_mem, u'_symm, hu'⟩ + intro x hx + obtain ⟨v, hv, w, hw, hvw⟩ : + ∃ v ∈ 𝓝[s] q, ∃ w ∈ 𝓝[k] x, v ×ˢ w ⊆ f.uncurry ⁻¹' {z | (f q x, z) ∈ u'} := + mem_nhdsWithin_prod_iff.1 (hf (q, x) ⟨hq, hx⟩ (mem_nhds_left (f q x) u'_mem)) + refine ⟨w, hw, v, hv, fun p hp y hy ↦ ?_⟩ + have A : (f q x, f p y) ∈ u' := hvw (⟨hp, hy⟩ : (p, y) ∈ v ×ˢ w) + have B : (f q x, f q y) ∈ u' := hvw (⟨mem_of_mem_nhdsWithin hq hv, hy⟩ : (q, y) ∈ v ×ˢ w) + exact hu' (prod_mk_mem_compRel (u'_symm A) B) + +section UniformConvergence + +/-- An equicontinuous family of functions defined on a compact uniform space is automatically +uniformly equicontinuous. -/ +theorem CompactSpace.uniformEquicontinuous_of_equicontinuous {ι : Type*} {F : ι → β → α} + [CompactSpace β] (h : Equicontinuous F) : UniformEquicontinuous F := by + rw [equicontinuous_iff_continuous] at h + rw [uniformEquicontinuous_iff_uniformContinuous] + exact CompactSpace.uniformContinuous_of_continuous h + +end UniformConvergence diff --git a/Mathlib/Topology/UniformSpace/OfCompactT2.lean b/Mathlib/Topology/UniformSpace/OfCompactT2.lean new file mode 100644 index 00000000000000..c9d49e9474570d --- /dev/null +++ b/Mathlib/Topology/UniformSpace/OfCompactT2.lean @@ -0,0 +1,107 @@ +/- +Copyright (c) 2020 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Yury Kudryashov +-/ +import Mathlib.Topology.Separation.Basic +import Mathlib.Topology.UniformSpace.Basic + +/-! +# Compact separated uniform spaces + +## Main statement + +* `uniformSpace_of_compact_t2`: every compact T2 topological structure is induced by a uniform + structure. This uniform structure is described by `compactSpace_uniformity`. + +## Implementation notes + +The construction `uniformSpace_of_compact_t2` is not declared as an instance, as it would badly +loop. + +## Tags + +uniform space, uniform continuity, compact space +-/ + +open Uniformity Topology Filter UniformSpace Set + +variable {γ : Type*} + +/-! +### Uniformity on compact spaces +-/ + + +/-- The unique uniform structure inducing a given compact topological structure. -/ +def uniformSpaceOfCompactT2 [TopologicalSpace γ] [CompactSpace γ] [T2Space γ] : UniformSpace γ where + uniformity := 𝓝ˢ (diagonal γ) + symm := continuous_swap.tendsto_nhdsSet fun _ => Eq.symm + comp := by + /- This is the difficult part of the proof. We need to prove that, for each neighborhood `W` + of the diagonal `Δ`, there exists a smaller neighborhood `V` such that `V ○ V ⊆ W`. + -/ + set 𝓝Δ := 𝓝ˢ (diagonal γ) + -- The filter of neighborhoods of Δ + set F := 𝓝Δ.lift' fun s : Set (γ × γ) => s ○ s + -- Compositions of neighborhoods of Δ + -- If this weren't true, then there would be V ∈ 𝓝Δ such that F ⊓ 𝓟 Vᶜ ≠ ⊥ + rw [le_iff_forall_inf_principal_compl] + intro V V_in + by_contra H + haveI : NeBot (F ⊓ 𝓟 Vᶜ) := ⟨H⟩ + -- Hence compactness would give us a cluster point (x, y) for F ⊓ 𝓟 Vᶜ + obtain ⟨⟨x, y⟩, hxy⟩ : ∃ p : γ × γ, ClusterPt p (F ⊓ 𝓟 Vᶜ) := exists_clusterPt_of_compactSpace _ + -- In particular (x, y) is a cluster point of 𝓟 Vᶜ, hence is not in the interior of V, + -- and a fortiori not in Δ, so x ≠ y + have clV : ClusterPt (x, y) (𝓟 <| Vᶜ) := hxy.of_inf_right + have : (x, y) ∉ interior V := by + have : (x, y) ∈ closure Vᶜ := by rwa [mem_closure_iff_clusterPt] + rwa [closure_compl] at this + have diag_subset : diagonal γ ⊆ interior V := subset_interior_iff_mem_nhdsSet.2 V_in + have x_ne_y : x ≠ y := mt (@diag_subset (x, y)) this + -- Since γ is compact and Hausdorff, it is T₄, hence T₃. + -- So there are closed neighborhoods V₁ and V₂ of x and y contained in + -- disjoint open neighborhoods U₁ and U₂. + obtain + ⟨U₁, _, V₁, V₁_in, U₂, _, V₂, V₂_in, V₁_cl, V₂_cl, U₁_op, U₂_op, VU₁, VU₂, hU₁₂⟩ := + disjoint_nested_nhds x_ne_y + -- We set U₃ := (V₁ ∪ V₂)ᶜ so that W := U₁ ×ˢ U₁ ∪ U₂ ×ˢ U₂ ∪ U₃ ×ˢ U₃ is an open + -- neighborhood of Δ. + let U₃ := (V₁ ∪ V₂)ᶜ + have U₃_op : IsOpen U₃ := (V₁_cl.union V₂_cl).isOpen_compl + let W := U₁ ×ˢ U₁ ∪ U₂ ×ˢ U₂ ∪ U₃ ×ˢ U₃ + have W_in : W ∈ 𝓝Δ := by + rw [mem_nhdsSet_iff_forall] + rintro ⟨z, z'⟩ (rfl : z = z') + refine IsOpen.mem_nhds ?_ ?_ + · apply_rules [IsOpen.union, IsOpen.prod] + · simp only [W, mem_union, mem_prod, and_self_iff] + exact (_root_.em _).imp_left fun h => union_subset_union VU₁ VU₂ h + -- So W ○ W ∈ F by definition of F + have : W ○ W ∈ F := @mem_lift' _ _ _ (fun s => s ○ s) _ W_in + -- Porting note: was `by simpa only using mem_lift' W_in` + -- And V₁ ×ˢ V₂ ∈ 𝓝 (x, y) + have hV₁₂ : V₁ ×ˢ V₂ ∈ 𝓝 (x, y) := prod_mem_nhds V₁_in V₂_in + -- But (x, y) is also a cluster point of F so (V₁ ×ˢ V₂) ∩ (W ○ W) ≠ ∅ + -- However the construction of W implies (V₁ ×ˢ V₂) ∩ (W ○ W) = ∅. + -- Indeed assume for contradiction there is some (u, v) in the intersection. + obtain ⟨⟨u, v⟩, ⟨u_in, v_in⟩, w, huw, hwv⟩ := clusterPt_iff.mp hxy.of_inf_left hV₁₂ this + -- So u ∈ V₁, v ∈ V₂, and there exists some w such that (u, w) ∈ W and (w ,v) ∈ W. + -- Because u is in V₁ which is disjoint from U₂ and U₃, (u, w) ∈ W forces (u, w) ∈ U₁ ×ˢ U₁. + have uw_in : (u, w) ∈ U₁ ×ˢ U₁ := + (huw.resolve_right fun h => h.1 <| Or.inl u_in).resolve_right fun h => + hU₁₂.le_bot ⟨VU₁ u_in, h.1⟩ + -- Similarly, because v ∈ V₂, (w ,v) ∈ W forces (w, v) ∈ U₂ ×ˢ U₂. + have wv_in : (w, v) ∈ U₂ ×ˢ U₂ := + (hwv.resolve_right fun h => h.2 <| Or.inr v_in).resolve_left fun h => + hU₁₂.le_bot ⟨h.2, VU₂ v_in⟩ + -- Hence w ∈ U₁ ∩ U₂ which is empty. + -- 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, 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)] diff --git a/Mathlib/Topology/UniformSpace/OfFun.lean b/Mathlib/Topology/UniformSpace/OfFun.lean index 6a1ff605f190e7..1fa610f447327c 100644 --- a/Mathlib/Topology/UniformSpace/OfFun.lean +++ b/Mathlib/Topology/UniformSpace/OfFun.lean @@ -3,8 +3,8 @@ Copyright (c) 2023 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Topology.UniformSpace.Basic import Mathlib.Algebra.Order.Monoid.Defs +import Mathlib.Topology.UniformSpace.Basic /-! # Construct a `UniformSpace` from a `dist`-like function diff --git a/Mathlib/Topology/UniformSpace/Separation.lean b/Mathlib/Topology/UniformSpace/Separation.lean index 672378e6ebef9b..9b3a324dc67dfe 100644 --- a/Mathlib/Topology/UniformSpace/Separation.lean +++ b/Mathlib/Topology/UniformSpace/Separation.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Patrick Massot, Yury Kudryashov -/ import Mathlib.Tactic.ApplyFun -import Mathlib.Topology.UniformSpace.Basic import Mathlib.Topology.Separation.Basic +import Mathlib.Topology.UniformSpace.Basic /-! # Hausdorff properties of uniform spaces. Separation quotient. @@ -253,7 +253,7 @@ open Classical in TODO: unify with `SeparationQuotient.lift`. -/ def lift' [T0Space β] (f : α → β) : SeparationQuotient α → β := if hc : UniformContinuous f then lift f fun _ _ h => (h.map hc.continuous).eq - else fun x => f (Nonempty.some ⟨x.out'⟩) + else fun x => f (Nonempty.some ⟨x.out⟩) theorem lift'_mk [T0Space β] {f : α → β} (h : UniformContinuous f) (a : α) : lift' f (mk a) = f a := by rw [lift', dif_pos h, lift_mk] diff --git a/Mathlib/Topology/UniformSpace/UniformConvergence.lean b/Mathlib/Topology/UniformSpace/UniformConvergence.lean index aca68d49538bac..48ea1c9d19316f 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergence.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.UniformSpace.Basic import Mathlib.Topology.UniformSpace.Cauchy /-! diff --git a/Mathlib/Util/AtomM.lean b/Mathlib/Util/AtomM.lean index 0b829028c0b114..bc85531a753a4d 100644 --- a/Mathlib/Util/AtomM.lean +++ b/Mathlib/Util/AtomM.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro -/ import Mathlib.Init import Lean.Meta.Tactic.Simp.Types +import Qq /-! # A monad for tracking and deduplicating atoms @@ -44,13 +45,33 @@ def AtomM.run {α : Type} (red : TransparencyMode) (m : AtomM α) MetaM α := (m { red, evalAtom }).run' {} -/-- Get the index corresponding to an atomic expression, if it has already been encountered, or -put it in the list of atoms and return the new index, otherwise. -/ -def AtomM.addAtom (e : Expr) : AtomM Nat := do +/-- If an atomic expression has already been encountered, get the index and the stored form of the +atom (which will be defeq at the specified transparency, but not necessarily syntactically equal). +If the atomic expression has *not* already been encountered, store it in the list of atoms, and +return the new index (and the stored form of the atom, which will be itself). + +In a normalizing tactic, the expression returned by `addAtom` should be considered the normal form. +-/ +def AtomM.addAtom (e : Expr) : AtomM (Nat × Expr) := do let c ← get for h : i in [:c.atoms.size] 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 }) + return (i, c.atoms[i]) + modifyGet fun c ↦ ((c.atoms.size, e), { c with atoms := c.atoms.push e }) + +open Qq in +/-- If an atomic expression has already been encountered, get the index and the stored form of the +atom (which will be defeq at the specified transparency, but not necessarily syntactically equal). +If the atomic expression has *not* already been encountered, store it in the list of atoms, and +return the new index (and the stored form of the atom, which will be itself). + +In a normalizing tactic, the expression returned by `addAtomQ` should be considered the normal form. + +This is a strongly-typed version of `AtomM.addAtom` for code using `Qq`. +-/ +def AtomM.addAtomQ {u : Level} {α : Q(Type u)} (e : Q($α)) : + AtomM (Nat × {e' : Q($α) // $e =Q $e'}) := do + let (n, e') ← AtomM.addAtom e + return (n, ⟨e', ⟨⟩⟩) end Mathlib.Tactic diff --git a/Mathlib/Util/ParseCommand.lean b/Mathlib/Util/ParseCommand.lean new file mode 100644 index 00000000000000..d3c71c46e9aacc --- /dev/null +++ b/Mathlib/Util/ParseCommand.lean @@ -0,0 +1,57 @@ +/- +Copyright (c) 2024 Matthew Robert Ballard. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Matthew Robert Ballard, Damiano Testa +-/ + +import Lean.Elab.Command +import Mathlib.Init + +/-! +# `#parse` -- a command to parse text and log outputs +-/ + +namespace Mathlib.GuardExceptions + +open Lean Parser Elab Command +/-- `captureException env s input` uses the given `Environment` `env` to parse the `String` `input` +using the `ParserFn` `s`. + +This is a variation of `Lean.Parser.runParserCategory`. +-/ +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) + +/-- `#parse parserFnId => str` allows to capture parsing exceptions. +`parserFnId` is the identifier of a `ParserFn` and `str` is the string that +`parserFnId` should parse. + +If the parse is successful, then the output is logged; +if the parse is successful, then the output is captured in an exception. + +In either case, `#guard_msgs` can then be used to capture the resulting parsing errors. + +For instance, `#parse` can be used as follows +```lean +/-- error: :1:3: Stacks tags must be exactly 4 characters -/ +#guard_msgs in #parse Mathlib.Stacks.stacksTagFn => "A05" +``` +-/ +syntax (name := parseCmd) "#parse " ident " => " str : command + +@[inherit_doc parseCmd] +elab_rules : command + | `(command| #parse $parserFnId => $str) => do + elabCommand <| ← `(command| + run_cmd do + let exc ← Lean.ofExcept <| captureException (← getEnv) $parserFnId $str + logInfo $str) + +end Mathlib.GuardExceptions diff --git a/MathlibTest/CategoryTheory/ConcreteCategory/AlgebraCat.lean b/MathlibTest/CategoryTheory/ConcreteCategory/AlgebraCat.lean new file mode 100644 index 00000000000000..406d12cc89de4d --- /dev/null +++ b/MathlibTest/CategoryTheory/ConcreteCategory/AlgebraCat.lean @@ -0,0 +1,53 @@ +import Mathlib + +universe v u + +open CategoryTheory AlgebraCat + +set_option maxHeartbeats 10000 +set_option synthInstance.maxHeartbeats 2000 + +variable (R : Type u) [CommRing R] + +/- We test if all the coercions and `map_add` lemmas trigger correctly. -/ + +example (X : Type u) [Ring X] [Algebra R X] : ⇑(𝟙 (of R X)) = id := by simp + +example {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] (f : X →ₐ[R] Y) : + ⇑(ofHom f) = ⇑f := by simp + +example {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] (f : X →ₐ[R] Y) + (x : X) : (ofHom f) x = f x := by simp + +example {X Y Z : AlgebraCat R} (f : X ⟶ Y) (g : Y ⟶ Z) : ⇑(f ≫ g) = ⇑g ∘ ⇑f := by simp + +example {X Y Z : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] [Ring Z] + [Algebra R Z] (f : X →ₐ[R] Y) (g : Y →ₐ[R] Z) : + ⇑(ofHom f ≫ ofHom g) = g ∘ f := by simp + +example {X Y : Type v} [Ring X] [Algebra R X] [Ring Y] [Algebra R Y] {Z : AlgebraCat R} + (f : X →ₐ[R] Y) (g : of R Y ⟶ Z) : + ⇑(ofHom f ≫ g) = g ∘ f := by simp + +example {X Y : AlgebraCat R} {Z : Type v} [Ring Z] [Algebra R Z] (f : X ⟶ Y) (g : Y ⟶ of R Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {Y Z : AlgebraCat R} {X : Type v} [Ring X] [Algebra R X] (f : of R X ⟶ Y) (g : Y ⟶ Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {X Y Z : AlgebraCat R} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : (f ≫ g) x = g (f x) := by simp + +example {X Y : AlgebraCat R} (e : X ≅ Y) (x : X) : e.inv (e.hom x) = x := by simp + +example {X Y : AlgebraCat R} (e : X ≅ Y) (y : Y) : e.hom (e.inv y) = y := by simp + +example (X : AlgebraCat R) : ⇑(𝟙 X) = id := by simp + +example {M N : AlgebraCat.{v} R} (f : M ⟶ N) (x y : M) : f (x + y) = f x + f y := by + simp + +example {M N : AlgebraCat.{v} R} (f : M ⟶ N) : f 0 = 0 := by + simp + +example {M N : AlgebraCat.{v} R} (f : M ⟶ N) (r : R) (m : M) : f (r • m) = r • f m := by + simp diff --git a/MathlibTest/GCongr/inequalities.lean b/MathlibTest/GCongr/inequalities.lean index 2bce82a11a237f..3056ee3b5e6aa2 100644 --- a/MathlibTest/GCongr/inequalities.lean +++ b/MathlibTest/GCongr/inequalities.lean @@ -100,7 +100,7 @@ example {a b : ℚ} (h₁ : a < b) (c : ℝ) : (a + c : ℝ) < b + c := by gcong example {k m n : ℤ} (H : m ^ 2 ≤ n ^ 2) : k + m ^ 2 ≤ k + n ^ 2 := by gcongr -- test of behaviour when no lemmas are applicable -example (n k : ℕ) (H : n ^ k + 1 ≤ k ^ n + 1) : n ^ k ≤ k ^ n := by +example (n k : ℕ) (H : n % k + 1 ≤ k % n + 1) : n % k ≤ k % n := by success_if_fail_with_msg "gcongr did not make progress" (gcongr) diff --git a/MathlibTest/MinImports.lean b/MathlibTest/MinImports.lean index 43ee73fa011e91..87a0a011d07ad2 100644 --- a/MathlibTest/MinImports.lean +++ b/MathlibTest/MinImports.lean @@ -165,4 +165,28 @@ def def_with_multiple_dependencies := let _ := Mathlib.Meta.NormNum.evalNatDvd false +/-! Structures and inductives should be treated just like definitions. -/ + +/-- + +warning: Consider moving this declaration to the module Mathlib.Data.Nat.Notation. +note: this linter can be disabled with `set_option linter.upstreamableDecl false` +-/ +#guard_msgs in +structure ProposeToMoveThisStructure where + foo : ℕ + +/-- +warning: Consider moving this declaration to the module Mathlib.Data.Nat.Notation. +note: this linter can be disabled with `set_option linter.upstreamableDecl false` +-/ +#guard_msgs in +inductive ProposeToMoveThisInductive where +| foo : ℕ → ProposeToMoveThisInductive +| bar : ℕ → ProposeToMoveThisInductive → ProposeToMoveThisInductive + +-- This theorem depends on a local inductive, so should not be moved. +#guard_msgs in +theorem theorem_with_local_inductive : Nonempty ProposeToMoveThisInductive := ⟨.foo 0⟩ + end Linter.UpstreamableDecl diff --git a/MathlibTest/StacksAttribute.lean b/MathlibTest/StacksAttribute.lean index 3b70bdb5976105..6fbee7f267bc29 100644 --- a/MathlibTest/StacksAttribute.lean +++ b/MathlibTest/StacksAttribute.lean @@ -1,4 +1,5 @@ import Mathlib.Tactic.StacksAttribute +import Mathlib.Util.ParseCommand /-- info: No tags found. -/ #guard_msgs in @@ -30,6 +31,21 @@ example : True := .intro @[stacks 0X14 "I can also have a comment"] 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 + +/-- error: :1:3: Stacks tags must be exactly 4 characters -/ +#guard_msgs in #parse Mathlib.StacksTag.stacksTagFn => "A05" + +/-- error: :1:4: Stacks tags must consist only of digits and uppercase letters. -/ +#guard_msgs in #parse Mathlib.StacksTag.stacksTagFn => "A05b" + +/-- info: 0BD5 -/ +#guard_msgs in #parse Mathlib.StacksTag.stacksTagFn => "0BD5" + /-- info: [Stacks Tag A04Q](https://stacks.math.columbia.edu/tag/A04Q) corresponds to declaration 'X.tagged'. (A comment) diff --git a/MathlibTest/Variable.lean b/MathlibTest/Variable.lean index 327d36efd228eb..e93a74e81fbecc 100644 --- a/MathlibTest/Variable.lean +++ b/MathlibTest/Variable.lean @@ -1,8 +1,10 @@ -import Mathlib.Tactic.Variable -import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.Algebra.Defs +import Mathlib.Algebra.Field.Defs +import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.Ring.Regular import Mathlib.Algebra.Module.LinearMap.Basic -import Mathlib.RingTheory.UniqueFactorizationDomain +import Mathlib.RingTheory.UniqueFactorizationDomain.Basic +import Mathlib.Tactic.Variable set_option autoImplicit true namespace Tests diff --git a/MathlibTest/abel.lean b/MathlibTest/abel.lean index d59304f17cbfbd..f2235b46071cf8 100644 --- a/MathlibTest/abel.lean +++ b/MathlibTest/abel.lean @@ -141,3 +141,32 @@ example [AddCommGroup α] (x y z : α) (h : False) (w : x - x = y + z) : False : abel_nf at * guard_hyp w : 0 = y + z assumption + +section +abbrev myId (a : ℤ) : ℤ := a + +/- +Test that when `abel_nf` normalizes multiple expressions which contain a particular atom, it uses a +form for that atom which is consistent between expressions. + +We can't use `guard_hyp h :ₛ` here, as while it does tell apart `x` and `myId x`, it also complains +about differing instance paths. +-/ +/-- +info: α : Type _ +a b : α +x : ℤ +R : ℤ → ℤ → Prop +hR : Reflexive R +h : R (2 • myId x) (2 • myId x) +⊢ True +-/ +#guard_msgs (info) in +set_option pp.mvars false in +example (x : ℤ) (R : ℤ → ℤ → Prop) (hR : Reflexive R) : True := by + have h : R (myId x + x) (x + myId x) := hR .. + abel_nf at h + trace_state + trivial + +end diff --git a/MathlibTest/apply_rules.lean b/MathlibTest/apply_rules.lean index d621b7bb85ae8c..ab93b4c736a697 100644 --- a/MathlibTest/apply_rules.lean +++ b/MathlibTest/apply_rules.lean @@ -49,4 +49,4 @@ example [LinearOrderedField α] {a b : α} (hb : 0 ≤ b) (hab : a ≤ b) : a / fail_if_success apply_rules (config := { transparency := .reducible }) [mul_le_mul] guard_target = a / 2 ≤ b / 2 - exact div_le_div hb hab zero_lt_two le_rfl + exact div_le_div₀ hb hab zero_lt_two le_rfl diff --git a/MathlibTest/fun_prop2.lean b/MathlibTest/fun_prop2.lean index e98b764c72c0ac..8a5d906d3f74b2 100644 --- a/MathlibTest/fun_prop2.lean +++ b/MathlibTest/fun_prop2.lean @@ -76,7 +76,7 @@ example : AEMeasurable T := by fun_prop -private theorem t1 : (5: ℕ) + (1 : ℕ∞) ≤ (12 : ℕ∞) := by norm_cast +private theorem t1 : (5: ℕ) + (1 : ℕ∞) ≤ (12 : WithTop ℕ∞) := by norm_cast example {f : ℝ → ℝ} (hf : ContDiff ℝ 12 f) : Differentiable ℝ (iteratedDeriv 5 (fun x => f (2*(f (x + x))) + x)) := by diff --git a/MathlibTest/fun_prop_dev.lean b/MathlibTest/fun_prop_dev.lean index f78abae43617ab..866e3b6aebefa0 100644 --- a/MathlibTest/fun_prop_dev.lean +++ b/MathlibTest/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 Mathlib.Tactic.SuccessIfFailWithMsg import Aesop /-! # Tests for the `fun_prop` tactic @@ -536,14 +537,15 @@ example [Add α] (a : α) : -- 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 + [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 : α): @@ -553,3 +555,68 @@ example [Add α] (y : α): have : Con f := by fun_prop set_option trace.Meta.Tactic.fun_prop true in fun_prop + + + +--- pefromance tests - mainly testing fast failure --- +------------------------------------------------------ + + +section PerformanceTests +-- set_option trace.Meta.Tactic.fun_prop true +-- set_option profiler true + +variable {R : Type*} [Add R] [∀ n, OfNat R n] +example (f : R → R) (hf : Con f) : + Con (fun x ↦ f (x + 3)) := by fun_prop -- succeeds in 5ms +example (f : R → R) (hf : Con f) : + Con (fun x ↦ (f (x + 3)) + 2) := by fun_prop -- succeeds in 6ms +example (f : R → R) (hf : Con f) : + Con (fun x ↦ (f (x + 3)) + (2 + f (x + 1))) := by fun_prop -- succeeds in 8ms +example (f : R → R) (hf : Con f) : + Con (fun x ↦ (f (x + 3)) + (2 + f (x + 1)) + x) := by fun_prop -- succeeds in 10ms +example (f : R → R) (hf : Con f) : + Con (fun x ↦ (f (x + 3)) + 2 + f (x + 1) + x + 1) := by fun_prop -- succeeds in 11ms + +-- This used to fail in exponentially increasing time, up to 6s for the last example +-- We set maxHearthbeats to 1000 such that the last three examples should fail if the exponential +-- blow happen again. +set_option maxHeartbeats 1000 in +example (f : R → R) : + Con (fun x ↦ f (x + 3)) := by + fail_if_success fun_prop + apply silentSorry + +example (f : R → R) : + Con (fun x ↦ (f (x + 3)) + 2) := by + fail_if_success fun_prop + apply silentSorry + +set_option maxHeartbeats 1000 in +example (f : R → R) : + Con (fun x ↦ ((f (x + 3)) + 2) + f (x + 1)) := by + fail_if_success fun_prop + apply silentSorry + +set_option maxHeartbeats 1000 in +example (f : R → R) : + Con (fun x ↦ ((f (x + 3)) + 2) + f (x + 1) + x) := by + fail_if_success fun_prop + apply silentSorry + +set_option maxHeartbeats 1000 in +example (f : R → R) : + Con (fun x ↦ ((f (x + 3)) + 2) + f (x + 1) + x + 1) := by + fail_if_success fun_prop + apply silentSorry + +end PerformanceTests + + +/-- +info: Con + add_Con, args: [4, 5], form: simple + add_Con', args: [4, 5], form: compositional +-/ +#guard_msgs in +#print_fun_prop_theorems HAdd.hAdd Con diff --git a/MathlibTest/levenshtein.lean b/MathlibTest/levenshtein.lean index 5d2c2d34f0d480..53932d20b2d568 100644 --- a/MathlibTest/levenshtein.lean +++ b/MathlibTest/levenshtein.lean @@ -1,5 +1,5 @@ import Mathlib.Data.List.EditDistance.Defs -import Mathlib.Algebra.Group.Nat +import Mathlib.Algebra.Group.Nat.Basic #guard (suffixLevenshtein Levenshtein.defaultCost "kitten".toList "sitting".toList).1 = diff --git a/MathlibTest/matrix.lean b/MathlibTest/matrix.lean index d8571679b3a9c8..f6e84240f8d076 100644 --- a/MathlibTest/matrix.lean +++ b/MathlibTest/matrix.lean @@ -13,8 +13,6 @@ variable {α β : Type} [Semiring α] [Ring β] namespace Matrix -open Matrix - /-! Test that the dimensions are inferred correctly, even for empty matrices -/ section dimensions diff --git a/MathlibTest/norm_cast.lean b/MathlibTest/norm_cast.lean index cb792593c1ef5a..2cd0529030d980 100644 --- a/MathlibTest/norm_cast.lean +++ b/MathlibTest/norm_cast.lean @@ -126,8 +126,6 @@ example (a b : ℕ) (h2 : ((a + b + 0 : ℕ) : ℤ) = 10) : -- example {x : ℚ} : ((x + 42 : ℚ) : ℝ) = x + 42 := by push_cast namespace ENNReal - -open ENNReal lemma half_lt_self_bis {a : ℝ≥0∞} (hz : a ≠ 0) (ht : a ≠ ⊤) : a / 2 < a := by lift a to NNReal using ht have h : (2 : ℝ≥0∞) = ((2 : NNReal) : ℝ≥0∞) := rfl diff --git a/MathlibTest/norm_num_ext.lean b/MathlibTest/norm_num_ext.lean index c864ac4fd8427e..de2675f268b147 100644 --- a/MathlibTest/norm_num_ext.lean +++ b/MathlibTest/norm_num_ext.lean @@ -449,3 +449,13 @@ example : (553105253 : ℤ) ∣ 553105253 * 776531401 := by norm_num1 example : ¬ (553105253 : ℤ) ∣ 553105253 * 776531401 + 1 := by norm_num1 end mod + +section num_den + +example : (6 / 15 : ℚ).num = 2 := by norm_num1 +example : (6 / 15 : ℚ).den = 5 := by norm_num1 + +example : (-6 / 15 : ℚ).num = -2 := by norm_num1 +example : (-6 / 15 : ℚ).den = 5 := by norm_num1 + +end num_den diff --git a/MathlibTest/positivity.lean b/MathlibTest/positivity.lean index da296d8d2860fd..b3f2b9b7af6bac 100644 --- a/MathlibTest/positivity.lean +++ b/MathlibTest/positivity.lean @@ -1,10 +1,10 @@ +import Mathlib.Tactic.Positivity import Mathlib.Data.Complex.Exponential import Mathlib.Data.Real.Sqrt import Mathlib.Analysis.Normed.Group.Basic import Mathlib.Analysis.SpecialFunctions.Pow.Real import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.MeasureTheory.Integral.Bochner -import Mathlib.Tactic.Positivity.Finset /-! # Tests for the `positivity` tactic diff --git a/MathlibTest/ring.lean b/MathlibTest/ring.lean index ffdfe755e4decb..8a0a07fea0178d 100644 --- a/MathlibTest/ring.lean +++ b/MathlibTest/ring.lean @@ -178,3 +178,28 @@ example {n : ℝ} (_hn : 0 ≤ n) : (n + 1 / 2) ^ 2 * (n + 1 + 1 / 3) ≤ (n + 1 ring_nf trace_state exact test_sorry + +section +abbrev myId (a : ℤ) : ℤ := a + +/- +Test that when `ring_nf` normalizes multiple expressions which contain a particular atom, it uses a +form for that atom which is consistent between expressions. + +We can't use `guard_hyp h :ₛ` here, as while it does tell apart `x` and `myId x`, it also complains +about differing instance paths. +-/ +/-- +info: x : ℤ +R : ℤ → ℤ → Prop +h : R (myId x * 2) (myId x * 2) +⊢ True +-/ +#guard_msgs (info) in +example (x : ℤ) (R : ℤ → ℤ → Prop) : True := by + have h : R (myId x + x) (x + myId x) := test_sorry + ring_nf at h + trace_state + trivial + +end diff --git a/MathlibTest/symm.lean b/MathlibTest/symm.lean index 7d88a908683622..ae72925a5b7a43 100644 --- a/MathlibTest/symm.lean +++ b/MathlibTest/symm.lean @@ -23,15 +23,6 @@ example (a b c : Nat) (ab : a = b) (bc : b = c) : c = a := by symm_saturate apply Eq.trans <;> assumption -def MulHom.inverse [Mul M] [Mul N] (f : M →ₙ* N) (g : N → M) (h₁ : Function.LeftInverse g f) - (h₂ : Function.RightInverse g f) : N →ₙ* M where - toFun := g - map_mul' x y := - calc - g (x * y) = g (f (g x) * f (g y)) := by rw [h₂ x, h₂ y] - _ = g (f (g x * g y)) := by rw [f.map_mul] - _ = g x * g y := h₁ _ - structure MulEquiv (M N : Type u) [Mul M] [Mul N] extends M ≃ N, M →ₙ* N /-- diff --git a/docs/100.yaml b/docs/100.yaml index 670ae3991e3303..550cf7682b3921 100644 --- a/docs/100.yaml +++ b/docs/100.yaml @@ -182,6 +182,8 @@ title : The Central Limit Theorem 48: title : Dirichlet’s Theorem + decl : Nat.setOf_prime_and_eq_mod_infinite + author : David Loeffler, Michael Stoll 49: title : The Cayley-Hamilton Theorem decl : Matrix.aeval_self_charpoly @@ -395,9 +397,14 @@ author : Manuel Candales 96: title : Principle of Inclusion/Exclusion + decls : + - Finset.inclusion_exclusion_sum_biUnion + - Finset.inclusion_exclusion_card_biUnion + - Finset.inclusion_exclusion_sum_inf_compl + - Finset.inclusion_exclusion_card_inf_compl links : github : https://github.com/NeilStrickland/lean_lib/blob/f88d162da2f990b87c4d34f5f46bbca2bbc5948e/src/combinatorics/matching.lean#L304 - author : Neil Strickland + author : Neil Strickland (outside mathlib), Yaël Dillies (in mathlib) 97: title : Cramer’s Rule decl : Matrix.mulVec_cramer diff --git a/docs/references.bib b/docs/references.bib index 5e88d180800659..0e5ce6b9bd0940 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -247,6 +247,21 @@ @Book{ beals2004 year = {2004} } +@Book{ Becker-Weispfenning1993, + address = {New York, NY}, + series = {Graduate Texts in Mathematics}, + title = {Gröbner Bases}, + volume = {141}, + isbn = {978-1-4612-6944-1}, + url = {http://link.springer.com/10.1007/978-1-4612-0913-3}, + doi = {10.1007/978-1-4612-0913-3}, + publisher = {Springer New York}, + author = {Becker, Thomas and Weispfenning, Volker}, + year = {1993}, + collection = {Graduate Texts in Mathematics}, + language = {en} +} + @Book{ behrends1979, author = {Ehrhard {Behrends}}, title = {{M-structure and the Banach-Stone theorem}}, @@ -305,6 +320,31 @@ @Article{ bernstein1912 number = {1–2} } +@Book{ Berthelot-1974, + author = {Berthelot, Pierre}, + year = {1974}, + series = {Lecture {{Notes}} in {{Mathematics}}}, + number = {407}, + publisher = {sv}, + keywords = {nosource}, + file = {/Users/chambert/Zotero/storage/WHF5R9LQ/Berthelot - 1974 - + Cohomologie cristalline des schémas de caractérist.djvu}, + title = {Cohomologie Cristalline Des Schémas de Caractéristique + {$p>0$}} +} + +@Book{ BerthelotOgus-1978, + title = {Notes on Crystalline Cohomology}, + author = {Berthelot, Pierre and Ogus, Arthur}, + year = {1978}, + series = {Math. {{Notes}}}, + number = {21}, + publisher = {pup}, + keywords = {nosource}, + file = {/Users/chambert/Zotero/storage/I3FNJEDB/Berthelot et Ogus + - 1978 - Notes on crystalline cohomology.djvu} +} + @InProceedings{ beylin1996, author = "Beylin, Ilya and Dybjer, Peter", editor = "Berardi, Stefano and Coppo, Mario", @@ -398,6 +438,19 @@ @Book{ bogachev2007 url = {https://doi.org/10.1007/978-3-540-34514-5} } +@Article{ bojanic74, + author = {Bojani\'c, Ranko}, + title = {A simple proof of {M}ahler's theorem on approximation of + continuous functions of a p-adic variable by polynomials}, + journal = {Journal of Number Theory}, + volume = {6}, + pages = {412-415}, + year = {1974}, + issn = {0022-314X}, + doi = {10.1016/0022-314X(74)90038-9}, + url = {https://doi.org/10.1016/0022-314X(74)90038-9} +} + @Book{ bollobas1986, author = {Bollob\'{a}s, B\'{e}la}, title = {Combinatorics: Set Systems, Hypergraphs, Families of @@ -1090,6 +1143,21 @@ @InProceedings{ deligne_formulaire mrreviewer = {Jacques Velu} } +@InProceedings{ demazure1970, + author = {Michel Demazure}, + editor = {M. Demazure, A. Grothendieck}, + title = {Expos\'{e} XXI, Don\'{e}es Radicielles}, + booktitle = {S\'{e}minaire de G\'{e}ométrie Alg\'{e}brique du Bois + Marie - 1962-64 - Sch\'{e}mas en groupes - (SGA 3) - vol. + 3, Structure des Sch\'{e}mas en Groupes Reductifs}, + series = {Lecture Notes in Mathematics}, + volume = {153}, + pages = {85--155}, + publisher = {Springer-Verlag}, + year = {1970}, + url = {https://wstein.org/sga/SGA3/Expo21-alpha.pdf} +} + @InProceedings{ demoura2015lean, author = {de Moura, Leonardo and Kong, Soonho and Avigad, Jeremy and van Doorn, Floris and von Raumer, Jakob}, @@ -2043,6 +2111,19 @@ @Book{ IrelandRosen1990 url = {https://doi.org/10.1007/978-1-4757-2103-4} } +@Article{ Isaacs1980, + author = {Isaacs, I. M.}, + title = {Roots of Polynomials in Algebraic Extensions of Fields}, + publisher = {Taylor \& Francis}, + year = {1980}, + pages = {543--544}, + journal = {The American Mathematical Monthly}, + volume = {87}, + number = {7}, + doi = {10.1080/00029890.1980.11995085}, + url = {https://doi.org/10.1080/00029890.1980.11995085} +} + @Book{ iversen, title = {Generic Local Structure of the Morphisms in Commutative Algebra}, @@ -2792,6 +2873,22 @@ @Article{ MR577178 url = {https://doi.org/10.1007/BF00417500} } +@Article{ Mulvey1986, + author = {Mulvey, Christopher J.}, + title = {\&}, + fjournal = {Supplemento ai Rendiconti del Circolo Matem{\`a}tico di + Palermo. Serie II}, + journal = {Suppl. Rend. Circ. Mat. Palermo (2)}, + issn = {1592-9531}, + volume = {12}, + pages = {99--104}, + year = {1986}, + language = {English}, + keywords = {46L60,46L05,81Q10}, + zbmath = {4030272}, + zbl = {0633.46065} +} + @Unpublished{ Naor-2015, author = {Assaf Naor}, title = {Metric Embeddings and Lipschitz Extensions}, @@ -3005,6 +3102,28 @@ @Misc{ RisingSea url = "https://math.stanford.edu/~vakil/216blog/" } +@Article{ Roby-1963, + title = {Lois polynomes et lois formelles en théorie des modules}, + author = {Roby, Norbert}, + year = {1963}, + journal = {Annales scientifiques de l'École Normale Supérieure}, + volume = {80}, + number = {3}, + pages = {213--348}, + doi = {10.24033/asens.1124}, + urldate = {2022-09-15}, + langid = {french} +} + +@Article{ Roby-1965, + title = {Les Algèbres à Puissances Divisées}, + author = {Roby, Norbert}, + year = {1965}, + journal = {Bulletin des Sciences Mathématiques. Deuxième Série}, + volume = {89}, + pages = {75--91} +} + @Article{ Rosenlicht_1972, author = {Rosenlicht, Maxwell}, title = {Integration in finite terms}, @@ -3422,6 +3541,15 @@ @Book{ verdier1996 mrnumber = {1453167} } +@Book{ Vickers1989, + author = {Vickers, Steven}, + title = {Topology via Logic}, + isbn = {0-521-57651-2}, + year = {1989}, + publisher = {University of Cambridge}, + language = {English} +} + @Misc{ vistoli2004, author = {Vistoli, Angelo}, title = {Notes on {Grothendieck} topologies, fibered categories and diff --git a/lake-manifest.json b/lake-manifest.json index 052044e77536dd..87f26956cfb52c 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,7 +5,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c0b56dfc7989168a9f936cd149db40cbdd2b4e77", + "rev": "8db191b5b58eb1c3c80edfd63b76ad78bdc13c92", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "finrange", @@ -65,7 +65,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "86d0d0584f5cd165353e2f8a30c455cd0e168ac2", + "rev": "d7caecce0d0f003fd5e9cce9a61f1dd6ba83142b", "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", "inputRev": "main", diff --git a/scripts/README.md b/scripts/README.md index 8f55ce30822bbf..3962da01936670 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -80,8 +80,7 @@ to learn about it as well! **Data files with linter exceptions** - `nolints.json` contains exceptions for all `env_linter`s in mathlib. For permanent and deliberate exceptions, add a `@[nolint lintername]` in the .lean file instead. -- `no_lints_prime_decls.txt` - contains temporary exceptions for the `docPrime` linter +- `nolints_prime_decls.txt` contains temporary exceptions for the `docPrime` linter Both of these files should tend to zero over time; please do not add new entries to these files. PRs removing (the need for) entries are welcome. @@ -94,9 +93,12 @@ please do not add new entries to these files. PRs removing (the need for) entrie to the appropriate topic on zulip. - `count-trans-deps.py`, `import-graph-report.py` and `import_trans_difference.sh` produce various summaries of changes in transitive imports that the `PR_summary` message incorporates. -- `zulip_emoji_merge_delegate.py` is called every hour by a Github action cronjob. - It looks through the latest 200 zulip posts: if a message mentions a PR that is delegated, or sent to bors, or merged, - then this script will post an emoji reaction `:peace_sign:`, or `:bors:`, or `:merge:` respectively to the message. +- `zulip_emoji_merge_delegate.py` is called + * every time a `bors d`, `bors merge` or `bors r+` comment is added to a PR and + * on every push to `master`. + It looks through all zulip posts containing a reference to the relevant PR + (delegated, or sent to bors, or merged) and it will post an emoji reaction + `:peace_sign:`, or `:bors:`, or `:merge:` respectively to the message. - `late_importers.sh` is the main script used by the `latest_import.yml` action: it formats the `linter.minImports` output, summarizing the data in a table. See the module docs of `late_importers.sh` for further details. diff --git a/scripts/bench_summary.lean b/scripts/bench_summary.lean index 9c9407ea066f44..17f0467b2ef972 100644 --- a/scripts/bench_summary.lean +++ b/scripts/bench_summary.lean @@ -147,6 +147,7 @@ open Lean Elab Command in as a comment to a pull request. It takes as input * the number `PR` and the name `repo` as a `String` containing the relevant pull-request (it reads and posts comments there) +* the optional `jobID` string for reporting the action that produced the output * the `String` `tempFile` of a temporary file where the command stores transient information. The code itself interfaces with the shell to retrieve and process json data and eventually @@ -162,9 +163,10 @@ Here is a summary of the steps: * process the final string to produce a summary (using `benchOutput`), * finally post the resulting output to the PR (using `gh pr comment ...`). -/ -def addBenchSummaryComment (PR : Nat) (repo : String) +def addBenchSummaryComment (PR : Nat) (repo : String) (jobID : String := "") (author : String := "leanprover-bot") (tempFile : String := "benchOutput.json") : CommandElabM Unit := do + let job_msg := s!"\n[CI run](https://github.com/{repo}/actions/runs/{jobID})" let PR := s!"{PR}" let jq := s!".comments | last | select(.author.login==\"{author}\") | .body" @@ -197,10 +199,10 @@ def addBenchSummaryComment (PR : Nat) (repo : String) IO.FS.writeFile (tempFile ++ ".src") bench -- Extract all instruction changes whose magnitude is larger than `threshold`. - let threshold := s!"{10 ^ 9}" + let threshold := 10 ^ 9 let jq1 : IO.Process.SpawnArgs := { cmd := "jq" - args := #["-r", "--arg", "thr", threshold, + args := #["-r", "--arg", "thr", s!"{threshold}", ".differences | .[] | ($thr|tonumber) as $th | select(.dimension.metric == \"instructions\" and ((.diff >= $th) or (.diff <= -$th)))", (tempFile ++ ".src")] } @@ -220,6 +222,12 @@ def addBenchSummaryComment (PR : Nat) (repo : String) jq -c '[\{file: .dimension.benchmark, diff: .diff, reldiff: .reldiff}]' {tempFile} > \ {tempFile}.2" let secondFilter ← IO.Process.run jq2 + if secondFilter == "" then + let _ ← IO.Process.run + { cmd := "gh", args := #["pr", "comment", PR, "--repo", repo, "--body", + s!"No benchmark entry differed by at least {formatDiff threshold} instructions." ++ + job_msg] } + else IO.FS.writeFile tempFile secondFilter let jq3 : IO.Process.SpawnArgs := { cmd := "jq", args := #["-n", "reduce inputs as $in (null; . + $in)", tempFile] } @@ -230,7 +238,7 @@ def addBenchSummaryComment (PR : Nat) (repo : String) IO.println report -- Post the computed summary as a github comment. let add_comment : IO.Process.SpawnArgs := - { cmd := "gh", args := #["pr", "comment", PR, "--repo", repo, "--body", report] } + { cmd := "gh", args := #["pr", "comment", PR, "--repo", repo, "--body", report ++ job_msg] } let _ ← IO.Process.run add_comment end BenchAction diff --git a/scripts/create-adaptation-pr.sh b/scripts/create-adaptation-pr.sh index b8ae7cf37b28fb..f8b5deb203b7e5 100755 --- a/scripts/create-adaptation-pr.sh +++ b/scripts/create-adaptation-pr.sh @@ -198,7 +198,7 @@ if git diff --name-only bump/$BUMPVERSION bump/nightly-$NIGHTLYDATE | grep -q .; echo "### [auto] post a link to the PR on Zulip" zulip_title="#$pr_number adaptations for nightly-$NIGHTLYDATE" - zulip_body="> $pr_title #$pr_number\\\n\\\nPlease review this PR. At the end of the month this diff will land in \\\`master\\\`." + zulip_body="> $pr_title #$pr_number"$'\n\nPlease review this PR. At the end of the month this diff will land in `master`.' echo "Posting the link to the PR in a new thread on the #nightly-testing channel on Zulip" echo "Here is the message:" diff --git a/scripts/import_trans_difference.sh b/scripts/import_trans_difference.sh index 9c103e3eabdaef..a13bebc4957cff 100755 --- a/scripts/import_trans_difference.sh +++ b/scripts/import_trans_difference.sh @@ -67,7 +67,16 @@ 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, -v all="${all}" -v ghLimit='261752' '{ diff[$1]+=$2 } END { + (awk -F, -v all="${all}" -v ghLimit='261752' -v newFiles="$( + # we pass the "A"dded files with respect to master, converting them to module names + git diff --name-only --diff-filter=A master | tr '\n' , | sed 's=\.lean,=,=g; s=/=.=g' + )" ' + BEGIN{ + # `arrayNewModules` maps integers to module names + split(newFiles, arrayNewModules, ",") + # `newModules` "just" stores the module names + for(v in arrayNewModules) { newModules[arrayNewModules[v]]=0 } + } { diff[$1]+=$2 } END { fileCount=0 outputLength=0 for(fil in diff) { @@ -75,7 +84,8 @@ printf '\n\n
Import changes for all files\n\n%s\n\n&2 echo "EVENT_NAME: '${EVENT_NAME}'" >&2 printf 'COMMENT\n%s\nEND COMMENT\n' "${PR_COMMENT}" -printf '%s requested a maintainer **%s** from %s on PR [#%s](%s):\n' "${AUTHOR}" "${M_or_D}" "${SOURCE}" "${PR}" "${URL}" -printf '```spoiler %s\n%s\n```\n' "${PR_TITLE}" "${PR_COMMENT}" +printf '%s requested a maintainer **%s** from %s on PR [#%s](%s):\n' "${AUTHOR}" "${M_or_D/$'?'/}" "${SOURCE}" "${PR}" "${URL}" +# if `maintainer merge/delegate` is followed by `?`, then print a `spoiler` with the full comment +if [ ${M_or_D: -1} == $'?' ] +then + # replace backticks in the title with single quotes + unbacktickedTitle="${PR_TITLE//\`/\'}" + + >&2 echo "neat title: '${unbacktickedTitle}'" + + printf '```spoiler %s\n%s\n```\n' "${unbacktickedTitle}" "${PR_COMMENT}" +# otherwise, just print the title of the PR +else + printf '> %s\n' "${PR_TITLE}" +fi diff --git a/scripts/nolints.json b/scripts/nolints.json index a64eacb27c056c..a698a174e13549 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -575,20 +575,7 @@ ["docBlame", "CategoryTheory.Limits.MultispanIndex.right"], ["docBlame", "CategoryTheory.Limits.MultispanIndex.snd"], ["docBlame", "CategoryTheory.Limits.MultispanIndex.sndFrom"], - ["docBlame", "CategoryTheory.Limits.PreservesColimit.preserves"], - ["docBlame", "CategoryTheory.Limits.PreservesLimit.preserves"], - ["docBlame", "CategoryTheory.Limits.ReflectsColimit.reflects"], - ["docBlame", "CategoryTheory.Limits.ReflectsColimitsOfShape.reflectsColimit"], - ["docBlame", - "CategoryTheory.Limits.ReflectsColimitsOfSize.reflectsColimitsOfShape"], - ["docBlame", "CategoryTheory.Limits.ReflectsLimit.reflects"], - ["docBlame", "CategoryTheory.Limits.ReflectsLimitsOfShape.reflectsLimit"], - ["docBlame", - "CategoryTheory.Limits.ReflectsLimitsOfSize.reflectsLimitsOfShape"], ["docBlame", "CategoryTheory.Monad.CreatesColimitOfIsSplitPair.out"], - ["docBlame", "CategoryTheory.Monad.PreservesColimitOfIsReflexivePair.out"], - ["docBlame", "CategoryTheory.Monad.PreservesColimitOfIsSplitPair.out"], - ["docBlame", "CategoryTheory.Monad.ReflectsColimitOfIsSplitPair.out"], ["docBlame", "CategoryTheory.Pretriangulated.Triangle.homMk"], ["docBlame", "CategoryTheory.Pretriangulated.Triangle.isoMk"], ["docBlame", "CategoryTheory.Triangulated.Octahedron.m₁"], diff --git a/scripts/no_lints_prime_decls.txt b/scripts/nolints_prime_decls.txt similarity index 99% rename from scripts/no_lints_prime_decls.txt rename to scripts/nolints_prime_decls.txt index f00efff46d47e5..414151f3446211 100644 --- a/scripts/no_lints_prime_decls.txt +++ b/scripts/nolints_prime_decls.txt @@ -686,11 +686,11 @@ 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' +iSupIndep.comp' +iSupIndep_def' +iSupIndep_def'' +iSupIndep_of_dfinsupp_sumAddHom_injective' +iSupIndep.supIndep' CompleteLattice.inf_continuous' CompleteLattice.sSup_continuous' CompletelyDistribLattice.MinimalAxioms.iInf_iSup_eq' @@ -1097,6 +1097,7 @@ div_le_iff_le_mul' div_le_iff_of_neg' div_le_one' div_lt_div' +div_lt_div₀' div_lt_div'' div_lt_div_iff' div_lt_div_left' @@ -2232,7 +2233,7 @@ LieIdeal.map_sup_ker_eq_map' LieModule.chainTop_isNonZero' LieModule.coe_chainTop' LieModule.genWeightSpaceChain_def' -LieModule.independent_genWeightSpace' +LieModule.iSupIndep_genWeightSpace' LieModule.instIsTrivialOfSubsingleton' LieModule.isNilpotent_of_top_iff' LieModule.iSup_genWeightSpace_eq_top' @@ -3314,7 +3315,6 @@ 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' @@ -3455,6 +3455,7 @@ 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_eq_zero''' norm_inv' @@ -3462,6 +3463,7 @@ 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_le_zero_iff''' norm_lt_of_mem_ball' @@ -3469,7 +3471,8 @@ norm_ne_zero_iff' norm_nonneg' norm_of_subsingleton' norm_one' -norm_pos_iff'' +norm_pos_iff' +norm_pos_iff' norm_pos_iff''' norm_sub_norm_le' norm_toNNReal' diff --git a/scripts/noshake.json b/scripts/noshake.json index 23b0f103e1de8e..4a06c0c7680d4b 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -323,8 +323,7 @@ ["Mathlib.Algebra.MvPolynomial.CommRing", "Mathlib.Algebra.Polynomial.Basic"], "Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs": ["Mathlib.Tactic.Algebraize"], - "Mathlib.RingTheory.Finiteness.Defs": - ["Mathlib.Tactic.Algebraize"], + "Mathlib.RingTheory.Finiteness.Defs": ["Mathlib.Tactic.Algebraize"], "Mathlib.RingTheory.Binomial": ["Mathlib.Algebra.Order.Floor"], "Mathlib.RingTheory.Adjoin.Basic": ["Mathlib.LinearAlgebra.Finsupp.SumProd"], "Mathlib.RepresentationTheory.FdRep": @@ -341,6 +340,7 @@ "Mathlib.Order.BoundedOrder": ["Mathlib.Tactic.Finiteness.Attr"], "Mathlib.Order.Basic": ["Batteries.Tactic.Classical", "Mathlib.Tactic.GCongr.Core"], + "Mathlib.NumberTheory.Harmonic.Defs": ["Mathlib.Algebra.Order.Field.Basic"], "Mathlib.NumberTheory.Cyclotomic.Basic": ["Mathlib.Init.Core"], "Mathlib.NumberTheory.ArithmeticFunction": ["Mathlib.Tactic.ArithMult"], "Mathlib.MeasureTheory.MeasurableSpace.Defs": ["Mathlib.Tactic.FunProp.Attr"], @@ -364,8 +364,8 @@ "Mathlib.Util.Superscript"], "Mathlib.Deprecated.NatLemmas": ["Batteries.Data.Nat.Lemmas", "Batteries.WF"], "Mathlib.Deprecated.MinMax": ["Mathlib.Order.MinMax"], + "Mathlib.Deprecated.LazyList": ["Mathlib.Lean.Thunk"], "Mathlib.Deprecated.ByteArray": ["Batteries.Data.ByteSubarray"], - "Mathlib.Data.ENat.Lattice": ["Mathlib.Algebra.Group.Action.Defs"], "Mathlib.Data.Vector.Basic": ["Mathlib.Control.Applicative"], "Mathlib.Data.Set.Image": ["Batteries.Tactic.Congr", "Mathlib.Data.Set.SymmDiff"], @@ -385,14 +385,19 @@ ["Mathlib.Control.Basic", "Mathlib.Data.Option.Basic"], "Mathlib.Data.LazyList.Basic": ["Mathlib.Lean.Thunk"], "Mathlib.Data.Int.Defs": ["Batteries.Data.Int.Order"], + "Mathlib.Data.Int.ConditionallyCompleteOrder": + ["Mathlib.Order.ConditionallyCompleteLattice.Basic"], "Mathlib.Data.FunLike.Basic": ["Mathlib.Logic.Function.Basic"], "Mathlib.Data.Finset.Insert": ["Mathlib.Data.Finset.Attr"], + "Mathlib.Data.ENat.Lattice": ["Mathlib.Algebra.Group.Action.Defs"], "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.Lean.Except", "Batteries.Tactic.Congr"], "Mathlib.Control.Basic": ["Mathlib.Logic.Function.Defs"], + "Mathlib.Combinatorics.SimpleGraph.Density": + ["Mathlib.Algebra.Order.Field.Basic"], "Mathlib.Combinatorics.SetFamily.AhlswedeZhang": ["Mathlib.Algebra.Order.Field.Basic"], "Mathlib.CategoryTheory.Sites.IsSheafFor": @@ -426,6 +431,7 @@ ["Mathlib.AlgebraicTopology.AlternatingFaceMapComplex"], "Mathlib.Algebra.Star.Module": ["Mathlib.Algebra.Module.LinearMap.Star"], "Mathlib.Algebra.Ring.CentroidHom": ["Mathlib.Algebra.Algebra.Defs"], + "Mathlib.Algebra.Order.Quantale": ["Mathlib.Tactic.Variable"], "Mathlib.Algebra.Order.CauSeq.Basic": ["Mathlib.Data.Setoid.Basic"], "Mathlib.Algebra.MonoidAlgebra.Basic": ["Mathlib.LinearAlgebra.Finsupp.SumProd"], diff --git a/scripts/technical-debt-metrics.sh b/scripts/technical-debt-metrics.sh index eb24ded1ce153f..b3f3df14ec9aa0 100755 --- a/scripts/technical-debt-metrics.sh +++ b/scripts/technical-debt-metrics.sh @@ -113,7 +113,7 @@ printf '%s|%s\n' "$(grep -c 'docBlame' scripts/nolints.json)" "documentation nol printf '%s|%s\n' "$(git grep '^set_option linter.style.longFile [0-9]*' Mathlib | wc -l)" "large files" printf '%s|%s\n' "$(git grep "^open .*Classical" | grep -v " in$" -c)" "bare open (scoped) Classical" -printf '%s|%s\n' "$(wc -l < scripts/no_lints_prime_decls.txt)" "exceptions for the docPrime linter" +printf '%s|%s\n' "$(wc -l < scripts/nolints_prime_decls.txt)" "exceptions for the docPrime linter" deprecatedFiles="$(git ls-files '**/Deprecated/*.lean' | xargs wc -l | sed 's=^ *==')" diff --git a/scripts/zulip_emoji_merge_delegate.py b/scripts/zulip_emoji_merge_delegate.py index d715df3bfbf9ae..b279fbc6e1e114 100644 --- a/scripts/zulip_emoji_merge_delegate.py +++ b/scripts/zulip_emoji_merge_delegate.py @@ -1,17 +1,20 @@ #!/usr/bin/env python3 import sys import zulip -import requests import re # Usage: -# python scripts/zulip_emoji_merge_delegate.py $ZULIP_API_KEY $ZULIP_EMAIL $ZULIP_SITE $GITHUB_TOKEN +# python scripts/zulip_emoji_merge_delegate.py $ZULIP_API_KEY $ZULIP_EMAIL $ZULIP_SITE $LABEL $PR_NUMBER # See .github/workflows/zulip_emoji_merge_delegate.yaml for the meaning of these variables ZULIP_API_KEY = sys.argv[1] ZULIP_EMAIL = sys.argv[2] ZULIP_SITE = sys.argv[3] -GITHUB_TOKEN = sys.argv[4] +LABEL = sys.argv[4] +PR_NUMBER = sys.argv[5] + +print(f"LABEL: '{LABEL}'") +print(f"PR_NUMBER: '{PR_NUMBER}'") # Initialize Zulip client client = zulip.Client( @@ -22,58 +25,74 @@ # Fetch the last 200 messages response = client.get_messages({ - "anchor": "newest", - "num_before": 200, - "num_after": 0, - "narrow": [{"operator": "channel", "operand": "PR reviews"}], + "operator": "search", + "operand": f"https://github\.com/leanprover-community/mathlib4/pull/{PR_NUMBER}", }) messages = response['messages'] -pr_pattern = re.compile(r'https://github\.com/leanprover-community/mathlib4/pull/(\d+)') for message in messages: content = message['content'] - match = pr_pattern.search(content) - if match: - pr_number = match.group(1) - # Check for emoji reactions - reactions = message['reactions'] - has_peace_sign = any(reaction['emoji_name'] == 'peace_sign' for reaction in reactions) - has_bors = any(reaction['emoji_name'] == 'bors' for reaction in reactions) - has_merge = any(reaction['emoji_name'] == 'merge' for reaction in reactions) + print(f"matched: '{message}'") + # Check for emoji reactions + reactions = message['reactions'] + has_peace_sign = any(reaction['emoji_name'] == 'peace_sign' for reaction in reactions) + has_bors = any(reaction['emoji_name'] == 'bors' for reaction in reactions) + has_merge = any(reaction['emoji_name'] == 'merge' for reaction in reactions) + + pr_url = f"https://api.github.com/repos/leanprover-community/mathlib4/pulls/{PR_NUMBER}" + + print('Removing peace_sign') + result = client.remove_reaction({ + "message_id": message['id'], + "emoji_name": "peace_sign" + }) + print(f"result: '{result}'") + print('Removing bors') + result = client.remove_reaction({ + "message_id": message['id'], + "emoji_name": "bors" + }) + print(f"result: '{result}'") + + print('Removing merge') + result = client.remove_reaction({ + "message_id": message['id'], + "emoji_name": "merge" + }) + print(f"result: '{result}'") - pr_url = f"https://api.github.com/repos/leanprover-community/mathlib4/pulls/{pr_number}" - pr_response = requests.get(pr_url, headers={"Authorization": GITHUB_TOKEN}) - pr_data = pr_response.json() - labels = [label['name'] for label in pr_data['labels']] + if 'delegated' == LABEL: + print('adding delegated') - if 'delegated' in labels: - client.add_reaction({ + client.add_reaction({ + "message_id": message['id'], + "emoji_name": "peace_sign" + }) + elif 'ready-to-merge' == LABEL: + print('adding ready-to-merge') + if has_peace_sign: + client.remove_reaction({ "message_id": message['id'], "emoji_name": "peace_sign" }) - elif 'ready-to-merge' in labels: - if has_peace_sign: - client.remove_reaction({ - "message_id": message['id'], - "emoji_name": "peace_sign" - }) - client.add_reaction({ + client.add_reaction({ + "message_id": message['id'], + "emoji_name": "bors" + }) + elif LABEL.startswith("[Merged by Bors]"): + print('adding [Merged by Bors]') + if has_peace_sign: + client.remove_reaction({ "message_id": message['id'], - "emoji_name": "bors" + "emoji_name": "peace_sign" }) - elif pr_data['title'].startswith("[Merged by Bors]"): - if has_peace_sign: - client.remove_reaction({ - "message_id": message['id'], - "emoji_name": "peace_sign" - }) - if has_bors: - client.remove_reaction({ - "message_id": message['id'], - "emoji_name": "bors" - }) - client.add_reaction({ + if has_bors: + client.remove_reaction({ "message_id": message['id'], - "emoji_name": "merge" + "emoji_name": "bors" }) + client.add_reaction({ + "message_id": message['id'], + "emoji_name": "merge" + })