mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-27 15:24:17 +00:00
Compare commits
5 Commits
fix-pr-rel
...
sofia/asyn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a6a5a6faf | ||
|
|
60641faa10 | ||
|
|
bfb060641f | ||
|
|
6a27cb38aa | ||
|
|
2a4ca6f5d0 |
@@ -46,21 +46,6 @@ This PR adds a `num?` parameter to `mkPatternFromTheorem` to control how many
|
||||
leading quantifiers are stripped when creating a pattern.
|
||||
```
|
||||
|
||||
**Changelog labels:** Add one `changelog-*` label to categorize the PR for release notes:
|
||||
- `changelog-language` - Language features and metaprograms
|
||||
- `changelog-tactics` - User facing tactics
|
||||
- `changelog-server` - Language server, widgets, and IDE extensions
|
||||
- `changelog-pp` - Pretty printing
|
||||
- `changelog-library` - Library
|
||||
- `changelog-compiler` - Compiler, runtime, and FFI
|
||||
- `changelog-lake` - Lake
|
||||
- `changelog-doc` - Documentation
|
||||
- `changelog-ffi` - FFI changes
|
||||
- `changelog-other` - Other changes
|
||||
- `changelog-no` - Do not include this PR in the release changelog
|
||||
|
||||
If you're unsure which label applies, it's fine to omit the label and let reviewers add it.
|
||||
|
||||
## CI Log Retrieval
|
||||
|
||||
When CI jobs fail, investigate immediately - don't wait for other jobs to complete. Individual job logs are often available even while other jobs are still running. Try `gh run view <run-id> --log` or `gh run view <run-id> --log-failed`, or use `gh run view <run-id> --job=<job-id>` to target the specific failed job. Sleeping is fine when asked to monitor CI and no failures exist yet, but once any job fails, investigate that failure immediately.
|
||||
|
||||
@@ -13,54 +13,12 @@ These comments explain the scripts' behavior, which repositories get special han
|
||||
## Arguments
|
||||
- `version`: The version to release (e.g., v4.24.0)
|
||||
|
||||
## Release Notes (Required for -rc1 releases)
|
||||
|
||||
For first release candidates (`-rc1`), you must create release notes BEFORE the reference-manual toolchain bump PR can be merged.
|
||||
|
||||
**Steps to create release notes:**
|
||||
|
||||
1. Generate the release notes:
|
||||
```bash
|
||||
cd /path/to/lean4
|
||||
python3 script/release_notes.py --since <previous_version> > /tmp/release-notes-<version>.md
|
||||
```
|
||||
Replace `<previous_version>` with the last stable release (e.g., `v4.27.0` when releasing `v4.28.0-rc1`).
|
||||
|
||||
2. Review `/tmp/release-notes-<version>.md` for common issues:
|
||||
- **Unterminated code blocks**: Look for code fences that aren't closed. Fetch original PR with `gh pr view <number>` to repair.
|
||||
- **Truncated descriptions**: Some may end mid-sentence. Complete them from the original PR.
|
||||
- **Markdown issues**: Other syntax problems that could cause parsing errors.
|
||||
|
||||
3. Create the release notes file in the reference-manual repository:
|
||||
- File path: `Manual/Releases/v<version>.lean` (e.g., `v4_28_0.lean`)
|
||||
- Use Verso format with proper imports and `#doc (Manual)` block
|
||||
- **Use `#` for headers, not `##`** (Verso uses level 1 for subsections)
|
||||
- **Use plain ` ``` ` not ` ```lean `** (the latter executes code)
|
||||
- **Wrap underscore identifiers in backticks**: `` `bv_decide` `` not `bv_decide`
|
||||
|
||||
4. Update `Manual/Releases.lean`:
|
||||
- Add import: `import Manual.Releases.«v4_28_0»`
|
||||
- Add include: `{include 0 Manual.Releases.«v4_28_0»}`
|
||||
|
||||
5. Build to verify: `lake build Manual.Releases.v4_28_0`
|
||||
|
||||
6. Create a **separate PR** for release notes (not bundled with toolchain bump):
|
||||
```bash
|
||||
git checkout -b v<version>-release-notes
|
||||
gh pr create --title "doc: add v<version> release notes"
|
||||
```
|
||||
|
||||
For subsequent RCs (`-rc2`, etc.) and stable releases, just update the version number in the existing release notes file title.
|
||||
|
||||
See `doc/dev/release_checklist.md` section "Writing the release notes" for full details.
|
||||
|
||||
## Process
|
||||
|
||||
1. Run `script/release_checklist.py {version}` to check the current status
|
||||
2. **CRITICAL: If preliminary lean4 checks fail, STOP immediately and alert the user**
|
||||
- Check for: release branch exists, CMake version correct, tag exists, release page exists, release notes file exists
|
||||
- Check for: release branch exists, CMake version correct, tag exists, release page exists, release notes exist
|
||||
- **IMPORTANT**: The release page is created AUTOMATICALLY by CI after pushing the tag - DO NOT create it manually
|
||||
- **IMPORTANT**: For -rc1 releases, release notes must be created before proceeding
|
||||
- Do NOT create any PRs or proceed with repository updates if these checks fail
|
||||
3. Create a todo list tracking all repositories that need updates
|
||||
4. **CRITICAL RULE: You can ONLY run `release_steps.py` for a repository if `release_checklist.py` explicitly says to do so**
|
||||
@@ -103,15 +61,6 @@ Every time you run `release_checklist.py`, you MUST:
|
||||
This summary should be provided EVERY time you run the checklist, not just after creating new PRs.
|
||||
The user needs to see the complete picture of what's waiting for review.
|
||||
|
||||
## Nightly Infrastructure
|
||||
|
||||
The nightly build system uses branches and tags across two repositories:
|
||||
|
||||
- `leanprover/lean4` has **branches** `nightly` and `nightly-with-mathlib` tracking the latest nightly builds
|
||||
- `leanprover/lean4-nightly` has **dated tags** like `nightly-2026-01-23`
|
||||
|
||||
When a nightly succeeds with mathlib, all three should point to the same commit. Don't confuse these: branches are in the main lean4 repo, dated tags are in lean4-nightly.
|
||||
|
||||
## Error Handling
|
||||
|
||||
**CRITICAL**: If something goes wrong or a command fails:
|
||||
|
||||
4
.github/workflows/build-template.yml
vendored
4
.github/workflows/build-template.yml
vendored
@@ -102,7 +102,7 @@ jobs:
|
||||
if: matrix.cmultilib
|
||||
- name: Restore Cache
|
||||
id: restore-cache
|
||||
uses: actions/cache/restore@v5
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `save` below and with `restore-cache` in `update-stage0.yml`
|
||||
path: |
|
||||
@@ -175,7 +175,7 @@ jobs:
|
||||
# Caching on cancellation created some mysterious issues perhaps related to improper build
|
||||
# shutdown
|
||||
if: steps.restore-cache.outputs.cache-hit != 'true' && !cancelled()
|
||||
uses: actions/cache/save@v5
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
path: |
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -115,7 +115,7 @@ jobs:
|
||||
CMAKE_MAJOR=$(grep -E "^set\(LEAN_VERSION_MAJOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_MINOR=$(grep -E "^set\(LEAN_VERSION_MINOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_PATCH=$(grep -E "^set\(LEAN_VERSION_PATCH " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_IS_RELEASE=$(grep -m 1 -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | sed -nE 's/^set\(LEAN_VERSION_IS_RELEASE ([0-9]+)\).*/\1/p')
|
||||
CMAKE_IS_RELEASE=$(grep -m 1 -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
|
||||
# Expected values from tag parsing
|
||||
TAG_MAJOR="${{ steps.set-release.outputs.LEAN_VERSION_MAJOR }}"
|
||||
@@ -433,7 +433,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
@@ -465,7 +465,7 @@ jobs:
|
||||
# Doesn't seem to be working when additionally fetching from lean4-nightly
|
||||
#filter: tree:0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
|
||||
83
.github/workflows/pr-release.yml
vendored
83
.github/workflows/pr-release.yml
vendored
@@ -20,9 +20,7 @@ on:
|
||||
jobs:
|
||||
on-success:
|
||||
runs-on: ubuntu-latest
|
||||
# Run even if CI fails, as long as build artifacts are available
|
||||
# The "Verify release artifacts exist" step will fail if necessary artifacts are missing
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.repository == 'leanprover/lean4'
|
||||
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' && github.repository == 'leanprover/lean4'
|
||||
steps:
|
||||
- name: Retrieve information about the original workflow
|
||||
uses: potiuk/get-workflow-origin@v1_1 # https://github.com/marketplace/actions/get-workflow-origin
|
||||
@@ -43,19 +41,6 @@ jobs:
|
||||
name: build-.*
|
||||
name_is_regexp: true
|
||||
|
||||
# Verify artifacts were downloaded before any side effects (tag creation, release deletion).
|
||||
- name: Verify release artifacts exist
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
files=(artifacts/*/*)
|
||||
if [ ${#files[@]} -eq 0 ]; then
|
||||
echo "::error::No artifacts found matching artifacts/*/*"
|
||||
exit 1
|
||||
fi
|
||||
echo "Found ${#files[@]} artifacts to upload:"
|
||||
printf '%s\n' "${files[@]}"
|
||||
|
||||
- name: Push tag
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
@@ -77,44 +62,42 @@ jobs:
|
||||
git -C lean4.git remote add pr-releases https://foo:'${{ secrets.PR_RELEASES_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-pr-releases.git
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-"${SHORT_SHA}"
|
||||
- name: Delete existing releases if present
|
||||
- name: Delete existing release if present
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
# Delete any existing releases for this PR.
|
||||
# The short format release is always recreated with the latest commit.
|
||||
# The SHA-suffixed release should be unique per commit, but delete just in case.
|
||||
# Try to delete any existing release for the current PR (just the version without the SHA suffix).
|
||||
gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} -y || true
|
||||
gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }} -y || true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
# We use `gh release create` instead of `softprops/action-gh-release` because
|
||||
# the latter enumerates all releases to check for existing ones, which fails
|
||||
# when the repository has more than 10000 releases (GitHub API pagination limit).
|
||||
# Upstream fix: https://github.com/softprops/action-gh-release/pull/725
|
||||
- name: Release (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
# There are coredump files in deeper subdirectories; artifacts/*/* gets the release archives.
|
||||
gh release create \
|
||||
--repo ${{ github.repository_owner }}/lean4-pr-releases \
|
||||
--title "Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}" \
|
||||
--notes "" \
|
||||
pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} \
|
||||
artifacts/*/*
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
draft: false
|
||||
tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
repository: ${{ github.repository_owner }}/lean4-pr-releases
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
gh release create \
|
||||
--repo ${{ github.repository_owner }}/lean4-pr-releases \
|
||||
--title "Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})" \
|
||||
--notes "" \
|
||||
pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }} \
|
||||
artifacts/*/*
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
draft: false
|
||||
tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}
|
||||
repository: ${{ github.repository_owner }}/lean4-pr-releases
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Report release status (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
@@ -396,18 +379,6 @@ jobs:
|
||||
# We next automatically create a Batteries branch using this toolchain.
|
||||
# Batteries doesn't itself have a mechanism to report results of CI from this branch back to Lean
|
||||
# Instead this is taken care of by Mathlib CI, which will fail if Batteries fails.
|
||||
|
||||
# Generate a token from the mathlib-nightly-testing GitHub App for cross-org access
|
||||
- name: Generate GitHub App token for leanprover-community repos
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
id: mathlib-app-token
|
||||
uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2
|
||||
with:
|
||||
app-id: ${{ secrets.MATHLIB_NIGHTLY_TESTING_APP_ID }}
|
||||
private-key: ${{ secrets.MATHLIB_NIGHTLY_TESTING_PRIVATE_KEY }}
|
||||
owner: leanprover-community
|
||||
repositories: batteries,mathlib4-nightly-testing
|
||||
|
||||
- name: Cleanup workspace
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
run: |
|
||||
@@ -419,7 +390,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ steps.mathlib-app-token.outputs.token }}
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
filter: tree:0
|
||||
@@ -479,7 +450,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
token: ${{ steps.mathlib-app-token.outputs.token }}
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
filter: tree:0
|
||||
|
||||
2
.github/workflows/update-stage0.yml
vendored
2
.github/workflows/update-stage0.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- name: Restore Cache
|
||||
if: env.should_update_stage0 == 'yes'
|
||||
uses: actions/cache/restore@v5
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
# NOTE: must be in sync with `restore-cache` in `build-template.yml`
|
||||
path: |
|
||||
|
||||
104
CMakeLists.txt
104
CMakeLists.txt
@@ -10,22 +10,22 @@ option(USE_MIMALLOC "use mimalloc" ON)
|
||||
get_cmake_property(vars CACHE_VARIABLES)
|
||||
foreach(var ${vars})
|
||||
get_property(currentHelpString CACHE "${var}" PROPERTY HELPSTRING)
|
||||
if(var MATCHES "STAGE0_(.*)")
|
||||
if("${var}" MATCHES "STAGE0_(.*)")
|
||||
list(APPEND STAGE0_ARGS "-D${CMAKE_MATCH_1}=${${var}}")
|
||||
elseif(var MATCHES "STAGE1_(.*)")
|
||||
elseif("${var}" MATCHES "STAGE1_(.*)")
|
||||
list(APPEND STAGE1_ARGS "-D${CMAKE_MATCH_1}=${${var}}")
|
||||
elseif(currentHelpString MATCHES "No help, variable specified on the command line." OR currentHelpString STREQUAL "")
|
||||
elseif("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
|
||||
list(APPEND CL_ARGS "-D${var}=${${var}}")
|
||||
if(var MATCHES "USE_GMP|CHECK_OLEAN_VERSION|LEAN_VERSION_.*|LEAN_SPECIAL_VERSION_DESC")
|
||||
if("${var}" MATCHES "USE_GMP|CHECK_OLEAN_VERSION|LEAN_VERSION_.*|LEAN_SPECIAL_VERSION_DESC")
|
||||
# must forward options that generate incompatible .olean format
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
elseif(var MATCHES "LLVM*|PKG_CONFIG|USE_LAKE|USE_MIMALLOC")
|
||||
elseif("${var}" MATCHES "LLVM*|PKG_CONFIG|USE_LAKE|USE_MIMALLOC")
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
elseif(var MATCHES "USE_MIMALLOC")
|
||||
elseif("${var}" MATCHES "USE_MIMALLOC")
|
||||
list(APPEND CL_ARGS "-D${var}=${${var}}")
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
elseif((var MATCHES "CMAKE_.*") AND NOT (var MATCHES "CMAKE_BUILD_TYPE") AND NOT (var MATCHES "CMAKE_HOME_DIRECTORY"))
|
||||
elseif(("${var}" MATCHES "CMAKE_.*") AND NOT ("${var}" MATCHES "CMAKE_BUILD_TYPE") AND NOT ("${var}" MATCHES "CMAKE_HOME_DIRECTORY"))
|
||||
list(APPEND PLATFORM_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -34,15 +34,15 @@ include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
|
||||
if(NOT (DEFINED STAGE0_CMAKE_EXECUTABLE_SUFFIX))
|
||||
set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
endif()
|
||||
|
||||
# Don't do anything with cadical on wasm
|
||||
if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
find_program(CADICAL cadical)
|
||||
if(NOT CADICAL)
|
||||
set(CADICAL_CXX c++)
|
||||
if(CADICAL_USE_CUSTOM_CXX)
|
||||
if (CADICAL_USE_CUSTOM_CXX)
|
||||
set(CADICAL_CXX ${CMAKE_CXX_COMPILER})
|
||||
# Use same platform flags as for Lean executables, in particular from `prepare-llvm-linux.sh`,
|
||||
# but not Lean-specific `LEAN_EXTRA_CXX_FLAGS` such as fsanitize.
|
||||
@@ -54,51 +54,42 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||
set(CADICAL_CXX "${CCACHE} ${CADICAL_CXX}")
|
||||
endif()
|
||||
# missing stdio locking API on Windows
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
string(APPEND CADICAL_CXXFLAGS " -DNUNLOCKED")
|
||||
endif()
|
||||
string(APPEND CADICAL_CXXFLAGS " -DNCLOSEFROM")
|
||||
ExternalProject_Add(
|
||||
cadical
|
||||
ExternalProject_add(cadical
|
||||
PREFIX cadical
|
||||
GIT_REPOSITORY https://github.com/arminbiere/cadical
|
||||
GIT_TAG rel-2.1.2
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND
|
||||
$(MAKE) -f ${CMAKE_SOURCE_DIR}/src/cadical.mk CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX}
|
||||
CXX=${CADICAL_CXX} CXXFLAGS=${CADICAL_CXXFLAGS} LDFLAGS=${CADICAL_LDFLAGS}
|
||||
BUILD_COMMAND $(MAKE) -f ${CMAKE_SOURCE_DIR}/src/cadical.mk
|
||||
CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX}
|
||||
CXX=${CADICAL_CXX}
|
||||
CXXFLAGS=${CADICAL_CXXFLAGS}
|
||||
LDFLAGS=${CADICAL_LDFLAGS}
|
||||
BUILD_IN_SOURCE ON
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
set(
|
||||
CADICAL
|
||||
${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX}
|
||||
CACHE FILEPATH
|
||||
"path to cadical binary"
|
||||
FORCE
|
||||
)
|
||||
INSTALL_COMMAND "")
|
||||
set(CADICAL ${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX} CACHE FILEPATH "path to cadical binary" FORCE)
|
||||
list(APPEND EXTRA_DEPENDS cadical)
|
||||
endif()
|
||||
list(APPEND CL_ARGS -DCADICAL=${CADICAL})
|
||||
endif()
|
||||
|
||||
if(USE_MIMALLOC)
|
||||
ExternalProject_Add(
|
||||
mimalloc
|
||||
if (USE_MIMALLOC)
|
||||
ExternalProject_add(mimalloc
|
||||
PREFIX mimalloc
|
||||
GIT_REPOSITORY https://github.com/microsoft/mimalloc
|
||||
GIT_TAG v2.2.3
|
||||
# just download, we compile it as part of each stage as it is small
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
INSTALL_COMMAND "")
|
||||
list(APPEND EXTRA_DEPENDS mimalloc)
|
||||
endif()
|
||||
|
||||
if(NOT STAGE1_PREV_STAGE)
|
||||
ExternalProject_Add(
|
||||
stage0
|
||||
if (NOT STAGE1_PREV_STAGE)
|
||||
ExternalProject_add(stage0
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}/stage0"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage0
|
||||
@@ -106,49 +97,38 @@ if(NOT STAGE1_PREV_STAGE)
|
||||
# (however, CI will override this as we need to embed the githash into the stage 1 library built
|
||||
# by stage 0)
|
||||
CMAKE_ARGS -DSTAGE=0 -DUSE_GITHASH=OFF ${PLATFORM_ARGS} ${STAGE0_ARGS}
|
||||
BUILD_ALWAYS
|
||||
ON # cmake doesn't auto-detect changes without a download method
|
||||
INSTALL_COMMAND
|
||||
"" # skip install
|
||||
BUILD_ALWAYS ON # cmake doesn't auto-detect changes without a download method
|
||||
INSTALL_COMMAND "" # skip install
|
||||
DEPENDS ${EXTRA_DEPENDS}
|
||||
)
|
||||
list(APPEND EXTRA_DEPENDS stage0)
|
||||
endif()
|
||||
ExternalProject_Add(
|
||||
stage1
|
||||
ExternalProject_add(stage1
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage1
|
||||
CMAKE_ARGS
|
||||
-DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0
|
||||
-DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${STAGE0_CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS} ${STAGE1_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=1 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage0 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${STAGE0_CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS} ${STAGE1_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS ${EXTRA_DEPENDS}
|
||||
STEP_TARGETS configure
|
||||
)
|
||||
ExternalProject_Add(
|
||||
stage2
|
||||
ExternalProject_add(stage2
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage2
|
||||
CMAKE_ARGS
|
||||
-DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX}
|
||||
${CL_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=2 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage1 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage1
|
||||
EXCLUDE_FROM_ALL ON
|
||||
STEP_TARGETS configure
|
||||
)
|
||||
ExternalProject_Add(
|
||||
stage3
|
||||
ExternalProject_add(stage3
|
||||
SOURCE_DIR "${LEAN_SOURCE_DIR}"
|
||||
SOURCE_SUBDIR src
|
||||
BINARY_DIR stage3
|
||||
CMAKE_ARGS
|
||||
-DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX}
|
||||
${CL_ARGS}
|
||||
CMAKE_ARGS -DSTAGE=3 -DPREV_STAGE=${CMAKE_BINARY_DIR}/stage2 -DPREV_STAGE_CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} ${CL_ARGS}
|
||||
BUILD_ALWAYS ON
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage2
|
||||
@@ -157,14 +137,24 @@ ExternalProject_Add(
|
||||
|
||||
# targets forwarded to appropriate stages
|
||||
|
||||
add_custom_target(update-stage0 COMMAND $(MAKE) -C stage1 update-stage0 DEPENDS stage1)
|
||||
add_custom_target(update-stage0
|
||||
COMMAND $(MAKE) -C stage1 update-stage0
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(update-stage0-commit COMMAND $(MAKE) -C stage1 update-stage0-commit DEPENDS stage1)
|
||||
add_custom_target(update-stage0-commit
|
||||
COMMAND $(MAKE) -C stage1 update-stage0-commit
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(test COMMAND $(MAKE) -C stage1 test DEPENDS stage1)
|
||||
add_custom_target(test
|
||||
COMMAND $(MAKE) -C stage1 test
|
||||
DEPENDS stage1)
|
||||
|
||||
add_custom_target(clean-stdlib COMMAND $(MAKE) -C stage1 clean-stdlib DEPENDS stage1)
|
||||
add_custom_target(clean-stdlib
|
||||
COMMAND $(MAKE) -C stage1 clean-stdlib
|
||||
DEPENDS stage1)
|
||||
|
||||
install(CODE "execute_process(COMMAND make -C stage1 install)")
|
||||
|
||||
add_custom_target(check-stage3 COMMAND diff "stage2/bin/lean" "stage3/bin/lean" DEPENDS stage3)
|
||||
add_custom_target(check-stage3
|
||||
COMMAND diff "stage2/bin/lean" "stage3/bin/lean"
|
||||
DEPENDS stage3)
|
||||
|
||||
@@ -218,21 +218,6 @@ Please read https://leanprover-community.github.io/contribute/tags_and_branches.
|
||||
|
||||
# Writing the release notes
|
||||
|
||||
Release notes content is only written for the first release candidate (`-rc1`). For subsequent RCs and stable releases,
|
||||
just update the title in the existing release notes file (see "Release notes title format" below).
|
||||
|
||||
## Release notes title format
|
||||
|
||||
The title in the `#doc (Manual)` line must follow these formats:
|
||||
|
||||
- **For -rc1**: `"Lean 4.7.0-rc1 (2024-03-15)"` — Include the RC suffix and the release date
|
||||
- **For -rc2, -rc3, etc.**: `"Lean 4.7.0-rc2 (2024-03-20)"` — Update the RC number and date
|
||||
- **For stable release**: `"Lean 4.7.0 (2024-04-01)"` — Remove the RC suffix but keep the date
|
||||
|
||||
The date should be the actual date when the tag was pushed (or when CI completed and created the release page).
|
||||
|
||||
## Generating the release notes
|
||||
|
||||
Release notes are automatically generated from the commit history, using `script/release_notes.py`.
|
||||
|
||||
Run this as `script/release_notes.py --since v4.6.0`, where `v4.6.0` is the *previous* release version.
|
||||
@@ -247,113 +232,4 @@ Some judgement is required here: ignore commits which look minor,
|
||||
but manually add items to the release notes for significant PRs that were rebase-merged.
|
||||
|
||||
There can also be pre-written entries in `./releases_drafts`, which should be all incorporated in the release notes and then deleted from the branch.
|
||||
|
||||
## Reviewing and fixing the generated markdown
|
||||
|
||||
Before adding the release notes to the reference manual, carefully review the generated markdown for these common issues:
|
||||
|
||||
1. **Unterminated code blocks**: PR descriptions sometimes have unclosed code fences. Look for code blocks
|
||||
that don't have a closing ` ``` `. If found, fetch the original PR description with `gh pr view <number>`
|
||||
and repair the code block with the complete content.
|
||||
|
||||
2. **Truncated descriptions**: Some PR descriptions may end abruptly mid-sentence. Review these and complete
|
||||
the descriptions based on the original PR.
|
||||
|
||||
3. **Markdown syntax issues**: Check for other markdown problems that could cause parsing errors.
|
||||
|
||||
## Creating the release notes file
|
||||
|
||||
The release notes go in `Manual/Releases/v4_7_0.lean` in the reference-manual repository.
|
||||
|
||||
The file structure must follow the Verso format:
|
||||
|
||||
```lean
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: <Your Name>
|
||||
-/
|
||||
|
||||
import VersoManual
|
||||
import Manual.Meta
|
||||
import Manual.Meta.Markdown
|
||||
|
||||
open Manual
|
||||
open Verso.Genre
|
||||
open Verso.Genre.Manual
|
||||
open Verso.Genre.Manual.InlineLean
|
||||
|
||||
#doc (Manual) "Lean 4.7.0-rc1 (2024-03-15)" =>
|
||||
%%%
|
||||
tag := "release-v4.7.0"
|
||||
file := "v4.7.0"
|
||||
%%%
|
||||
|
||||
<release notes content here>
|
||||
```
|
||||
|
||||
**Important formatting rules for Verso:**
|
||||
- Use `#` for section headers inside the document, not `##` (Verso uses header level 1 for subsections)
|
||||
- Use plain ` ``` ` for code blocks, not ` ```lean ` (the latter will cause Lean to execute the code)
|
||||
- Identifiers with underscores like `bv_decide` should be wrapped in backticks: `` `bv_decide` ``
|
||||
(otherwise the underscore may be interpreted as markdown emphasis)
|
||||
|
||||
## Updating Manual/Releases.lean
|
||||
|
||||
After creating the release notes file, update `Manual/Releases.lean` to include it:
|
||||
|
||||
1. Add the import near the top with other version imports:
|
||||
```lean
|
||||
import Manual.Releases.«v4_7_0»
|
||||
```
|
||||
|
||||
2. Add the include statement after the other includes:
|
||||
```lean
|
||||
{include 0 Manual.Releases.«v4_7_0»}
|
||||
```
|
||||
|
||||
## Building and verifying
|
||||
|
||||
Build the release notes to check for errors:
|
||||
```bash
|
||||
lake build Manual.Releases.v4_7_0
|
||||
```
|
||||
|
||||
Common errors and fixes:
|
||||
- "Wrong header nesting - got ## but expected at most #": Change `##` to `#`
|
||||
- "Tactic 'X' failed" or similar: Code is being executed; change ` ```lean ` to ` ``` `
|
||||
- "'_'" errors: Underscore in identifier being parsed as emphasis; wrap in backticks
|
||||
|
||||
## Creating the PR
|
||||
|
||||
**Important: Timing with the reference-manual tag**
|
||||
|
||||
The reference-manual repository deploys documentation when a version tag is pushed. If you merge
|
||||
release notes AFTER the tag is created, the deployed documentation won't include them.
|
||||
|
||||
You have two options:
|
||||
|
||||
1. **Preferred**: Include the release notes in the same PR as the toolchain bump (or merge the
|
||||
release notes PR before creating the tag). This ensures the tag includes the release notes.
|
||||
|
||||
2. **If release notes are merged after the tag**: You must regenerate the tag to trigger a new deployment:
|
||||
```bash
|
||||
cd /path/to/reference-manual
|
||||
git fetch origin
|
||||
git tag -d v4.7.0-rc1 # Delete local tag
|
||||
git tag v4.7.0-rc1 origin/main # Create tag at current main (which has release notes)
|
||||
git push origin :refs/tags/v4.7.0-rc1 # Delete remote tag
|
||||
git push origin v4.7.0-rc1 # Push new tag (triggers Deploy workflow)
|
||||
```
|
||||
|
||||
If creating a separate PR for release notes:
|
||||
```bash
|
||||
git checkout -b v4.7.0-release-notes
|
||||
git add Manual/Releases/v4_7_0.lean Manual/Releases.lean
|
||||
git commit -m "doc: add v4.7.0 release notes"
|
||||
git push -u origin v4.7.0-release-notes
|
||||
gh pr create --title "doc: add v4.7.0 release notes" --body "This PR adds the release notes for Lean v4.7.0."
|
||||
```
|
||||
|
||||
See `./releases_drafts/README.md` for more information about pre-written release note entries.
|
||||
See `./releases_drafts/README.md` for more information.
|
||||
|
||||
13
script/fmt
13
script/fmt
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# This script expects to be run from the repo root.
|
||||
|
||||
# Format cmake files
|
||||
find -regex '.*/CMakeLists\.txt\(\.in\)?\|.*\.cmake\(\.in\)?' \
|
||||
! -path './build/*' \
|
||||
! -path "./stage0/*" \
|
||||
-exec \
|
||||
uvx gersemi --in-place --line-length 120 --indent 2 \
|
||||
--definitions src/cmake/Modules/ src/CMakeLists.txt \
|
||||
-- {} +
|
||||
@@ -185,30 +185,6 @@ def get_release_notes(tag_name):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def check_release_notes_file_exists(toolchain, github_token):
|
||||
"""Check if the release notes file exists in the reference-manual repository.
|
||||
|
||||
For -rc1 releases, this checks that the release notes have been created.
|
||||
For subsequent RCs and stable releases, release notes should already exist.
|
||||
|
||||
Returns tuple (exists: bool, is_rc1: bool) where is_rc1 indicates if this is
|
||||
the first release candidate (when release notes need to be written).
|
||||
"""
|
||||
# Determine the release notes file path
|
||||
# e.g., v4.28.0-rc1 -> Manual/Releases/v4_28_0.lean
|
||||
base_version = strip_rc_suffix(toolchain.lstrip('v')) # "4.28.0"
|
||||
file_name = f"v{base_version.replace('.', '_')}.lean" # "v4_28_0.lean"
|
||||
file_path = f"Manual/Releases/{file_name}"
|
||||
|
||||
is_rc1 = toolchain.endswith("-rc1")
|
||||
|
||||
repo_url = "https://github.com/leanprover/reference-manual"
|
||||
|
||||
# Check if the file exists on main branch
|
||||
content = get_branch_content(repo_url, "main", file_path, github_token)
|
||||
|
||||
return (content is not None, is_rc1)
|
||||
|
||||
def get_branch_content(repo_url, branch, file_path, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/contents/{file_path}?ref={branch}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
@@ -525,76 +501,6 @@ def check_proofwidgets4_release(repo_url, target_toolchain, github_token):
|
||||
print(f" You will need to create and push a tag v0.0.{next_version}")
|
||||
return False
|
||||
|
||||
def check_reference_manual_release_title(repo_url, toolchain, pr_branch, github_token):
|
||||
"""Check if the reference-manual release notes title matches the release type.
|
||||
|
||||
For RC releases (e.g., v4.27.0-rc1), the title should contain the exact RC suffix.
|
||||
For final releases (e.g., v4.27.0), the title should NOT contain any "-rc".
|
||||
|
||||
Returns True if check passes or is not applicable, False if title needs updating.
|
||||
"""
|
||||
is_rc = is_release_candidate(toolchain)
|
||||
|
||||
# For RC releases, get the base version and RC suffix
|
||||
# e.g., "v4.27.0-rc1" -> version="4.27.0", rc_suffix="-rc1"
|
||||
if is_rc:
|
||||
parts = toolchain.lstrip('v').split('-', 1)
|
||||
version = parts[0]
|
||||
rc_suffix = '-' + parts[1] if len(parts) > 1 else ''
|
||||
else:
|
||||
version = toolchain.lstrip('v')
|
||||
rc_suffix = ''
|
||||
|
||||
# Construct the release notes file path (e.g., Manual/Releases/v4_27_0.lean for v4.27.0)
|
||||
file_name = f"v{version.replace('.', '_')}.lean" # "v4_27_0.lean"
|
||||
file_path = f"Manual/Releases/{file_name}"
|
||||
|
||||
# Try to get the file from the PR branch first, then fall back to main branch
|
||||
content = get_branch_content(repo_url, pr_branch, file_path, github_token)
|
||||
if content is None:
|
||||
# Try the default branch
|
||||
content = get_branch_content(repo_url, "main", file_path, github_token)
|
||||
|
||||
if content is None:
|
||||
print(f" ⚠️ Could not check release notes file: {file_path}")
|
||||
return True # Don't block on this
|
||||
|
||||
# Look for the #doc line with the title
|
||||
for line in content.splitlines():
|
||||
if line.strip().startswith('#doc') and 'Manual' in line:
|
||||
has_rc_in_title = '-rc' in line.lower()
|
||||
|
||||
if is_rc:
|
||||
# For RC releases, title should contain the exact RC suffix (e.g., "-rc1")
|
||||
# Use regex to match exact suffix followed by non-digit (to avoid -rc1 matching -rc10)
|
||||
# Pattern matches the RC suffix followed by a non-digit or end-of-string context
|
||||
# e.g., "-rc1" followed by space, quote, paren, or similar
|
||||
exact_match = re.search(rf'{re.escape(rc_suffix)}(?![0-9])', line, re.IGNORECASE)
|
||||
if exact_match:
|
||||
print(f" ✅ Release notes title correctly shows {rc_suffix}")
|
||||
return True
|
||||
elif has_rc_in_title:
|
||||
print(f" ❌ Release notes title shows wrong RC version (expected {rc_suffix})")
|
||||
print(f" Update {file_path} to use '{rc_suffix}' in the title")
|
||||
return False
|
||||
else:
|
||||
print(f" ❌ Release notes title missing RC suffix")
|
||||
print(f" Update {file_path} to include '{rc_suffix}' in the title")
|
||||
return False
|
||||
else:
|
||||
# For final releases, title should NOT contain -rc
|
||||
if has_rc_in_title:
|
||||
print(f" ❌ Release notes title still shows RC version")
|
||||
print(f" Update {file_path} to remove '-rcN' from the title")
|
||||
return False
|
||||
else:
|
||||
print(f" ✅ Release notes title is updated for final release")
|
||||
return True
|
||||
|
||||
# If we didn't find the #doc line, don't block
|
||||
print(f" ⚠️ Could not find release notes title in {file_path}")
|
||||
return True
|
||||
|
||||
def run_mathlib_verify_version_tags(toolchain, verbose=False):
|
||||
"""Run mathlib4's verify_version_tags.py script to validate the release tag.
|
||||
|
||||
@@ -738,27 +644,6 @@ def main():
|
||||
else:
|
||||
print(f" ✅ Release notes page title looks good ('{actual_title}').")
|
||||
|
||||
# Check if release notes file exists in reference-manual repository
|
||||
# For -rc1 releases, this is when release notes need to be written
|
||||
# For subsequent RCs and stable releases, they should already exist
|
||||
release_notes_exists, is_rc1 = check_release_notes_file_exists(toolchain, github_token)
|
||||
base_version = strip_rc_suffix(toolchain.lstrip('v'))
|
||||
release_notes_file = f"Manual/Releases/v{base_version.replace('.', '_')}.lean"
|
||||
|
||||
if not release_notes_exists:
|
||||
if is_rc1:
|
||||
print(f" ❌ Release notes file not found: {release_notes_file}")
|
||||
print(f" This is an -rc1 release, so release notes need to be written.")
|
||||
print(f" Run `script/release_notes.py --since <previous_version>` to generate them.")
|
||||
print(f" See doc/dev/release_checklist.md section 'Writing the release notes' for details.")
|
||||
lean4_success = False
|
||||
else:
|
||||
print(f" ❌ Release notes file not found: {release_notes_file}")
|
||||
print(f" Release notes should have been created for -rc1. Check the reference-manual repository.")
|
||||
lean4_success = False
|
||||
else:
|
||||
print(f" ✅ Release notes file exists: {release_notes_file}")
|
||||
|
||||
repo_status["lean4"] = lean4_success
|
||||
|
||||
# If the release page doesn't exist, skip repository checks and master branch checks
|
||||
@@ -824,11 +709,6 @@ def main():
|
||||
print(f" ⚠️ CI: {ci_message}")
|
||||
else:
|
||||
print(f" ❓ CI: {ci_message}")
|
||||
|
||||
# For reference-manual, check that the release notes title has been updated
|
||||
if name == "reference-manual":
|
||||
pr_branch = f"bump_to_{toolchain}"
|
||||
check_reference_manual_release_title(url, toolchain, pr_branch, github_token)
|
||||
else:
|
||||
print(f" ❌ PR with title '{pr_title}' does not exist")
|
||||
print(f" Run `script/release_steps.py {toolchain} {name}` to create it")
|
||||
|
||||
@@ -14,6 +14,13 @@ repositories:
|
||||
bump-branch: true
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: lean4checker
|
||||
url: https://github.com/leanprover/lean4checker
|
||||
toolchain-tag: true
|
||||
@@ -35,14 +42,6 @@ repositories:
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- plausible
|
||||
|
||||
- name: import-graph
|
||||
url: https://github.com/leanprover-community/import-graph
|
||||
toolchain-tag: true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -142,7 +142,6 @@ is classically true but not constructively. -/
|
||||
|
||||
/-- Transfer decidability of `¬ p` to decidability of `p`. -/
|
||||
-- This can not be an instance as it would be tried everywhere.
|
||||
@[instance_reducible]
|
||||
def decidable_of_decidable_not (p : Prop) [h : Decidable (¬ p)] : Decidable p :=
|
||||
match h with
|
||||
| isFalse h => isTrue (Classical.not_not.mp h)
|
||||
|
||||
@@ -121,11 +121,6 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (ExceptT ε m) where
|
||||
@[simp] theorem run_control [Monad m] [LawfulMonad m] (f : ({β : Type u} → ExceptT ε m β → m (stM m (ExceptT ε m) β)) → m (stM m (ExceptT ε m) α)) :
|
||||
ExceptT.run (control f) = f fun x => x.run := run_controlAt f
|
||||
|
||||
@[simp, grind =]
|
||||
theorem run_adapt [Monad m] (f : ε → ε') (x : ExceptT ε m α)
|
||||
: run (ExceptT.adapt f x : ExceptT ε' m α) = Except.mapError f <$> run x :=
|
||||
rfl
|
||||
|
||||
end ExceptT
|
||||
|
||||
/-! # Except -/
|
||||
@@ -472,33 +467,15 @@ namespace EStateM
|
||||
@[simp, grind =] theorem run_throw (e : ε) (s : σ):
|
||||
EStateM.run (throw e : EStateM ε σ PUnit) s = .error e s := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind (x : EStateM ε σ α) (f : α → EStateM ε σ β)
|
||||
: EStateM.run (x >>= f : EStateM ε σ β) s
|
||||
=
|
||||
match EStateM.run x s with
|
||||
| .ok x s => EStateM.run (f x) s
|
||||
| .error e s => .error e s :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem run_adaptExcept (f : ε → ε') (x : EStateM ε σ α) (s : σ)
|
||||
: EStateM.run (EStateM.adaptExcept f x : EStateM ε' σ α) s
|
||||
=
|
||||
match EStateM.run x s with
|
||||
| .ok x s => .ok x s
|
||||
| .error e s => .error (f e) s := by
|
||||
simp only [EStateM.run, EStateM.adaptExcept]
|
||||
cases (x s) <;> rfl
|
||||
|
||||
instance : LawfulMonad (EStateM ε σ) := .mk'
|
||||
(id_map := fun x => funext <| fun s => by
|
||||
simp only [Functor.map, EStateM.map]
|
||||
dsimp only [EStateM.instMonad, EStateM.map]
|
||||
match x s with
|
||||
| .ok _ _ => rfl
|
||||
| .error _ _ => rfl)
|
||||
(pure_bind := fun _ _ => by rfl)
|
||||
(bind_assoc := fun x _ _ => funext <| fun s => by
|
||||
simp only [bind, EStateM.bind]
|
||||
dsimp only [EStateM.instMonad, EStateM.bind]
|
||||
match x s with
|
||||
| .ok _ _ => rfl
|
||||
| .error _ _ => rfl)
|
||||
|
||||
@@ -70,7 +70,7 @@ information to the return value, except a trivial proof of {name}`True`.
|
||||
This instance is used whenever no more useful {name}`MonadAttach` instance can be implemented.
|
||||
It always has a {name}`WeaklyLawfulMonadAttach`, but usually no {name}`LawfulMonadAttach` instance.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose]
|
||||
public protected def MonadAttach.trivial {m : Type u → Type v} [Monad m] : MonadAttach m where
|
||||
CanReturn _ _ := True
|
||||
attach x := (⟨·, .intro⟩) <$> x
|
||||
|
||||
@@ -51,10 +51,6 @@ scoped syntax (name := withAnnotateState)
|
||||
/-- `skip` does nothing. -/
|
||||
syntax (name := skip) "skip" : conv
|
||||
|
||||
/-- `cbv` performs simplification that closely mimics call-by-value evaluation,
|
||||
using equations associated with definitions and the matchers. -/
|
||||
syntax (name := cbv) "cbv" : conv
|
||||
|
||||
/--
|
||||
Traverses into the left subterm of a binary operator.
|
||||
|
||||
|
||||
@@ -932,14 +932,6 @@ noncomputable def HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sor
|
||||
noncomputable def HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} {β : Sort u2} {b : β} (h : a ≍ b) (m : motive a) : motive b :=
|
||||
h.rec m
|
||||
|
||||
/-- `HEq.ndrec` specialized to homogeneous heterogeneous equality -/
|
||||
noncomputable def HEq.homo_ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : α → Sort u1} (m : motive a) {b : α} (h : a ≍ b) : motive b :=
|
||||
(eq_of_heq h).ndrec m
|
||||
|
||||
/-- `HEq.ndrec` specialized to homogeneous heterogeneous equality, symmetric variant -/
|
||||
noncomputable def HEq.homo_ndrec_symm.{u1, u2} {α : Sort u2} {a : α} {motive : α → Sort u1} (m : motive a) {b : α} (h : b ≍ a) : motive b :=
|
||||
(eq_of_heq h).ndrec_symm m
|
||||
|
||||
/-- `HEq.ndrec` variant -/
|
||||
noncomputable def HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : a ≍ b) (h₂ : p a) : p b :=
|
||||
eq_of_heq h₁ ▸ h₂
|
||||
@@ -1486,29 +1478,6 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
|
||||
|
||||
/-! # Dependent products -/
|
||||
|
||||
instance {α : Type u} {β : α → Type v} [h₁ : DecidableEq α] [h₂ : ∀ a, DecidableEq (β a)] :
|
||||
DecidableEq (Sigma β)
|
||||
| ⟨a₁, b₁⟩, ⟨a₂, b₂⟩ =>
|
||||
match a₁, b₁, a₂, b₂, h₁ a₁ a₂ with
|
||||
| _, b₁, _, b₂, isTrue (Eq.refl _) =>
|
||||
match b₁, b₂, h₂ _ b₁ b₂ with
|
||||
| _, _, isTrue (Eq.refl _) => isTrue rfl
|
||||
| _, _, isFalse n => isFalse fun h ↦
|
||||
Sigma.noConfusion rfl .rfl (heq_of_eq h) fun _ e₂ ↦ n (eq_of_heq e₂)
|
||||
| _, _, _, _, isFalse n => isFalse fun h ↦
|
||||
Sigma.noConfusion rfl .rfl (heq_of_eq h) fun e₁ _ ↦ n (eq_of_heq e₁)
|
||||
|
||||
instance {α : Sort u} {β : α → Sort v} [h₁ : DecidableEq α] [h₂ : ∀ a, DecidableEq (β a)] : DecidableEq (PSigma β)
|
||||
| ⟨a₁, b₁⟩, ⟨a₂, b₂⟩ =>
|
||||
match a₁, b₁, a₂, b₂, h₁ a₁ a₂ with
|
||||
| _, b₁, _, b₂, isTrue (Eq.refl _) =>
|
||||
match b₁, b₂, h₂ _ b₁ b₂ with
|
||||
| _, _, isTrue (Eq.refl _) => isTrue rfl
|
||||
| _, _, isFalse n => isFalse fun h ↦
|
||||
PSigma.noConfusion rfl .rfl (heq_of_eq h) fun _ e₂ ↦ n (eq_of_heq e₂)
|
||||
| _, _, _, _, isFalse n => isFalse fun h ↦
|
||||
PSigma.noConfusion rfl .rfl (heq_of_eq h) fun e₁ _ ↦ n (eq_of_heq e₁)
|
||||
|
||||
theorem Exists.of_psigma_prop {α : Sort u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
|
||||
| ⟨x, hx⟩ => ⟨x, hx⟩
|
||||
|
||||
@@ -2360,10 +2329,8 @@ namespace Lean
|
||||
/--
|
||||
Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations.
|
||||
-/
|
||||
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
|
||||
axiom trustCompiler : True
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`.
|
||||
The kernel will not use the interpreter if `c` is not a constant.
|
||||
@@ -2383,13 +2350,11 @@ Recall that the compiler trusts the correctness of all `[implemented_by ...]` an
|
||||
If an extern function is executed, then the trusted code base will also include the implementation of the associated
|
||||
foreign function.
|
||||
-/
|
||||
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
|
||||
opaque reduceBool (b : Bool) : Bool :=
|
||||
-- This ensures that `#print axioms` will track use of `reduceBool`.
|
||||
have := trustCompiler
|
||||
b
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
Similar to `Lean.reduceBool` for closed `Nat` terms.
|
||||
|
||||
@@ -2397,14 +2362,12 @@ Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α)
|
||||
The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression.
|
||||
We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection).
|
||||
-/
|
||||
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
|
||||
opaque reduceNat (n : Nat) : Nat :=
|
||||
-- This ensures that `#print axioms` will track use of `reduceNat`.
|
||||
have := trustCompiler
|
||||
n
|
||||
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`.
|
||||
|
||||
@@ -2418,10 +2381,8 @@ external type checkers that do not implement this feature.
|
||||
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
|
||||
So, you are mainly losing the capability of type checking your development using external checkers.
|
||||
-/
|
||||
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
|
||||
axiom ofReduceBool (a b : Bool) (h : reduceBool a = b) : a = b
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool`.
|
||||
|
||||
@@ -2431,7 +2392,6 @@ external type checkers that do not implement this feature.
|
||||
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
|
||||
So, you are mainly losing the capability of type checking your development using external checkers.
|
||||
-/
|
||||
@[deprecated "in-kernel native reduction is deprecated; assert native evaluations with axioms instead" (since := "2026-02-01")]
|
||||
axiom ofReduceNat (a b : Nat) (h : reduceNat a = b) : a = b
|
||||
|
||||
|
||||
@@ -2482,7 +2442,7 @@ class IdempotentOp (op : α → α → α) : Prop where
|
||||
idempotent : (x : α) → op x x = x
|
||||
|
||||
/--
|
||||
`LeftIdentity op o` indicates `o` is a left identity of `op`.
|
||||
`LeftIdentify op o` indicates `o` is a left identity of `op`.
|
||||
|
||||
This class does not require a proof that `o` is an identity, and
|
||||
is used primarily for inferring the identity using class resolution.
|
||||
@@ -2490,7 +2450,7 @@ is used primarily for inferring the identity using class resolution.
|
||||
class LeftIdentity (op : α → β → β) (o : outParam α) : Prop
|
||||
|
||||
/--
|
||||
`LawfulLeftIdentity op o` indicates `o` is a verified left identity of
|
||||
`LawfulLeftIdentify op o` indicates `o` is a verified left identity of
|
||||
`op`.
|
||||
-/
|
||||
class LawfulLeftIdentity (op : α → β → β) (o : outParam α) : Prop extends LeftIdentity op o where
|
||||
@@ -2498,7 +2458,7 @@ class LawfulLeftIdentity (op : α → β → β) (o : outParam α) : Prop extend
|
||||
left_id : ∀ a, op o a = a
|
||||
|
||||
/--
|
||||
`RightIdentity op o` indicates `o` is a right identity `o` of `op`.
|
||||
`RightIdentify op o` indicates `o` is a right identity `o` of `op`.
|
||||
|
||||
This class does not require a proof that `o` is an identity, and is used
|
||||
primarily for inferring the identity using class resolution.
|
||||
@@ -2506,7 +2466,7 @@ primarily for inferring the identity using class resolution.
|
||||
class RightIdentity (op : α → β → α) (o : outParam β) : Prop
|
||||
|
||||
/--
|
||||
`LawfulRightIdentity op o` indicates `o` is a verified right identity of
|
||||
`LawfulRightIdentify op o` indicates `o` is a verified right identity of
|
||||
`op`.
|
||||
-/
|
||||
class LawfulRightIdentity (op : α → β → α) (o : outParam β) : Prop extends RightIdentity op o where
|
||||
|
||||
@@ -30,6 +30,3 @@ public import Init.Data.Array.Erase
|
||||
public import Init.Data.Array.Zip
|
||||
public import Init.Data.Array.InsertIdx
|
||||
public import Init.Data.Array.Extract
|
||||
public import Init.Data.Array.MinMax
|
||||
public import Init.Data.Array.Nat
|
||||
public import Init.Data.Array.Int
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.Count
|
||||
import Init.Grind.Util
|
||||
|
||||
public section
|
||||
|
||||
@@ -93,18 +92,6 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
/-- This lemma is only relevant for `grind`. -/
|
||||
@[grind ←=]
|
||||
theorem _root_.Std.Internal.Array.countP_eq_zero_of_forall {xs : Array α} (h : ∀ x ∈ xs, ¬ p x) : xs.countP p = 0 :=
|
||||
countP_eq_zero.mpr h
|
||||
|
||||
/-- This lemma is only relevant for `grind`. -/
|
||||
theorem _root_.Std.Internal.Array.not_of_countP_eq_zero_of_mem {xs : Array α} (h : xs.countP p = 0) (h' : x ∈ xs) : ¬ p x :=
|
||||
countP_eq_zero.mp h _ h'
|
||||
|
||||
grind_pattern Std.Internal.Array.not_of_countP_eq_zero_of_mem => xs.countP p, x ∈ xs where
|
||||
guard xs.countP p = 0
|
||||
|
||||
@[simp] theorem countP_eq_size {p} : countP p xs = xs.size ↔ ∀ a ∈ xs, p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Nat.Find
|
||||
import Init.Data.List.Nat.Sum
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Range
|
||||
|
||||
@@ -115,7 +114,7 @@ theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten
|
||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
||||
List.findSome?_isSome_iff, isSome_getElem?]
|
||||
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
|
||||
List.sum_pos_iff_exists_pos_nat, List.mem_map] at h
|
||||
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
exact ⟨xs, m, by simpa using h⟩
|
||||
|
||||
@@ -675,39 +674,6 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
|
||||
simp [Array.size]
|
||||
|
||||
/-! ### find? and findFinIdx? -/
|
||||
|
||||
theorem find?_eq_map_findFinIdx?_getElem {xs : Array α} {p : α → Bool} :
|
||||
xs.find? p = (xs.findFinIdx? p).map (xs[·]) := by
|
||||
cases xs
|
||||
simp [List.find?_eq_map_findFinIdx?_getElem]
|
||||
rfl
|
||||
|
||||
theorem find?_eq_bind_findIdx?_getElem? {xs : Array α} {p : α → Bool} :
|
||||
xs.find? p = (xs.findIdx? p).bind (xs[·]?) := by
|
||||
cases xs
|
||||
simp [List.find?_eq_bind_findIdx?_getElem?]
|
||||
|
||||
theorem find?_eq_getElem?_findIdx {xs : Array α} {p : α → Bool} :
|
||||
xs.find? p = xs[xs.findIdx p]? := by
|
||||
cases xs
|
||||
simp [List.find?_eq_getElem?_findIdx]
|
||||
|
||||
theorem findIdx?_eq_bind_find?_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = (xs.find? p).bind (xs.idxOf? ·) := by
|
||||
cases xs
|
||||
simp [List.findIdx?_eq_bind_find?_idxOf?]
|
||||
|
||||
theorem findFinIdx?_eq_bind_find?_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {p : α → Bool} :
|
||||
xs.findFinIdx? p = (xs.find? p).bind (xs.finIdxOf? ·) := by
|
||||
cases xs
|
||||
simp [List.findFinIdx?_eq_bind_find?_finIdxOf?]
|
||||
|
||||
theorem findIdx_eq_getD_bind_find?_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx p = ((xs.find? p).bind (xs.idxOf? ·)).getD xs.size := by
|
||||
cases xs
|
||||
simp [List.findIdx_eq_getD_bind_find?_idxOf?]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
The verification API for `idxOf` is still incomplete.
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Sebastian Graf, Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Int.Sum
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Int.DivMod.Bootstrap
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.List.MinMax
|
||||
|
||||
public section
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem sum_replicate_int {n : Nat} {a : Int} : (replicate n a).sum = n * a := by
|
||||
rw [← List.toArray_replicate, List.sum_toArray]
|
||||
simp
|
||||
|
||||
theorem sum_append_int {as₁ as₂ : Array Int} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
simp [sum_append]
|
||||
|
||||
theorem sum_reverse_int (xs : Array Int) : xs.reverse.sum = xs.sum := by
|
||||
simp [sum_reverse]
|
||||
|
||||
theorem sum_eq_foldl_int {xs : Array Int} : xs.sum = xs.foldl (init := 0) (· + ·) := by
|
||||
simp only [foldl_eq_foldr_reverse, Int.add_comm, ← sum_eq_foldr, sum_reverse_int]
|
||||
|
||||
end Array
|
||||
@@ -482,18 +482,9 @@ theorem mem_iff_getElem {a} {xs : Array α} : a ∈ xs ↔ ∃ (i : Nat) (h : i
|
||||
theorem mem_iff_getElem? {a} {xs : Array α} : a ∈ xs ↔ ∃ i : Nat, xs[i]? = some a := by
|
||||
simp [getElem?_eq_some_iff, mem_iff_getElem]
|
||||
|
||||
theorem exists_mem_iff_exists_getElem {P : α → Prop} {xs : Array α} :
|
||||
(∃ x ∈ xs, P x) ↔ ∃ (i : Nat), ∃ (hi : i < xs.size), P (xs[i]) := by
|
||||
cases xs; simp [List.exists_mem_iff_exists_getElem]
|
||||
|
||||
theorem forall_mem_iff_forall_getElem {P : α → Prop} {xs : Array α} :
|
||||
(∀ x ∈ xs, P x) ↔ ∀ (i : Nat) (hi : i < xs.size), P (xs[i]) := by
|
||||
cases xs; simp [List.forall_mem_iff_forall_getElem]
|
||||
|
||||
@[deprecated forall_mem_iff_forall_getElem (since := "2026-01-29")]
|
||||
theorem forall_getElem {xs : Array α} {p : α → Prop} :
|
||||
(∀ (i : Nat) h, p (xs[i]'h)) ↔ ∀ a, a ∈ xs → p a := by
|
||||
exact forall_mem_iff_forall_getElem.symm
|
||||
cases xs; simp [List.forall_getElem]
|
||||
|
||||
/-! ### isEmpty -/
|
||||
|
||||
@@ -1978,14 +1969,6 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
· left; exact ⟨as.toList, by simp⟩
|
||||
· right; exact ⟨cs.toList, by simp⟩
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_left {ws xs ys zs : Array α} (h : ws.size = xs.size) :
|
||||
ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
simpa [← Array.toList_inj] using List.append_eq_append_iff_of_size_eq_left h
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_right {ws xs ys zs : Array α} (h : ys.size = zs.size) :
|
||||
ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
simpa [← Array.toList_inj] using List.append_eq_append_iff_of_size_eq_right h
|
||||
|
||||
@[grind =] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
|
||||
(xs ++ ys).set i x =
|
||||
if h' : i < xs.size then
|
||||
@@ -2517,6 +2500,10 @@ theorem flatMap_replicate {f : α → Array β} : (replicate n a).flatMap f = (r
|
||||
rw [← List.toArray_replicate, List.isEmpty_toArray]
|
||||
simp
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
rw [← List.toArray_replicate, List.sum_toArray]
|
||||
simp
|
||||
|
||||
/-! ### Preliminaries about `swap` needed for `reverse`. -/
|
||||
|
||||
@[grind =]
|
||||
@@ -3078,18 +3065,6 @@ theorem foldl_eq_foldlM {f : β → α → β} {b} {xs : Array α} {start stop :
|
||||
theorem foldr_eq_foldrM {f : α → β → β} {b} {xs : Array α} {start stop : Nat} :
|
||||
xs.foldr f b start stop = (xs.foldrM (m := Id) (pure <| f · ·) b start stop).run := rfl
|
||||
|
||||
public theorem foldl_eq_foldl_extract {xs : Array α} {f : β → α → β} {init : β} :
|
||||
xs.foldl (init := init) (start := start) (stop := stop) f =
|
||||
(xs.extract start stop).foldl (init := init) f := by
|
||||
simp only [foldl_eq_foldlM]
|
||||
rw [foldlM_start_stop]
|
||||
|
||||
public theorem foldr_eq_foldr_extract {xs : Array α} {f : α → β → β} {init : β} :
|
||||
xs.foldr (init := init) (start := start) (stop := stop) f =
|
||||
(xs.extract stop start).foldr (init := init) f := by
|
||||
simp only [foldr_eq_foldrM]
|
||||
rw [foldrM_start_stop]
|
||||
|
||||
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b} {xs : Array α} {start stop : Nat} :
|
||||
Id.run (xs.foldlM f b start stop) = xs.foldl (f · · |>.run) b start stop := rfl
|
||||
|
||||
@@ -4302,31 +4277,19 @@ theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then
|
||||
/-! ### sum -/
|
||||
|
||||
@[simp, grind =] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
|
||||
theorem sum_eq_foldr [Add α] [Zero α] {xs : Array α} :
|
||||
xs.sum = xs.foldr (init := 0) (· + ·) :=
|
||||
rfl
|
||||
|
||||
-- Without further algebraic hypotheses, there's no useful `sum_push` lemma.
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_toList [Add α] [Zero α] {as : Array α} : as.toList.sum = as.sum := by
|
||||
theorem sum_eq_sum_toList [Add α] [Zero α] {as : Array α} : as.toList.sum = as.sum := by
|
||||
cases as
|
||||
simp [Array.sum, List.sum]
|
||||
|
||||
@[deprecated sum_toList (since := "2026-01-14")]
|
||||
def sum_eq_sum_toList := @sum_toList
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_append [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.LeftIdentity (α := α) (· + ·) 0] [Std.LawfulLeftIdentity (α := α) (· + ·) 0]
|
||||
{as₁ as₂ : Array α} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
simp [← sum_toList, List.sum_append]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.Commutative (α := α) (· + ·)]
|
||||
[Std.LawfulLeftIdentity (α := α) (· + ·) 0] (xs : Array α) : xs.reverse.sum = xs.sum := by
|
||||
simp [← sum_toList, List.sum_reverse]
|
||||
theorem sum_append_nat {as₁ as₂ : Array Nat} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
cases as₁
|
||||
cases as₂
|
||||
simp [List.sum_append_nat]
|
||||
|
||||
theorem foldl_toList_eq_flatMap {l : List α} {acc : Array β}
|
||||
{F : Array β → α → Array β} {G : α → List β}
|
||||
|
||||
@@ -1,401 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Bootstrap
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.DecidableEq
|
||||
import Init.Data.List.MinMax
|
||||
import Init.Data.List.ToArray
|
||||
|
||||
namespace Array
|
||||
|
||||
/-! ## Minima and maxima -/
|
||||
|
||||
/-! ### min -/
|
||||
|
||||
/--
|
||||
Returns the smallest element of a non-empty array.
|
||||
|
||||
Examples:
|
||||
* `#[4].min (by decide) = 4`
|
||||
* `#[1, 4, 2, 10, 6].min (by decide) = 1`
|
||||
-/
|
||||
public protected def min [Min α] (arr : Array α) (h : arr ≠ #[]) : α :=
|
||||
haveI : arr.size > 0 := by simp [Array.size_pos_iff, h]
|
||||
arr.foldl min arr[0] (start := 1)
|
||||
|
||||
/-! ### min? -/
|
||||
|
||||
/--
|
||||
Returns the smallest element of the array if it is not empty, or `none` if it is empty.
|
||||
|
||||
Examples:
|
||||
* `#[].min? = none`
|
||||
* `#[4].min? = some 4`
|
||||
* `#[1, 4, 2, 10, 6].min? = some 1`
|
||||
-/
|
||||
public protected def min? [Min α] (arr : Array α) : Option α :=
|
||||
if h : arr ≠ #[] then
|
||||
some (arr.min h)
|
||||
else
|
||||
none
|
||||
|
||||
/-! ### max -/
|
||||
|
||||
/--
|
||||
Returns the largest element of a non-empty array.
|
||||
|
||||
Examples:
|
||||
* `#[4].max (by decide) = 4`
|
||||
* `#[1, 4, 2, 10, 6].max (by decide) = 10`
|
||||
-/
|
||||
public protected def max [Max α] (arr : Array α) (h : arr ≠ #[]) : α :=
|
||||
haveI : arr.size > 0 := by simp [Array.size_pos_iff, h]
|
||||
arr.foldl max arr[0] (start := 1)
|
||||
|
||||
/-! ### max? -/
|
||||
|
||||
/--
|
||||
Returns the largest element of the array if it is not empty, or `none` if it is empty.
|
||||
|
||||
Examples:
|
||||
* `#[].max? = none`
|
||||
* `#[4].max? = some 4`
|
||||
* `#[1, 4, 2, 10, 6].max? = some 10`
|
||||
-/
|
||||
public protected def max? [Max α] (arr : Array α) : Option α :=
|
||||
if h : arr ≠ #[] then
|
||||
some (arr.max h)
|
||||
else
|
||||
none
|
||||
|
||||
/-! ### Compatibility with `List` -/
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem _root_.List.min_toArray [Min α] {l : List α} {h} :
|
||||
l.toArray.min h = l.min (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
let h' : l ≠ [] := by simpa [List.ne_nil_iff_length_pos] using h
|
||||
change l.toArray.min h = l.min h'
|
||||
rw [Array.min]
|
||||
· induction l
|
||||
· contradiction
|
||||
· rename_i x xs
|
||||
simp only [List.getElem_toArray, List.getElem_cons_zero, List.size_toArray, List.length_cons]
|
||||
rw [List.toArray_cons, foldl_eq_foldl_extract]
|
||||
rw [← Array.foldl_toList, Array.toList_extract, List.extract_eq_drop_take]
|
||||
simp [List.min]
|
||||
|
||||
public theorem _root_.List.min_eq_min_toArray [Min α] {l : List α} {h} :
|
||||
l.min h = l.toArray.min (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min_toList [Min α] {xs : Array α} {h} :
|
||||
xs.toList.min h = xs.min (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
cases xs; simp
|
||||
|
||||
public theorem min_eq_min_toList [Min α] {xs : Array α} {h} :
|
||||
xs.min h = xs.toList.min (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem _root_.List.min?_toArray [Min α] {l : List α} :
|
||||
l.toArray.min? = l.min? := by
|
||||
rw [Array.min?]
|
||||
split
|
||||
· simp [List.min_toArray, List.min_eq_get_min?, - List.get_min?]
|
||||
· simp_all
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_toList [Min α] {xs : Array α} :
|
||||
xs.toList.min? = xs.min? := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem _root_.List.max_toArray [Max α] {l : List α} {h} :
|
||||
l.toArray.max h = l.max (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
let h' : l ≠ [] := by simpa [List.ne_nil_iff_length_pos] using h
|
||||
change l.toArray.max h = l.max h'
|
||||
rw [Array.max]
|
||||
· induction l
|
||||
· contradiction
|
||||
· rename_i x xs
|
||||
simp only [List.getElem_toArray, List.getElem_cons_zero, List.size_toArray, List.length_cons]
|
||||
rw [List.toArray_cons, foldl_eq_foldl_extract]
|
||||
rw [← Array.foldl_toList, Array.toList_extract, List.extract_eq_drop_take]
|
||||
simp [List.max]
|
||||
|
||||
public theorem _root_.List.max_eq_max_toArray [Max α] {l : List α} {h} :
|
||||
l.max h = l.toArray.max (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max_toList [Max α] {xs : Array α} {h} :
|
||||
xs.toList.max h = xs.max (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
cases xs; simp
|
||||
|
||||
public theorem max_eq_max_toList [Max α] {xs : Array α} {h} :
|
||||
xs.max h = xs.toList.max (by simpa [List.ne_nil_iff_length_pos] using h) := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem _root_.List.max?_toArray [Max α] {l : List α} :
|
||||
l.toArray.max? = l.max? := by
|
||||
rw [Array.max?]
|
||||
split
|
||||
· simp [List.max_toArray, List.max_eq_get_max?, - List.get_max?]
|
||||
· simp_all
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_toList [Max α] {xs : Array α} :
|
||||
xs.toList.max? = xs.max? := by
|
||||
cases xs; simp
|
||||
|
||||
/-! ### Lemmas about `min?` -/
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_empty [Min α] : (#[] : Array α).min? = none :=
|
||||
(rfl)
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_singleton [Min α] {x : α} : #[x].min? = some x :=
|
||||
(rfl)
|
||||
|
||||
-- We don't put `@[simp]` on `min?_singleton_append'`,
|
||||
-- because the definition in terms of `foldl` is not useful for proofs.
|
||||
public theorem min?_singleton_append' [Min α] {xs : Array α} :
|
||||
(#[x] ++ xs).min? = some (xs.foldl min x) := by
|
||||
simp [← min?_toList, toList_append, List.min?]
|
||||
|
||||
@[simp]
|
||||
public theorem min?_singleton_append [Min α] [Std.Associative (min : α → α → α)] {xs : Array α} :
|
||||
(#[x] ++ xs).min? = some (xs.min?.elim x (min x)) := by
|
||||
simp [← min?_toList, toList_append, List.min?_cons]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_eq_none_iff {xs : Array α} [Min α] : xs.min? = none ↔ xs = #[] := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem isSome_min?_iff {xs : Array α} [Min α] : xs.min?.isSome ↔ xs ≠ #[] := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[grind .]
|
||||
public theorem isSome_min?_of_mem {xs : Array α} [Min α] {a : α} (h : a ∈ xs) :
|
||||
xs.min?.isSome := by
|
||||
rw [← min?_toList]
|
||||
apply List.isSome_min?_of_mem (a := a)
|
||||
simpa
|
||||
|
||||
public theorem isSome_min?_of_ne_empty [Min α] (xs : Array α) (h : xs ≠ #[]) : xs.min?.isSome := by
|
||||
rw [← min?_toList]
|
||||
apply List.isSome_min?_of_ne_nil
|
||||
simpa
|
||||
|
||||
public theorem min?_mem [Min α] [Std.MinEqOr α] (xs : Array α) (h : xs.min? = some a) : a ∈ xs := by
|
||||
rw [← min?_toList] at h
|
||||
simpa using List.min?_mem h
|
||||
|
||||
public theorem le_min?_iff [Min α] [LE α] [Std.LawfulOrderInf α] :
|
||||
{xs : Array α} → xs.min? = some a → ∀ {x}, x ≤ a ↔ ∀ b, b ∈ xs → x ≤ b := by
|
||||
intro xs h x
|
||||
simp only [← min?_toList] at h
|
||||
simpa using List.le_min?_iff h
|
||||
|
||||
public theorem min?_eq_some_iff [Min α] [LE α] {xs : Array α} [Std.IsLinearOrder α]
|
||||
[Std.LawfulOrderMin α] : xs.min? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
rcases xs with ⟨l⟩
|
||||
simpa using List.min?_eq_some_iff
|
||||
|
||||
public theorem min?_replicate [Min α] [Std.IdempotentOp (min : α → α → α)] {n : Nat} {a : α} :
|
||||
(replicate n a).min? = if n = 0 then none else some a := by
|
||||
rw [← List.toArray_replicate, List.min?_toArray, List.min?_replicate]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_replicate_of_pos [Min α] [Std.MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).min? = some a := by
|
||||
simp [min?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
public theorem foldl_min [Min α] [Std.IdempotentOp (min : α → α → α)]
|
||||
[Std.Associative (min : α → α → α)] {xs : Array α} {a : α} :
|
||||
xs.foldl (init := a) min = min a (xs.min?.getD a) := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.foldl_min]
|
||||
|
||||
/-! ### Lemmas about `max?` -/
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_empty [Max α] : (#[] : Array α).max? = none :=
|
||||
(rfl)
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_singleton [Max α] {x : α} : #[x].max? = some x :=
|
||||
(rfl)
|
||||
|
||||
-- We don't put `@[simp]` on `max?_singleton_append'`,
|
||||
-- because the definition in terms of `foldl` is not useful for proofs.
|
||||
public theorem max?_singleton_append' [Max α] {xs : Array α} : (#[x] ++ xs).max? = some (xs.foldl max x) := by
|
||||
simp [← max?_toList, toList_append, List.max?]
|
||||
|
||||
@[simp]
|
||||
public theorem max?_singleton_append [Max α] [Std.Associative (max : α → α → α)] {xs : Array α} :
|
||||
(#[x] ++ xs).max? = some (xs.max?.elim x (max x)) := by
|
||||
simp [← max?_toList, toList_append, List.max?_cons]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_eq_none_iff {xs : Array α} [Max α] : xs.max? = none ↔ xs = #[] := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem isSome_max?_iff {xs : Array α} [Max α] : xs.max?.isSome ↔ xs ≠ #[] := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[grind .]
|
||||
public theorem isSome_max?_of_mem {xs : Array α} [Max α] {a : α} (h : a ∈ xs) :
|
||||
xs.max?.isSome := by
|
||||
rw [← max?_toList]
|
||||
apply List.isSome_max?_of_mem (a := a)
|
||||
simpa
|
||||
|
||||
public theorem isSome_max?_of_ne_empty [Max α] (xs : Array α) (h : xs ≠ #[]) : xs.max?.isSome := by
|
||||
rw [← max?_toList]
|
||||
apply List.isSome_max?_of_ne_nil
|
||||
simpa
|
||||
|
||||
public theorem max?_mem [Max α] [Std.MaxEqOr α] (xs : Array α) (h : xs.max? = some a) : a ∈ xs := by
|
||||
rw [← max?_toList] at h
|
||||
simpa using List.max?_mem h
|
||||
|
||||
public theorem max?_le_iff [Max α] [LE α] [Std.LawfulOrderSup α] :
|
||||
{xs : Array α} → xs.max? = some a → ∀ {x}, a ≤ x ↔ ∀ b, b ∈ xs → b ≤ x := by
|
||||
intro xs h x
|
||||
simp only [← max?_toList] at h
|
||||
simpa using List.max?_le_iff h
|
||||
|
||||
public theorem max?_eq_some_iff [Max α] [LE α] {xs : Array α} [Std.IsLinearOrder α]
|
||||
[Std.LawfulOrderMax α] : xs.max? = some a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
rcases xs with ⟨l⟩
|
||||
simpa using List.max?_eq_some_iff
|
||||
|
||||
public theorem max?_replicate [Max α] [Std.IdempotentOp (max : α → α → α)] {n : Nat} {a : α} :
|
||||
(replicate n a).max? = if n = 0 then none else some a := by
|
||||
rw [← List.toArray_replicate, List.max?_toArray, List.max?_replicate]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_replicate_of_pos [Max α] [Std.MaxEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).max? = some a := by
|
||||
simp [max?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
public theorem foldl_max [Max α] [Std.IdempotentOp (max : α → α → α)] [Std.Associative (max : α → α → α)]
|
||||
{xs : Array α} {a : α} : xs.foldl (init := a) max = max a (xs.max?.getD a) := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.foldl_max]
|
||||
|
||||
/-! ### Lemmas about `min` -/
|
||||
|
||||
@[simp, grind =]
|
||||
theorem min_singleton [Min α] {x : α} :
|
||||
#[x].min (ne_empty_of_size_eq_add_one rfl) = x := by
|
||||
(rfl)
|
||||
|
||||
public theorem min?_eq_some_min [Min α] : {xs : Array α} → (h : xs ≠ #[]) →
|
||||
xs.min? = some (xs.min h)
|
||||
| ⟨a::as⟩, _ => by simp [Array.min, Array.min?]
|
||||
|
||||
public theorem min_eq_get_min? [Min α] : (xs : Array α) → (h : xs ≠ #[]) →
|
||||
xs.min h = xs.min?.get (xs.isSome_min?_of_ne_empty h)
|
||||
| ⟨a::as⟩, _ => by simp [Array.min, Array.min?]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem get_min? [Min α] {xs : Array α} {h : xs.min?.isSome} :
|
||||
xs.min?.get h = xs.min (isSome_min?_iff.mp h) := by
|
||||
simp [min?_eq_some_min (isSome_min?_iff.mp h)]
|
||||
|
||||
@[grind .]
|
||||
public theorem min_mem [Min α] [Std.MinEqOr α] {xs : Array α} (h : xs ≠ #[]) : xs.min h ∈ xs :=
|
||||
xs.min?_mem (min?_eq_some_min h)
|
||||
|
||||
@[grind .]
|
||||
public theorem min_le_of_mem [Min α] [LE α] [Std.IsLinearOrder α] [Std.LawfulOrderMin α]
|
||||
{xs : Array α} {a : α} (ha : a ∈ xs) :
|
||||
xs.min (ne_empty_of_mem ha) ≤ a :=
|
||||
(Array.min?_eq_some_iff.mp (min?_eq_some_min (ne_empty_of_mem ha))).right a ha
|
||||
|
||||
public protected theorem le_min_iff [Min α] [LE α] [Std.LawfulOrderInf α]
|
||||
{xs : Array α} (h : xs ≠ #[]) : ∀ {x}, x ≤ xs.min h ↔ ∀ b, b ∈ xs → x ≤ b :=
|
||||
le_min?_iff (min?_eq_some_min h)
|
||||
|
||||
public theorem min_eq_iff [Min α] [LE α] {xs : Array α} [Std.IsLinearOrder α] [Std.LawfulOrderMin α]
|
||||
(h : xs ≠ #[]) : xs.min h = a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → a ≤ b := by
|
||||
simpa [min?_eq_some_min h] using (min?_eq_some_iff (xs := xs))
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min_replicate [Min α] [Std.MinEqOr α] {n : Nat} {a : α} (h : (replicate n a) ≠ #[]) :
|
||||
(replicate n a).min h = a := by
|
||||
have n_pos : 0 < n := by simpa [Nat.ne_zero_iff_zero_lt] using h
|
||||
simpa [min?_eq_some_min h] using (min?_replicate_of_pos (a := a) n_pos)
|
||||
|
||||
public theorem foldl_min_eq_min [Min α] [Std.IdempotentOp (min : α → α → α)]
|
||||
[Std.Associative (min : α → α → α)] {xs : Array α} (h : xs ≠ #[]) {a : α} :
|
||||
xs.foldl min a = min a (xs.min h) := by
|
||||
simpa [min?_eq_some_min h] using foldl_min (xs := xs)
|
||||
|
||||
/-! ### Lemmas about `max` -/
|
||||
|
||||
@[simp, grind =]
|
||||
theorem max_singleton [Max α] {x : α} :
|
||||
#[x].max (ne_empty_of_size_eq_add_one rfl) = x := by
|
||||
(rfl)
|
||||
|
||||
public theorem max?_eq_some_max [Max α] : {xs : Array α} → (h : xs ≠ #[]) →
|
||||
xs.max? = some (xs.max h)
|
||||
| ⟨a::as⟩, _ => by simp [Array.max, Array.max?]
|
||||
|
||||
public theorem max_eq_get_max? [Max α] : (xs : Array α) → (h : xs ≠ #[]) →
|
||||
xs.max h = xs.max?.get (xs.isSome_max?_of_ne_empty h)
|
||||
| ⟨a::as⟩, _ => by simp [Array.max, Array.max?]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem get_max? [Max α] {xs : Array α} {h : xs.max?.isSome} :
|
||||
xs.max?.get h = xs.max (isSome_max?_iff.mp h) := by
|
||||
simp [max?_eq_some_max (isSome_max?_iff.mp h)]
|
||||
|
||||
@[grind .]
|
||||
public theorem max_mem [Max α] [Std.MaxEqOr α] {xs : Array α} (h : xs ≠ #[]) : xs.max h ∈ xs :=
|
||||
xs.max?_mem (max?_eq_some_max h)
|
||||
|
||||
public protected theorem max_le_iff [Max α] [LE α] [Std.LawfulOrderSup α]
|
||||
{xs : Array α} (h : xs ≠ #[]) : ∀ {x}, xs.max h ≤ x ↔ ∀ b, b ∈ xs → b ≤ x :=
|
||||
max?_le_iff (max?_eq_some_max h)
|
||||
|
||||
public theorem max_eq_iff [Max α] [LE α] {xs : Array α} [Std.IsLinearOrder α] [Std.LawfulOrderMax α]
|
||||
(h : xs ≠ #[]) : xs.max h = a ↔ a ∈ xs ∧ ∀ b, b ∈ xs → b ≤ a := by
|
||||
simpa [max?_eq_some_max h] using (max?_eq_some_iff (xs := xs))
|
||||
|
||||
@[grind .]
|
||||
public theorem le_max_of_mem [Max α] [LE α] [Std.IsLinearOrder α] [Std.LawfulOrderMax α]
|
||||
{xs : Array α} {a : α} (ha : a ∈ xs) :
|
||||
a ≤ xs.max (ne_empty_of_mem ha) :=
|
||||
(Array.max?_eq_some_iff.mp (max?_eq_some_max (ne_empty_of_mem ha))).right a ha
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max_replicate [Max α] [Std.MaxEqOr α] {n : Nat} {a : α} (h : (replicate n a) ≠ #[]) :
|
||||
(replicate n a).max h = a := by
|
||||
have n_pos : 0 < n := by simpa [Nat.ne_zero_iff_zero_lt] using h
|
||||
simpa [max?_eq_some_max h] using (max?_replicate_of_pos (a := a) n_pos)
|
||||
|
||||
public theorem foldl_max_eq_max [Max α] [Std.IdempotentOp (max : α → α → α)]
|
||||
[Std.Associative (max : α → α → α)] {xs : Array α} (h : xs ≠ #[]) {a : α} :
|
||||
xs.foldl max a = max a (xs.max h) := by
|
||||
simpa [max?_eq_some_max h] using foldl_max (xs := xs)
|
||||
|
||||
end Array
|
||||
@@ -1,39 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Sebastian Graf, Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.Sum
|
||||
|
||||
public section
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Array
|
||||
|
||||
protected theorem sum_pos_iff_exists_pos_nat {xs : Array Nat} : 0 < xs.sum ↔ ∃ x ∈ xs, 0 < x := by
|
||||
simp [← sum_toList, List.sum_pos_iff_exists_pos_nat]
|
||||
|
||||
protected theorem sum_eq_zero_iff_forall_eq_nat {xs : Array Nat} :
|
||||
xs.sum = 0 ↔ ∀ x ∈ xs, x = 0 := by
|
||||
simp [← sum_toList, List.sum_eq_zero_iff_forall_eq_nat]
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
rw [← List.toArray_replicate, List.sum_toArray]
|
||||
simp
|
||||
|
||||
theorem sum_append_nat {as₁ as₂ : Array Nat} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
simp [sum_append]
|
||||
|
||||
theorem sum_reverse_nat (xs : Array Nat) : xs.reverse.sum = xs.sum := by
|
||||
simp [sum_reverse]
|
||||
|
||||
theorem sum_eq_foldl_nat {xs : Array Nat} : xs.sum = xs.foldl (init := 0) (· + ·) := by
|
||||
simp only [foldl_eq_foldr_reverse, Nat.add_comm, ← sum_eq_foldr, sum_reverse_nat]
|
||||
|
||||
end Array
|
||||
@@ -53,11 +53,6 @@ theorem ofFn_succ' {f : Fin (n+1) → α} :
|
||||
apply Array.toList_inj.mp
|
||||
simp [List.ofFn_succ]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_getElem {xs : Array α} :
|
||||
Array.ofFn (fun i : Fin xs.size => xs[i.val]) = xs := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
|
||||
rw [← Array.toList_inj]
|
||||
@@ -72,12 +67,6 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem map_ofFn {f : Fin n → α} {g : α → β} :
|
||||
(Array.ofFn f).map g = Array.ofFn (g ∘ f) := by
|
||||
apply Array.ext_getElem?
|
||||
simp [Array.getElem?_ofFn]
|
||||
|
||||
/-! ### ofFnM -/
|
||||
|
||||
/-- Construct (in a monadic context) an array by applying a monadic function to each index. -/
|
||||
|
||||
@@ -636,7 +636,7 @@ def boolPredToPred : Coe (α → Bool) (α → Prop) where
|
||||
This should not be turned on globally as an instance because it degrades performance in Mathlib,
|
||||
but may be used locally.
|
||||
-/
|
||||
@[expose, instance_reducible] def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
@[expose] def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
coe r := fun a b => Eq (r a b) true
|
||||
|
||||
/-! ### subtypes -/
|
||||
|
||||
@@ -286,21 +286,4 @@ theorem extract_zero_max_size {a : ByteArray} {i : Nat} : a.extract 0 (max i a.s
|
||||
ext1
|
||||
simp [Nat.le_max_right]
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_left {ws xs ys zs : ByteArray} (h : ws.size = xs.size) :
|
||||
ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
simpa [ByteArray.ext_iff] using Array.append_eq_append_iff_of_size_eq_left h
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_right {ws xs ys zs : ByteArray} (h : ys.size = zs.size) :
|
||||
ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
simpa [ByteArray.ext_iff] using Array.append_eq_append_iff_of_size_eq_right h
|
||||
|
||||
@[simp]
|
||||
theorem size_push {bs : ByteArray} {b : UInt8} : (bs.push b).size = bs.size + 1 := by
|
||||
rw [ByteArray.size, data_push, Array.size_push, ← ByteArray.size]
|
||||
|
||||
theorem ext_getElem {a b : ByteArray} (h₀ : a.size = b.size) (h : ∀ (i : Nat) hi hi', a[i]'hi = b[i]'hi') : a = b := by
|
||||
rw [ByteArray.ext_iff]
|
||||
apply Array.ext (by simpa using h₀)
|
||||
simpa [← ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
end ByteArray
|
||||
|
||||
@@ -48,7 +48,6 @@ instance ltTrans : Trans (· < · : Char → Char → Prop) (· < ·) (· < ·)
|
||||
trans := Char.lt_trans
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
@[instance_reducible]
|
||||
def notLTTrans : Trans (¬ · < · : Char → Char → Prop) (¬ · < ·) (¬ · < ·) where
|
||||
trans h₁ h₂ := by simpa using Char.le_trans (by simpa using h₂) (by simpa using h₁)
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ public import Init.Grind.Ordered.Ring
|
||||
|
||||
/-! # Internal `grind` algebra instances for `Dyadic`. -/
|
||||
|
||||
@[expose] public section
|
||||
|
||||
open Lean.Grind
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
@@ -4,9 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
import Init.Data.Dyadic.Round
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
@@ -14,8 +12,6 @@ import Init.Grind.Ordered.Ring
|
||||
# Inversion for dyadic numbers
|
||||
-/
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
import Init.Data.Dyadic.Instances
|
||||
import all Init.Data.Dyadic.Instances
|
||||
import Init.Grind.Ordered.Rat
|
||||
import Init.Grind.Ordered.Field
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
natCast a := Fin.ofNat n a
|
||||
|
||||
@@ -140,7 +140,7 @@ This is not a global instance, but may be activated locally via `open Fin.IntCas
|
||||
|
||||
See the doc-string for `Fin.NatCast.instNatCast` for more details.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose]
|
||||
def instIntCast (n : Nat) [NeZero n] : IntCast (Fin n) where
|
||||
intCast := Fin.intCast
|
||||
|
||||
|
||||
@@ -1153,15 +1153,6 @@ theorem ediv_le_iff_le_mul {k x y : Int} (h : 0 < k) : x / k ≤ y ↔ x < y * k
|
||||
rw [Int.le_iff_lt_add_one, Int.ediv_lt_iff_lt_mul h, Int.add_mul]
|
||||
omega
|
||||
|
||||
theorem le_mul_iff_le_left {x y z : Int} (hz : 0 < z) :
|
||||
x ≤ y * z ↔ (x + z - 1) / z ≤ y := by
|
||||
rw [Int.ediv_le_iff_le_mul hz]
|
||||
omega
|
||||
|
||||
theorem le_mul_iff_le_right {x y z : Int} (hy : 0 < y) :
|
||||
x ≤ y * z ↔ (x + y - 1) / y ≤ z := by
|
||||
rw [← le_mul_iff_le_left hy, Int.mul_comm]
|
||||
|
||||
protected theorem le_mul_of_ediv_le {a b c : Int} (H1 : 0 ≤ b) (H2 : b ∣ a) (H3 : a / b ≤ c) :
|
||||
a ≤ c * b := by
|
||||
rw [← Int.ediv_mul_cancel H2]; exact Int.mul_le_mul_of_nonneg_right H3 H1
|
||||
@@ -1215,11 +1206,6 @@ theorem add_ediv {a b c : Int} (h : c ≠ 0) :
|
||||
protected theorem ediv_le_ediv {a b c : Int} (H : 0 < c) (H' : a ≤ b) : a / c ≤ b / c :=
|
||||
Int.le_ediv_of_mul_le H (Int.le_trans (Int.ediv_mul_le _ (Int.ne_of_gt H)) H')
|
||||
|
||||
theorem ediv_add_ediv_le_add_ediv {x y z : Int} (hz : 0 < z) :
|
||||
x / z + y / z ≤ (x + y) / z := by
|
||||
rw [Int.le_ediv_iff_mul_le hz, Int.add_mul]
|
||||
apply Int.add_le_add <;> apply Int.ediv_mul_le <;> omega
|
||||
|
||||
/-- If `n > 0` then `m` is not divisible by `n` iff it is between `n * k` and `n * (k + 1)`
|
||||
for some `k`. -/
|
||||
theorem not_dvd_iff_lt_mul_succ (m : Int) (hn : 0 < n) :
|
||||
@@ -1797,12 +1783,12 @@ theorem ediv_lt_ediv_iff_of_dvd_of_neg_of_neg {a b c d : Int} (hb : b < 0) (hd :
|
||||
|
||||
theorem ediv_lt_ediv_of_lt {a b c : Int} (h : a < b) (hcb : c ∣ b) (hc : 0 < c) :
|
||||
a / c < b / c :=
|
||||
Int.lt_ediv_of_mul_lt (Int.le_of_lt hc) hcb
|
||||
Int.lt_ediv_of_mul_lt (Int.le_of_lt hc) hcb
|
||||
(Int.lt_of_le_of_lt (Int.ediv_mul_le _ (Int.ne_of_gt hc)) h)
|
||||
|
||||
|
||||
theorem ediv_lt_ediv_of_lt_of_neg {a b c : Int} (h : b < a) (hca : c ∣ a) (hc : c < 0) :
|
||||
a / c < b / c :=
|
||||
(Int.ediv_lt_iff_of_dvd_of_neg hc hca).2
|
||||
(Int.ediv_lt_iff_of_dvd_of_neg hc hca).2
|
||||
(Int.lt_of_le_of_lt (Int.mul_ediv_self_le (Int.ne_of_lt hc)) h)
|
||||
|
||||
/-! ### `tdiv` and ordering -/
|
||||
|
||||
@@ -1447,12 +1447,4 @@ instance : LawfulOrderLT Int where
|
||||
lt_iff := by
|
||||
simp [← Int.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
instance : LawfulOrderLeftLeaningMin Int where
|
||||
min_eq_left _ _ := Int.min_eq_left
|
||||
min_eq_right _ _ h := Int.min_eq_right (le_of_lt (not_le.1 h))
|
||||
|
||||
instance : LawfulOrderLeftLeaningMax Int where
|
||||
max_eq_left _ _ := Int.max_eq_left
|
||||
max_eq_right _ _ h := Int.max_eq_right (le_of_lt (not_le.1 h))
|
||||
|
||||
end Int
|
||||
|
||||
@@ -94,9 +94,8 @@ By convention, the monadic iterator associated with an object can be obtained vi
|
||||
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
|
||||
|
||||
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
convert an iterator `it` into a list and `it.ensureTermination.toList` guarantees that this
|
||||
operation will terminate, given a proof that the iterator is finite.
|
||||
It is also always possible to manually iterate using
|
||||
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
|
||||
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
|
||||
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
|
||||
See `Iter` for a more convenient interface in case that no monadic effects are needed (`m = Id`).
|
||||
@@ -140,9 +139,8 @@ By convention, the monadic iterator associated with an object can be obtained vi
|
||||
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
|
||||
|
||||
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
convert an iterator `it` into a list and `it.ensureTermination.toList` guarantees that this
|
||||
operation will terminate, given a proof that the iterator is finite.
|
||||
It is also always possible to manually iterate using
|
||||
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
|
||||
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
|
||||
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
|
||||
See `IterM` for iterators that operate in a monad.
|
||||
@@ -756,8 +754,8 @@ def IterM.finitelyManySteps {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
Termination measure to be used in recursive functions built with `WellFounded.extrinsicFix`
|
||||
recursing over a finite iterator without requiring a proof of finiteness (see also `Finite`).
|
||||
Termination measure to be used in well-founded recursive functions recursing over a finite iterator
|
||||
(see also `Finite`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySteps! {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
@@ -798,11 +796,6 @@ def Iter.finitelyManySteps {α : Type w} {β : Type w} [Iterator α Id β] [Iter
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
|
||||
it.toIterM.finitelyManySteps
|
||||
|
||||
@[inherit_doc IterM.finitelyManySteps!, expose]
|
||||
def Iter.finitelyManySteps! {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
|
||||
it.toIterM.finitelyManySteps!
|
||||
|
||||
/--
|
||||
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
|
||||
with `IterM.finitelyManySteps`.
|
||||
@@ -909,16 +902,6 @@ def IterM.finitelyManySkips {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterators.Productive α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
Termination measure to be used in recursive functions built with `WellFounded.extrinsicFix`
|
||||
recursing over a productive iterator without requiring a proof of productiveness
|
||||
(see also `Productive`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySkips! {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
|
||||
with `IterM.finitelyManySkips`.
|
||||
@@ -939,11 +922,6 @@ def Iter.finitelyManySkips {α : Type w} {β : Type w} [Iterator α Id β] [Iter
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
|
||||
it.toIterM.finitelyManySkips
|
||||
|
||||
@[inherit_doc IterM.finitelyManySkips!, expose]
|
||||
def Iter.finitelyManySkips! {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
|
||||
it.toIterM.finitelyManySkips!
|
||||
|
||||
/--
|
||||
This theorem is used by a `decreasing_trivial` extension. It powers automatic termination proofs
|
||||
with `Iter.finitelyManySkips`.
|
||||
|
||||
@@ -21,70 +21,21 @@ If possible, takes `n` steps with the iterator `it` and
|
||||
returns the `n`-th emitted value, or `none` if `it` finished
|
||||
before emitting `n` values.
|
||||
|
||||
If the iterator is not productive, this function might run forever in an endless loop of iterator
|
||||
steps. The variant `it.ensureTermination.atIdxSlow?` is guaranteed to terminate after finitely many
|
||||
steps.
|
||||
This function requires a `Productive` instance proving that the iterator will always emit a value
|
||||
after a finite number of skips. If the iterator is not productive or such an instance is not
|
||||
available, consider using `it.allowNontermination.atIdxSlow?` instead of `it.atIdxSlow?`. However,
|
||||
it is not possible to formally verify the behavior of the partial variant.
|
||||
-/
|
||||
@[specialize]
|
||||
def Iter.atIdxSlow? {α β} [Iterator α Id β]
|
||||
def Iter.atIdxSlow? {α β} [Iterator α Id β] [Productive α Id]
|
||||
(n : Nat) (it : Iter (α := α) β) : Option β :=
|
||||
WellFounded.extrinsicFix₂ (C₂ := fun _ _ => Option β) (α := Iter (α := α) β) (β := fun _ => Nat)
|
||||
(InvImage
|
||||
(Prod.Lex WellFoundedRelation.rel IterM.TerminationMeasures.Productive.Rel)
|
||||
(fun p => (p.2, p.1.finitelyManySkips!)))
|
||||
(fun it n recur =>
|
||||
match it.step with
|
||||
| .yield it' out _ =>
|
||||
match n with
|
||||
| 0 => some out
|
||||
| k + 1 => recur it' k (by decreasing_tactic)
|
||||
| .skip it' _ => recur it' n (by decreasing_tactic)
|
||||
| .done _ => none) it n
|
||||
|
||||
-- We provide the functional induction principle by hand because `atIdxSlow?` is implemented using
|
||||
-- `extrinsicFix₂` and not using well-founded recursion.
|
||||
/-
|
||||
An induction principle for `Iter.atIdxSlow?`.
|
||||
|
||||
This lemma provides a functional induction principle for reasoning about `Iter.atIdxSlow? n it`.
|
||||
|
||||
The induction follows the structure of iterator steps.
|
||||
- base case: when we reach the desired index (`n = 0`) and get a `.yield` step
|
||||
- inductive case: when we have a `.yield` step but need to continue (`n > 0`)
|
||||
- skip case: when we encounter a `.skip` step and continue with the same index
|
||||
- done case: when the iterator is exhausted and we return `none`
|
||||
-/
|
||||
theorem Iter.atIdxSlow?.induct_unfolding {α β : Type u} [Iterator α Id β] [Productive α Id]
|
||||
(motive : Nat → Iter β → Option β → Prop)
|
||||
-- Base case: we have reached index 0 and found a value
|
||||
(yield_zero : ∀ (it it' : Iter (α := α) β) (out : β) (property : it.IsPlausibleStep (IterStep.yield it' out)),
|
||||
it.step = ⟨IterStep.yield it' out, property⟩ → motive 0 it (some out))
|
||||
-- Inductive case: we have a yield but need to continue to a higher index
|
||||
(yield_succ : ∀ (it it' : Iter (α := α) β) (out : β) (property : it.IsPlausibleStep (IterStep.yield it' out)),
|
||||
it.step = ⟨IterStep.yield it' out, property⟩ →
|
||||
∀ (k : Nat), motive k it' (Iter.atIdxSlow? k it') → motive k.succ it (Iter.atIdxSlow? k it'))
|
||||
-- Skip case: we encounter a skip and continue with the same index
|
||||
(skip_case : ∀ (n : Nat) (it it' : Iter β) (property : it.IsPlausibleStep (IterStep.skip it')),
|
||||
it.step = ⟨IterStep.skip it', property⟩ →
|
||||
motive n it' (Iter.atIdxSlow? n it') → motive n it (Iter.atIdxSlow? n it'))
|
||||
-- Done case: the iterator is exhausted, return none
|
||||
(done_case : ∀ (n : Nat) (it : Iter β) (property : it.IsPlausibleStep IterStep.done),
|
||||
it.step = ⟨IterStep.done, property⟩ → motive n it none)
|
||||
-- The conclusion: the property holds for all indices and iterators
|
||||
(n : Nat) (it : Iter β) : motive n it (Iter.atIdxSlow? n it) := by
|
||||
simp only [atIdxSlow?] at *
|
||||
rw [WellFounded.extrinsicFix₂_eq_apply]
|
||||
· split
|
||||
· split
|
||||
· apply yield_zero <;> assumption
|
||||
· apply yield_succ
|
||||
all_goals try assumption
|
||||
apply Iter.atIdxSlow?.induct_unfolding <;> assumption
|
||||
· apply skip_case
|
||||
all_goals try assumption
|
||||
apply Iter.atIdxSlow?.induct_unfolding <;> assumption
|
||||
· apply done_case <;> assumption
|
||||
· exact InvImage.wf _ WellFoundedRelation.wf
|
||||
match it.step with
|
||||
| .yield it' out _ =>
|
||||
match n with
|
||||
| 0 => some out
|
||||
| k + 1 => it'.atIdxSlow? k
|
||||
| .skip it' _ => it'.atIdxSlow? n
|
||||
| .done _ => none
|
||||
termination_by (n, it.finitelyManySkips)
|
||||
|
||||
/--
|
||||
@@ -92,21 +43,22 @@ If possible, takes `n` steps with the iterator `it` and
|
||||
returns the `n`-th emitted value, or `none` if `it` finished
|
||||
before emitting `n` values.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
productive. If such a proof is not available, consider using `Iter.toArray`.
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Productive` instance, consider using `Iter.atIdxSlow?` instead.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.atIdxSlow? {α β} [Iterator α Id β] [Productive α Id]
|
||||
(n : Nat) (it : Iter.Total (α := α) β) : Option β :=
|
||||
it.it.atIdxSlow? n
|
||||
|
||||
@[inline, inherit_doc Iter.atIdxSlow?, deprecated Iter.atIdxSlow? (since := "2026-01-28")]
|
||||
def Iter.Partial.atIdxSlow? {α β} [Iterator α Id β]
|
||||
(n : Nat) (it : Iter.Partial (α := α) β) : Option β :=
|
||||
it.it.atIdxSlow? n
|
||||
@[specialize]
|
||||
partial def Iter.Partial.atIdxSlow? {α β} [Iterator α Id β] [Monad Id]
|
||||
(n : Nat) (it : Iter.Partial (α := α) β) : Option β := do
|
||||
match it.it.step with
|
||||
| .yield it' out _ =>
|
||||
match n with
|
||||
| 0 => some out
|
||||
| k + 1 => (⟨it'⟩ : Iter.Partial (α := α) β).atIdxSlow? k
|
||||
| .skip it' _ => (⟨it'⟩ : Iter.Partial (α := α) β).atIdxSlow? n
|
||||
| .done _ => none
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.atIdx?]
|
||||
def Iter.atIdx? {α β} [Iterator α Id β] [IteratorAccess α Id]
|
||||
def Iter.atIdx? {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id]
|
||||
(n : Nat) (it : Iter (α := α) β) : Option β :=
|
||||
match (IteratorAccess.nextAtIdx? it.toIterM n).run.val with
|
||||
| .yield _ out => some out
|
||||
|
||||
@@ -630,79 +630,6 @@ def Iter.Total.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id
|
||||
(it : Iter.Total (α := α) β) (f : β → Bool) : Option β :=
|
||||
it.it.find? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator, or `none` if no such output is found.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of `it` is examined.
|
||||
|
||||
If the iterator is not productive, this function might run forever. The variant
|
||||
`it.ensureTermination.first?` always terminates after finitely many steps.
|
||||
|
||||
Examples:
|
||||
* `[7, 6].iter.first? = some 7`
|
||||
* `[].iter.first? = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.first? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Option β :=
|
||||
it.toIterM.first?.run
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator, or `none` if no such output is found.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. The elements in `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
productive. If such a proof is not available, consider using `Iter.first?`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6].iter.first? = some 7`
|
||||
* `[].iter.first? = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.first? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id] [Productive α Id]
|
||||
(it : Iter.Total (α := α) β) : Option β :=
|
||||
it.it.first?
|
||||
|
||||
/--
|
||||
Returns `true` if the iterator yields no values.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of `it` is examined.
|
||||
|
||||
If the iterator is not productive, this function might run forever. The variant
|
||||
`it.ensureTermination.isEmpty` always terminates after finitely many steps.
|
||||
|
||||
Examples:
|
||||
* `[].iter.isEmpty = true`
|
||||
* `[1].iter.isEmpty = false`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.isEmpty {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Bool :=
|
||||
it.toIterM.isEmpty.run.down
|
||||
|
||||
/--
|
||||
Returns `true` if the iterator yields no values.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of `it` is examined.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
productive. If such a proof is not available, consider using `Iter.isEmpty`.
|
||||
|
||||
Examples:
|
||||
* `[].iter.isEmpty = true`
|
||||
* `[1].iter.isEmpty = false`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.isEmpty {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id] [Productive α Id]
|
||||
(it : Iter.Total (α := α) β) : Bool :=
|
||||
it.it.isEmpty
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
@@ -711,15 +638,9 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.length {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.toIterM.length.run.down
|
||||
|
||||
@[inline, inherit_doc Iter.length, deprecated Iter.length (since := "2026-01-28"), expose]
|
||||
def Iter.count := @Iter.length
|
||||
|
||||
@[inline, inherit_doc Iter.length, deprecated Iter.length (since := "2025-10-29"), expose]
|
||||
def Iter.size := @Iter.length
|
||||
it.toIterM.count.run.down
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
@@ -728,10 +649,22 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.length (since := "2025-12-04")]
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.count
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-12-04")]
|
||||
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.it.toIterM.length.run.down
|
||||
it.it.toIterM.count.run.down
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
@@ -740,9 +673,9 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.length (since := "2025-10-29")]
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.it.length
|
||||
it.it.count
|
||||
|
||||
end Std
|
||||
|
||||
@@ -185,8 +185,8 @@ instance instLawfulIteratorLoopDefaultImplementation (α : Type w) (m : Type w
|
||||
constructor; simp
|
||||
|
||||
theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
|
||||
{α β : Type w} {γ : Type x} [Iterator α m β] [Finite α m] {P : β → γ → ForInStep γ → Prop} :
|
||||
WellFounded α m (γ := γ) P := by
|
||||
{α β : Type w} {γ : Type x} [Iterator α m β] [Finite α m] :
|
||||
WellFounded α m (γ := γ) fun _ _ _ => True := by
|
||||
apply Subrelation.wf
|
||||
(r := InvImage IterM.TerminationMeasures.Finite.Rel (fun p => p.1.finitelyManySteps))
|
||||
· intro p' p h
|
||||
@@ -197,16 +197,6 @@ theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
|
||||
· apply InvImage.wf
|
||||
exact WellFoundedRelation.wf
|
||||
|
||||
theorem IteratorLoop.wellFounded_of_productive {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β] [IteratorLoop α m m] [Productive α m] {P : β → γ → ForInStep γ → Prop}
|
||||
(hp : ∀ {b g s}, P b g s → s matches ForInStep.done ..) :
|
||||
WellFounded α m (γ := γ) P := by
|
||||
rw [WellFounded]
|
||||
unfold IteratorLoop.rel
|
||||
have {b g q} : ¬ P b g (ForInStep.yield q) := fun h => by simpa using hp h
|
||||
simp only [and_false, exists_false, false_or, this]
|
||||
exact Subrelation.wf And.left (InvImage.wf Prod.fst Productive.wf)
|
||||
|
||||
/--
|
||||
This `ForIn'`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
|
||||
-/
|
||||
@@ -912,76 +902,6 @@ def IterM.Total.find? {α β : Type w} {m : Type w → Type w'} [Monad m] [Itera
|
||||
m (Option β) :=
|
||||
it.it.find? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator, or `none` if no such output is found.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of `it` is examined.
|
||||
|
||||
If the iterator is not productive, this function might run forever. The variant
|
||||
`it.ensureTermination.first?` always terminates after finitely many steps.
|
||||
|
||||
Examples:
|
||||
* `([7, 6].iterM Id).first? = pure (some 7)`
|
||||
* `([].iterM Id).first? = pure none`
|
||||
-/
|
||||
@[inline]
|
||||
def IterM.first? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] (it : IterM (α := α) m β) : m (Option β) :=
|
||||
IteratorLoop.forIn (fun _ _ => flip Bind.bind) _ (fun b _ s => s = ForInStep.done (some b)) it
|
||||
none (fun b _ _ => pure ⟨ForInStep.done (some b), rfl⟩)
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator, or `none` if no such output is found.
|
||||
|
||||
`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. The elements in `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
productive. If such a proof is not available, consider using `IterM.first?`.
|
||||
|
||||
Examples:
|
||||
* `([7, 6].iterM Id).first? = pure (some 7)`
|
||||
* `([].iterM Id).first? = pure none`
|
||||
-/
|
||||
@[inline]
|
||||
def IterM.Total.first? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Productive α m] (it : IterM.Total (α := α) m β) : m (Option β) :=
|
||||
it.it.first?
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`ULift.up true` if the iterator {name}`it` yields no values.
|
||||
|
||||
{lit}`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of {name}`it` is examined.
|
||||
|
||||
If the iterator is not productive, this function might run forever. The variant
|
||||
{lit}`it.ensureTermination.isEmpty` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline]
|
||||
def IterM.isEmpty {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] (it : IterM (α := α) m β) : m (ULift Bool) :=
|
||||
IteratorLoop.forIn (fun _ _ => flip Bind.bind) _ (fun _ _ s => s = ForInStep.done (.up false)) it
|
||||
(.up true) (fun _ _ _ => pure ⟨ForInStep.done (.up false), rfl⟩)
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`ULift.up true` if the iterator {name}`it` yields no values.
|
||||
|
||||
{lit}`O(|it|)` since the iterator may skip an unknown number of times before returning a result.
|
||||
Short-circuits upon encountering the first result. Only the first element of {name}`it` is examined.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using {name}`IterM.isEmpty`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.Total.isEmpty {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [Productive α m] (it : IterM.Total (α := α) m β) :
|
||||
m (ULift Bool) :=
|
||||
it.it.isEmpty
|
||||
|
||||
section Count
|
||||
|
||||
/--
|
||||
@@ -992,16 +912,10 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.length {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
def IterM.count {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoop α m m] [Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
|
||||
it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
|
||||
|
||||
@[inline, inherit_doc IterM.length, deprecated IterM.length (since := "2026-01-28"), expose]
|
||||
def IterM.count := @IterM.length
|
||||
|
||||
@[inline, inherit_doc IterM.length, deprecated IterM.length (since := "2025-10-29"), expose]
|
||||
def IterM.size := @IterM.length
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
@@ -1009,7 +923,19 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.length (since := "2025-12-04")]
|
||||
@[always_inline, inline, deprecated IterM.count (since := "2025-10-29")]
|
||||
def IterM.size {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoop α m m] [Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
|
||||
it.count
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.count (since := "2025-12-04")]
|
||||
def IterM.Partial.count {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoop α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
|
||||
it.it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
|
||||
@@ -1021,10 +947,10 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.length (since := "2025-10-29")]
|
||||
@[always_inline, inline, deprecated IterM.Partial.count (since := "2025-10-29")]
|
||||
def IterM.Partial.size {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoop α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
|
||||
it.it.length
|
||||
it.it.count
|
||||
|
||||
end Count
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ consumers such as `toList`. They can be used without any proof of termination su
|
||||
or `Productive`, but as they are implemented with the `partial` declaration modifier, they are
|
||||
opaque for the kernel and it is impossible to prove anything about them.
|
||||
-/
|
||||
@[always_inline, inline, deprecated "The consumers on iterators do not require proofs of termination anymore. For example, use `it.toList` instead of `it.allowNontermination.toList`." (since := "2026-01-28")]
|
||||
@[always_inline, inline]
|
||||
def IterM.allowNontermination {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
(it : IterM (α := α) m β) : IterM.Partial (α := α) m β :=
|
||||
⟨it⟩
|
||||
|
||||
@@ -29,7 +29,7 @@ consumers such as `toList`. They can be used without any proof of termination su
|
||||
or `Productive`, but as they are implemented with the `partial` declaration modifier, they are
|
||||
opaque for the kernel and it is impossible to prove anything about them.
|
||||
-/
|
||||
@[always_inline, inline, deprecated "The consumers on iterators do not require proofs of termination anymore. For example, use `it.toList` instead of `it.allowNontermination.toList`." (since := "2026-01-28")]
|
||||
@[always_inline, inline]
|
||||
def Iter.allowNontermination {α : Type w} {β : Type w}
|
||||
(it : Iter (α := α) β) : Iter.Partial (α := α) β :=
|
||||
⟨it⟩
|
||||
|
||||
@@ -111,11 +111,6 @@ instance {n : Type u → Type w} [Monad n] [LawfulMonad n] :
|
||||
liftBind_pure := by simp
|
||||
liftBind_bind := by simp
|
||||
|
||||
instance {m : Type u → Type v} [Monad m] [LawfulMonad m] :
|
||||
LawfulMonadLiftBindFunction (m := m) (n := m) (fun _ _ => flip Bind.bind) where
|
||||
liftBind_pure := by simp [flip]
|
||||
liftBind_bind := by simp [flip]
|
||||
|
||||
end LiftBind
|
||||
|
||||
end Std.Internal
|
||||
|
||||
@@ -79,15 +79,12 @@ theorem Iter.toArray_attachWith [Iterator α Id β]
|
||||
simp [Iter.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_attachWith [Iterator α Id β]
|
||||
theorem Iter.count_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
[LawfulIteratorLoop α Id Id] :
|
||||
(it.attachWith P hP).length = it.length := by
|
||||
rw [← Iter.length_toList_eq_length, toList_attachWith]
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
rw [← Iter.length_toList_eq_count, toList_attachWith]
|
||||
simp
|
||||
|
||||
@[deprecated Iter.length_attachWith (since := "2026-01-28")]
|
||||
def Iter.count_attachWith := @Iter.length_attachWith
|
||||
|
||||
end Std
|
||||
|
||||
@@ -722,14 +722,11 @@ end Fold
|
||||
section Count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_map {α β β' : Type w} [Iterator α Id β]
|
||||
theorem Iter.count_map {α β β' : Type w} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → β'} :
|
||||
(it.map f).length = it.length := by
|
||||
simp [map_eq_toIter_map_toIterM, length_eq_length_toIterM]
|
||||
|
||||
@[deprecated Iter.length_map (since := "2026-01-28")]
|
||||
def Iter.count_map := @Iter.length_map
|
||||
(it.map f).count = it.count := by
|
||||
simp [map_eq_toIter_map_toIterM, count_eq_count_toIterM]
|
||||
|
||||
end Count
|
||||
|
||||
|
||||
@@ -60,15 +60,12 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.length_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
theorem IterM.count_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorLoop α m m] [LawfulMonad m] [LawfulIteratorLoop α m m] :
|
||||
(it.attachWith P hP).length = it.length := by
|
||||
rw [← up_length_toList_eq_length, ← up_length_toList_eq_length,
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
rw [← up_length_toList_eq_count, ← up_length_toList_eq_count,
|
||||
← map_unattach_toList_attachWith (it := it) (P := P) (hP := hP)]
|
||||
simp only [Functor.map_map, List.length_unattach]
|
||||
|
||||
@[deprecated IterM.length_attachWith (since := "2026-01-28")]
|
||||
def IterM.count_attachWith := @IterM.length_attachWith
|
||||
|
||||
end Std
|
||||
|
||||
@@ -1620,21 +1620,18 @@ end Fold
|
||||
section Count
|
||||
|
||||
@[simp]
|
||||
theorem IterM.length_map {α β β' : Type w} {m : Type w → Type w'} [Iterator α m β] [Monad m]
|
||||
theorem IterM.count_map {α β β' : Type w} {m : Type w → Type w'} [Iterator α m β] [Monad m]
|
||||
[IteratorLoop α m m] [Finite α m] [LawfulMonad m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → β'} :
|
||||
(it.map f).length = it.length := by
|
||||
(it.map f).count = it.count := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [length_eq_match_step, length_eq_match_step, step_map, bind_assoc]
|
||||
rw [count_eq_match_step, count_eq_match_step, step_map, bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
@[deprecated IterM.length_map (since := "2026-01-28")]
|
||||
def IterM.count_map := @IterM.length_map
|
||||
|
||||
end Count
|
||||
|
||||
section AnyAll
|
||||
|
||||
@@ -66,14 +66,14 @@ theorem IterM.toArray_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.length_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
theorem IterM.count_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorLoop α m m]
|
||||
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorLoop α m m]
|
||||
[LawfulMonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).length =
|
||||
(.up ·.down.down) <$> (monadLift (n := ULiftT n) it.length).run := by
|
||||
(it.uLift n).count =
|
||||
(.up ·.down.down) <$> (monadLift (n := ULiftT n) it.count).run := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [length_eq_match_step, length_eq_match_step, monadLift_bind, map_eq_pure_bind, step_uLift]
|
||||
rw [count_eq_match_step, count_eq_match_step, monadLift_bind, map_eq_pure_bind, step_uLift]
|
||||
simp only [bind_assoc, ULiftT.run_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.down.inflate using PlausibleIterStep.casesOn
|
||||
@@ -81,7 +81,4 @@ theorem IterM.length_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
@[deprecated IterM.length_uLift (since := "2026-01-28")]
|
||||
def IterM.count_uLift := @IterM.length_uLift
|
||||
|
||||
end Std
|
||||
|
||||
@@ -47,18 +47,18 @@ theorem Iter.atIdxSlow?_take {α β}
|
||||
[Iterator α Id β] [Productive α Id] {k l : Nat}
|
||||
{it : Iter (α := α) β} :
|
||||
(it.take k).atIdxSlow? l = if l < k then it.atIdxSlow? l else none := by
|
||||
induction l, it using Iter.atIdxSlow?.induct_unfolding generalizing k
|
||||
case yield_zero it it' out h h' =>
|
||||
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
|
||||
fun_induction it.atIdxSlow? l generalizing k
|
||||
case case1 it it' out h h' =>
|
||||
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
|
||||
cases k <;> simp
|
||||
case yield_succ it it' out h h' l ih =>
|
||||
simp only [Nat.succ_eq_add_one, atIdxSlow?_eq_match (it := it.take k), step_take, h']
|
||||
case case2 it it' out h h' l ih =>
|
||||
simp only [Nat.succ_eq_add_one, atIdxSlow?.eq_def (it := it.take k), step_take, h']
|
||||
cases k <;> cases l <;> simp [ih]
|
||||
case skip_case l it it' h h' ih =>
|
||||
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
|
||||
case case3 l it it' h h' ih =>
|
||||
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
|
||||
cases k <;> cases l <;> simp [ih]
|
||||
case done_case l it h h' =>
|
||||
simp only [atIdxSlow?_eq_match (it := it.take k), step_take, h']
|
||||
case case4 l it h h' =>
|
||||
simp only [atIdxSlow?.eq_def (it := it.take k), step_take, h']
|
||||
cases k <;> cases l <;> simp
|
||||
|
||||
@[simp]
|
||||
|
||||
@@ -57,14 +57,11 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
simp [-toArray_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
theorem Iter.count_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] :
|
||||
it.uLift.length = it.length := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, length_eq_length_toIterM, toIterM_toIter]
|
||||
rw [IterM.length_uLift]
|
||||
it.uLift.count = it.count := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, count_eq_count_toIterM, toIterM_toIter]
|
||||
rw [IterM.count_uLift]
|
||||
simp [monadLift]
|
||||
|
||||
@[deprecated Iter.length_uLift (since := "2026-01-28")]
|
||||
def Iter.count_uLift := @Iter.length_uLift
|
||||
|
||||
end Std
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Consumers.Access
|
||||
import Init.Data.Iterators.Lemmas.Basic
|
||||
|
||||
namespace Std.Iter
|
||||
open Std.Iterators
|
||||
@@ -22,6 +21,6 @@ public theorem atIdxSlow?_eq_match [Iterator α Id β] [Productive α Id]
|
||||
| n + 1 => it'.atIdxSlow? n
|
||||
| .skip it' => it'.atIdxSlow? n
|
||||
| .done => none) := by
|
||||
induction n, it using Iter.atIdxSlow?.induct_unfolding <;> simp_all
|
||||
fun_induction it.atIdxSlow? n <;> simp_all
|
||||
|
||||
end Std.Iter
|
||||
|
||||
@@ -19,10 +19,6 @@ public section
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
@[simp]
|
||||
theorem IterM.run_toList_mk' {α : Type u} {β : Type u} [Std.Iterator α Id β] (a : α) :
|
||||
(Std.IterM.mk' (m := Id) a).toList.run = (Std.Iter.mk a).toList := rfl
|
||||
|
||||
theorem Iter.toArray_eq_toArray_toIterM {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.toIterM.toArray.run :=
|
||||
@@ -167,14 +163,12 @@ theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
|
||||
{it : Iter (α := α) β} {k : Nat} :
|
||||
it.toList[k]? = it.atIdxSlow? k := by
|
||||
induction it using Iter.inductSteps generalizing k with | step it ihy ihs
|
||||
rw [toList_eq_match_step, atIdxSlow?, WellFounded.extrinsicFix₂_eq_apply]
|
||||
· obtain ⟨step, h⟩ := it.step
|
||||
cases step
|
||||
· cases k <;> simp [ihy h, atIdxSlow?]
|
||||
· simp [ihs h, atIdxSlow?]
|
||||
· simp
|
||||
· apply InvImage.wf
|
||||
exact WellFoundedRelation.wf
|
||||
rw [toList_eq_match_step, atIdxSlow?]
|
||||
obtain ⟨step, h⟩ := it.step
|
||||
cases step
|
||||
· cases k <;> simp [ihy h]
|
||||
· simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_of_atIdxSlow?_eq {α₁ α₂ β}
|
||||
[Iterator α₁ Id β] [Finite α₁ Id]
|
||||
|
||||
@@ -460,90 +460,69 @@ theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [F
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
|
||||
theorem Iter.length_eq_length_toIterM {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.count_eq_count_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] {it : Iter (α := α) β} :
|
||||
it.length = it.toIterM.length.run.down :=
|
||||
it.count = it.toIterM.count.run.down :=
|
||||
(rfl)
|
||||
|
||||
@[deprecated Iter.length_eq_length_toIterM (since := "2026-01-28")]
|
||||
def Iter.count_eq_count_toIterM := @Iter.length_eq_length_toIterM
|
||||
|
||||
theorem Iter.length_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.count_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
|
||||
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
|
||||
{it : Iter (α := α) β} :
|
||||
it.length = it.fold (γ := Nat) (init := 0) (fun acc _ => acc + 1) := by
|
||||
rw [length_eq_length_toIterM, IterM.length_eq_fold, ← fold_eq_fold_toIterM]
|
||||
it.count = it.fold (γ := Nat) (init := 0) (fun acc _ => acc + 1) := by
|
||||
rw [count_eq_count_toIterM, IterM.count_eq_fold, ← fold_eq_fold_toIterM]
|
||||
rw [← fold_hom (f := ULift.down)]
|
||||
simp
|
||||
|
||||
@[deprecated Iter.length_eq_fold (since := "2026-01-28")]
|
||||
def Iter.count_eq_fold := @Iter.length_eq_fold
|
||||
|
||||
theorem Iter.length_eq_forIn {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.count_eq_forIn {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
|
||||
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
|
||||
{it : Iter (α := α) β} :
|
||||
it.length = (ForIn.forIn (m := Id) it 0 (fun _ acc => return .yield (acc + 1))).run := by
|
||||
rw [length_eq_fold, forIn_pure_yield_eq_fold, Id.run_pure]
|
||||
it.count = (ForIn.forIn (m := Id) it 0 (fun _ acc => return .yield (acc + 1))).run := by
|
||||
rw [count_eq_fold, forIn_pure_yield_eq_fold, Id.run_pure]
|
||||
|
||||
@[deprecated Iter.length_eq_forIn (since := "2026-01-28")]
|
||||
def Iter.count_eq_forIn := @Iter.length_eq_forIn
|
||||
|
||||
theorem Iter.length_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.count_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.length = (match it.step.val with
|
||||
| .yield it' _ => it'.length + 1
|
||||
| .skip it' => it'.length
|
||||
it.count = (match it.step.val with
|
||||
| .yield it' _ => it'.count + 1
|
||||
| .skip it' => it'.count
|
||||
| .done => 0) := by
|
||||
simp only [length_eq_length_toIterM]
|
||||
rw [IterM.length_eq_match_step]
|
||||
simp only [count_eq_count_toIterM]
|
||||
rw [IterM.count_eq_match_step]
|
||||
simp only [bind_pure_comp, id_map', Id.run_bind, Iter.step]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[deprecated Iter.length_eq_match_step (since := "2026-01-28")]
|
||||
def Iter.count_eq_match_step := @Iter.length_eq_match_step
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_length {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.size_toArray_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray.size = it.length := by
|
||||
simp only [toArray_eq_toArray_toIterM, length_eq_length_toIterM, Id.run_map,
|
||||
← IterM.up_size_toArray_eq_length]
|
||||
it.toArray.size = it.count := by
|
||||
simp only [toArray_eq_toArray_toIterM, count_eq_count_toIterM, Id.run_map,
|
||||
← IterM.up_size_toArray_eq_count]
|
||||
|
||||
@[deprecated Iter.size_toArray_eq_length (since := "2025-10-29")]
|
||||
def Iter.size_toArray_eq_size := @size_toArray_eq_length
|
||||
|
||||
@[deprecated Iter.size_toArray_eq_length (since := "2026-01-28")]
|
||||
def Iter.size_toArray_eq_count := @size_toArray_eq_length
|
||||
@[deprecated Iter.size_toArray_eq_count (since := "2025-10-29")]
|
||||
def Iter.size_toArray_eq_size := @size_toArray_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toList_eq_length {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.length_toList_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList.length = it.length := by
|
||||
rw [← toList_toArray, Array.length_toList, size_toArray_eq_length]
|
||||
it.toList.length = it.count := by
|
||||
rw [← toList_toArray, Array.length_toList, size_toArray_eq_count]
|
||||
|
||||
@[deprecated Iter.length_toList_eq_length (since := "2025-10-29")]
|
||||
def Iter.length_toList_eq_size := @length_toList_eq_length
|
||||
|
||||
@[deprecated Iter.length_toList_eq_length (since := "2026-01-28")]
|
||||
def Iter.length_toList_eq_count := @length_toList_eq_length
|
||||
@[deprecated Iter.length_toList_eq_count (since := "2025-10-29")]
|
||||
def Iter.length_toList_eq_size := @length_toList_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toListRev_eq_length {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.length_toListRev_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev.length = it.length := by
|
||||
rw [toListRev_eq, List.length_reverse, length_toList_eq_length]
|
||||
it.toListRev.length = it.count := by
|
||||
rw [toListRev_eq, List.length_reverse, length_toList_eq_count]
|
||||
|
||||
@[deprecated Iter.length_toListRev_eq_length (since := "2025-10-29")]
|
||||
def Iter.length_toListRev_eq_size := @length_toListRev_eq_length
|
||||
|
||||
@[deprecated Iter.length_toListRev_eq_length (since := "2026-01-28")]
|
||||
def Iter.length_toListRev_eq_count := @length_toListRev_eq_length
|
||||
@[deprecated Iter.length_toListRev_eq_count (since := "2025-10-29")]
|
||||
def Iter.length_toListRev_eq_size := @length_toListRev_eq_count
|
||||
|
||||
theorem Iter.anyM_eq_forIn {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -936,50 +915,4 @@ theorem Iter.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.first?_eq_first?_toIterM {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.first? = it.toIterM.first?.run := (rfl)
|
||||
|
||||
theorem Iter.first?_eq_match_step {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Productive α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
|
||||
it.first? = match it.step.val with
|
||||
| .yield _ out => some out
|
||||
| .skip it' => it'.first?
|
||||
| .done => none := by
|
||||
rw [Iter.first?_eq_first?_toIterM, IterM.first?_eq_match_step]
|
||||
simp only [Id.run_bind, step]
|
||||
generalize it.toIterM.step.run.inflate = s
|
||||
rcases s with ⟨_|_|_, _⟩ <;> simp [Iter.first?_eq_first?_toIterM]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem Iter.head?_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.head? = it.first? := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [first?_eq_match_step, toList_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn <;> simp [*]
|
||||
|
||||
theorem Iter.isEmpty_eq_isEmpty_toIterM {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.isEmpty = it.toIterM.isEmpty.run.down := (rfl)
|
||||
|
||||
theorem Iter.isEmpty_eq_match_step {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Productive α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
|
||||
it.isEmpty = match it.step.val with
|
||||
| .yield _ _ => false
|
||||
| .skip it' => it'.isEmpty
|
||||
| .done => true := by
|
||||
rw [Iter.isEmpty_eq_isEmpty_toIterM, IterM.isEmpty_eq_match_step]
|
||||
simp only [Id.run_bind, step]
|
||||
generalize it.toIterM.step.run.inflate = s
|
||||
rcases s with ⟨_|_|_, _⟩ <;> simp [Iter.isEmpty_eq_isEmpty_toIterM]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem Iter.isEmpty_toList {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.isEmpty = it.isEmpty := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [isEmpty_eq_match_step, toList_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn <;> simp [*]
|
||||
|
||||
end Std
|
||||
|
||||
@@ -15,15 +15,6 @@ public section
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn_eq {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type x → Type x'} [Monad n] [Iterator α m β]
|
||||
{lift : (γ : Type w) → (δ : Type x) → (γ → n δ) → m γ → n δ}
|
||||
{plausible_forInStep : β → γ → ForInStep γ → Prop} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))} :
|
||||
letI : IteratorLoop α m n := .defaultImplementation
|
||||
IteratorLoop.forIn lift γ plausible_forInStep it init f =
|
||||
IterM.DefaultConsumers.forIn' lift γ plausible_forInStep it init _ (fun _ => id) f := rfl
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β] {n : Type x → Type x'} [Monad n] [LawfulMonad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
@@ -476,33 +467,27 @@ theorem IterM.drain_eq_map_toArray {α β : Type w} {m : Type w → Type w'} [It
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
simp [IterM.drain_eq_map_toList]
|
||||
|
||||
theorem IterM.length_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
theorem IterM.count_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.length = it.fold (init := .up 0) (fun acc _ => .up <| acc.down + 1) :=
|
||||
it.count = it.fold (init := .up 0) (fun acc _ => .up <| acc.down + 1) :=
|
||||
(rfl)
|
||||
|
||||
@[deprecated IterM.length_eq_fold (since := "2026-01-28")]
|
||||
def IterM.count_eq_fold := @IterM.length_eq_fold
|
||||
|
||||
theorem IterM.length_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
theorem IterM.count_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.length = ForIn.forIn it (.up 0) (fun _ acc => return .yield (.up (acc.down + 1))) :=
|
||||
it.count = ForIn.forIn it (.up 0) (fun _ acc => return .yield (.up (acc.down + 1))) :=
|
||||
(rfl)
|
||||
|
||||
@[deprecated IterM.length_eq_forIn (since := "2026-01-28")]
|
||||
def IterM.count_eq_forIn := @IterM.length_eq_forIn
|
||||
|
||||
theorem IterM.length_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
theorem IterM.count_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.length = (do
|
||||
it.count = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' _ => return .up ((← it'.length).down + 1)
|
||||
| .skip it' => return .up (← it'.length).down
|
||||
| .yield it' _ => return .up ((← it'.count).down + 1)
|
||||
| .skip it' => return .up (← it'.count).down
|
||||
| .done => return .up 0) := by
|
||||
simp only [length_eq_fold]
|
||||
simp only [count_eq_fold]
|
||||
have (acc : Nat) (it' : IterM (α := α) m β) :
|
||||
it'.fold (init := ULift.up acc) (fun acc _ => .up (acc.down + 1)) =
|
||||
(ULift.up <| ·.down + acc) <$>
|
||||
@@ -518,45 +503,33 @@ theorem IterM.length_eq_match_step {α β : Type w} {m : Type w → Type w'} [It
|
||||
· simp
|
||||
· simp
|
||||
|
||||
@[deprecated IterM.length_eq_match_step (since := "2026-01-28")]
|
||||
def IterM.count_eq_match_step := @IterM.length_eq_match_step
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_size_toArray_eq_length {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
theorem IterM.up_size_toArray_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.size) <$> it.toArray = it.length := by
|
||||
rw [toArray_eq_fold, length_eq_fold, ← fold_hom]
|
||||
(.up <| ·.size) <$> it.toArray = it.count := by
|
||||
rw [toArray_eq_fold, count_eq_fold, ← fold_hom]
|
||||
· simp only [List.size_toArray, List.length_nil]; rfl
|
||||
· simp
|
||||
|
||||
@[deprecated IterM.up_size_toArray_eq_length (since := "2026-01-28")]
|
||||
def IterM.up_size_toArray_eq_count := @IterM.up_size_toArray_eq_length
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_length_toList_eq_length {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
theorem IterM.up_length_toList_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toList = it.length := by
|
||||
rw [toList_eq_fold, length_eq_fold, ← fold_hom]
|
||||
(.up <| ·.length) <$> it.toList = it.count := by
|
||||
rw [toList_eq_fold, count_eq_fold, ← fold_hom]
|
||||
· simp only [List.length_nil]; rfl
|
||||
· simp
|
||||
|
||||
@[deprecated IterM.up_length_toList_eq_length (since := "2026-01-28")]
|
||||
def IterM.up_length_toList_eq_count := @IterM.up_length_toList_eq_length
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_length_toListRev_eq_length {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
theorem IterM.up_length_toListRev_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toListRev = it.length := by
|
||||
simp only [toListRev_eq, Functor.map_map, List.length_reverse, up_length_toList_eq_length]
|
||||
|
||||
@[deprecated IterM.up_length_toListRev_eq_length (since := "2026-01-28")]
|
||||
def IterM.up_length_toListRev_eq_count := @IterM.up_length_toListRev_eq_length
|
||||
(.up <| ·.length) <$> it.toListRev = it.count := by
|
||||
simp only [toListRev_eq, Functor.map_map, List.length_reverse, up_length_toList_eq_count]
|
||||
|
||||
theorem IterM.anyM_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
@@ -758,7 +731,7 @@ theorem IterM.findSomeM?_eq_match_step {α β γ : Type w} {m : Type w → Type
|
||||
· simp
|
||||
|
||||
theorem IterM.findSome?_eq_findSomeM? {α β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [Finite α m]
|
||||
{it : IterM (α := α) m β} {f : β → Option γ} :
|
||||
it.findSome? f = it.findSomeM? (pure <| f ·) :=
|
||||
(rfl)
|
||||
@@ -859,44 +832,4 @@ theorem IterM.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.first?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Productive α m]
|
||||
[LawfulIteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.first? = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield _ out => return (some out)
|
||||
| .skip it' => it'.first?
|
||||
| .done => return none) := by
|
||||
simp only [first?]
|
||||
have := IteratorLoop.wellFounded_of_productive (α := α) (β := β) (m := m)
|
||||
(P := fun b g s => s = ForInStep.done (some b)) (by simp)
|
||||
simp only [LawfulIteratorLoop.lawful _ _ _ _ _ this]
|
||||
rw [IterM.DefaultConsumers.forIn_eq, IterM.DefaultConsumers.forIn'_eq_match_step _ this]
|
||||
simp only [flip, pure_bind]
|
||||
congr
|
||||
ext s
|
||||
split <;> try (simp [*]; done)
|
||||
simp only [DefaultConsumers.forIn_eq, *]
|
||||
exact IterM.DefaultConsumers.forIn'_eq_forIn' _ this (by simp)
|
||||
|
||||
theorem IterM.isEmpty_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Productive α m]
|
||||
[LawfulIteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.isEmpty = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield _ _ => return .up false
|
||||
| .skip it' => it'.isEmpty
|
||||
| .done => return .up true) := by
|
||||
simp only [isEmpty]
|
||||
have := IteratorLoop.wellFounded_of_productive (α := α) (β := β) (m := m)
|
||||
(P := fun _ _ s => s = ForInStep.done (ULift.up false)) (by simp)
|
||||
simp only [LawfulIteratorLoop.lawful _ _ _ _ _ this]
|
||||
rw [IterM.DefaultConsumers.forIn_eq, IterM.DefaultConsumers.forIn'_eq_match_step _ this]
|
||||
simp only [flip, pure_bind]
|
||||
congr
|
||||
ext s
|
||||
split <;> try (simp [*]; done)
|
||||
simp only [DefaultConsumers.forIn_eq, *]
|
||||
exact IterM.DefaultConsumers.forIn'_eq_forIn' _ this (by simp)
|
||||
|
||||
end Std
|
||||
|
||||
@@ -16,11 +16,8 @@ public import Init.Data.List.Find
|
||||
public import Init.Data.List.Impl
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.MinMax
|
||||
public import Init.Data.List.MinMaxIdx
|
||||
public import Init.Data.List.MinMaxOn
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.Nat
|
||||
public import Init.Data.List.Int
|
||||
public import Init.Data.List.Notation
|
||||
public import Init.Data.List.Pairwise
|
||||
public import Init.Data.List.Sublist
|
||||
|
||||
@@ -2017,7 +2017,6 @@ def sum {α} [Add α] [Zero α] : List α → α :=
|
||||
|
||||
@[simp, grind =] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
|
||||
@[simp, grind =] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
theorem sum_eq_foldr [Add α] [Zero α] {l : List α} : l.sum = l.foldr (· + ·) 0 := rfl
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Sublist
|
||||
import Init.Grind.Util
|
||||
|
||||
public section
|
||||
|
||||
@@ -98,18 +97,6 @@ theorem countP_le_length : countP p l ≤ l.length := by
|
||||
@[simp] theorem countP_eq_zero {p} : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by
|
||||
simp only [countP_eq_length_filter, length_eq_zero_iff, filter_eq_nil_iff]
|
||||
|
||||
/-- This lemma is only relevant for `grind`. -/
|
||||
@[grind ←=]
|
||||
theorem _root_.Std.Internal.List.countP_eq_zero_of_forall {xs : List α} (h : ∀ x ∈ xs, ¬ p x) : xs.countP p = 0 :=
|
||||
countP_eq_zero.mpr h
|
||||
|
||||
/-- This lemma is only relevant for `grind`. -/
|
||||
theorem _root_.Std.Internal.List.not_of_countP_eq_zero_of_mem {xs : List α} (h : xs.countP p = 0) (h' : x ∈ xs) : ¬ p x :=
|
||||
countP_eq_zero.mp h _ h'
|
||||
|
||||
grind_pattern Std.Internal.List.not_of_countP_eq_zero_of_mem => xs.countP p, x ∈ xs where
|
||||
guard xs.countP p = 0
|
||||
|
||||
@[simp] theorem countP_eq_length {p} : countP p l = l.length ↔ ∀ a ∈ l, p a := by
|
||||
rw [countP_eq_length_filter, length_filter_eq_length_iff]
|
||||
|
||||
|
||||
@@ -1077,37 +1077,6 @@ theorem isNone_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
simp [hf, findFinIdx?_cons]
|
||||
split <;> simp [ih, Function.comp_def]
|
||||
|
||||
/-! ### find? and findFinIdx? -/
|
||||
|
||||
theorem find?_eq_map_findFinIdx?_getElem {xs : List α} {p : α → Bool} :
|
||||
xs.find? p = (xs.findFinIdx? p).map (xs[·]) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [find?_cons, findFinIdx?_cons]
|
||||
split <;> rename_i h
|
||||
· simp [h]
|
||||
· simp [h, ih, Function.comp_def]
|
||||
|
||||
theorem find?_eq_bind_findIdx?_getElem? {xs : List α} {p : α → Bool} :
|
||||
xs.find? p = (xs.findIdx? p).bind (xs[·]?) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [find?_cons, findIdx?_cons]
|
||||
split <;> rename_i h
|
||||
· simp [h]
|
||||
· simp [h, ih, Option.bind_map, Function.comp_def]
|
||||
|
||||
theorem find?_eq_getElem?_findIdx {xs : List α} {p : α → Bool} :
|
||||
xs.find? p = xs[xs.findIdx p]? := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [find?_cons, findIdx_cons]
|
||||
split <;> rename_i h
|
||||
· simp [h]
|
||||
· simp [h, ih]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
@@ -1134,6 +1103,8 @@ theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
|
||||
|
||||
|
||||
theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.idxOf a = l.length := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -1142,6 +1113,8 @@ theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.
|
||||
simp only [idxOf_cons, cond_eq_ite, beq_iff_eq]
|
||||
split <;> simp_all
|
||||
|
||||
|
||||
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.idxOf a < l.length := by
|
||||
induction l with
|
||||
| nil => simp at h
|
||||
@@ -1170,6 +1143,8 @@ theorem idxOf_lt_length_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
|
||||
grind_pattern idxOf_lt_length_iff => l.idxOf a, l.length
|
||||
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
The verification API for `finIdxOf?` is still incomplete.
|
||||
@@ -1239,9 +1214,7 @@ The lemmas below should be made consistent with those for `findIdx?` (and proved
|
||||
· rintro w x h rfl
|
||||
contradiction
|
||||
|
||||
theorem idxOf?_eq_some_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} {i : Nat} :
|
||||
l.idxOf? a = some i ↔ ∃ (h : i < l.length), l[i] = a ∧ ∀ j (_ : j < i), ¬l[j] = a := by
|
||||
simp [idxOf?, findIdx?_eq_some_iff_getElem]
|
||||
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
@@ -1257,56 +1230,6 @@ theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isNone = ¬ a ∈ l := by
|
||||
simp
|
||||
|
||||
theorem finIdxOf?_eq_pmap_idxOf? {l : List α} {a : α} [BEq α] [LawfulBEq α] :
|
||||
l.finIdxOf? a =
|
||||
(l.idxOf? a).pmap
|
||||
(fun i h => ⟨i, (idxOf?_eq_some_iff.mp h).1⟩)
|
||||
(fun _ h => h) := by
|
||||
ext ⟨i, h⟩
|
||||
simp only [finIdxOf?_eq_some_iff, Fin.getElem_fin, Fin.forall_iff, Fin.mk_lt_mk,
|
||||
idxOf?_eq_some_iff, Option.pmap_eq_some_iff, Fin.mk.injEq, exists_and_left, exists_prop,
|
||||
and_self_left, exists_eq_right', h, exists_true_left, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· intro w j h₁
|
||||
apply w <;> omega
|
||||
· intro w j h₁ h₂
|
||||
apply w <;> omega
|
||||
|
||||
/-! ### find? and idxOf? -/
|
||||
|
||||
theorem findIdx?_eq_bind_find?_idxOf? [BEq α] [LawfulBEq α] {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = (xs.find? p).bind (xs.idxOf?) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp [findIdx?_cons, find?_cons]
|
||||
split <;> rename_i h
|
||||
· simp [h, idxOf?_cons]
|
||||
· simp [h, ih, Function.comp_def, idxOf?_cons]
|
||||
cases w : xs.find? p with
|
||||
| none => simp
|
||||
| some x' =>
|
||||
simp
|
||||
rintro rfl
|
||||
have := find?_some w
|
||||
contradiction
|
||||
|
||||
theorem findFinIdx?_eq_bind_find?_finIdxOf? [BEq α] [LawfulBEq α] {xs : List α} {p : α → Bool} :
|
||||
xs.findFinIdx? p = (xs.find? p).bind (xs.finIdxOf?) := by
|
||||
simp only [findFinIdx?_eq_pmap_findIdx?, findIdx?_eq_bind_find?_idxOf?, finIdxOf?_eq_pmap_idxOf?]
|
||||
ext i
|
||||
simp only [Option.bind_eq_some_iff, Option.pmap_eq_some_iff, exists_and_left, and_exists_self]
|
||||
constructor
|
||||
· rintro ⟨a, ⟨h₁, h₂⟩, rfl⟩
|
||||
exact ⟨h₁, by simp [h₂]⟩
|
||||
· rintro ⟨h₁, h₂, a, h₃, rfl⟩
|
||||
exact ⟨a, ⟨h₁, h₂, h₃⟩, rfl⟩
|
||||
|
||||
theorem findIdx_eq_getD_bind_find?_idxOf? [BEq α] [LawfulBEq α] {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx p = ((xs.find? p).bind (xs.idxOf?)).getD xs.length := by
|
||||
rw [findIdx_eq_getD_findIdx?, findIdx?_eq_bind_find?_idxOf?]
|
||||
|
||||
/-! ### lookup -/
|
||||
|
||||
section lookup
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Int.Sum
|
||||
@@ -1,107 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Sebastian Graf, Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Int.DivMod.Bootstrap
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.List.MinMax
|
||||
|
||||
public section
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp]
|
||||
theorem sum_replicate_int {n : Nat} {a : Int} : (replicate n a).sum = n * a := by
|
||||
induction n <;> simp_all [replicate_succ, Int.add_mul, Int.add_comm]
|
||||
|
||||
theorem sum_append_int {l₁ l₂ : List Int} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
simp [sum_append]
|
||||
|
||||
theorem sum_reverse_int (xs : List Int) : xs.reverse.sum = xs.sum := by
|
||||
simp [sum_reverse]
|
||||
|
||||
theorem min_mul_length_le_sum_int {xs : List Int} (h : xs ≠ []) :
|
||||
xs.min h * xs.length ≤ xs.sum := by
|
||||
induction xs
|
||||
· contradiction
|
||||
· rename_i x xs ih
|
||||
cases xs
|
||||
· simp_all [List.min_singleton]
|
||||
· simp only [ne_eq, reduceCtorEq, not_false_eq_true, min_eq_get_min?,
|
||||
List.min?_cons (α := Int), Option.get_some, length_cons, Int.natCast_add, Int.cast_ofNat_Int,
|
||||
forall_const] at ih ⊢
|
||||
rw [Int.mul_add, Int.mul_one, Int.add_comm]
|
||||
apply Int.add_le_add
|
||||
· apply Int.min_le_left
|
||||
· refine Int.le_trans ?_ ih
|
||||
rw [Int.mul_le_mul_right (by omega)]
|
||||
apply Int.min_le_right
|
||||
|
||||
theorem mul_length_le_sum_of_min?_eq_some_int {xs : List Int} (h : xs.min? = some x) :
|
||||
x * xs.length ≤ xs.sum := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [min?_eq_some_min (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using min_mul_length_le_sum_int _
|
||||
|
||||
theorem min_le_sum_div_length_int {xs : List Int} (h : xs ≠ []) :
|
||||
xs.min h ≤ xs.sum / xs.length := by
|
||||
have := min_mul_length_le_sum_int h
|
||||
rwa [Int.le_ediv_iff_mul_le]
|
||||
simp [List.length_pos_iff, h]
|
||||
|
||||
theorem le_sum_div_length_of_min?_eq_some_int {xs : List Int} (h : xs.min? = some x) :
|
||||
x ≤ xs.sum / xs.length := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [min?_eq_some_min (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using min_le_sum_div_length_int _
|
||||
|
||||
theorem sum_le_max_mul_length_int {xs : List Int} (h : xs ≠ []) :
|
||||
xs.sum ≤ xs.max h * xs.length := by
|
||||
induction xs
|
||||
· contradiction
|
||||
· rename_i x xs ih
|
||||
cases xs
|
||||
· simp_all [List.max_singleton]
|
||||
· simp only [ne_eq, reduceCtorEq, not_false_eq_true, max_eq_get_max?,
|
||||
List.max?_cons (α := Int), Option.get_some, length_cons, Int.natCast_add, Int.cast_ofNat_Int,
|
||||
forall_const] at ih ⊢
|
||||
rw [Int.mul_add, Int.mul_one, Int.add_comm]
|
||||
apply Int.add_le_add
|
||||
· apply Int.le_max_left
|
||||
· refine Int.le_trans ih ?_
|
||||
rw [Int.mul_le_mul_right (by omega)]
|
||||
apply Int.le_max_right
|
||||
|
||||
theorem sum_le_max_mul_length_of_max?_eq_some_int {xs : List Int} (h : xs.max? = some x) :
|
||||
xs.sum ≤ x * xs.length := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [max?_eq_some_max (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using sum_le_max_mul_length_int _
|
||||
|
||||
theorem sum_div_length_le_max_int {xs : List Int} (h : xs ≠ []) :
|
||||
xs.sum / xs.length ≤ xs.max h := by
|
||||
have := sum_le_max_mul_length_int h
|
||||
rw [Int.ediv_le_iff_le_mul]
|
||||
· refine Int.lt_of_le_of_lt this ?_
|
||||
apply Int.lt_add_of_pos_right
|
||||
simp [← Nat.ne_zero_iff_zero_lt, h]
|
||||
· simp [List.length_pos_iff, h]
|
||||
|
||||
theorem sum_div_length_le_max_of_max?_eq_some_int {xs : List Int} (h : xs.max? = some x) :
|
||||
xs.sum / xs.length ≤ x := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [max?_eq_some_max (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using sum_div_length_le_max_int _
|
||||
|
||||
end List
|
||||
@@ -482,28 +482,25 @@ theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (i : Nat) (h : i < l
|
||||
theorem mem_iff_getElem? {a} {l : List α} : a ∈ l ↔ ∃ i : Nat, l[i]? = some a := by
|
||||
simp [getElem?_eq_some_iff, mem_iff_getElem]
|
||||
|
||||
theorem exists_mem_iff_exists_getElem {P : α → Prop} {l : List α} :
|
||||
(∃ x ∈ l, P x) ↔ ∃ (i : Nat), ∃ hi, P (l[i]) := by
|
||||
simp only [mem_iff_getElem]
|
||||
apply Iff.intro
|
||||
· rintro ⟨_, ⟨i, hi, rfl⟩, hP⟩
|
||||
exact ⟨i, hi, hP⟩
|
||||
· rintro ⟨i, hi, hP⟩
|
||||
exact ⟨_, ⟨i, hi, rfl⟩, hP⟩
|
||||
|
||||
theorem forall_mem_iff_forall_getElem {P : α → Prop} {l : List α} :
|
||||
(∀ x ∈ l, P x) ↔ ∀ (i : Nat) hi, P (l[i]) := by
|
||||
simp only [mem_iff_getElem]
|
||||
apply Iff.intro
|
||||
· intro h i hi
|
||||
exact h l[i] ⟨i, hi, rfl⟩
|
||||
· rintro h _ ⟨i, hi, rfl⟩
|
||||
exact h i hi
|
||||
|
||||
@[deprecated forall_mem_iff_forall_getElem (since := "2026-01-29")]
|
||||
theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
(∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a :=
|
||||
forall_mem_iff_forall_getElem.symm
|
||||
(∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [length_cons, mem_cons, forall_eq_or_imp]
|
||||
constructor
|
||||
· intro w
|
||||
constructor
|
||||
· exact w 0 (by simp)
|
||||
· apply ih.1
|
||||
intro n h
|
||||
simpa using w (n+1) (Nat.add_lt_add_right h 1)
|
||||
· rintro ⟨h, w⟩
|
||||
rintro (_ | n) h
|
||||
· simpa
|
||||
· apply w
|
||||
simp only [getElem_cons_succ]
|
||||
exact getElem_mem (lt_of_succ_lt_succ h)
|
||||
|
||||
@[simp] theorem elem_eq_contains [BEq α] {a : α} {l : List α} :
|
||||
elem a l = l.contains a := by
|
||||
@@ -1830,17 +1827,12 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
rw [eq_comm, map_eq_append_iff]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_append [Add α] [Zero α] [Std.LawfulLeftIdentity (α := α) (· + ·) 0]
|
||||
[Std.Associative (α := α) (· + ·)] {l₁ l₂ : List α} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
induction l₁ generalizing l₂ <;> simp_all [Std.Associative.assoc, Std.LawfulLeftIdentity.left_id]
|
||||
theorem sum_append_nat {l₁ l₂ : List Nat} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
induction l₁ generalizing l₂ <;> simp_all [Nat.add_assoc]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.Commutative (α := α) (· + ·)]
|
||||
[Std.LawfulLeftIdentity (α := α) (· + ·) 0] (xs : List α) : xs.reverse.sum = xs.sum := by
|
||||
induction xs <;>
|
||||
simp_all [sum_append, Std.Commutative.comm (α := α) _ 0,
|
||||
Std.LawfulLeftIdentity.left_id, Std.Commutative.comm]
|
||||
theorem sum_reverse_nat (xs : List Nat) : xs.reverse.sum = xs.sum := by
|
||||
induction xs <;> simp_all [Nat.add_comm]
|
||||
|
||||
/-! ### concat
|
||||
|
||||
@@ -2371,6 +2363,9 @@ theorem replicateRecOn {α : Type _} {p : List α → Prop} (l : List α)
|
||||
exact hi _ _ _ _ h hn (replicateRecOn (b :: l') h0 hr hi)
|
||||
termination_by l.length
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
induction n <;> simp_all [replicate_succ, Nat.add_mul, Nat.add_comm]
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp, grind =] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
|
||||
|
||||
@@ -85,7 +85,7 @@ theorem cons_lex_cons_iff : Lex r (a :: l₁) (b :: l₂) ↔ r a b ∨ a = b
|
||||
|
||||
theorem cons_lt_cons_iff [LT α] {a b} {l₁ l₂ : List α} :
|
||||
(a :: l₁) < (b :: l₂) ↔ a < b ∨ a = b ∧ l₁ < l₂ := by
|
||||
simp only [LT.lt, List.lt]
|
||||
dsimp only [instLT, List.lt]
|
||||
simp [cons_lex_cons_iff]
|
||||
|
||||
@[simp] theorem cons_lt_cons_self [LT α] [i₀ : Std.Irrefl (· < · : α → α → Prop)] {l₁ l₂ : List α} :
|
||||
@@ -101,7 +101,7 @@ theorem cons_le_cons_iff [LT α]
|
||||
[i₂ : Std.Trichotomous (· < · : α → α → Prop)]
|
||||
{a b} {l₁ l₂ : List α} :
|
||||
(a :: l₁) ≤ (b :: l₂) ↔ a < b ∨ a = b ∧ l₁ ≤ l₂ := by
|
||||
simp only [LE.le, LT.lt, List.le, List.lt]
|
||||
dsimp only [instLE, instLT, List.le, List.lt]
|
||||
open Classical in
|
||||
simp only [not_cons_lex_cons_iff, ne_eq]
|
||||
constructor
|
||||
|
||||
@@ -29,11 +29,7 @@ open Nat
|
||||
|
||||
/-! ### min? -/
|
||||
|
||||
@[simp, grind =] theorem min?_nil [Min α] : ([] : List α).min? = none := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem min?_singleton [Min α] {x : α} : [x].min? = some x :=
|
||||
(rfl)
|
||||
@[simp] theorem min?_nil [Min α] : ([] : List α).min? = none := rfl
|
||||
|
||||
-- We don't put `@[simp]` on `min?_cons'`,
|
||||
-- because the definition in terms of `foldl` is not useful for proofs.
|
||||
@@ -43,20 +39,15 @@ theorem min?_cons' [Min α] {xs : List α} : (x :: xs).min? = some (foldl min x
|
||||
(x :: xs).min? = some (xs.min?.elim x (min x)) := by
|
||||
cases xs <;> simp [min?_cons', foldl_assoc]
|
||||
|
||||
@[simp, grind =] theorem min?_eq_none_iff {xs : List α} [Min α] : xs.min? = none ↔ xs = [] := by
|
||||
@[simp] theorem min?_eq_none_iff {xs : List α} [Min α] : xs.min? = none ↔ xs = [] := by
|
||||
cases xs <;> simp [min?]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem isSome_min?_iff [Min α] {xs : List α} : xs.min?.isSome ↔ xs ≠ [] := by
|
||||
cases xs <;> simp [min?]
|
||||
|
||||
@[grind .]
|
||||
theorem isSome_min?_of_mem {l : List α} [Min α] {a : α} (h : a ∈ l) :
|
||||
l.min?.isSome := by
|
||||
cases l <;> simp_all [min?_cons']
|
||||
|
||||
theorem isSome_min?_of_ne_nil [Min α] {l : List α} (hl : l ≠ []) : l.min?.isSome := by
|
||||
rwa [isSome_min?_iff]
|
||||
theorem isSome_min?_of_ne_nil [Min α] : {l : List α} → (hl : l ≠ []) → l.min?.isSome
|
||||
| x::xs, h => by simp [min?_cons']
|
||||
|
||||
theorem min?_eq_head? {α : Type u} [Min α] {l : List α}
|
||||
(h : l.Pairwise (fun a b => min a b = a)) : l.min? = l.head? := by
|
||||
@@ -152,8 +143,7 @@ theorem min?_replicate [Min α] [Std.IdempotentOp (min : α → α → α)] {n :
|
||||
| zero => rfl
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons', Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem min?_replicate_of_pos [Min α] [MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
@[simp] theorem min?_replicate_of_pos [Min α] [MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).min? = some a := by
|
||||
simp [min?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@@ -170,11 +160,6 @@ theorem foldl_min [Min α] [Std.IdempotentOp (min : α → α → α)] [Std.Asso
|
||||
|
||||
/-! ### min -/
|
||||
|
||||
@[simp, grind =]
|
||||
theorem min_singleton [Min α] {x : α} :
|
||||
[x].min (cons_ne_nil _ _) = x := by
|
||||
(rfl)
|
||||
|
||||
theorem min?_eq_some_min [Min α] : {l : List α} → (hl : l ≠ []) →
|
||||
l.min? = some (l.min hl)
|
||||
| a::as, _ => by simp [List.min, List.min?_cons']
|
||||
@@ -183,22 +168,15 @@ theorem min_eq_get_min? [Min α] : (l : List α) → (hl : l ≠ []) →
|
||||
l.min hl = l.min?.get (isSome_min?_of_ne_nil hl)
|
||||
| a::as, _ => by simp [List.min, List.min?_cons']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get_min? [Min α] {l : List α} {h : l.min?.isSome} :
|
||||
l.min?.get h = l.min (isSome_min?_iff.mp h) := by
|
||||
simp [min?_eq_some_min (isSome_min?_iff.mp h)]
|
||||
|
||||
theorem min_eq_head {α : Type u} [Min α] {l : List α} (hl : l ≠ [])
|
||||
(h : l.Pairwise (fun a b => min a b = a)) : l.min hl = l.head hl := by
|
||||
apply Option.some.inj
|
||||
rw [← min?_eq_some_min, ← head?_eq_some_head]
|
||||
exact min?_eq_head? h
|
||||
|
||||
@[grind .]
|
||||
theorem min_mem [Min α] [MinEqOr α] {l : List α} (hl : l ≠ []) : l.min hl ∈ l :=
|
||||
min?_mem (min?_eq_some_min hl)
|
||||
|
||||
@[grind .]
|
||||
theorem min_le_of_mem [Min α] [LE α] [Std.IsLinearOrder α] [Std.LawfulOrderMin α]
|
||||
{l : List α} {a : α} (ha : a ∈ l) :
|
||||
l.min (ne_nil_of_mem ha) ≤ a :=
|
||||
@@ -212,7 +190,7 @@ theorem min_eq_iff [Min α] [LE α] {l : List α} [IsLinearOrder α] [LawfulOrde
|
||||
l.min hl = a ↔ a ∈ l ∧ ∀ b, b ∈ l → a ≤ b := by
|
||||
simpa [min?_eq_some_min hl] using (min?_eq_some_iff (xs := l))
|
||||
|
||||
@[simp, grind =] theorem min_replicate [Min α] [MinEqOr α] {n : Nat} {a : α} (h : replicate n a ≠ []) :
|
||||
@[simp] theorem min_replicate [Min α] [MinEqOr α] {n : Nat} {a : α} (h : replicate n a ≠ []) :
|
||||
(replicate n a).min h = a := by
|
||||
have n_pos : 0 < n := Nat.pos_of_ne_zero (fun hn => by simp [hn] at h)
|
||||
simpa [min?_eq_some_min h] using (min?_replicate_of_pos (a := a) n_pos)
|
||||
@@ -224,11 +202,7 @@ theorem foldl_min_eq_min [Min α] [Std.IdempotentOp (min : α → α → α)] [S
|
||||
|
||||
/-! ### max? -/
|
||||
|
||||
@[simp, grind =] theorem max?_nil [Max α] : ([] : List α).max? = none := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem max?_singleton [Max α] {x : α} : [x].max? = some x :=
|
||||
(rfl)
|
||||
@[simp] theorem max?_nil [Max α] : ([] : List α).max? = none := rfl
|
||||
|
||||
-- We don't put `@[simp]` on `max?_cons'`,
|
||||
-- because the definition in terms of `foldl` is not useful for proofs.
|
||||
@@ -238,20 +212,15 @@ theorem max?_cons' [Max α] {xs : List α} : (x :: xs).max? = some (foldl max x
|
||||
(x :: xs).max? = some (xs.max?.elim x (max x)) := by
|
||||
cases xs <;> simp [max?_cons', foldl_assoc]
|
||||
|
||||
@[simp, grind =] theorem max?_eq_none_iff {xs : List α} [Max α] : xs.max? = none ↔ xs = [] := by
|
||||
@[simp] theorem max?_eq_none_iff {xs : List α} [Max α] : xs.max? = none ↔ xs = [] := by
|
||||
cases xs <;> simp [max?]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem isSome_max?_iff [Max α] {xs : List α} : xs.max?.isSome ↔ xs ≠ [] := by
|
||||
cases xs <;> simp [max?]
|
||||
|
||||
@[grind .]
|
||||
theorem isSome_max?_of_mem {l : List α} [Max α] {a : α} (h : a ∈ l) :
|
||||
l.max?.isSome := by
|
||||
cases l <;> simp_all [max?_cons']
|
||||
|
||||
theorem isSome_max?_of_ne_nil [Max α] {l : List α} (hl : l ≠ []) : l.max?.isSome := by
|
||||
rwa [isSome_max?_iff]
|
||||
theorem isSome_max?_of_ne_nil [Max α] : {l : List α} → (hl : l ≠ []) → l.max?.isSome
|
||||
| x::xs, h => by simp [max?_cons']
|
||||
|
||||
theorem max?_eq_head? {α : Type u} [Max α] {l : List α}
|
||||
(h : l.Pairwise (fun a b => max a b = a)) : l.max? = l.head? := by
|
||||
@@ -360,8 +329,7 @@ theorem max?_replicate [Max α] [Std.IdempotentOp (max : α → α → α)] {n :
|
||||
| zero => rfl
|
||||
| succ n ih => cases n <;> simp_all [replicate_succ, max?_cons', Std.IdempotentOp.idempotent]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem max?_replicate_of_pos [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
@[simp] theorem max?_replicate_of_pos [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : 0 < n) :
|
||||
(replicate n a).max? = some a := by
|
||||
simp [max?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@@ -378,11 +346,6 @@ theorem foldl_max [Max α] [Std.IdempotentOp (max : α → α → α)] [Std.Asso
|
||||
|
||||
/-! ### max -/
|
||||
|
||||
@[simp, grind =]
|
||||
theorem max_singleton [Max α] {x : α} :
|
||||
[x].max (cons_ne_nil _ _) = x := by
|
||||
(rfl)
|
||||
|
||||
theorem max?_eq_some_max [Max α] : {l : List α} → (hl : l ≠ []) →
|
||||
l.max? = some (l.max hl)
|
||||
| a::as, _ => by simp [List.max, List.max?_cons']
|
||||
@@ -391,18 +354,12 @@ theorem max_eq_get_max? [Max α] : (l : List α) → (hl : l ≠ []) →
|
||||
l.max hl = l.max?.get (isSome_max?_of_ne_nil hl)
|
||||
| a::as, _ => by simp [List.max, List.max?_cons']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem get_max? [Max α] {l : List α} {h : l.max?.isSome} :
|
||||
l.max?.get h = l.max (isSome_max?_iff.mp h) := by
|
||||
simp [max?_eq_some_max (isSome_max?_iff.mp h)]
|
||||
|
||||
theorem max_eq_head {α : Type u} [Max α] {l : List α} (hl : l ≠ [])
|
||||
(h : l.Pairwise (fun a b => max a b = a)) : l.max hl = l.head hl := by
|
||||
apply Option.some.inj
|
||||
rw [← max?_eq_some_max, ← head?_eq_some_head]
|
||||
exact max?_eq_head? h
|
||||
|
||||
@[grind .]
|
||||
theorem max_mem [Max α] [MaxEqOr α] {l : List α} (hl : l ≠ []) : l.max hl ∈ l :=
|
||||
max?_mem (max?_eq_some_max hl)
|
||||
|
||||
@@ -414,13 +371,12 @@ theorem max_eq_iff [Max α] [LE α] {l : List α} [IsLinearOrder α] [LawfulOrde
|
||||
l.max hl = a ↔ a ∈ l ∧ ∀ b, b ∈ l → b ≤ a := by
|
||||
simpa [max?_eq_some_max hl] using (max?_eq_some_iff (xs := l))
|
||||
|
||||
@[grind .]
|
||||
theorem le_max_of_mem [Max α] [LE α] [Std.IsLinearOrder α] [Std.LawfulOrderMax α]
|
||||
{l : List α} {a : α} (ha : a ∈ l) :
|
||||
a ≤ l.max (List.ne_nil_of_mem ha) :=
|
||||
(max?_eq_some_iff.mp (max?_eq_some_max (List.ne_nil_of_mem ha))).right a ha
|
||||
|
||||
@[simp, grind =] theorem max_replicate [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : replicate n a ≠ []) :
|
||||
@[simp] theorem max_replicate [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : replicate n a ≠ []) :
|
||||
(replicate n a).max h = a := by
|
||||
have n_pos : 0 < n := Nat.pos_of_ne_zero (fun hn => by simp [hn] at h)
|
||||
simpa [max?_eq_some_max h] using (max?_replicate_of_pos (a := a) n_pos)
|
||||
|
||||
@@ -1,830 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.MinMaxOn
|
||||
import Init.Data.List.MinMaxOn
|
||||
public import Init.Data.List.Pairwise
|
||||
public import Init.Data.Subtype.Order
|
||||
import Init.Data.Order.Lemmas
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
import Init.Data.Order.Opposite
|
||||
import Init.Data.Nat.Order
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
open scoped OppositeOrderInstances
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace List
|
||||
|
||||
/--
|
||||
Returns the index of an element of the non-empty list {name}`xs` that minimizes {name}`f`.
|
||||
If {given}`x, y` are such that {lean}`f x = f y`, it returns the index of whichever comes first
|
||||
in the list.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
-/
|
||||
@[inline]
|
||||
def minIdxOn [LE β] [DecidableLE β] (f : α → β) (xs : List α) (h : xs ≠ []) : Nat :=
|
||||
match xs with
|
||||
| y :: ys => go y 0 1 ys
|
||||
where
|
||||
@[specialize]
|
||||
go (x : α) (i : Nat) (j : Nat) (xs : List α) :=
|
||||
match xs with
|
||||
| [] => i
|
||||
| y :: ys =>
|
||||
if f x ≤ f y then
|
||||
go x i (j + 1) ys
|
||||
else
|
||||
go y j (j + 1) ys
|
||||
|
||||
/--
|
||||
Returns the index of an element of {name}`xs` that minimizes {name}`f`. If {given}`x, y`
|
||||
are such that {lean}`f x = f y`, it returns the index of whichever comes first in the list.
|
||||
Returns {name}`none` if the list is empty.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
-/
|
||||
@[inline]
|
||||
def minIdxOn? [LE β] [DecidableLE β] (f : α → β) (xs : List α) : Option Nat :=
|
||||
match xs with
|
||||
| [] => none
|
||||
| y :: ys => some ((y :: ys).minIdxOn f (nomatch ·))
|
||||
|
||||
/--
|
||||
Returns the index of an element of the non-empty list {name}`xs` that maximizes {name}`f`.
|
||||
If {given}`x, y` are such that {lean}`f x = f y`, it returns the index of whichever comes first
|
||||
in the list.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
-/
|
||||
@[inline]
|
||||
def maxIdxOn [LE β] [DecidableLE β] (f : α → β) (xs : List α) (h : xs ≠ []) : Nat :=
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
xs.minIdxOn f h
|
||||
|
||||
/--
|
||||
Returns the index of an element of {name}`xs` that maximizes {name}`f`. If {given}`x, y`
|
||||
are such that {lean}`f x = f y`, it returns the index of whichever comes first in the list.
|
||||
Returns {name}`none` if the list is empty.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
-/
|
||||
@[inline]
|
||||
def maxIdxOn? [LE β] [DecidableLE β] (f : α → β) (xs : List α) : Option Nat :=
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
xs.minIdxOn? f
|
||||
|
||||
protected theorem maxIdxOn_eq_minIdxOn {le : LE β} {_ : DecidableLE β} {f : α → β}
|
||||
{xs : List α} {h} :
|
||||
xs.maxIdxOn f h = (letI := le.opposite; xs.minIdxOn f h) :=
|
||||
(rfl)
|
||||
|
||||
private theorem minIdxOn.go_lt_length_add [LE β] [DecidableLE β] {f : α → β} {x : α}
|
||||
{i j : Nat} {xs : List α} (h : i < j) :
|
||||
List.minIdxOn.go f x i j xs < xs.length + j := by
|
||||
induction xs generalizing x i j
|
||||
· simp [go, h]
|
||||
· rename_i y ys ih
|
||||
simp only [go, length_cons, Nat.add_assoc, Nat.add_comm 1]
|
||||
split
|
||||
· exact ih (Nat.lt_succ_of_lt ‹i < j›)
|
||||
· exact ih (Nat.lt_succ_self j)
|
||||
|
||||
private theorem minIdxOn.go_eq_of_forall_le [LE β] [DecidableLE β] {f : α → β}
|
||||
{x : α} {i j : Nat} {xs : List α} (h : ∀ y ∈ xs, f x ≤ f y) :
|
||||
List.minIdxOn.go f x i j xs = i := by
|
||||
induction xs generalizing x i j
|
||||
· simp [go]
|
||||
· rename_i y ys ih
|
||||
simp only [go]
|
||||
split
|
||||
· apply ih
|
||||
simp_all
|
||||
· simp_all
|
||||
|
||||
private theorem exists_getElem_eq_of_drop_eq_cons {xs : List α} {k : Nat} {y : α} {ys : List α}
|
||||
(h : xs.drop k = y :: ys) : ∃ hlt : k < xs.length, xs[k] = y := by
|
||||
have hlt : k < xs.length := by
|
||||
false_or_by_contra
|
||||
have : drop k xs = [] := drop_of_length_le (by omega)
|
||||
simp [this] at h
|
||||
refine ⟨hlt, ?_⟩
|
||||
have := take_append_drop k xs
|
||||
rw [h] at this
|
||||
simp +singlePass only [← this]
|
||||
rw [getElem_append_right (length_take_le _ _)]
|
||||
simp [length_take_of_le (Nat.le_of_lt hlt)]
|
||||
|
||||
private theorem take_succ_eq_append_of_drop_eq_cons {xs : List α} {k : Nat} {y : α}
|
||||
{ys : List α} (h : xs.drop k = y :: ys) : xs.take (k + 1) = xs.take k ++ [y] := by
|
||||
obtain ⟨hlt, rfl⟩ := exists_getElem_eq_of_drop_eq_cons h
|
||||
rw [take_succ_eq_append_getElem hlt]
|
||||
|
||||
private theorem minIdxOn_eq_go_drop [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{xs : List α} (h : xs ≠ []) {k : Nat} :
|
||||
∃ (i : Nat) (hlt : i < xs.length), i ≤ k ∧ xs[i] = (xs.take (k + 1)).minOn f (by simpa) ∧
|
||||
xs.minIdxOn f h = List.minIdxOn.go f ((xs.take (k + 1)).minOn f (by cases xs <;> simp_all)) i (k + 1) (xs.drop (k + 1)) := by
|
||||
match xs with
|
||||
| y :: ys =>
|
||||
simp only [drop_succ_cons]
|
||||
induction k
|
||||
· simp [minIdxOn]
|
||||
· rename_i k ih
|
||||
specialize ih
|
||||
obtain ⟨i, hlt, hi, ih⟩ := ih
|
||||
simp only [ih, ← drop_drop]
|
||||
simp only [length_cons] at hlt
|
||||
match h : drop k ys with
|
||||
| [] =>
|
||||
have : ys.length ≤ k := by simp_all
|
||||
simp [drop_nil, minIdxOn.go, take_of_length_le, hi, ih, hlt, this, Nat.le_succ_of_le]
|
||||
| z :: zs =>
|
||||
simp only [minIdxOn.go]
|
||||
have : take (k + 1 + 1) (y :: ys) = take (k + 1) (y :: ys) ++ [z] := by apply take_succ_eq_append_of_drop_eq_cons ‹_›
|
||||
simp only [this, List.minOn_append (xs := take (k + 1) (y :: ys)) (by simp) (cons_ne_nil _ _)]
|
||||
simp only [take_succ_cons] at this
|
||||
split
|
||||
· simp only [List.minOn_singleton, minOn_eq_left, length_cons, *]
|
||||
exact ⟨i, by omega, Nat.le_succ_of_le ‹i ≤ k›, by simp [ih], rfl⟩
|
||||
· simp only [List.minOn_singleton, not_false_eq_true, minOn_eq_right, length_cons, *]
|
||||
obtain ⟨hlt, rfl⟩ := exists_getElem_eq_of_drop_eq_cons h
|
||||
exact ⟨k + 1, by omega, Nat.le_refl _, by simp, rfl⟩
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn_nil_eq_iff_true [LE β] [DecidableLE β] {f : α → β} {x : Nat}
|
||||
(h : [] ≠ []) : ([] : List α).minIdxOn f h = x ↔ True :=
|
||||
nomatch h
|
||||
|
||||
protected theorem minIdxOn_nil_eq_iff_false [LE β] [DecidableLE β] {f : α → β} {x : Nat}
|
||||
(h : [] ≠ []) : ([] : List α).minIdxOn f h = x ↔ False :=
|
||||
nomatch h
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].minIdxOn f (of_decide_eq_false rfl) = 0 := by
|
||||
rw [minIdxOn, minIdxOn.go]
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn_lt_length [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.minIdxOn f h < xs.length := by
|
||||
rw [minIdxOn.eq_def]
|
||||
split
|
||||
simp [minIdxOn.go_lt_length_add]
|
||||
|
||||
protected theorem minIdxOn_le_of_apply_getElem_le_apply_minOn [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ [])
|
||||
{k : Nat} (hi : k < xs.length) (hle : f xs[k] ≤ f (xs.minOn f h)) :
|
||||
xs.minIdxOn f h ≤ k := by
|
||||
obtain ⟨i, _, hi, _, h'⟩ := minIdxOn_eq_go_drop (f := f) h (k := k)
|
||||
rw [h']
|
||||
refine Nat.le_trans ?_ hi
|
||||
apply Nat.le_of_eq
|
||||
apply minIdxOn.go_eq_of_forall_le
|
||||
intro y hy
|
||||
refine le_trans (List.apply_minOn_le_of_mem (y := xs[k]) (by rw [mem_take_iff_getElem]; exact ⟨k, by omega, rfl⟩)) ?_
|
||||
refine le_trans hle ?_
|
||||
apply List.apply_minOn_le_of_mem
|
||||
apply mem_of_mem_drop
|
||||
exact hy
|
||||
|
||||
protected theorem apply_minOn_lt_apply_getElem_of_lt_minIdxOn [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ [])
|
||||
{k : Nat} (hk : k < xs.minIdxOn f h) :
|
||||
f (xs.minOn f h) < f (xs[k]'(by haveI := List.minIdxOn_lt_length (f := f) h; omega)) := by
|
||||
simp only [← not_le] at hk ⊢
|
||||
apply hk.imp
|
||||
apply List.minIdxOn_le_of_apply_getElem_le_apply_minOn
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem_minIdxOn [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) :
|
||||
xs[xs.minIdxOn f h] = xs.minOn f h := by
|
||||
obtain ⟨i, hlt, hi, heq, h'⟩ := minIdxOn_eq_go_drop (f := f) h (k := xs.length)
|
||||
simp only [drop_eq_nil_of_le (as := xs) (i := xs.length + 1) (by omega), minIdxOn.go] at h'
|
||||
simp [h', heq, take_of_length_le (l := xs) (i := xs.length + 1) (by omega)]
|
||||
|
||||
protected theorem le_minIdxOn_of_apply_getElem_lt_apply_getElem [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β] {f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} (hi : i < xs.length)
|
||||
(hi' : ∀ j, (_ : j < i) → f xs[i] < f xs[j]) :
|
||||
i ≤ xs.minIdxOn f h := by
|
||||
false_or_by_contra; rename_i hgt
|
||||
simp only [not_le] at hgt
|
||||
specialize hi' _ hgt
|
||||
simp only [List.getElem_minIdxOn] at hi'
|
||||
apply (not_le.mpr hi').elim
|
||||
apply List.apply_minOn_le_of_mem
|
||||
simp
|
||||
|
||||
protected theorem minIdxOn_le_of_apply_getElem_le_apply_getElem [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} (hi : i < xs.length)
|
||||
(hi' : ∀ j, (_ : j < xs.length) → f xs[i] ≤ f xs[j]) :
|
||||
xs.minIdxOn f h ≤ i := by
|
||||
apply List.minIdxOn_le_of_apply_getElem_le_apply_minOn h hi
|
||||
simp only [List.le_apply_minOn_iff, List.mem_iff_getElem]
|
||||
rintro _ ⟨j, hj, rfl⟩
|
||||
exact hi' _ hj
|
||||
|
||||
protected theorem minIdxOn_eq_iff [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} :
|
||||
xs.minIdxOn f h = i ↔ ∃ (h : i < xs.length),
|
||||
(∀ j, (_ : j < xs.length) → f xs[i] ≤ f xs[j]) ∧
|
||||
(∀ j, (_ : j < i) → f xs[i] < f xs[j]) := by
|
||||
apply Iff.intro
|
||||
· rintro rfl
|
||||
simp only [List.getElem_minIdxOn]
|
||||
refine ⟨List.minIdxOn_lt_length h, ?_, ?_⟩
|
||||
· simp [List.apply_minOn_le_of_mem]
|
||||
· exact fun j hj => List.apply_minOn_lt_apply_getElem_of_lt_minIdxOn h hj
|
||||
· rintro ⟨hi, h₁, h₂⟩
|
||||
apply le_antisymm
|
||||
· apply List.minIdxOn_le_of_apply_getElem_le_apply_getElem h hi h₁
|
||||
· apply List.le_minIdxOn_of_apply_getElem_lt_apply_getElem h hi h₂
|
||||
|
||||
protected theorem minIdxOn_eq_iff_eq_minOn [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β] {f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} :
|
||||
xs.minIdxOn f h = i ↔ ∃ hi : i < xs.length, xs[i] = xs.minOn f h ∧
|
||||
∀ (j : Nat) (hj : j < i), f (xs.minOn f h) < f xs[j] := by
|
||||
apply Iff.intro
|
||||
· rintro rfl
|
||||
refine ⟨List.minIdxOn_lt_length h, List.getElem_minIdxOn h, ?_⟩
|
||||
intro j hj
|
||||
exact List.apply_minOn_lt_apply_getElem_of_lt_minIdxOn h hj
|
||||
· rintro ⟨hlt, heq, h'⟩
|
||||
specialize h' (xs.minIdxOn f h)
|
||||
simp only [List.getElem_minIdxOn] at h'
|
||||
apply le_antisymm
|
||||
· apply List.minIdxOn_le_of_apply_getElem_le_apply_minOn h hlt
|
||||
simp [heq, le_refl]
|
||||
· simpa [lt_irrefl] using h'
|
||||
|
||||
private theorem minIdxOn.go_eq
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
|
||||
List.minIdxOn.go f x i j xs =
|
||||
if h : xs = [] then i
|
||||
else if f x ≤ f (xs.minOn f h) then i
|
||||
else (xs.minIdxOn f h) + j := by
|
||||
open scoped Classical.Order in
|
||||
induction xs generalizing x i j
|
||||
· simp [go]
|
||||
· rename_i y ys ih
|
||||
simp only [go, reduceCtorEq, ↓reduceDIte]
|
||||
split
|
||||
· rw [ih]
|
||||
split
|
||||
· simp [*]
|
||||
· simp only [List.minOn_cons, ↓reduceDIte, le_apply_minOn_iff, true_and, *]
|
||||
split
|
||||
· rfl
|
||||
· rename_i hlt
|
||||
simp only [minIdxOn]
|
||||
split
|
||||
simp only [ih, reduceCtorEq, ↓reduceDIte]
|
||||
rw [if_neg]
|
||||
· simp [minIdxOn, Nat.add_assoc, Nat.add_comm 1]
|
||||
· simp only [not_le] at hlt ⊢
|
||||
exact lt_of_lt_of_le hlt ‹_›
|
||||
· rename_i hlt
|
||||
rw [if_neg]
|
||||
· rw [minIdxOn, ih]
|
||||
split
|
||||
· simp [*, go]
|
||||
· simp only [↓reduceDIte, *]
|
||||
split
|
||||
· simp
|
||||
· simp only [Nat.add_assoc, Nat.add_comm 1]
|
||||
· simp only [not_le] at hlt ⊢
|
||||
exact lt_of_le_of_lt (List.apply_minOn_le_of_mem mem_cons_self) hlt
|
||||
|
||||
protected theorem minIdxOn_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
|
||||
(x :: xs).minIdxOn f (by exact of_decide_eq_false rfl) =
|
||||
if h : xs = [] then 0
|
||||
else if f x ≤ f (xs.minOn f h) then 0
|
||||
else (xs.minIdxOn f h) + 1 := by
|
||||
simpa [List.minIdxOn] using minIdxOn.go_eq
|
||||
|
||||
protected theorem minIdxOn_eq_zero_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) :
|
||||
xs.minIdxOn f h = 0 ↔ ∀ x ∈ xs, f (xs.head h) ≤ f x := by
|
||||
rw [minIdxOn.eq_def]
|
||||
split
|
||||
rename_i y ys _
|
||||
simp only [mem_cons, head_cons, forall_eq_or_imp, le_refl, true_and]
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
cases ys
|
||||
· simp
|
||||
· intro a ha
|
||||
refine le_trans ?_ (List.apply_minOn_le_of_mem ha)
|
||||
simpa [minIdxOn.go_eq] using h
|
||||
· intro h
|
||||
cases ys
|
||||
· simp [minIdxOn.go]
|
||||
· simpa [minIdxOn.go_eq, List.le_apply_minOn_iff] using h
|
||||
|
||||
section Append
|
||||
|
||||
/-!
|
||||
The proof of {name}`List.minOn_append` uses associativity of {name}`minOn` and applies {name}`foldl_assoc`.
|
||||
The proof of {name (scope := "Init.Data.List.MinMaxIdx")}`minIdxOn_append` is analogous, but the
|
||||
aggregation operation, {name (scope := "Init.Data.List.MinMaxIdx")}`combineMinIdxOn`, depends on
|
||||
the length of the lists to combine. After proving associativity of the aggregation operation,
|
||||
the proof closely follows the proof of {name}`foldl_assoc`.
|
||||
-/
|
||||
|
||||
private def combineMinIdxOn [LE β] [DecidableLE β]
|
||||
(f : α → β) {xs ys : List α} (i j : Nat) (hi : i < xs.length) (hj : j < ys.length) : Nat :=
|
||||
if f xs[i] ≤ f ys[j] then
|
||||
i
|
||||
else
|
||||
xs.length + j
|
||||
|
||||
private theorem combineMinIdxOn_lt [LE β] [DecidableLE β]
|
||||
(f : α → β) {xs ys : List α} {i j : Nat} (hi : i < xs.length) (hj : j < ys.length) :
|
||||
combineMinIdxOn f i j hi hj < (xs ++ ys).length := by
|
||||
simp only [combineMinIdxOn]
|
||||
split <;> (simp; omega)
|
||||
|
||||
private theorem combineMinIdxOn_assoc [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys zs : List α} {i j k : Nat} {f : α → β} (hi : i < xs.length) (hj : j < ys.length)
|
||||
(hk : k < zs.length) :
|
||||
combineMinIdxOn f (combineMinIdxOn f i j _ _) k
|
||||
(combineMinIdxOn_lt f hi hj) hk = combineMinIdxOn f i (combineMinIdxOn f j k _ _) hi (combineMinIdxOn_lt f hj hk) := by
|
||||
open scoped Classical.Order in
|
||||
simp only [combineMinIdxOn]
|
||||
split
|
||||
· rw [getElem_append_left (by omega)]
|
||||
split
|
||||
· split
|
||||
· rw [getElem_append_left (by omega)]
|
||||
simp [*]
|
||||
· rw [getElem_append_right (by omega)]
|
||||
simp [*]
|
||||
· split
|
||||
· have := le_trans ‹f xs[i] ≤ f ys[j]› ‹f ys[j] ≤ f zs[k]›
|
||||
contradiction
|
||||
· rw [getElem_append_right (by omega)]
|
||||
simp [*, Nat.add_assoc]
|
||||
· rw [getElem_append_right (by omega)]
|
||||
simp only [Nat.add_sub_cancel_left]
|
||||
split
|
||||
· rw [getElem_append_left (by omega), if_neg ‹_›]
|
||||
· rename_i h₁ h₂
|
||||
rw [not_le] at h₁ h₂
|
||||
rw [getElem_append_right (by omega)]
|
||||
simp only [Nat.add_sub_cancel_left]
|
||||
have := not_le.mpr <| lt_trans h₂ h₁
|
||||
simp [*, Nat.add_assoc]
|
||||
|
||||
private theorem minIdxOn_cons_aux [LE β] [DecidableLE β]
|
||||
[IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} (hxs : xs ≠ []) :
|
||||
(x :: xs).minIdxOn f (by simp) =
|
||||
combineMinIdxOn f _ _
|
||||
(List.minIdxOn_lt_length (f := f) (cons_ne_nil x []))
|
||||
(List.minIdxOn_lt_length (f := f) hxs) := by
|
||||
rw [minIdxOn, combineMinIdxOn]
|
||||
simp [minIdxOn.go_eq, hxs, List.getElem_minIdxOn, Nat.add_comm 1]
|
||||
|
||||
private theorem minIdxOn_append_aux [LE β] [DecidableLE β]
|
||||
[IsLinearPreorder β] {xs ys : List α} {f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
(xs ++ ys).minIdxOn f (by simp [hxs]) =
|
||||
combineMinIdxOn f _ _
|
||||
(List.minIdxOn_lt_length (f := f) hxs)
|
||||
(List.minIdxOn_lt_length (f := f) hys) := by
|
||||
induction xs
|
||||
· contradiction
|
||||
· rename_i x xs ih
|
||||
match xs with
|
||||
| [] => simp [minIdxOn_cons_aux (xs := ys) ‹_›]
|
||||
| z :: zs =>
|
||||
simp +singlePass only [cons_append]
|
||||
simp only [minIdxOn_cons_aux (xs := z :: zs ++ ys) (by simp), ih (by simp),
|
||||
minIdxOn_cons_aux (xs := z :: zs) (by simp), combineMinIdxOn_assoc]
|
||||
|
||||
protected theorem minIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
(xs ++ ys).minIdxOn f (by simp [hxs]) =
|
||||
if f (xs.minOn f hxs) ≤ f (ys.minOn f hys) then
|
||||
xs.minIdxOn f hxs
|
||||
else
|
||||
xs.length + ys.minIdxOn f hys := by
|
||||
simp [minIdxOn_append_aux hxs hys, combineMinIdxOn, List.getElem_minIdxOn]
|
||||
|
||||
end Append
|
||||
|
||||
protected theorem left_le_minIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : xs ≠ []) :
|
||||
xs.minIdxOn f h ≤ (xs ++ ys).minIdxOn f (by simp [h]) := by
|
||||
by_cases hys : ys = []
|
||||
· simp [hys]
|
||||
· rw [List.minIdxOn_append h hys]
|
||||
split
|
||||
· apply Nat.le_refl
|
||||
· have := List.minIdxOn_lt_length (f := f) h
|
||||
omega
|
||||
|
||||
protected theorem minIdxOn_take_le [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {i : Nat} (h : xs.take i ≠ []) :
|
||||
(xs.take i).minIdxOn f h ≤ xs.minIdxOn f (List.ne_nil_of_take_ne_nil h) := by
|
||||
have := take_append_drop i xs
|
||||
conv => rhs; simp +singlePass only [← this]
|
||||
apply List.left_le_minIdxOn_append
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn_replicate [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
(replicate n a).minIdxOn f h = 0 := by
|
||||
match n with
|
||||
| 0 => simp at h
|
||||
| n + 1 =>
|
||||
simp only [minIdxOn, replicate_succ]
|
||||
generalize 1 = j
|
||||
induction n generalizing j
|
||||
· simp [minIdxOn.go]
|
||||
· simp only [replicate_succ, minIdxOn.go] at *
|
||||
split
|
||||
· simp [*]
|
||||
· have := le_refl (f a)
|
||||
contradiction
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn_nil_eq_iff_true [LE β] [DecidableLE β] {f : α → β} {x : Nat}
|
||||
(h : [] ≠ []) : ([] : List α).maxIdxOn f h = x ↔ True :=
|
||||
nomatch h
|
||||
|
||||
protected theorem maxIdxOn_nil_eq_iff_false [LE β] [DecidableLE β] {f : α → β} {x : Nat}
|
||||
(h : [] ≠ []) : ([] : List α).maxIdxOn f h = x ↔ False :=
|
||||
nomatch h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].maxIdxOn f (of_decide_eq_false rfl) = 0 :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minIdxOn_singleton
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn_lt_length [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.maxIdxOn f h < xs.length :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minIdxOn_lt_length h
|
||||
|
||||
protected theorem maxIdxOn_le_of_apply_getElem_le_apply_maxOn [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ [])
|
||||
{k : Nat} (hi : k < xs.length) (hle : f (xs.maxOn f h) ≤ f xs[k]) :
|
||||
xs.maxIdxOn f h ≤ k := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn] at hle ⊢
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minIdxOn_le_of_apply_getElem_le_apply_minOn h hi (by simpa [LE.le_opposite_iff] using hle)
|
||||
|
||||
protected theorem apply_maxOn_lt_apply_getElem_of_lt_maxIdxOn [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ [])
|
||||
{k : Nat} (hk : k < xs.maxIdxOn f h) :
|
||||
f (xs[k]'(by haveI := List.maxIdxOn_lt_length (f := f) h; omega)) < f (xs.maxOn f h) := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn] at hk ⊢
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
letI : LT β := LT.opposite inferInstance
|
||||
simpa [LT.lt_opposite_iff] using List.apply_minOn_lt_apply_getElem_of_lt_minIdxOn (f := f) h hk
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem_maxIdxOn [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) :
|
||||
xs[xs.maxIdxOn f h] = xs.maxOn f h := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.getElem_minIdxOn h
|
||||
|
||||
protected theorem le_maxIdxOn_of_apply_getElem_lt_apply_getElem [LE β] [DecidableLE β] [LT β]
|
||||
[IsLinearPreorder β] [LawfulOrderLT β] {f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat}
|
||||
(hi : i < xs.length) (hi' : ∀ j, (_ : j < i) → f xs[j] < f xs[i]) :
|
||||
i ≤ xs.maxIdxOn f h := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
letI : LT β := LT.opposite inferInstance
|
||||
simpa [LE.le_opposite_iff] using List.le_minIdxOn_of_apply_getElem_lt_apply_getElem h hi
|
||||
(by simpa [LT.lt_opposite_iff] using hi')
|
||||
|
||||
protected theorem maxIdxOn_le_of_apply_getElem_le_apply_getElem [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} (hi : i < xs.length)
|
||||
(hi' : ∀ j, (_ : j < xs.length) → f xs[j] ≤ f xs[i]) :
|
||||
xs.maxIdxOn f h ≤ i := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn_le_of_apply_getElem_le_apply_getElem (f := f) h hi
|
||||
(by simpa [LE.le_opposite_iff] using hi')
|
||||
|
||||
protected theorem maxIdxOn_eq_iff [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β]
|
||||
{f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} :
|
||||
xs.maxIdxOn f h = i ↔ ∃ (h : i < xs.length),
|
||||
(∀ j, (_ : j < xs.length) → f xs[j] ≤ f xs[i]) ∧
|
||||
(∀ j, (_ : j < i) → f xs[j] < f xs[i]) := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
letI : LT β := LT.opposite inferInstance
|
||||
simpa [LE.le_opposite_iff, LT.lt_opposite_iff] using List.minIdxOn_eq_iff (f := f) h
|
||||
|
||||
protected theorem maxIdxOn_eq_iff_eq_maxOn [LE β] [DecidableLE β] [LT β] [IsLinearPreorder β]
|
||||
[LawfulOrderLT β] {f : α → β} {xs : List α} (h : xs ≠ []) {i : Nat} :
|
||||
xs.maxIdxOn f h = i ↔ ∃ hi : i < xs.length, xs[i] = xs.maxOn f h ∧
|
||||
∀ (j : Nat) (hj : j < i), f xs[j] < f (xs.maxOn f h) := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
letI : LT β := LT.opposite inferInstance
|
||||
simpa [LT.lt_opposite_iff] using List.minIdxOn_eq_iff_eq_minOn (f := f) h
|
||||
|
||||
protected theorem maxIdxOn_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
|
||||
(x :: xs).maxIdxOn f (by exact of_decide_eq_false rfl) =
|
||||
if h : xs = [] then 0
|
||||
else if f (xs.maxOn f h) ≤ f x then 0
|
||||
else (xs.maxIdxOn f h) + 1 := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn_cons (f := f)
|
||||
|
||||
protected theorem maxIdxOn_eq_zero_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) :
|
||||
xs.maxIdxOn f h = 0 ↔ ∀ x ∈ xs, f x ≤ f (xs.head h) := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn_eq_zero_iff h (f := f)
|
||||
|
||||
protected theorem maxIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
(xs ++ ys).maxIdxOn f (by simp [hxs]) =
|
||||
if f (ys.maxOn f hys) ≤ f (xs.maxOn f hxs) then
|
||||
xs.maxIdxOn f hxs
|
||||
else
|
||||
xs.length + ys.maxIdxOn f hys := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn_append hxs hys (f := f)
|
||||
|
||||
protected theorem left_le_maxIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : xs ≠ []) :
|
||||
xs.maxIdxOn f h ≤ (xs ++ ys).maxIdxOn f (by simp [h]) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.left_le_minIdxOn_append h
|
||||
|
||||
protected theorem maxIdxOn_take_le [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {i : Nat} (h : xs.take i ≠ []) :
|
||||
(xs.take i).maxIdxOn f h ≤ xs.maxIdxOn f (List.ne_nil_of_take_ne_nil h) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minIdxOn_take_le h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn_replicate [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
(replicate n a).maxIdxOn f h = 0 :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minIdxOn_replicate h
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn?_nil [LE β] [DecidableLE β] {f : α → β} :
|
||||
([] : List α).minIdxOn? f = none :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn?_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].minIdxOn? f = some 0 :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem isSome_minIdxOn?_iff [LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
(xs.minIdxOn? f).isSome ↔ xs ≠ [] := by
|
||||
cases xs <;> simp [minIdxOn?]
|
||||
|
||||
protected theorem minIdxOn_eq_get_minIdxOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.minIdxOn f h = (xs.minIdxOn? f).get (List.isSome_minIdxOn?_iff.mpr h) := by
|
||||
match xs with
|
||||
| [] => contradiction
|
||||
| _ :: _ => simp [minIdxOn?]
|
||||
|
||||
@[simp]
|
||||
protected theorem get_minIdxOn?_eq_minIdxOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : (xs.minIdxOn? f).isSome) :
|
||||
(xs.minIdxOn? f).get h = xs.minIdxOn f (List.isSome_minIdxOn?_iff.mp h) := by
|
||||
rw [List.minIdxOn_eq_get_minIdxOn?]
|
||||
|
||||
protected theorem minIdxOn?_eq_some_minIdxOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.minIdxOn? f = some (xs.minIdxOn f h) := by
|
||||
match xs with
|
||||
| [] => contradiction
|
||||
| _ :: _ => simp [minIdxOn?]
|
||||
|
||||
protected theorem minIdxOn_eq_of_minIdxOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {i : Nat} (h : xs.minIdxOn? f = some i) :
|
||||
xs.minIdxOn f (List.isSome_minIdxOn?_iff.mp (Option.isSome_of_eq_some h)) = i := by
|
||||
have h' := List.isSome_minIdxOn?_iff.mp (Option.isSome_of_eq_some h)
|
||||
rwa [List.minIdxOn?_eq_some_minIdxOn h', Option.some.injEq] at h
|
||||
|
||||
protected theorem isSome_minIdxOn?_of_mem
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
(xs.minIdxOn? f).isSome := by
|
||||
apply List.isSome_minIdxOn?_iff.mpr
|
||||
exact ne_nil_of_mem h
|
||||
|
||||
protected theorem minIdxOn?_cons_eq_some_minIdxOn
|
||||
[LE β] [DecidableLE β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).minIdxOn? f = some ((x :: xs).minIdxOn f (nomatch ·)) := by
|
||||
simp [List.minIdxOn?_eq_some_minIdxOn]
|
||||
|
||||
protected theorem minIdxOn?_eq_if
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
xs.minIdxOn? f =
|
||||
if h : xs ≠ [] then
|
||||
some (xs.minIdxOn f h)
|
||||
else
|
||||
none := by
|
||||
cases xs <;> simp [List.minIdxOn?_cons_eq_some_minIdxOn]
|
||||
|
||||
protected theorem minIdxOn?_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).minIdxOn? f = some
|
||||
(if h : xs = [] then 0
|
||||
else if f x ≤ f (xs.minOn f h) then 0
|
||||
else (xs.minIdxOn f h) + 1) := by
|
||||
simp [List.minIdxOn?_eq_some_minIdxOn, List.minIdxOn_cons]
|
||||
|
||||
protected theorem ne_nil_of_minIdxOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {k : Nat} {xs : List α} (h : xs.minIdxOn? f = some k) :
|
||||
xs ≠ [] := by
|
||||
rintro rfl
|
||||
simp at h
|
||||
|
||||
protected theorem lt_length_of_minIdxOn?_eq_some [LE β] [DecidableLE β] {f : α → β}
|
||||
{xs : List α} (h : xs.minIdxOn? f = some i) : i < xs.length := by
|
||||
have hne : xs ≠ [] := List.ne_nil_of_minIdxOn?_eq_some h
|
||||
rw [List.minIdxOn?_eq_some_minIdxOn hne] at h
|
||||
have := List.minIdxOn_lt_length (f := f) hne
|
||||
simp_all
|
||||
|
||||
@[simp]
|
||||
protected theorem get_minIdxOn?_lt_length [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : (xs.minIdxOn? f).isSome) : (xs.minIdxOn? f).get h < xs.length := by
|
||||
rw [List.get_minIdxOn?_eq_minIdxOn]
|
||||
apply List.minIdxOn_lt_length
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem_get_minIdxOn? [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : (xs.minIdxOn? f).isSome) :
|
||||
xs[(xs.minIdxOn? f).get h] = xs.minOn f (List.isSome_minIdxOn?_iff.mp h) := by
|
||||
rw [getElem_congr rfl (List.get_minIdxOn?_eq_minIdxOn _), List.getElem_minIdxOn]
|
||||
|
||||
protected theorem minIdxOn?_eq_some_zero_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} :
|
||||
xs.minIdxOn? f = some 0 ↔ ∃ h : xs ≠ [], ∀ x ∈ xs, f (xs.head h) ≤ f x := by
|
||||
simp [Option.eq_some_iff_get_eq, List.minIdxOn_eq_zero_iff]
|
||||
|
||||
protected theorem minIdxOn?_replicate [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} :
|
||||
(replicate n a).minIdxOn? f = if n = 0 then none else some 0 := by
|
||||
simp [List.minIdxOn?_eq_if]
|
||||
|
||||
@[simp]
|
||||
protected theorem minIdxOn?_replicate_of_pos [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} (h : 0 < n) :
|
||||
(replicate n a).minIdxOn? f = some 0 := by
|
||||
simp [List.minIdxOn?_replicate, Nat.ne_zero_of_lt h]
|
||||
|
||||
/-! ### maxIdxOn? -/
|
||||
|
||||
protected theorem maxIdxOn?_eq_minIdxOn? {le : LE β} {_ : DecidableLE β} {f : α → β}
|
||||
{xs : List α} :
|
||||
xs.maxIdxOn? f = (letI := le.opposite; xs.minIdxOn? f) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn?_nil [LE β] [DecidableLE β] {f : α → β} :
|
||||
([] : List α).maxIdxOn? f = none :=
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
List.minIdxOn?_nil
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn?_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].maxIdxOn? f = some 0 :=
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
List.minIdxOn?_singleton
|
||||
|
||||
@[simp]
|
||||
protected theorem isSome_maxIdxOn?_iff [LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
(xs.maxIdxOn? f).isSome ↔ xs ≠ [] := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.isSome_minIdxOn?_iff
|
||||
|
||||
protected theorem maxIdxOn_eq_get_maxIdxOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.maxIdxOn f h = (xs.maxIdxOn? f).get (List.isSome_maxIdxOn?_iff.mpr h) := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn_eq_get_minIdxOn? h
|
||||
|
||||
@[simp]
|
||||
protected theorem get_maxIdxOn?_eq_maxIdxOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : (xs.maxIdxOn? f).isSome) :
|
||||
(xs.maxIdxOn? f).get h = xs.maxIdxOn f (List.isSome_maxIdxOn?_iff.mp h) := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.get_minIdxOn?_eq_minIdxOn h
|
||||
|
||||
protected theorem maxIdxOn?_eq_some_maxIdxOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.maxIdxOn? f = some (xs.maxIdxOn f h) := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn?_eq_some_minIdxOn h
|
||||
|
||||
protected theorem maxIdxOn_eq_of_maxIdxOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {i : Nat} (h : xs.maxIdxOn? f = some i) :
|
||||
xs.maxIdxOn f (List.isSome_maxIdxOn?_iff.mp (Option.isSome_of_eq_some h)) = i := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn_eq_of_minIdxOn?_eq_some h
|
||||
|
||||
protected theorem isSome_maxIdxOn?_of_mem
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
(xs.maxIdxOn? f).isSome := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.isSome_minIdxOn?_of_mem h
|
||||
|
||||
protected theorem maxIdxOn?_cons_eq_some_maxIdxOn
|
||||
[LE β] [DecidableLE β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).maxIdxOn? f = some ((x :: xs).maxIdxOn f (nomatch ·)) := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn?_cons_eq_some_minIdxOn
|
||||
|
||||
protected theorem maxIdxOn?_eq_if
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
xs.maxIdxOn? f =
|
||||
if h : xs ≠ [] then
|
||||
some (xs.maxIdxOn f h)
|
||||
else
|
||||
none := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn?_eq_if
|
||||
|
||||
protected theorem maxIdxOn?_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).maxIdxOn? f = some
|
||||
(if h : xs = [] then 0
|
||||
else if f (xs.maxOn f h) ≤ f x then 0
|
||||
else (xs.maxIdxOn f h) + 1) := by
|
||||
simp only [List.maxIdxOn_eq_minIdxOn, List.maxOn_eq_minOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn?_cons (f := f)
|
||||
|
||||
protected theorem ne_nil_of_maxIdxOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {k : Nat} {xs : List α} (h : xs.maxIdxOn? f = some k) :
|
||||
xs ≠ [] := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.ne_nil_of_minIdxOn?_eq_some (by simpa only [List.maxIdxOn?_eq_minIdxOn?] using h)
|
||||
|
||||
protected theorem lt_length_of_maxIdxOn?_eq_some [LE β] [DecidableLE β] {f : α → β}
|
||||
{xs : List α} (h : xs.maxIdxOn? f = some i) : i < xs.length := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.lt_length_of_minIdxOn?_eq_some h
|
||||
|
||||
@[simp]
|
||||
protected theorem get_maxIdxOn?_lt_length [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : (xs.maxIdxOn? f).isSome) : (xs.maxIdxOn? f).get h < xs.length := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.get_minIdxOn?_lt_length h
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem_get_maxIdxOn? [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{f : α → β} {xs : List α} (h : (xs.maxIdxOn? f).isSome) :
|
||||
xs[(xs.maxIdxOn? f).get h] = xs.maxOn f (List.isSome_maxIdxOn?_iff.mp h) := by
|
||||
simp only [List.maxIdxOn?_eq_minIdxOn?, List.maxOn_eq_minOn]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.getElem_get_minIdxOn? h
|
||||
|
||||
protected theorem maxIdxOn?_eq_some_zero_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} :
|
||||
xs.maxIdxOn? f = some 0 ↔ ∃ h : xs ≠ [], ∀ x ∈ xs, f x ≤ f (xs.head h) := by
|
||||
simp only [List.maxIdxOn?_eq_minIdxOn?]
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
simpa [LE.le_opposite_iff] using List.minIdxOn?_eq_some_zero_iff (f := f)
|
||||
|
||||
protected theorem maxIdxOn?_replicate [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} :
|
||||
(replicate n a).maxIdxOn? f = if n = 0 then none else some 0 := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn?_replicate
|
||||
|
||||
@[simp]
|
||||
protected theorem maxIdxOn?_replicate_of_pos [LE β] [DecidableLE β] [Refl (α := β) (· ≤ ·)]
|
||||
{n : Nat} {a : α} {f : α → β} (h : 0 < n) :
|
||||
(replicate n a).maxIdxOn? f = some 0 := by
|
||||
letI : LE β := LE.opposite inferInstance
|
||||
exact List.minIdxOn?_replicate_of_pos h
|
||||
|
||||
end List
|
||||
@@ -1,623 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.MinMaxOn
|
||||
public import Init.Data.Int.OfNat
|
||||
public import Init.Data.List.Lemmas
|
||||
public import Init.Data.List.TakeDrop
|
||||
import Init.Data.Order.Lemmas
|
||||
import Init.Data.List.Sublist
|
||||
import Init.Data.List.MinMax
|
||||
import Init.Data.Order.Opposite
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
open scoped OppositeOrderInstances
|
||||
|
||||
namespace List
|
||||
|
||||
/--
|
||||
Returns an element of the non-empty list {name}`l` that minimizes {name}`f`. If {given}`x, y` are
|
||||
such that {lean}`f x = f y`, it returns whichever comes first in the list.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
The property that {name}`List.minOn` is the first minimizer in the list is guaranteed by the lemma
|
||||
{name (scope := "Init.Data.List.MinMaxIdx")}`List.getElem_minIdxOn`.
|
||||
-/
|
||||
@[inline, suggest_for List.argmin]
|
||||
protected def minOn [LE β] [DecidableLE β] (f : α → β) (l : List α) (h : l ≠ []) : α :=
|
||||
match l with
|
||||
| x :: xs => xs.foldl (init := x) (minOn f)
|
||||
|
||||
/--
|
||||
Returns an element of the non-empty list {name}`l` that maximizes {name}`f`. If {given}`x, y` are
|
||||
such that {lean}`f x = f y`, it returns whichever comes first in the list.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
The property that {name}`List.maxOn` is the first maximizer in the list is guaranteed by the lemma
|
||||
{name (scope := "Init.Data.List.MinMaxIdx")}`List.getElem_maxIdxOn`.
|
||||
-/
|
||||
@[inline, suggest_for List.argmax]
|
||||
protected def maxOn [i : LE β] [DecidableLE β] (f : α → β) (l : List α) (h : l ≠ []) : α :=
|
||||
letI : LE β := i.opposite
|
||||
l.minOn f h
|
||||
|
||||
/--
|
||||
Returns an element of {name}`l` that minimizes {name}`f`. If {given}`x, y` are such that
|
||||
{lean}`f x = f y`, it returns whichever comes first in the list. Returns {name}`none` if the list is
|
||||
empty.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
The property that {name}`List.minOn?` is the first minimizer in the list is guaranteed by the lemma
|
||||
{name (scope := "Init.Data.List.MinMaxIdx")}`List.getElem_get_minIdxOn?`
|
||||
-/
|
||||
@[inline, suggest_for List.argmin? List.argmin] -- Mathlib's `List.argmin` returns an `Option α`
|
||||
protected def minOn? [LE β] [DecidableLE β] (f : α → β) (l : List α) : Option α :=
|
||||
match l with
|
||||
| [] => none
|
||||
| x :: xs => some (xs.foldl (init := x) (minOn f))
|
||||
|
||||
/--
|
||||
Returns an element of {name}`l` that maximizes {name}`f`. If {given}`x, y` are such that
|
||||
{lean}`f x = f y`, it returns whichever comes first in the list. Returns {name}`none` if the list is
|
||||
empty.
|
||||
|
||||
The correctness of this function assumes {name}`β` to be linearly pre-ordered.
|
||||
The property that {name}`List.maxOn?` is the first minimizer in the list is guaranteed by the lemma
|
||||
{name (scope := "Init.Data.List.MinMaxIdx")}`List.getElem_get_maxIdxOn?`.
|
||||
-/
|
||||
@[inline, suggest_for List.argmax? List.argmax] -- Mathlib's `List.argmax` returns an `Option α`
|
||||
protected def maxOn? [i : LE β] [DecidableLE β] (f : α → β) (l : List α) : Option α :=
|
||||
letI : LE β := i.opposite
|
||||
l.minOn? f
|
||||
|
||||
/-! ### minOn -/
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].minOn f (of_decide_eq_false rfl) = x := by
|
||||
simp [List.minOn]
|
||||
|
||||
protected theorem minOn_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
|
||||
(x :: xs).minOn f (by exact of_decide_eq_false rfl) =
|
||||
if h : xs = [] then x else minOn f x (xs.minOn f h) := by
|
||||
simp only [List.minOn]
|
||||
match xs with
|
||||
| [] => simp
|
||||
| y :: xs => simp [foldl_assoc]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_id [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α]
|
||||
{xs : List α} (h : xs ≠ []) :
|
||||
xs.minOn id h = xs.min h := by
|
||||
have : minOn (α := α) id = min := by ext; apply minOn_id
|
||||
simp only [List.minOn, List.min, this]
|
||||
match xs with
|
||||
| _ :: _ => simp
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_mem [LE β] [DecidableLE β] {xs : List α}
|
||||
{f : α → β} {h : xs ≠ []} : xs.minOn f h ∈ xs := by
|
||||
simp only [List.minOn]
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
fun_induction xs.foldl (init := x) (_root_.minOn f)
|
||||
· simp
|
||||
· rename_i x y _ ih
|
||||
simp only [ne_eq, reduceCtorEq, not_false_eq_true, mem_cons, forall_const, foldl_cons] at ih ⊢
|
||||
cases ih <;> rename_i heq
|
||||
· cases minOn_eq_or (f := f) (x := x) (y := y) <;> simp_all
|
||||
· simp [*]
|
||||
|
||||
protected theorem apply_minOn_le_of_mem [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {y : α} (hx : y ∈ xs) :
|
||||
f (xs.minOn f (List.ne_nil_of_mem hx)) ≤ f y := by
|
||||
have h : xs ≠ [] := List.ne_nil_of_mem hx
|
||||
simp only [List.minOn]
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
fun_induction xs.foldl (init := x) (_root_.minOn f) generalizing y
|
||||
· simp only [mem_cons] at hx
|
||||
simp_all
|
||||
· rename_i x y _ ih
|
||||
simp at ih ⊢
|
||||
rcases mem_cons.mp hx with rfl | hx
|
||||
· exact le_trans ih.1 apply_minOn_le_left
|
||||
· rcases mem_cons.mp hx with rfl | hx
|
||||
· exact le_trans ih.1 apply_minOn_le_right
|
||||
· apply ih.2
|
||||
assumption
|
||||
|
||||
protected theorem le_apply_minOn_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
b ≤ f (xs.minOn f h) ↔ ∀ x ∈ xs, b ≤ f x := by
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
rw [List.minOn]
|
||||
induction xs generalizing x
|
||||
· simp
|
||||
· rw [foldl_cons, foldl_assoc, le_apply_minOn_iff]
|
||||
simp_all
|
||||
|
||||
protected theorem apply_minOn_le_iff [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
f (xs.minOn f h) ≤ b ↔ ∃ x ∈ xs, f x ≤ b := by
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
rw [List.minOn] at h
|
||||
induction xs generalizing x
|
||||
· simpa using h
|
||||
· rename_i y ys ih _
|
||||
rw [foldl_cons] at h
|
||||
specialize ih (minOn f x y) (by simp) h
|
||||
obtain ⟨z, hm, hle⟩ := ih
|
||||
rcases mem_cons.mp hm with rfl | hm
|
||||
· cases minOn_eq_or (f := f) (x := x) (y := y)
|
||||
· exact ⟨x, by simp_all⟩
|
||||
· exact ⟨y, by simp_all⟩
|
||||
· exact ⟨z, by simp_all⟩
|
||||
· rintro ⟨x, hm, hx⟩
|
||||
exact le_trans (List.apply_minOn_le_of_mem hm) hx
|
||||
|
||||
protected theorem lt_apply_minOn_iff
|
||||
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
b < f (xs.minOn f h) ↔ ∀ x ∈ xs, b < f x := by
|
||||
simpa [not_le] using not_congr <| xs.apply_minOn_le_iff (f := f) h (b := b)
|
||||
|
||||
protected theorem apply_minOn_lt_iff
|
||||
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
f (xs.minOn f h) < b ↔ ∃ x ∈ xs, f x < b := by
|
||||
simpa [not_le] using not_congr <| xs.le_apply_minOn_iff (f := f) h (b := b)
|
||||
|
||||
protected theorem apply_minOn_le_apply_minOn_of_subset [LE β] [DecidableLE β]
|
||||
[IsLinearPreorder β] {xs ys : List α} {f : α → β} (hxs : ys ⊆ xs) (hys : ys ≠ []) :
|
||||
haveI : xs ≠ [] := by intro h; rw [h] at hxs; simp_all [subset_nil]
|
||||
f (xs.minOn f this) ≤ f (ys.minOn f hys) := by
|
||||
rw [List.le_apply_minOn_iff]
|
||||
intro x hx
|
||||
exact List.apply_minOn_le_of_mem (hxs hx)
|
||||
|
||||
protected theorem le_apply_minOn_take [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {i : Nat} (h : xs.take i ≠ []) :
|
||||
f (xs.minOn f (List.ne_nil_of_take_ne_nil h)) ≤ f ((xs.take i).minOn f h) := by
|
||||
apply List.apply_minOn_le_apply_minOn_of_subset
|
||||
apply take_subset
|
||||
|
||||
protected theorem apply_minOn_append_le_left [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : xs ≠ []) :
|
||||
f ((xs ++ ys).minOn f (append_ne_nil_of_left_ne_nil h ys)) ≤
|
||||
f (xs.minOn f h) := by
|
||||
apply List.apply_minOn_le_apply_minOn_of_subset
|
||||
apply subset_append_left
|
||||
|
||||
protected theorem apply_minOn_append_le_right [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : ys ≠ []) :
|
||||
f ((xs ++ ys).minOn f (append_ne_nil_of_right_ne_nil xs h)) ≤
|
||||
f (ys.minOn f h) := by
|
||||
apply List.apply_minOn_le_apply_minOn_of_subset
|
||||
apply subset_append_right
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_append [LE β] [DecidableLE β] [IsLinearPreorder β] {xs ys : List α}
|
||||
{f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
(xs ++ ys).minOn f (by simp [hxs]) = minOn f (xs.minOn f hxs) (ys.minOn f hys) := by
|
||||
match xs, ys with
|
||||
| x :: xs, y :: ys => simp [List.minOn, foldl_assoc]
|
||||
|
||||
protected theorem minOn_eq_head [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) (h' : ∀ x ∈ xs, f (xs.head h) ≤ f x) :
|
||||
xs.minOn f h = xs.head h := by
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
simp only [List.minOn]
|
||||
induction xs
|
||||
· simp
|
||||
· simp only [foldl_cons, head_cons]
|
||||
rw [minOn_eq_left] <;> simp_all
|
||||
|
||||
protected theorem min_map
|
||||
[LE β] [DecidableLE β] [Min β] [IsLinearPreorder β] [LawfulOrderLeftLeaningMin β] {xs : List α}
|
||||
{f : α → β} (h : xs ≠ []) :
|
||||
(xs.map f).min (by simpa) = f (xs.minOn f h) := by
|
||||
match xs with
|
||||
| x :: xs =>
|
||||
simp only [List.minOn, map_cons, List.min, foldl_map]
|
||||
rw [foldl_hom]
|
||||
simp [min_apply]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
(replicate n a).minOn f h = a := by
|
||||
induction n
|
||||
· simp at h
|
||||
· rename_i n ih
|
||||
simp only [ne_eq, replicate_eq_nil_iff] at ih
|
||||
simp +contextual [List.replicate, List.minOn_cons, ih]
|
||||
|
||||
/-! ### maxOn -/
|
||||
|
||||
protected theorem maxOn_eq_minOn {le : LE β} {dle : DecidableLE β} {xs : List α} {f : α → β} {h} :
|
||||
xs.maxOn f h = (letI := le.opposite; xs.minOn f h) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].maxOn f (of_decide_eq_false rfl) = x := by
|
||||
simp [List.maxOn]
|
||||
|
||||
protected theorem maxOn_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {x : α} {xs : List α} {f : α → β} :
|
||||
(x :: xs).maxOn f (by exact of_decide_eq_false rfl) =
|
||||
if h : xs = [] then x else maxOn f x (xs.maxOn f h) := by
|
||||
simp only [maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minOn_cons (f := f)
|
||||
|
||||
protected theorem min_eq_max {min : Min α} {xs : List α} {h} :
|
||||
xs.min h = (letI := min.oppositeMax; xs.max h) := by
|
||||
simp only [List.min, List.max]
|
||||
rw [Min.oppositeMax_def]
|
||||
simp
|
||||
|
||||
protected theorem max_eq_min {max : Max α} {xs : List α} {h} :
|
||||
xs.max h = (letI := max.oppositeMin; xs.min h) := by
|
||||
simp only [List.min, List.max]
|
||||
rw [Max.oppositeMin_def]
|
||||
simp
|
||||
|
||||
protected theorem max?_eq_min? {max : Max α} {xs : List α} :
|
||||
xs.max? = (letI := max.oppositeMin; xs.min?) := by
|
||||
simp only [List.min?, List.max?]
|
||||
rw [Max.oppositeMin_def]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
|
||||
{xs : List α} (h : xs ≠ []) :
|
||||
xs.maxOn id h = xs.max h := by
|
||||
simp only [List.maxOn_eq_minOn]
|
||||
letI : LE α := (inferInstanceAs (LE α)).opposite
|
||||
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
|
||||
simpa only [List.max_eq_min] using List.minOn_id h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_mem [LE β] [DecidableLE β] {xs : List α}
|
||||
{f : α → β} {h : xs ≠ []} : xs.maxOn f h ∈ xs :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn_mem (f := f)
|
||||
|
||||
protected theorem le_apply_maxOn_of_mem [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {y : α} (hx : y ∈ xs) :
|
||||
f y ≤ f (xs.maxOn f (List.ne_nil_of_mem hx)) := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_minOn_le_of_mem (f := f) hx
|
||||
|
||||
protected theorem apply_maxOn_le_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
|
||||
{f : α → β} (h : xs ≠ []) {b : β} :
|
||||
f (xs.maxOn f h) ≤ b ↔ ∀ x ∈ xs, f x ≤ b := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.le_apply_minOn_iff (f := f) h
|
||||
|
||||
protected theorem le_apply_maxOn_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
|
||||
{f : α → β} (h : xs ≠ []) {b : β} :
|
||||
b ≤ f (xs.maxOn f h) ↔ ∃ x ∈ xs, b ≤ f x := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_minOn_le_iff (f := f) h
|
||||
|
||||
protected theorem apply_maxOn_lt_iff
|
||||
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
f (xs.maxOn f h) < b ↔ ∀ x ∈ xs, f x < b := by
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
letI : LT β := (inferInstanceAs (LT β)).opposite
|
||||
simpa [LT.lt_opposite_iff] using List.lt_apply_minOn_iff (f := f) h
|
||||
|
||||
protected theorem lt_apply_maxOn_iff
|
||||
[LE β] [DecidableLE β] [LT β] [IsLinearPreorder β] [LawfulOrderLT β]
|
||||
{xs : List α} {f : α → β} (h : xs ≠ []) {b : β} :
|
||||
b < f (xs.maxOn f h) ↔ ∃ x ∈ xs, b < f x := by
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
letI : LT β := (inferInstanceAs (LT β)).opposite
|
||||
simpa [LT.lt_opposite_iff] using List.apply_minOn_lt_iff (f := f) h
|
||||
|
||||
protected theorem apply_maxOn_le_apply_maxOn_of_subset [LE β] [DecidableLE β]
|
||||
[IsLinearPreorder β] {xs ys : List α} {f : α → β} (hxs : ys ⊆ xs) (hys : ys ≠ []) :
|
||||
haveI : xs ≠ [] := by intro h; rw [h] at hxs; simp_all [subset_nil]
|
||||
f (ys.maxOn f hys) ≤ f (xs.maxOn f this) := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_minOn_le_apply_minOn_of_subset (f := f) hxs hys
|
||||
|
||||
protected theorem apply_maxOn_take_le [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs : List α} {f : α → β} {i : Nat} (h : xs.take i ≠ []) :
|
||||
f ((xs.take i).maxOn f h) ≤ f (xs.maxOn f (List.ne_nil_of_take_ne_nil h)) := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.le_apply_minOn_take (f := f) h
|
||||
|
||||
protected theorem le_apply_maxOn_append_left [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : xs ≠ []) :
|
||||
f (xs.maxOn f h) ≤
|
||||
f ((xs ++ ys).maxOn f (append_ne_nil_of_left_ne_nil h ys)) := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_minOn_append_le_left (f := f) h
|
||||
|
||||
protected theorem le_apply_maxOn_append_right [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (h : ys ≠ []) :
|
||||
f (ys.maxOn f h) ≤
|
||||
f ((xs ++ ys).maxOn f (append_ne_nil_of_right_ne_nil xs h)) := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_minOn_append_le_right (f := f) h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β] {xs ys : List α}
|
||||
{f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
(xs ++ ys).maxOn f (by simp [hxs]) = maxOn f (xs.maxOn f hxs) (ys.maxOn f hys) := by
|
||||
simp only [List.maxOn_eq_minOn, maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.minOn_append (f := f) hxs hys
|
||||
|
||||
protected theorem maxOn_eq_head [LE β] [DecidableLE β] [IsLinearPreorder β] {xs : List α}
|
||||
{f : α → β} (h : xs ≠ []) (h' : ∀ x ∈ xs, f x ≤ f (xs.head h)) :
|
||||
xs.maxOn f h = xs.head h := by
|
||||
rw [List.maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.minOn_eq_head (f := f) h (by simpa [LE.le_opposite_iff] using h')
|
||||
|
||||
protected theorem max_map
|
||||
[LE β] [DecidableLE β] [Max β] [IsLinearPreorder β] [LawfulOrderLeftLeaningMax β] {xs : List α}
|
||||
{f : α → β} (h : xs ≠ []) : (xs.map f).max (by simpa) = f (xs.maxOn f h) := by
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
letI : Min β := (inferInstanceAs (Max β)).oppositeMin
|
||||
simpa [List.max_eq_min] using List.min_map (f := f) h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
(replicate n a).maxOn f h = a :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn_replicate (f := f) h
|
||||
|
||||
/-! ### minOn? -/
|
||||
|
||||
/-- {lit}`List.minOn?` returns {name}`none` when applied to an empty list. -/
|
||||
@[simp]
|
||||
protected theorem minOn?_nil [LE β] [DecidableLE β] {f : α → β} :
|
||||
([] : List α).minOn? f = none := by
|
||||
simp [List.minOn?]
|
||||
|
||||
protected theorem minOn?_cons_eq_some_minOn
|
||||
[LE β] [DecidableLE β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).minOn? f = some ((x :: xs).minOn f (fun h => nomatch h)) := by
|
||||
simp [List.minOn?, List.minOn]
|
||||
|
||||
protected theorem minOn?_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).minOn? f = some ((xs.minOn? f).elim x (minOn f x)) := by
|
||||
simp only [List.minOn?]
|
||||
split <;> simp [foldl_assoc]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn?_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].minOn? f = some x := by
|
||||
simp [List.minOn?_cons_eq_some_minOn]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn?_id [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α]
|
||||
{xs : List α} : xs.minOn? id = xs.min? := by
|
||||
cases xs
|
||||
· simp
|
||||
· simp only [List.minOn?_cons_eq_some_minOn, List.minOn_id, List.min?_eq_some_min (List.cons_ne_nil _ _)]
|
||||
|
||||
protected theorem minOn?_eq_if
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {xs : List α} :
|
||||
xs.minOn? f =
|
||||
if h : xs ≠ [] then
|
||||
some (xs.minOn f h)
|
||||
else
|
||||
none := by
|
||||
fun_cases xs.minOn? f <;> simp [List.minOn]
|
||||
|
||||
@[simp]
|
||||
protected theorem isSome_minOn?_iff [LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
(xs.minOn? f).isSome ↔ xs ≠ [] := by
|
||||
fun_cases xs.minOn? f <;> simp
|
||||
|
||||
protected theorem minOn_eq_get_minOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.minOn f h = (xs.minOn? f).get (List.isSome_minOn?_iff.mpr h) := by
|
||||
fun_cases xs.minOn? f
|
||||
· contradiction
|
||||
· simp [List.minOn?, List.minOn]
|
||||
|
||||
protected theorem minOn?_eq_some_minOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.minOn? f = some (xs.minOn f h) := by
|
||||
simp [List.minOn_eq_get_minOn? h]
|
||||
|
||||
@[simp]
|
||||
protected theorem get_minOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : (xs.minOn? f).get (List.isSome_minOn?_iff.mpr h) = xs.minOn f h := by
|
||||
rw [List.minOn_eq_get_minOn?]
|
||||
|
||||
protected theorem minOn_eq_of_minOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : xs.minOn? f = some x) :
|
||||
xs.minOn f (List.isSome_minOn?_iff.mp (Option.isSome_of_eq_some h)) = x := by
|
||||
have h' := List.isSome_minOn?_iff.mp (Option.isSome_of_eq_some h)
|
||||
rwa [List.minOn?_eq_some_minOn h', Option.some.injEq] at h
|
||||
|
||||
protected theorem isSome_minOn?_of_mem
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
(xs.minOn? f).isSome := by
|
||||
apply List.isSome_minOn?_iff.mpr
|
||||
exact ne_nil_of_mem h
|
||||
|
||||
protected theorem apply_get_minOn?_le_of_mem
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
f ((xs.minOn? f).get (List.isSome_minOn?_of_mem h)) ≤ f x := by
|
||||
rw [List.get_minOn? (ne_nil_of_mem h)]
|
||||
apply List.apply_minOn_le_of_mem h
|
||||
|
||||
protected theorem minOn?_mem [LE β] [DecidableLE β] {xs : List α}
|
||||
{f : α → β} (h : xs.minOn? f = some a) : a ∈ xs := by
|
||||
rw [← List.minOn_eq_of_minOn?_eq_some h]
|
||||
apply List.minOn_mem
|
||||
|
||||
protected theorem minOn?_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} :
|
||||
(replicate n a).minOn? f = if n = 0 then none else some a := by
|
||||
split
|
||||
· simp [*]
|
||||
· rw [List.minOn?_eq_some_minOn, List.minOn_replicate]
|
||||
simp [*]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn?_replicate_of_pos [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : 0 < n) :
|
||||
(replicate n a).minOn? f = some a := by
|
||||
simp [List.minOn?_replicate, show n ≠ 0 from Nat.ne_zero_of_lt h]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn?_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
(xs ys : List α) (f : α → β) :
|
||||
(xs ++ ys).minOn? f =
|
||||
(xs.minOn? f).merge (_root_.minOn f) (ys.minOn? f) := by
|
||||
by_cases xs = [] <;> by_cases ys = [] <;> simp [*, List.minOn?_eq_if, List.minOn_append]
|
||||
|
||||
/-! ### maxOn? -/
|
||||
|
||||
protected theorem maxOn?_eq_minOn? {le : LE β} {dle : DecidableLE β} {xs : List α} {f : α → β} :
|
||||
xs.maxOn? f = (letI := le.opposite; xs.minOn? f) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn?_nil [LE β] [DecidableLE β] {f : α → β} :
|
||||
([] : List α).maxOn? f = none :=
|
||||
List.minOn?_nil (f := f)
|
||||
|
||||
protected theorem maxOn?_cons_eq_some_maxOn
|
||||
[LE β] [DecidableLE β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).maxOn? f = some ((x :: xs).maxOn f (fun h => nomatch h)) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_cons_eq_some_minOn
|
||||
|
||||
protected theorem maxOn?_cons
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {x : α} {xs : List α} :
|
||||
(x :: xs).maxOn? f = some ((xs.maxOn? f).elim x (maxOn f x)) := by
|
||||
have : maxOn f x = (letI : LE β := LE.opposite inferInstance; minOn f x) := by
|
||||
ext; simp only [maxOn_eq_minOn]
|
||||
simp only [List.maxOn?_eq_minOn?, this]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minOn?_cons
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn?_singleton [LE β] [DecidableLE β] {x : α} {f : α → β} :
|
||||
[x].maxOn? f = some x :=
|
||||
List.minOn?_singleton (f := f)
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn?_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
|
||||
{xs : List α} : xs.maxOn? id = xs.max? := by
|
||||
letI : LE α := (inferInstanceAs (LE α)).opposite
|
||||
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
|
||||
simpa only [List.maxOn?_eq_minOn?, List.max?_eq_min?] using List.minOn?_id (α := α)
|
||||
|
||||
protected theorem maxOn?_eq_if
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {xs : List α} :
|
||||
xs.maxOn? f =
|
||||
if h : xs ≠ [] then
|
||||
some (xs.maxOn f h)
|
||||
else
|
||||
none :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_eq_if
|
||||
|
||||
@[simp]
|
||||
protected theorem isSome_maxOn?_iff [LE β] [DecidableLE β] {f : α → β} {xs : List α} :
|
||||
(xs.maxOn? f).isSome ↔ xs ≠ [] := by
|
||||
fun_cases xs.maxOn? f <;> simp
|
||||
|
||||
protected theorem maxOn_eq_get_maxOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.maxOn f h = (xs.maxOn? f).get (List.isSome_maxOn?_iff.mpr h) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn_eq_get_minOn? (f := f) h
|
||||
|
||||
protected theorem maxOn?_eq_some_maxOn [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : xs.maxOn? f = some (xs.maxOn f h) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_eq_some_minOn (f := f) h
|
||||
|
||||
@[simp]
|
||||
protected theorem get_maxOn? [LE β] [DecidableLE β] {f : α → β} {xs : List α}
|
||||
(h : xs ≠ []) : (xs.maxOn? f).get (List.isSome_maxOn?_iff.mpr h) = xs.maxOn f h :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.get_minOn? (f := f) h
|
||||
|
||||
protected theorem maxOn_eq_of_maxOn?_eq_some
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : xs.maxOn? f = some x) :
|
||||
xs.maxOn f (List.isSome_maxOn?_iff.mp (Option.isSome_of_eq_some h)) = x :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn_eq_of_minOn?_eq_some (f := f) h
|
||||
|
||||
protected theorem isSome_maxOn?_of_mem
|
||||
[LE β] [DecidableLE β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
(xs.maxOn? f).isSome :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.isSome_minOn?_of_mem (f := f) h
|
||||
|
||||
protected theorem le_apply_get_maxOn?_of_mem
|
||||
[LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} {xs : List α} {x : α} (h : x ∈ xs) :
|
||||
f x ≤ f ((xs.maxOn? f).get (List.isSome_maxOn?_of_mem h)) := by
|
||||
simp only [List.maxOn?_eq_minOn?]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa [LE.le_opposite_iff] using List.apply_get_minOn?_le_of_mem (f := f) h
|
||||
|
||||
protected theorem maxOn?_mem [LE β] [DecidableLE β] {xs : List α}
|
||||
{f : α → β} (h : xs.maxOn? f = some a) : a ∈ xs :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_mem (f := f) h
|
||||
|
||||
protected theorem maxOn?_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} :
|
||||
(replicate n a).maxOn? f = if n = 0 then none else some a :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_replicate
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn?_replicate_of_pos [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : 0 < n) :
|
||||
(replicate n a).maxOn? f = some a :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
List.minOn?_replicate_of_pos (f := f) h
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn?_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
(xs ys : List α) (f : α → β) : (xs ++ ys).maxOn? f =
|
||||
(xs.maxOn? f).merge (_root_.maxOn f) (ys.maxOn? f) := by
|
||||
have : maxOn f = (letI : LE β := LE.opposite inferInstance; minOn f) := by
|
||||
ext; simp only [maxOn_eq_minOn]
|
||||
simp only [List.maxOn?_eq_minOn?, this]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minOn?_append xs ys f
|
||||
|
||||
end List
|
||||
@@ -12,7 +12,6 @@ public import Init.Data.List.Nat.Range
|
||||
public import Init.Data.List.Nat.Sublist
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
public import Init.Data.List.Nat.Count
|
||||
public import Init.Data.List.Nat.Sum
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Nat.Find
|
||||
public import Init.Data.List.Nat.BEq
|
||||
|
||||
@@ -254,18 +254,4 @@ theorem le_max?_getD_of_mem {l : List Nat} {a k : Nat} (h : a ∈ l) :
|
||||
a ≤ l.max?.getD k :=
|
||||
Option.get_eq_getD _ ▸ le_max?_get_of_mem h
|
||||
|
||||
/-! #### append -/
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_left {ws xs ys zs : List α}
|
||||
(h : ws.length = xs.length) : ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
rw [append_eq_append_iff]
|
||||
refine ⟨?_, ?_⟩
|
||||
· rintro (⟨as, rfl, rfl⟩|⟨as, rfl, rfl⟩) <;> simp_all
|
||||
· rintro ⟨rfl, rfl⟩ <;> simp_all
|
||||
|
||||
theorem append_eq_append_iff_of_size_eq_right {ws xs ys zs : List α}
|
||||
(h : ys.length = zs.length) : ws ++ ys = xs ++ zs ↔ ws = xs ∧ ys = zs := by
|
||||
rw [← reverse_inj, reverse_append, reverse_append,
|
||||
append_eq_append_iff_of_size_eq_left (by simpa), reverse_inj, reverse_inj, and_comm]
|
||||
|
||||
end List
|
||||
|
||||
@@ -13,6 +13,13 @@ public section
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
protected theorem Nat.sum_pos_iff_exists_pos {l : List Nat} : 0 < l.sum ↔ ∃ x ∈ l, 0 < x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp [← ih]
|
||||
omega
|
||||
|
||||
namespace List
|
||||
|
||||
open Nat
|
||||
|
||||
@@ -131,14 +131,6 @@ theorem suffix_iff_eq_drop : l₁ <:+ l₂ ↔ l₁ = drop (length l₂ - length
|
||||
⟨fun h => append_cancel_left <| (suffix_iff_eq_append.1 h).trans (take_append_drop _ _).symm,
|
||||
fun e => e.symm ▸ drop_suffix _ _⟩
|
||||
|
||||
theorem prefix_map_iff_of_injective {f : α → β} (hf : Function.Injective f) :
|
||||
l₁.map f <+: l₂.map f ↔ l₁ <+: l₂ := by
|
||||
simp [prefix_iff_eq_take, ← map_take, map_inj_right hf]
|
||||
|
||||
theorem suffix_map_iff_of_injective {f : α → β} (hf : Function.Injective f) :
|
||||
l₁.map f <:+ l₂.map f ↔ l₁ <:+ l₂ := by
|
||||
simp [suffix_iff_eq_drop, ← map_drop, map_inj_right hf]
|
||||
|
||||
@[grind =] theorem prefix_take_le_iff {xs : List α} (hm : i < xs.length) :
|
||||
xs.take i <+: xs.take j ↔ i ≤ j := by
|
||||
simp only [prefix_iff_eq_take, length_take]
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison, Sebastian Graf, Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Int.DivMod.Bootstrap
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.List.MinMax
|
||||
|
||||
public section
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace List
|
||||
|
||||
protected theorem sum_pos_iff_exists_pos_nat {l : List Nat} : 0 < l.sum ↔ ∃ x ∈ l, 0 < x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp [← ih]
|
||||
omega
|
||||
|
||||
@[deprecated List.sum_pos_iff_exists_pos_nat (since := "2025-01-15")]
|
||||
protected def _root_.Nat.sum_pos_iff_exists_pos := @List.sum_pos_iff_exists_pos_nat
|
||||
|
||||
protected theorem sum_eq_zero_iff_forall_eq_nat {xs : List Nat} :
|
||||
xs.sum = 0 ↔ ∀ x ∈ xs, x = 0 := by
|
||||
rw [← Decidable.not_iff_not]
|
||||
simp [← Nat.pos_iff_ne_zero, List.sum_pos_iff_exists_pos_nat]
|
||||
|
||||
@[deprecated List.sum_pos_iff_exists_pos_nat (since := "2025-01-15")]
|
||||
protected def _root_.Nat.sum_eq_zero_iff_forall_eq := @List.sum_eq_zero_iff_forall_eq_nat
|
||||
|
||||
@[simp]
|
||||
theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
induction n <;> simp_all [replicate_succ, Nat.add_mul, Nat.add_comm]
|
||||
|
||||
theorem sum_append_nat {l₁ l₂ : List Nat} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
simp [sum_append]
|
||||
|
||||
theorem sum_reverse_nat (xs : List Nat) : xs.reverse.sum = xs.sum := by
|
||||
simp [sum_reverse]
|
||||
|
||||
theorem sum_eq_foldl_nat {xs : List Nat} : xs.sum = xs.foldl (init := 0) (· + ·) := by
|
||||
simp only [foldl_eq_foldr_reverse, Nat.add_comm, ← sum_eq_foldr, sum_reverse_nat]
|
||||
|
||||
theorem min_mul_length_le_sum_nat {xs : List Nat} (h : xs ≠ []) :
|
||||
xs.min h * xs.length ≤ xs.sum := by
|
||||
induction xs
|
||||
· contradiction
|
||||
· rename_i x xs ih
|
||||
cases xs
|
||||
· simp_all [List.min_singleton]
|
||||
· simp only [ne_eq, reduceCtorEq, not_false_eq_true, min_eq_get_min?,
|
||||
List.min?_cons (α := Nat), Option.get_some, length_cons,
|
||||
forall_const] at ih ⊢
|
||||
rw [Nat.mul_add, Nat.mul_one, Nat.add_comm]
|
||||
apply Nat.add_le_add
|
||||
· apply Nat.min_le_left
|
||||
· refine Nat.le_trans ?_ ih
|
||||
rw [Nat.mul_le_mul_right_iff (by omega)]
|
||||
apply Nat.min_le_right
|
||||
|
||||
theorem mul_length_le_sum_of_min?_eq_some_nat {xs : List Nat} (h : xs.min? = some x) :
|
||||
x * xs.length ≤ xs.sum := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [min?_eq_some_min (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using min_mul_length_le_sum_nat _
|
||||
|
||||
theorem min_le_sum_div_length_nat {xs : List Nat} (h : xs ≠ []) :
|
||||
xs.min h ≤ xs.sum / xs.length := by
|
||||
have := min_mul_length_le_sum_nat h
|
||||
rwa [Nat.le_div_iff_mul_le]
|
||||
simp [List.length_pos_iff, h]
|
||||
|
||||
theorem le_sum_div_length_of_min?_eq_some_nat {xs : List Nat} (h : xs.min? = some x) :
|
||||
x ≤ xs.sum / xs.length := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [min?_eq_some_min (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa [← h] using min_le_sum_div_length_nat _
|
||||
|
||||
theorem sum_le_max_mul_length_nat {xs : List Nat} (h : xs ≠ []) :
|
||||
xs.sum ≤ xs.max h * xs.length := by
|
||||
induction xs
|
||||
· contradiction
|
||||
· rename_i x xs ih
|
||||
cases xs
|
||||
· simp_all [List.max_singleton]
|
||||
· simp only [ne_eq, reduceCtorEq, not_false_eq_true, max_eq_get_max?,
|
||||
List.max?_cons (α := Nat), Option.get_some, length_cons,
|
||||
forall_const, Option.elim_some] at ih ⊢
|
||||
rw [Nat.mul_add, Nat.mul_one, Nat.add_comm]
|
||||
apply Nat.add_le_add
|
||||
· apply Nat.le_max_left
|
||||
· refine Nat.le_trans ih ?_
|
||||
rw [Nat.mul_le_mul_right_iff (by omega)]
|
||||
apply Nat.le_max_right
|
||||
|
||||
theorem sum_le_max_mul_length_of_max?_eq_some_nat {xs : List Nat} (h : xs.max? = some x) :
|
||||
xs.sum ≤ x * xs.length := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [max?_eq_some_max (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simp only [← h]
|
||||
apply sum_le_max_mul_length_nat
|
||||
|
||||
theorem sum_div_length_le_max_nat {xs : List Nat} (h : xs ≠ []) :
|
||||
xs.sum / xs.length ≤ xs.max h := by
|
||||
have := sum_le_max_mul_length_nat h
|
||||
rw [Nat.div_le_iff_le_mul, Nat.add_sub_assoc]
|
||||
· exact Nat.le_trans this (Nat.le_add_right _ _)
|
||||
· simp [Nat.one_le_iff_ne_zero, h]
|
||||
· simp [← Nat.ne_zero_iff_zero_lt, h]
|
||||
|
||||
theorem sum_div_length_le_max_of_max?_eq_some_nat {xs : List Nat} (h : xs.max? = some x) :
|
||||
xs.sum / xs.length ≤ x := by
|
||||
cases xs
|
||||
· simp_all
|
||||
· simp only [max?_eq_some_max (cons_ne_nil _ _), Option.some.injEq] at h
|
||||
simpa only [← h] using sum_div_length_le_max_nat _
|
||||
|
||||
end List
|
||||
@@ -137,15 +137,10 @@ theorem take_append {l₁ l₂ : List α} {i : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem take_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
|
||||
(l₁ ++ l₂).take i = l₁.take i := by
|
||||
simp [take_append, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
@[grind =]
|
||||
theorem take_append_length {l₁ l₂ : List α} : (l₁ ++ l₂).take l₁.length = l₁ := by
|
||||
simp
|
||||
|
||||
/-- Taking the first `l₁.length + i` elements in `l₁ ++ l₂` is the same as appending the first
|
||||
`i` elements of `l₂` to `l₁`. -/
|
||||
theorem take_length_add_append {l₁ l₂ : List α} (i : Nat) :
|
||||
@@ -309,6 +304,7 @@ theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) :
|
||||
|
||||
/-- Dropping the elements up to `i` in `l₁ ++ l₂` is the same as dropping the elements up to `i`
|
||||
in `l₁`, dropping the elements up to `i - l₁.length` in `l₂`, and appending them. -/
|
||||
@[grind =]
|
||||
theorem drop_append {l₁ l₂ : List α} {i : Nat} :
|
||||
drop i (l₁ ++ l₂) = drop i l₁ ++ drop (i - l₁.length) l₂ := by
|
||||
induction l₁ generalizing i
|
||||
@@ -319,15 +315,10 @@ theorem drop_append {l₁ l₂ : List α} {i : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem drop_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
|
||||
(l₁ ++ l₂).drop i = l₁.drop i ++ l₂ := by
|
||||
simp [drop_append, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
@[grind =]
|
||||
theorem drop_append_length {l₁ l₂ : List α} : (l₁ ++ l₂).drop l₁.length = l₂ := by
|
||||
simp [List.drop_append_of_le_length (Nat.le_refl _)]
|
||||
|
||||
/-- Dropping the elements up to `l₁.length + i` in `l₁ + l₂` is the same as dropping the elements
|
||||
up to `i` in `l₂`. -/
|
||||
@[simp]
|
||||
@@ -373,7 +364,7 @@ theorem drop_take : ∀ {i j : Nat} {l : List α}, drop i (take j l) = take (j -
|
||||
simp only [take_succ_cons, drop_succ_cons, drop_take, take_eq_take_iff, length_drop]
|
||||
omega
|
||||
|
||||
@[simp, grind =] theorem drop_take_self : drop i (take i l) = [] := by
|
||||
@[simp] theorem drop_take_self : drop i (take i l) = [] := by
|
||||
rw [drop_take]
|
||||
simp
|
||||
|
||||
|
||||
@@ -100,11 +100,6 @@ theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_getElem {xs : List α} :
|
||||
List.ofFn (fun i : Fin xs.length => xs[i.val]) = xs := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp 500, grind =]
|
||||
theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
@@ -114,12 +109,6 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem map_ofFn {f : Fin n → α} {g : α → β} :
|
||||
(List.ofFn f).map g = List.ofFn (g ∘ f) := by
|
||||
apply List.ext_getElem?
|
||||
simp [List.getElem?_ofFn]
|
||||
|
||||
@[grind =] theorem head_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
|
||||
@@ -580,7 +580,7 @@ theorem sublist_flatten_iff {L : List (List α)} {l} :
|
||||
· rintro ⟨L', rfl, h⟩
|
||||
simp only [flatten_nil, sublist_nil, flatten_eq_nil_iff]
|
||||
simp only [getElem?_nil, Option.getD_none, sublist_nil] at h
|
||||
exact (forall_mem_iff_forall_getElem (P := (· = []))).2 h
|
||||
exact (forall_getElem (p := (· = []))).1 h
|
||||
| cons l' L ih =>
|
||||
simp only [flatten_cons, sublist_append_iff, ih]
|
||||
constructor
|
||||
@@ -1124,11 +1124,9 @@ theorem drop_subset (i) (l : List α) : drop i l ⊆ l :=
|
||||
|
||||
grind_pattern drop_subset => drop i l ⊆ l
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take i) : a ∈ l :=
|
||||
take_subset _ _ h
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_drop {i} {l : List α} (h : a ∈ l.drop i) : a ∈ l :=
|
||||
drop_subset _ _ h
|
||||
|
||||
|
||||
@@ -54,15 +54,6 @@ theorem div_le_iff_le_mul (h : 0 < k) : x / k ≤ y ↔ x ≤ y * k + k - 1 := b
|
||||
rw [le_iff_lt_add_one, Nat.div_lt_iff_lt_mul h, Nat.add_one_mul]
|
||||
omega
|
||||
|
||||
theorem le_mul_iff_le_left (hz : 0 < z) :
|
||||
x ≤ y * z ↔ (x + z - 1) / z ≤ y := by
|
||||
rw [Nat.div_le_iff_le_mul hz]
|
||||
omega
|
||||
|
||||
theorem le_mul_iff_le_right (hy : 0 < y) :
|
||||
x ≤ y * z ↔ (x + y - 1) / y ≤ z := by
|
||||
rw [← le_mul_iff_le_left hy, Nat.mul_comm]
|
||||
|
||||
-- TODO: reprove `div_eq_of_lt_le` in terms of this:
|
||||
protected theorem div_eq_iff (h : 0 < k) : x / k = y ↔ y * k ≤ x ∧ x ≤ y * k + k - 1 := by
|
||||
rw [Nat.eq_iff_le_and_ge, and_comm, le_div_iff_mul_le h, Nat.div_le_iff_le_mul h]
|
||||
@@ -104,12 +95,6 @@ theorem div_add_le_right {z : Nat} (h : 0 < z) (x y : Nat) :
|
||||
x / (y + z) ≤ x / z :=
|
||||
div_le_div_left (Nat.le_add_left z y) h
|
||||
|
||||
theorem div_add_div_le_add_div {x y z : Nat} : x / z + y / z ≤ (x + y) / z := by
|
||||
by_cases hc : z > 0
|
||||
· rw [Nat.le_div_iff_mul_le hc, Nat.add_mul]
|
||||
apply Nat.add_le_add <;> apply Nat.div_mul_le_self
|
||||
· simp_all
|
||||
|
||||
theorem succ_div_of_dvd {a b : Nat} (h : b ∣ a + 1) :
|
||||
(a + 1) / b = a / b + 1 := by
|
||||
replace h := mod_eq_zero_of_dvd h
|
||||
|
||||
@@ -883,10 +883,6 @@ theorem guard_or_guard : (guard p a).or (guard q a) = guard (fun x => p x || q x
|
||||
simp only [guard]
|
||||
split <;> simp_all
|
||||
|
||||
theorem any_or_of_any_left {o₁ o₂ : Option α} {f : α → Bool} (h : o₁.any f) :
|
||||
(o₁.or o₂).any f := by
|
||||
cases o₁ <;> simp_all
|
||||
|
||||
/-! ### `orElse` -/
|
||||
|
||||
/-- The `simp` normal form of `o <|> o'` is `o.or o'` via `orElse_eq_orElse` and `orElse_eq_or`. -/
|
||||
|
||||
@@ -609,22 +609,21 @@ protected theorem compare_nil_right_eq_eq {α} [Ord α] {xs : List α} :
|
||||
end List
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
@[expose, instance_reducible]
|
||||
def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
@[expose] def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
/--
|
||||
Constructs an `BEq` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.eq`.
|
||||
-/
|
||||
@[expose, instance_reducible] def beqOfOrd [Ord α] : BEq α where
|
||||
@[expose] def beqOfOrd [Ord α] : BEq α where
|
||||
beq a b := (compare a b).isEq
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.lt`.
|
||||
-/
|
||||
@[expose, instance_reducible] def ltOfOrd [Ord α] : LT α where
|
||||
@[expose] def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
|
||||
@[inline]
|
||||
|
||||
@@ -13,6 +13,4 @@ public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.LemmasExtra
|
||||
public import Init.Data.Order.Factories
|
||||
public import Init.Data.Order.FactoriesExtra
|
||||
public import Init.Data.Order.MinMaxOn
|
||||
public import Init.Data.Order.Opposite
|
||||
public import Init.Data.Order.PackageFactories
|
||||
|
||||
@@ -23,7 +23,7 @@ preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMin α` instance.
|
||||
-/
|
||||
@[inline, instance_reducible]
|
||||
@[inline]
|
||||
public def _root_.Min.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
@@ -33,7 +33,7 @@ preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMax α` instance.
|
||||
-/
|
||||
@[inline, instance_reducible]
|
||||
@[inline]
|
||||
public def _root_.Max.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Creates an `LE α` instance from an `Ord α` instance.
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LE α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose]
|
||||
public def _root_.LE.ofOrd (α : Type u) [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@@ -38,7 +38,7 @@ Creates an `LT α` instance from an `Ord α` instance.
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LT α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose]
|
||||
public def _root_.LT.ofOrd (α : Type u) [Ord α] :
|
||||
LT α where
|
||||
lt a b := compare a b = .lt
|
||||
@@ -82,7 +82,7 @@ public def _root_.DecidableLT.ofOrd (α : Type u) [LE α] [LT α] [Ord α] [Lawf
|
||||
|
||||
/--
|
||||
Creates a `BEq α` instance from an `Ord α` instance. -/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose]
|
||||
public def _root_.BEq.ofOrd (α : Type u) [Ord α] :
|
||||
BEq α where
|
||||
beq a b := compare a b = .eq
|
||||
|
||||
@@ -90,13 +90,9 @@ end AxiomaticInstances
|
||||
|
||||
section LE
|
||||
|
||||
@[simp]
|
||||
public theorem le_refl {α : Type u} [LE α] [Refl (α := α) (· ≤ ·)] (a : α) : a ≤ a := by
|
||||
simp [Refl.refl]
|
||||
|
||||
public theorem le_of_eq [LE α] [Refl (α := α) (· ≤ ·)] {a b : α} : a = b → a ≤ b :=
|
||||
(· ▸ le_refl _)
|
||||
|
||||
public theorem le_antisymm {α : Type u} [LE α] [Std.Antisymm (α := α) (· ≤ ·)] {a b : α}
|
||||
(hab : a ≤ b) (hba : b ≤ a) : a = b :=
|
||||
Antisymm.antisymm _ _ hab hba
|
||||
@@ -146,10 +142,6 @@ public theorem not_gt_of_lt {α : Type u} [LT α] [i : Std.Asymm (α := α) (·
|
||||
(h : a < b) : ¬ b < a :=
|
||||
i.asymm a b h
|
||||
|
||||
public theorem lt_irrefl {α : Type u} [LT α] [i : Std.Irrefl (α := α) (· < ·)] {a : α} :
|
||||
¬ a < a :=
|
||||
i.irrefl a
|
||||
|
||||
public theorem le_of_lt {α : Type u} [LT α] [LE α] [LawfulOrderLT α] {a b : α} (h : a < b) :
|
||||
a ≤ b := (lt_iff_le_and_not_ge.1 h).1
|
||||
|
||||
@@ -230,18 +222,6 @@ public theorem lt_of_le_of_ne {α : Type u} [LE α] [LT α]
|
||||
intro hge
|
||||
exact hne.elim <| Std.Antisymm.antisymm a b hle hge
|
||||
|
||||
public theorem ne_of_lt {α : Type u} [LT α] [Std.Irrefl (α := α) (· < ·)] {a b : α} : a < b → a ≠ b :=
|
||||
fun h h' => absurd (h' ▸ h) (h' ▸ lt_irrefl)
|
||||
|
||||
public theorem le_iff_lt_or_eq [LE α] [LT α] [LawfulOrderLT α] [IsPartialOrder α] {a b : α} :
|
||||
a ≤ b ↔ a < b ∨ a = b := by
|
||||
refine ⟨fun h => ?_, fun h => h.elim le_of_lt le_of_eq⟩
|
||||
simp [Classical.or_iff_not_imp_left, Std.lt_iff_le_and_not_ge, h, ← Std.le_antisymm_iff]
|
||||
|
||||
public theorem lt_iff_le_and_ne [LE α] [LT α] [LawfulOrderLT α] [IsPartialOrder α] {a b : α} :
|
||||
a < b ↔ a ≤ b ∧ a ≠ b := by
|
||||
simpa [le_iff_lt_or_eq, or_and_right] using Std.ne_of_lt
|
||||
|
||||
end LT
|
||||
end Std
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public theorem compare_eq_eq_iff_eq {α : Type u} [Ord α] [LawfulEqOrd α] {a b
|
||||
|
||||
public theorem IsLinearPreorder.of_ord {α : Type u} [LE α] [Ord α] [LawfulOrderOrd α]
|
||||
[TransOrd α] : IsLinearPreorder α where
|
||||
le_refl a := by simp
|
||||
le_refl a := by simp [← isLE_compare]
|
||||
le_trans a b c := by simpa [← isLE_compare] using TransOrd.isLE_trans
|
||||
le_total a b := Total.total a b
|
||||
|
||||
|
||||
@@ -1,198 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.Opposite
|
||||
|
||||
open Std
|
||||
open scoped OppositeOrderInstances
|
||||
|
||||
/-! ## Definitions -/
|
||||
|
||||
/--
|
||||
Returns either `x` or `y`, the one with the smaller value under `f`.
|
||||
|
||||
If `f x ≤ f y`, it returns `x`, and otherwise returns `y`.
|
||||
-/
|
||||
public def minOn [LE β] [DecidableLE β] (f : α → β) (x y : α) :=
|
||||
if f x ≤ f y then x else y
|
||||
|
||||
/--
|
||||
Returns either `x` or `y`, the one with the greater value under `f`.
|
||||
|
||||
If `f y ≤ f x`, it returns `x`, and otherwise returns `y`.
|
||||
-/
|
||||
public def maxOn [i : LE β] [DecidableLE β] (f : α → β) (x y : α) :=
|
||||
letI := i.opposite
|
||||
minOn f x y
|
||||
|
||||
/-! ## `minOn` Lemmas -/
|
||||
|
||||
public theorem minOn_id [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α] {x y : α} :
|
||||
minOn id x y = min x y := by
|
||||
simp [minOn, min_eq_if]
|
||||
|
||||
public theorem maxOn_id [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α] {x y : α} :
|
||||
maxOn id x y = max x y := by
|
||||
letI : LE α := (inferInstanceAs (LE α)).opposite
|
||||
letI : Min α := (inferInstanceAs (Max α)).oppositeMin
|
||||
simp [maxOn, minOn_id, Max.min_oppositeMin, this]
|
||||
|
||||
public theorem minOn_eq_or [LE β] [DecidableLE β] {f : α → β} {x y : α} :
|
||||
minOn f x y = x ∨ minOn f x y = y := by
|
||||
rw [minOn]
|
||||
split
|
||||
· exact Or.inl rfl
|
||||
· exact Or.inr rfl
|
||||
|
||||
@[simp]
|
||||
public theorem minOn_self [LE β] [DecidableLE β] {f : α → β} {x : α} :
|
||||
minOn f x x = x := by
|
||||
cases minOn_eq_or (f := f) (x := x) (y := x) <;> assumption
|
||||
|
||||
public theorem minOn_eq_left [LE β] [DecidableLE β] {f : α → β} {x y : α} (h : f x ≤ f y) :
|
||||
minOn f x y = x := by
|
||||
simp [minOn, h]
|
||||
|
||||
public theorem minOn_eq_right [LE β] [DecidableLE β] {f : α → β} {x y : α} (h : ¬ f x ≤ f y) :
|
||||
minOn f x y = y := by
|
||||
simp [minOn, h]
|
||||
|
||||
public theorem minOn_eq_right_of_lt
|
||||
[LE β] [DecidableLE β] [LT β] [Total (α := β) (· ≤ ·)] [LawfulOrderLT β]
|
||||
{f : α → β} {x y : α} (h : f y < f x) :
|
||||
minOn f x y = y := by
|
||||
apply minOn_eq_right
|
||||
simpa [not_le] using h
|
||||
|
||||
public theorem apply_minOn_le_left [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} : f (minOn f x y) ≤ f x := by
|
||||
rw [minOn]
|
||||
split
|
||||
· apply le_refl
|
||||
· exact le_of_not_ge ‹_›
|
||||
|
||||
public theorem apply_minOn_le_right [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} : f (minOn f x y) ≤ f y := by
|
||||
rw [minOn]
|
||||
split
|
||||
· assumption
|
||||
· apply le_refl
|
||||
|
||||
public theorem le_apply_minOn_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} {b : β} :
|
||||
b ≤ f (minOn f x y) ↔ b ≤ f x ∧ b ≤ f y := by
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
exact ⟨le_trans h apply_minOn_le_left, le_trans h apply_minOn_le_right⟩
|
||||
· intro h
|
||||
cases minOn_eq_or (f := f) (x := x) (y := y) <;> simp_all
|
||||
|
||||
public theorem minOn_assoc [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y z : α} : minOn f (minOn f x y) z = minOn f x (minOn f y z) := by
|
||||
open scoped Classical.Order in
|
||||
simp only [minOn]
|
||||
split
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· rfl
|
||||
· split
|
||||
· have : ¬ f x ≤ f z := by assumption
|
||||
have : f x ≤ f z := le_trans ‹f x ≤ f y› ‹f y ≤ f z›
|
||||
contradiction
|
||||
· rfl
|
||||
· split
|
||||
· rfl
|
||||
· have : f z < f y := not_le.mp ‹¬ f y ≤ f z›
|
||||
have : f y < f x := not_le.mp ‹¬ f x ≤ f y›
|
||||
have : f z < f x := lt_trans ‹_› ‹_›
|
||||
rw [if_neg]
|
||||
exact not_le.mpr ‹_›
|
||||
|
||||
public instance [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} :
|
||||
Associative (minOn f) where
|
||||
assoc := by apply minOn_assoc
|
||||
|
||||
public theorem min_apply [LE β] [DecidableLE β] [Min β] [LawfulOrderLeftLeaningMin β]
|
||||
{f : α → β} {x y : α} : min (f x) (f y) = f (minOn f x y) := by
|
||||
rw [min_eq_if, minOn]
|
||||
split <;> rfl
|
||||
|
||||
/-! ## `maxOn` Lemmas -/
|
||||
|
||||
public theorem maxOn_eq_minOn [le : LE β] [DecidableLE β] {f : α → β} {x y : α} :
|
||||
maxOn f x y = (letI := le.opposite; minOn f x y) :=
|
||||
(rfl)
|
||||
|
||||
public theorem maxOn_eq_or [LE β] [DecidableLE β] {f : α → β} {x y : α} :
|
||||
maxOn f x y = x ∨ maxOn f x y = y :=
|
||||
@minOn_eq_or ..
|
||||
|
||||
@[simp]
|
||||
public theorem maxOn_self [LE β] [DecidableLE β] {f : α → β} {x : α} :
|
||||
maxOn f x x = x :=
|
||||
@minOn_self ..
|
||||
|
||||
public theorem maxOn_eq_left [le : LE β] [DecidableLE β] {f : α → β} {x y : α} (h : f y ≤ f x) :
|
||||
maxOn f x y = x := by
|
||||
simp only [maxOn_eq_minOn]
|
||||
exact @minOn_eq_left (h := by simpa [LE.opposite_def]) ..
|
||||
|
||||
public theorem maxOn_eq_right [LE β] [DecidableLE β] {f : α → β} {x y : α} (h : ¬ f y ≤ f x) :
|
||||
maxOn f x y = y := by
|
||||
simp only [maxOn_eq_minOn]
|
||||
exact @minOn_eq_right (h := by simpa [LE.opposite_def]) ..
|
||||
|
||||
public theorem maxOn_eq_right_of_lt
|
||||
[LE β] [DecidableLE β] [LT β] [Total (α := β) (· ≤ ·)] [LawfulOrderLT β]
|
||||
{f : α → β} {x y : α} (h : f x < f y) :
|
||||
maxOn f x y = y :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
letI : LT β := (inferInstanceAs (LT β)).opposite
|
||||
minOn_eq_right_of_lt (h := by simpa [LT.lt_opposite_iff] using h) ..
|
||||
|
||||
public theorem left_le_apply_maxOn [le : LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} : f x ≤ f (maxOn f x y) := by
|
||||
rw [maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa only [LE.le_opposite_iff] using apply_minOn_le_left (f := f) ..
|
||||
|
||||
public theorem right_le_apply_maxOn [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} : f y ≤ f (maxOn f x y) := by
|
||||
rw [maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa only [LE.le_opposite_iff] using apply_minOn_le_right (f := f)
|
||||
|
||||
public theorem apply_maxOn_le_iff [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y : α} {b : β} :
|
||||
f (maxOn f x y) ≤ b ↔ f x ≤ b ∧ f y ≤ b := by
|
||||
rw [maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
simpa only [LE.le_opposite_iff] using le_apply_minOn_iff (f := f)
|
||||
|
||||
public theorem maxOn_assoc [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β}
|
||||
{x y z : α} : maxOn f (maxOn f x y) z = maxOn f x (maxOn f y z) :=
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
minOn_assoc (f := f)
|
||||
|
||||
public instance [LE β] [DecidableLE β] [IsLinearPreorder β] {f : α → β} :
|
||||
Associative (maxOn f) where
|
||||
assoc := by
|
||||
apply maxOn_assoc
|
||||
|
||||
public theorem max_apply [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeaningMax β]
|
||||
{f : α → β} {x y : α} : max (f x) (f y) = f (maxOn f x y) := by
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
letI : Min β := (inferInstanceAs (Max β)).oppositeMin
|
||||
simpa [Max.min_oppositeMin] using min_apply (f := f)
|
||||
|
||||
public theorem apply_maxOn [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeaningMax β]
|
||||
{f : α → β} {x y : α} : f (maxOn f x y) = max (f x) (f y) :=
|
||||
max_apply.symm
|
||||
@@ -1,407 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Order.ClassesExtra
|
||||
public import Init.Data.Order.LemmasExtra
|
||||
|
||||
public section
|
||||
|
||||
open Std
|
||||
|
||||
set_option linter.missingDocs true
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
/-
|
||||
Note: We're having verso docstrings disabled because the examples depend on instances that
|
||||
are provided later in the module. They will be converted into verso docstrings at the end
|
||||
of the module.
|
||||
-/
|
||||
|
||||
/--
|
||||
Inverts an {name}`LE` instance.
|
||||
|
||||
The result is an {lean}`LE α` instance where {lit}`a ≤ b` holds when {name}`le` would have
|
||||
{lit}`b ≤ a` hold.
|
||||
|
||||
If {name}`le` obeys laws, then {lean}`le.opposite` obeys the opposite laws. For example, if
|
||||
{name}`le` encodes a linear order, then {lean}`le.opposite` also encodes a linear order.
|
||||
To automatically derive these laws, use {lit}`open Std.OppositeOrderInstances`.
|
||||
|
||||
For example, {name}`LE.opposite` can be used to derive maximum operations from minimum operations,
|
||||
since finding the minimum in the opposite order is the same as finding the maximum in the original order:
|
||||
|
||||
```lean +warning
|
||||
def min' [LE α] [DecidableLE α] (a b : α) : α :=
|
||||
if a ≤ b then a else b
|
||||
|
||||
open scoped Std.OppositeOrderInstances in
|
||||
def max' [LE α] [DecidableLE α] (a b : α) : α :=
|
||||
letI : LE α := (inferInstanceAs (LE α)).opposite
|
||||
-- `DecidableLE` for the opposite order is derived automatically via `OppositeOrderInstances`
|
||||
min' a b
|
||||
```
|
||||
|
||||
Without the `open scoped` command, Lean would not find the required {lit}`DecidableLE α`
|
||||
instance for the opposite order.
|
||||
-/
|
||||
def LE.opposite (le : LE α) : LE α where
|
||||
le a b := b ≤ a
|
||||
|
||||
theorem LE.opposite_def {le : LE α} :
|
||||
le.opposite = ⟨fun a b => b ≤ a⟩ :=
|
||||
(rfl)
|
||||
|
||||
theorem LE.le_opposite_iff {le : LE α} {a b : α} :
|
||||
(haveI := le.opposite; a ≤ b) ↔ b ≤ a := by
|
||||
exact Iff.rfl
|
||||
|
||||
/--
|
||||
Inverts an {name}`LT` instance.
|
||||
|
||||
The result is an {lean}`LT α` instance where {lit}`a < b` holds when {name}`lt` would have
|
||||
{lit}`b < a` hold.
|
||||
|
||||
If {name}`lt` obeys laws, then {lean}`lt.opposite` obeys the opposite laws.
|
||||
To automatically derive these laws, use {lit}`open scoped Std.OppositeOrderInstances`.
|
||||
|
||||
For example, one can use the derived instances to prove properties about the opposite {name}`LT`
|
||||
instance:
|
||||
|
||||
```lean
|
||||
open scoped Std.OppositeOrderInstances in
|
||||
example [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsLinearOrder α] {x y : α} :
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : LT α := LT.opposite inferInstance
|
||||
¬ y ≤ x ↔ x < y :=
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : LT α := LT.opposite inferInstance
|
||||
Std.not_le
|
||||
```
|
||||
|
||||
Without the `open scoped` command, Lean would not find the {lit}`LawfulOrderLT α`
|
||||
and {lit}`IsLinearOrder α` instances for the opposite order that are required by {name}`not_le`.
|
||||
-/
|
||||
def LT.opposite (lt : LT α) : LT α where
|
||||
lt a b := b < a
|
||||
|
||||
theorem LT.opposite_def {lt : LT α} :
|
||||
lt.opposite = ⟨fun a b => b < a⟩ :=
|
||||
(rfl)
|
||||
|
||||
theorem LT.lt_opposite_iff {lt : LT α} {a b : α} :
|
||||
(haveI := lt.opposite; a < b) ↔ b < a := by
|
||||
exact Iff.rfl
|
||||
|
||||
/--
|
||||
Creates a {name}`Max` instance from a {name}`Min` instance.
|
||||
|
||||
The result is a {lean}`Max α` instance that uses {lean}`min.min` as its {name}`max` operation.
|
||||
|
||||
If {name}`min` obeys laws, then {lean}`min.oppositeMax` obeys the corresponding laws for {name}`Max`.
|
||||
To automatically derive these laws, use {lit}`open scoped Std.OppositeOrderInstances`.
|
||||
|
||||
For example, one can use the derived instances to prove properties about the opposite {name}`Max`
|
||||
instance:
|
||||
|
||||
```lean
|
||||
open scoped Std.OppositeOrderInstances in
|
||||
example [LE α] [DecidableLE α] [Min α] [Std.LawfulOrderLeftLeaningMin α] {a b : α} :
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : Max α := (inferInstance : Min α).oppositeMax
|
||||
max a b = if b ≤ a then a else b :=
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : Max α := (inferInstance : Min α).oppositeMax
|
||||
Std.max_eq_if
|
||||
```
|
||||
|
||||
Without the `open scoped` command, Lean would not find the {lit}`LawfulOrderLeftLeaningMax α`
|
||||
instance for the opposite order that is required by {name}`max_eq_if`.
|
||||
-/
|
||||
def Min.oppositeMax (min : Min α) : Max α where
|
||||
max a b := Min.min a b
|
||||
|
||||
theorem Min.oppositeMax_def {min : Min α} :
|
||||
min.oppositeMax = ⟨Min.min⟩ :=
|
||||
(rfl)
|
||||
|
||||
theorem Min.max_oppositeMax {min : Min α} {a b : α} :
|
||||
(haveI := min.oppositeMax; Max.max a b) = Min.min a b :=
|
||||
(rfl)
|
||||
|
||||
/--
|
||||
Creates a {name}`Min` instance from a {name}`Max` instance.
|
||||
|
||||
The result is a {lean}`Min α` instance that uses {lean}`max.max` as its {name}`min` operation.
|
||||
|
||||
If {name}`max` obeys laws, then {lean}`max.oppositeMin` obeys the corresponding laws for {name}`Min`.
|
||||
To automatically derive these laws, use {lit}`open scoped Std.OppositeOrderInstances`.
|
||||
|
||||
For example, one can use the derived instances to prove properties about the opposite {name}`Min`
|
||||
instance:
|
||||
|
||||
```lean
|
||||
open scoped Std.OppositeOrderInstances in
|
||||
example [LE α] [DecidableLE α] [Max α] [Std.LawfulOrderLeftLeaningMax α] {a b : α} :
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : Min α := (inferInstance : Max α).oppositeMin
|
||||
min a b = if a ≤ b then a else b :=
|
||||
letI : LE α := LE.opposite inferInstance
|
||||
letI : Min α := (inferInstance : Max α).oppositeMin
|
||||
Std.min_eq_if
|
||||
```
|
||||
|
||||
Without the `open scoped` command, Lean would not find the {lit}`LawfulOrderLeftLeaningMin α`
|
||||
instance for the opposite order that is required by {name}`min_eq_if`.
|
||||
-/
|
||||
def Max.oppositeMin (max : Max α) : Min α where
|
||||
min a b := Max.max a b
|
||||
|
||||
theorem Max.oppositeMin_def {min : Max α} :
|
||||
min.oppositeMin = ⟨Max.max⟩ :=
|
||||
(rfl)
|
||||
|
||||
theorem Max.min_oppositeMin {max : Max α} {a b : α} :
|
||||
(haveI := max.oppositeMin; Min.min a b) = Max.max a b :=
|
||||
(rfl)
|
||||
|
||||
namespace Std.OppositeOrderInstances
|
||||
|
||||
@[no_expose]
|
||||
scoped instance (priority := low) instDecidableLEOpposite {i : LE α} [id : DecidableLE α] :
|
||||
haveI := i.opposite
|
||||
DecidableLE α :=
|
||||
fun a b => id b a
|
||||
|
||||
@[no_expose]
|
||||
scoped instance (priority := low) instDecidableLTOpposite {i : LT α} [id : DecidableLT α] :
|
||||
haveI := i.opposite
|
||||
DecidableLT α :=
|
||||
fun a b => id b a
|
||||
|
||||
scoped instance (priority := low) instLEReflOpposite {i : LE α} [Refl (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Refl (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ refl a := letI := i; le_refl a }
|
||||
|
||||
scoped instance (priority := low) instLESymmOpposite {i : LE α} [Symm (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Symm (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ symm a b hab := by
|
||||
simp only [LE.opposite] at *
|
||||
letI := i
|
||||
exact Symm.symm b a hab }
|
||||
|
||||
scoped instance (priority := low) instLEAntisymmOpposite {i : LE α} [Antisymm (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Antisymm (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ antisymm a b hab hba := by
|
||||
simp only [LE.opposite] at *
|
||||
letI := i
|
||||
exact le_antisymm hba hab }
|
||||
|
||||
scoped instance (priority := low) instLEAsymmOpposite {i : LE α} [Asymm (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Asymm (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ asymm a b hab := by
|
||||
simp only [LE.opposite] at *
|
||||
letI := i
|
||||
exact Asymm.asymm b a hab }
|
||||
|
||||
scoped instance (priority := low) instLETransOpposite {i : LE α}
|
||||
[Trans (· ≤ ·) (· ≤ ·) (· ≤ · : α → α → Prop)] :
|
||||
haveI := i.opposite
|
||||
Trans (· ≤ ·) (· ≤ ·) (· ≤ · : α → α → Prop) :=
|
||||
letI := i.opposite
|
||||
{ trans hab hbc := by
|
||||
simp only [LE.opposite] at *
|
||||
letI := i
|
||||
exact Trans.trans hbc hab }
|
||||
|
||||
scoped instance (priority := low) instLETotalOpposite {i : LE α} [Total (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Total (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ total a b := letI := i; le_total (a := b) (b := a) }
|
||||
|
||||
scoped instance (priority := low) instLEIrreflOpposite {i : LE α} [Irrefl (α := α) (· ≤ ·)] :
|
||||
haveI := i.opposite
|
||||
Irrefl (α := α) (· ≤ ·) :=
|
||||
letI := i.opposite
|
||||
{ irrefl a := letI := i; Irrefl.irrefl (r := (· ≤ ·)) a }
|
||||
|
||||
scoped instance (priority := low) instIsPreorderOpposite {i : LE α} [IsPreorder α] :
|
||||
haveI := i.opposite
|
||||
IsPreorder α :=
|
||||
letI := i.opposite
|
||||
{ le_refl a := le_refl a
|
||||
le_trans _ _ _ := le_trans }
|
||||
|
||||
scoped instance (priority := low) instIsPartialOrderOpposite {i : LE α} [IsPartialOrder α] :
|
||||
haveI := i.opposite
|
||||
IsPartialOrder α :=
|
||||
letI := i.opposite
|
||||
{ le_antisymm _ _ := le_antisymm }
|
||||
|
||||
scoped instance (priority := low) instIsLinearPreorderOpposite {i : LE α} [IsLinearPreorder α] :
|
||||
haveI := i.opposite
|
||||
IsLinearPreorder α :=
|
||||
letI := i.opposite
|
||||
{ le_total _ _ := le_total }
|
||||
|
||||
scoped instance (priority := low) instIsLinearOrderOpposite {i : LE α} [IsLinearOrder α] :
|
||||
haveI := i.opposite
|
||||
IsLinearOrder α :=
|
||||
letI := i.opposite; {}
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderOrdOpposite {il : LE α} {io : Ord α}
|
||||
[LawfulOrderOrd α] :
|
||||
haveI := il.opposite
|
||||
haveI := io.opposite
|
||||
LawfulOrderOrd α :=
|
||||
letI := il.opposite
|
||||
letI := io.opposite
|
||||
{ isLE_compare a b := by
|
||||
simp only [LE.opposite, Ord.opposite]
|
||||
letI := il; letI := io
|
||||
apply isLE_compare
|
||||
isGE_compare a b := by
|
||||
simp only [LE.opposite, Ord.opposite]
|
||||
letI := il; letI := io
|
||||
apply isGE_compare }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderLTOpposite {il : LE α} {it : LT α}
|
||||
[LawfulOrderLT α] :
|
||||
haveI := il.opposite
|
||||
haveI := it.opposite
|
||||
LawfulOrderLT α :=
|
||||
letI := il.opposite
|
||||
letI := it.opposite
|
||||
{ lt_iff a b := by
|
||||
simp only [LE.opposite, LT.opposite]
|
||||
letI := il; letI := it
|
||||
exact LawfulOrderLT.lt_iff b a }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderBEqOpposite {il : LE α} {ib : BEq α}
|
||||
[LawfulOrderBEq α] :
|
||||
haveI := il.opposite
|
||||
LawfulOrderBEq α :=
|
||||
letI := il.opposite
|
||||
{ beq_iff_le_and_ge a b := by
|
||||
simp only [LE.opposite]
|
||||
letI := il; letI := ib
|
||||
rw [LawfulOrderBEq.beq_iff_le_and_ge]
|
||||
exact and_comm }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderInfOpposite {il : LE α} {im : Min α}
|
||||
[LawfulOrderInf α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMax
|
||||
LawfulOrderSup α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMax
|
||||
{ max_le_iff a b c := by
|
||||
simp only [LE.opposite, Min.oppositeMax]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderInf.le_min_iff c a b }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderMinOpposite {il : LE α} {im : Min α}
|
||||
[LawfulOrderMin α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMax
|
||||
LawfulOrderMax α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMax
|
||||
{ max_eq_or a b := by
|
||||
simp only [Min.oppositeMax]
|
||||
letI := il; letI := im
|
||||
exact MinEqOr.min_eq_or a b
|
||||
max_le_iff a b c := by
|
||||
simp only [LE.opposite, Min.oppositeMax]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderInf.le_min_iff c a b }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderSupOpposite {il : LE α} {im : Max α}
|
||||
[LawfulOrderSup α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMin
|
||||
LawfulOrderInf α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMin
|
||||
{ le_min_iff a b c := by
|
||||
simp only [LE.opposite, Max.oppositeMin]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderSup.max_le_iff b c a }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderMaxOpposite {il : LE α} {im : Max α}
|
||||
[LawfulOrderMax α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMin
|
||||
LawfulOrderMin α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMin
|
||||
{ min_eq_or a b := by
|
||||
simp only [Max.oppositeMin]
|
||||
letI := il; letI := im
|
||||
exact MaxEqOr.max_eq_or a b
|
||||
le_min_iff a b c := by
|
||||
simp only [LE.opposite, Max.oppositeMin]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderSup.max_le_iff b c a }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderLeftLeaningMinOpposite {il : LE α} {im : Min α}
|
||||
[LawfulOrderLeftLeaningMin α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMax
|
||||
LawfulOrderLeftLeaningMax α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMax
|
||||
{ max_eq_left a b hab := by
|
||||
simp only [Min.oppositeMax]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderLeftLeaningMin.min_eq_left a b hab
|
||||
max_eq_right a b hab := by
|
||||
simp only [Min.oppositeMax]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderLeftLeaningMin.min_eq_right a b hab }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderLeftLeaningMaxOpposite {il : LE α} {im : Max α}
|
||||
[LawfulOrderLeftLeaningMax α] :
|
||||
haveI := il.opposite
|
||||
haveI := im.oppositeMin
|
||||
LawfulOrderLeftLeaningMin α :=
|
||||
letI := il.opposite
|
||||
letI := im.oppositeMin
|
||||
{ min_eq_left a b hab := by
|
||||
simp only [Max.oppositeMin]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderLeftLeaningMax.max_eq_left a b hab
|
||||
min_eq_right a b hab := by
|
||||
simp only [Max.oppositeMin]
|
||||
letI := il; letI := im
|
||||
exact LawfulOrderLeftLeaningMax.max_eq_right a b hab }
|
||||
|
||||
end OppositeOrderInstances
|
||||
|
||||
-- When imported from a non-module, these instances are exposed, and reducing them during
|
||||
-- type class resolution is too inefficient.
|
||||
attribute [irreducible] LE.opposite LT.opposite Min.oppositeMax Max.oppositeMin
|
||||
|
||||
section DocsToVerso
|
||||
|
||||
set_option linter.unusedVariables false -- Otherwise, we get warnings about Verso code blocks.
|
||||
docs_to_verso LE.opposite
|
||||
docs_to_verso LT.opposite
|
||||
docs_to_verso Min.oppositeMax
|
||||
docs_to_verso Max.oppositeMin
|
||||
|
||||
end DocsToVerso
|
||||
@@ -663,7 +663,7 @@ public def LinearPreorderPackage.ofOrd (α : Type u)
|
||||
isGE_compare]
|
||||
decidableLE := args.decidableLE
|
||||
decidableLT := args.decidableLT
|
||||
le_refl a := by simp
|
||||
le_refl a := by simp [← isLE_compare]
|
||||
le_total a b := by cases h : compare a b <;> simp [h, ← isLE_compare (a := a), ← isGE_compare (a := a)]
|
||||
le_trans a b c := by simpa [← isLE_compare] using TransOrd.isLE_trans }
|
||||
|
||||
|
||||
@@ -240,9 +240,6 @@ This propositional typeclass ensures that `UpwardEnumerable.succ?` will never re
|
||||
In other words, it ensures that there will always be a successor.
|
||||
-/
|
||||
class InfinitelyUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
/--
|
||||
Every element of `α` has a successor.
|
||||
-/
|
||||
isSome_succ? : ∀ a : α, (UpwardEnumerable.succ? a).isSome
|
||||
|
||||
/--
|
||||
|
||||
@@ -409,7 +409,7 @@ Examples:
|
||||
* `(if (5 : Int8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int8_dec_lt", instance_reducible]
|
||||
@[extern "lean_int8_dec_lt"]
|
||||
def Int8.decLt (a b : Int8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -425,7 +425,7 @@ Examples:
|
||||
* `(if (15 : Int8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int8_dec_le", instance_reducible]
|
||||
@[extern "lean_int8_dec_le"]
|
||||
def Int8.decLe (a b : Int8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -778,7 +778,7 @@ Examples:
|
||||
* `(if (5 : Int16) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int16) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int16_dec_lt", instance_reducible]
|
||||
@[extern "lean_int16_dec_lt"]
|
||||
def Int16.decLt (a b : Int16) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -794,7 +794,7 @@ Examples:
|
||||
* `(if (15 : Int16) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int16) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int16_dec_le", instance_reducible]
|
||||
@[extern "lean_int16_dec_le"]
|
||||
def Int16.decLe (a b : Int16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1163,7 +1163,7 @@ Examples:
|
||||
* `(if (5 : Int32) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int32) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int32_dec_lt", instance_reducible]
|
||||
@[extern "lean_int32_dec_lt"]
|
||||
def Int32.decLt (a b : Int32) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -1179,7 +1179,7 @@ Examples:
|
||||
* `(if (15 : Int32) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int32) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int32_dec_le", instance_reducible]
|
||||
@[extern "lean_int32_dec_le"]
|
||||
def Int32.decLe (a b : Int32) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1568,7 +1568,7 @@ Examples:
|
||||
* `(if (5 : Int64) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int64) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int64_dec_lt", instance_reducible]
|
||||
@[extern "lean_int64_dec_lt"]
|
||||
def Int64.decLt (a b : Int64) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
/--
|
||||
@@ -1583,7 +1583,7 @@ Examples:
|
||||
* `(if (15 : Int64) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int64) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int64_dec_le", instance_reducible]
|
||||
@[extern "lean_int64_dec_le"]
|
||||
def Int64.decLe (a b : Int64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1958,7 +1958,7 @@ Examples:
|
||||
* `(if (5 : ISize) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : ISize) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_isize_dec_lt", instance_reducible]
|
||||
@[extern "lean_isize_dec_lt"]
|
||||
def ISize.decLt (a b : ISize) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -1974,7 +1974,7 @@ Examples:
|
||||
* `(if (15 : ISize) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : ISize) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_isize_dec_le", instance_reducible]
|
||||
@[extern "lean_isize_dec_le"]
|
||||
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ instance SubarrayIterator.instFinite : Finite (SubarrayIterator α) Id :=
|
||||
|
||||
instance [Monad m] : IteratorLoop (SubarrayIterator α) Id m := .defaultImplementation
|
||||
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose]
|
||||
def Subarray.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.SubarrayData α)) (β := α) (SubarrayIterator α) (⟨⟨·⟩⟩)
|
||||
attribute [instance] Subarray.instToIterator
|
||||
|
||||
@@ -85,12 +85,9 @@ theorem toList_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
· rw [dif_neg]; rotate_left; exact h
|
||||
simp_all [it.internalState.xs.stop_le_array_size]
|
||||
|
||||
theorem length_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.length = it.internalState.xs.stop - it.internalState.xs.start := by
|
||||
simp [← Iter.length_toList_eq_length, toList_eq, it.internalState.xs.stop_le_array_size]
|
||||
|
||||
@[deprecated length_eq (since := "2026-01-28")]
|
||||
def count_eq := @length_eq
|
||||
theorem count_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.count = it.internalState.xs.stop - it.internalState.xs.start := by
|
||||
simp [← Iter.length_toList_eq_count, toList_eq, it.internalState.xs.stop_le_array_size]
|
||||
|
||||
end SubarrayIterator
|
||||
|
||||
@@ -108,7 +105,7 @@ theorem toList_internalIter {α : Type u} {s : Subarray α} :
|
||||
public instance : LawfulSliceSize (Internal.SubarrayData α) where
|
||||
lawful s := by
|
||||
simp [SliceSize.size, ToIterator.iter_eq, Iter.toIter_toIterM,
|
||||
← Iter.length_toList_eq_length, SubarrayIterator.toList_eq,
|
||||
← Iter.length_toList_eq_count, SubarrayIterator.toList_eq,
|
||||
s.internalRepresentation.stop_le_array_size, start, stop, array]
|
||||
|
||||
public theorem toArray_eq_sliceToArray {α : Type u} {s : Subarray α} :
|
||||
|
||||
@@ -60,15 +60,12 @@ public theorem forIn_toArray {γ : Type u} {β : Type v}
|
||||
ForIn.forIn s.toArray init f = ForIn.forIn s init f := by
|
||||
rw [← forIn_internalIter, ← Iter.forIn_toArray, Slice.toArray]
|
||||
|
||||
theorem Internal.size_eq_length_iter [ToIterator (Slice γ) Id α β]
|
||||
theorem Internal.size_eq_count_iter [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{s : Slice γ} [SliceSize γ] [LawfulSliceSize γ] :
|
||||
s.size = (Internal.iter s).length := by
|
||||
simp only [Slice.size, iter, LawfulSliceSize.lawful, ← Iter.length_toList_eq_length]
|
||||
|
||||
@[deprecated Internal.size_eq_length_iter (since := "2026-01-28")]
|
||||
def Internal.size_eq_count_iter := @Internal.size_eq_length_iter
|
||||
s.size = (Internal.iter s).count := by
|
||||
simp only [Slice.size, iter, LawfulSliceSize.lawful, ← Iter.length_toList_eq_count]
|
||||
|
||||
theorem Internal.toArray_eq_toArray_iter {s : Slice γ} [ToIterator (Slice γ) Id α β]
|
||||
[Iterator α Id β]
|
||||
@@ -94,7 +91,7 @@ theorem size_toArray_eq_size [ToIterator (Slice γ) Id α β]
|
||||
{s : Slice γ} :
|
||||
s.toArray.size = s.size := by
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
rw [Internal.size_eq_length_iter, Internal.toArray_eq_toArray_iter, Iter.size_toArray_eq_length]
|
||||
rw [Internal.size_eq_count_iter, Internal.toArray_eq_toArray_iter, Iter.size_toArray_eq_count]
|
||||
|
||||
@[simp]
|
||||
theorem length_toList_eq_size [ToIterator (Slice γ) Id α β]
|
||||
@@ -103,7 +100,7 @@ theorem length_toList_eq_size [ToIterator (Slice γ) Id α β]
|
||||
[Finite α Id] :
|
||||
s.toList.length = s.size := by
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
rw [Internal.size_eq_length_iter, Internal.toList_eq_toList_iter, Iter.length_toList_eq_length]
|
||||
rw [Internal.size_eq_count_iter, Internal.toList_eq_toList_iter, Iter.length_toList_eq_count]
|
||||
|
||||
@[simp]
|
||||
theorem length_toListRev_eq_size [ToIterator (Slice γ) Id α β]
|
||||
@@ -112,7 +109,7 @@ theorem length_toListRev_eq_size [ToIterator (Slice γ) Id α β]
|
||||
[Finite α Id]
|
||||
[LawfulIteratorLoop α Id Id] :
|
||||
s.toListRev.length = s.size := by
|
||||
rw [Internal.size_eq_length_iter, Internal.toListRev_eq_toListRev_iter,
|
||||
Iter.length_toListRev_eq_length]
|
||||
rw [Internal.size_eq_count_iter, Internal.toListRev_eq_toListRev_iter,
|
||||
Iter.length_toListRev_eq_count]
|
||||
|
||||
end Std.Slice
|
||||
|
||||
@@ -24,7 +24,7 @@ open Std Slice PRange Iterators
|
||||
|
||||
variable {α : Type u}
|
||||
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose]
|
||||
def ListSlice.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.ListSliceData α)) _ (fun s => match s.internalRepresentation.stop with
|
||||
| some n => s.internalRepresentation.list.iter.take n
|
||||
@@ -34,7 +34,7 @@ attribute [instance] ListSlice.instToIterator
|
||||
universe v w
|
||||
|
||||
instance : SliceSize (Internal.ListSliceData α) where
|
||||
size s := (Internal.iter s).length
|
||||
size s := (Internal.iter s).count
|
||||
|
||||
@[no_expose]
|
||||
instance {α : Type u} {m : Type v → Type w} [Monad m] :
|
||||
|
||||
@@ -60,7 +60,7 @@ public theorem toList_toArray {xs : ListSlice α} :
|
||||
@[simp, grind =]
|
||||
public theorem length_toList {xs : ListSlice α} :
|
||||
xs.toList.length = xs.size := by
|
||||
simp [ListSlice.toList_eq, Std.Slice.size, Std.Slice.SliceSize.size, ← Iter.length_toList_eq_length,
|
||||
simp [ListSlice.toList_eq, Std.Slice.size, Std.Slice.SliceSize.size, ← Iter.length_toList_eq_count,
|
||||
toList_internalIter]; rfl
|
||||
|
||||
@[grind =]
|
||||
|
||||
@@ -45,7 +45,7 @@ class LawfulSliceSize (γ : Type u) [SliceSize γ] [ToIterator (Slice γ) Id α
|
||||
/-- The iterator of a slice `s` of type `Slice γ` emits exactly `SliceSize.size s` elements. -/
|
||||
lawful :
|
||||
letI : IteratorLoop α Id Id := .defaultImplementation
|
||||
∀ s : Slice γ, SliceSize.size s = (ToIterator.iter (γ := Slice γ) s).length
|
||||
∀ s : Slice γ, SliceSize.size s = (ToIterator.iter (γ := Slice γ) s).count
|
||||
|
||||
/--
|
||||
Returns the number of elements with distinct indices in the given slice.
|
||||
|
||||
@@ -25,5 +25,4 @@ public import Init.Data.String.Termination
|
||||
public import Init.Data.String.ToSlice
|
||||
public import Init.Data.String.Search
|
||||
public import Init.Data.String.Legacy
|
||||
public import Init.Data.String.OrderInstances
|
||||
public import Init.Data.String.FindPos
|
||||
public import Init.Data.String.Grind
|
||||
|
||||
@@ -1740,6 +1740,38 @@ theorem Pos.copy_toSlice_eq_cast {s : String} (p : s.Pos) :
|
||||
p.toSlice.copy = p.cast copy_toSlice.symm :=
|
||||
Pos.ext (by simp)
|
||||
|
||||
/-- Given a byte position within a string slice, obtains the smallest valid position that is
|
||||
strictly greater than the given byte position. -/
|
||||
@[inline]
|
||||
def Slice.findNextPos (offset : String.Pos.Raw) (s : Slice) (_h : offset < s.rawEndPos) : s.Pos :=
|
||||
go offset.inc
|
||||
where
|
||||
go (offset : String.Pos.Raw) : s.Pos :=
|
||||
if h : offset < s.rawEndPos then
|
||||
if h' : (s.getUTF8Byte offset h).IsUTF8FirstByte then
|
||||
s.pos offset (Pos.Raw.isValidForSlice_iff_isUTF8FirstByte.2 (Or.inr ⟨_, h'⟩))
|
||||
else
|
||||
go offset.inc
|
||||
else
|
||||
s.endPos
|
||||
termination_by s.utf8ByteSize - offset.byteIdx
|
||||
decreasing_by
|
||||
simp only [Pos.Raw.lt_iff, byteIdx_rawEndPos, utf8ByteSize_eq, Pos.Raw.byteIdx_inc] at h ⊢
|
||||
omega
|
||||
|
||||
private theorem Slice.le_offset_findNextPosGo {s : Slice} {o : String.Pos.Raw} (h : o ≤ s.rawEndPos) :
|
||||
o ≤ (findNextPos.go s o).offset := by
|
||||
fun_induction findNextPos.go with
|
||||
| case1 => simp
|
||||
| case2 x h₁ h₂ ih =>
|
||||
refine Pos.Raw.le_of_lt (Pos.Raw.lt_of_lt_of_le Pos.Raw.lt_inc (ih ?_))
|
||||
rw [Pos.Raw.le_iff, Pos.Raw.byteIdx_inc]
|
||||
exact Nat.succ_le_iff.2 h₁
|
||||
| case3 x h => exact h
|
||||
|
||||
theorem Slice.lt_offset_findNextPos {s : Slice} {o : String.Pos.Raw} (h) : o < (s.findNextPos o h).offset :=
|
||||
Pos.Raw.lt_of_lt_of_le Pos.Raw.lt_inc (le_offset_findNextPosGo (Pos.Raw.inc_le.2 h))
|
||||
|
||||
theorem Slice.Pos.prevAuxGo_le_self {s : Slice} {p : Nat} {h : p < s.utf8ByteSize} :
|
||||
prevAux.go p h ≤ ⟨p⟩ := by
|
||||
induction p with
|
||||
@@ -2012,15 +2044,6 @@ theorem Slice.Pos.next_le_of_lt {s : Slice} {p q : s.Pos} {h} : p < q → p.next
|
||||
theorem Pos.ofToSlice_le_iff {s : String} {p : s.toSlice.Pos} {q : s.Pos} :
|
||||
ofToSlice p ≤ q ↔ p ≤ q.toSlice := Iff.rfl
|
||||
|
||||
theorem Pos.ofToSlice_lt_iff {s : String} {p : s.toSlice.Pos} {q : s.Pos} :
|
||||
ofToSlice p < q ↔ p < q.toSlice := Iff.rfl
|
||||
|
||||
theorem Pos.lt_ofToSlice_iff {s : String} {p : s.Pos} {q : s.toSlice.Pos} :
|
||||
p < ofToSlice q ↔ p.toSlice < q := Iff.rfl
|
||||
|
||||
theorem Pos.le_ofToSlice_iff {s : String} {p : s.Pos} {q : s.toSlice.Pos} :
|
||||
p ≤ ofToSlice q ↔ p.toSlice ≤ q := Iff.rfl
|
||||
|
||||
@[simp]
|
||||
theorem Pos.toSlice_lt_toSlice_iff {s : String} {p q : s.Pos} :
|
||||
p.toSlice < q.toSlice ↔ p < q := Iff.rfl
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
/-!
|
||||
# Finding positions in a string relative to a given raw position
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
/--
|
||||
Obtains the smallest valid position that is greater than or equal to the given byte position.
|
||||
-/
|
||||
def Slice.posGE (s : Slice) (offset : String.Pos.Raw) (_h : offset ≤ s.rawEndPos) : s.Pos :=
|
||||
if h : offset < s.rawEndPos then
|
||||
if h' : (s.getUTF8Byte offset h).IsUTF8FirstByte then
|
||||
s.pos offset (Pos.Raw.isValidForSlice_iff_isUTF8FirstByte.2 (Or.inr ⟨_, h'⟩))
|
||||
else
|
||||
s.posGE offset.inc (by simpa)
|
||||
else
|
||||
s.endPos
|
||||
termination_by s.utf8ByteSize - offset.byteIdx
|
||||
decreasing_by
|
||||
simp only [Pos.Raw.lt_iff, byteIdx_rawEndPos, utf8ByteSize_eq, Pos.Raw.byteIdx_inc] at h ⊢
|
||||
omega
|
||||
|
||||
/--
|
||||
Obtains the smallest valid position that is strictly greater than the given byte position.
|
||||
-/
|
||||
@[inline]
|
||||
def Slice.posGT (s : Slice) (offset : String.Pos.Raw) (h : offset < s.rawEndPos) : s.Pos :=
|
||||
s.posGE offset.inc (by simpa)
|
||||
|
||||
@[deprecated Slice.posGT (since := "2026-02-03")]
|
||||
def Slice.findNextPos (offset : String.Pos.Raw) (s : Slice) (h : offset < s.rawEndPos) : s.Pos :=
|
||||
s.posGT offset h
|
||||
|
||||
/--
|
||||
Obtains the smallest valid position that is greater than or equal to the given byte position.
|
||||
-/
|
||||
@[inline]
|
||||
def posGE (s : String) (offset : String.Pos.Raw) (h : offset ≤ s.rawEndPos) : s.Pos :=
|
||||
Pos.ofToSlice (s.toSlice.posGE offset (by simpa))
|
||||
|
||||
/--
|
||||
Obtains the smallest valid position that is strictly greater than the given byte position.
|
||||
-/
|
||||
@[inline]
|
||||
def posGT (s : String) (offset : String.Pos.Raw) (h : offset < s.rawEndPos) : s.Pos :=
|
||||
Pos.ofToSlice (s.toSlice.posGT offset (by simpa))
|
||||
|
||||
end String
|
||||
@@ -9,9 +9,6 @@ prelude
|
||||
public import Init.Data.String.Lemmas.Splits
|
||||
public import Init.Data.String.Lemmas.Modify
|
||||
public import Init.Data.String.Lemmas.Search
|
||||
public import Init.Data.String.Lemmas.FindPos
|
||||
public import Init.Data.String.Lemmas.Basic
|
||||
public import Init.Data.String.Lemmas.Order
|
||||
public import Init.Data.Char.Order
|
||||
public import Init.Data.Char.Lemmas
|
||||
public import Init.Data.List.Lex
|
||||
|
||||
@@ -55,21 +55,4 @@ theorem Slice.Pos.startPos_le {s : Slice} (p : s.Pos) : s.startPos ≤ p := by
|
||||
theorem Slice.Pos.le_endPos {s : Slice} (p : s.Pos) : p ≤ s.endPos :=
|
||||
p.isValidForSlice.le_rawEndPos
|
||||
|
||||
theorem getUTF8Byte_eq_getUTF8Byte_toSlice {s : String} {p : String.Pos.Raw} {h} :
|
||||
s.getUTF8Byte p h = s.toSlice.getUTF8Byte p (by simpa) := by
|
||||
simp [Slice.getUTF8Byte]
|
||||
|
||||
theorem getUTF8Byte_toSlice {s : String} {p : String.Pos.Raw} {h} :
|
||||
s.toSlice.getUTF8Byte p h = s.getUTF8Byte p (by simpa) := by
|
||||
simp [Slice.getUTF8Byte]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.byte_toSlice {s : String} {p : s.Pos} {h} :
|
||||
p.toSlice.byte h = p.byte (ne_of_apply_ne Pos.toSlice (by simpa)) := by
|
||||
simp [byte]
|
||||
|
||||
theorem Pos.byte_eq_byte_toSlice {s : String} {p : s.Pos} {h} :
|
||||
p.byte h = p.toSlice.byte (ne_of_apply_ne Pos.ofToSlice (by simpa)) := by
|
||||
simp
|
||||
|
||||
end String
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.FindPos
|
||||
import all Init.Data.String.FindPos
|
||||
import Init.Data.String.OrderInstances
|
||||
import Init.Data.String.Lemmas.Basic
|
||||
import Init.Data.String.Lemmas.Order
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
namespace Slice
|
||||
|
||||
@[simp]
|
||||
theorem le_offset_posGE {s : Slice} {p : Pos.Raw} {h : p ≤ s.rawEndPos} :
|
||||
p ≤ (s.posGE p h).offset := by
|
||||
fun_induction posGE with
|
||||
| case1 => simp
|
||||
| case2 => exact Std.le_trans (Std.le_of_lt (Pos.Raw.lt_inc)) ‹_›
|
||||
| case3 => assumption
|
||||
|
||||
@[simp]
|
||||
theorem posGE_le_iff {s : Slice} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
s.posGE p h ≤ q ↔ p ≤ q.offset := by
|
||||
fun_induction posGE with
|
||||
| case1 => simp [Pos.le_iff]
|
||||
| case2 r h₁ h₂ h₃ ih =>
|
||||
suffices r ≠ q.offset by simp [ih, Pos.Raw.inc_le, Std.le_iff_lt_or_eq (a := r), this]
|
||||
exact fun h => h₃ (h ▸ q.isUTF8FirstByte_getUTF8Byte_offset)
|
||||
| case3 r h₁ h₂ =>
|
||||
obtain rfl : r = s.rawEndPos := Std.le_antisymm h₁ (Std.not_lt.1 h₂)
|
||||
simp only [Pos.endPos_le, ← offset_endPos, ← Pos.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem lt_posGE_iff {s : Slice} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
q < s.posGE p h ↔ q.offset < p := by
|
||||
rw [← Std.not_le, posGE_le_iff, Std.not_le]
|
||||
|
||||
theorem posGE_eq_iff {s : Slice} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
s.posGE p h = q ↔ p ≤ q.offset ∧ ∀ q', p ≤ q'.offset → q ≤ q' :=
|
||||
⟨by rintro rfl; simp, fun ⟨h₁, h₂⟩ => Std.le_antisymm (by simpa) (h₂ _ (by simp))⟩
|
||||
|
||||
theorem posGT_eq_posGE {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} :
|
||||
s.posGT p h = s.posGE p.inc (by simpa) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem posGE_inc {s : Slice} {p : Pos.Raw} {h : p.inc ≤ s.rawEndPos} :
|
||||
s.posGE p.inc h = s.posGT p (by simpa) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem lt_offset_posGT {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} :
|
||||
p < (s.posGT p h).offset :=
|
||||
Std.lt_of_lt_of_le p.lt_inc (by simp [posGT_eq_posGE, -posGE_inc])
|
||||
|
||||
@[simp]
|
||||
theorem posGT_le_iff {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
s.posGT p h ≤ q ↔ p < q.offset := by
|
||||
rw [posGT_eq_posGE, posGE_le_iff, Pos.Raw.inc_le]
|
||||
|
||||
@[simp]
|
||||
theorem lt_posGT_iff {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
q < s.posGT p h ↔ q.offset ≤ p := by
|
||||
rw [posGT_eq_posGE, lt_posGE_iff, Pos.Raw.lt_inc_iff]
|
||||
|
||||
theorem posGT_eq_iff {s : Slice} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
s.posGT p h = q ↔ p < q.offset ∧ ∀ q', p < q'.offset → q ≤ q' := by
|
||||
simp [posGT_eq_posGE, -posGE_inc, posGE_eq_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.posGE_offset {s : Slice} {p : s.Pos} : s.posGE p.offset (by simp) = p := by
|
||||
simp [posGE_eq_iff, Pos.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem offset_posGE_eq_self_iff {s : Slice} {p : String.Pos.Raw} {h} :
|
||||
(s.posGE p h).offset = p ↔ p.IsValidForSlice s :=
|
||||
⟨fun h' => by simpa [h'] using (s.posGE p h).isValidForSlice,
|
||||
fun h' => by simpa using congrArg Pos.offset (Pos.posGE_offset (p := s.pos p h'))⟩
|
||||
|
||||
theorem posGE_eq_pos {s : Slice} {p : String.Pos.Raw} (h : p.IsValidForSlice s) :
|
||||
s.posGE p h.le_rawEndPos = s.pos p h := by
|
||||
simpa using Pos.posGE_offset (p := s.pos p h)
|
||||
|
||||
theorem pos_eq_posGE {s : Slice} {p : String.Pos.Raw} {h} :
|
||||
s.pos p h = s.posGE p h.le_rawEndPos := by
|
||||
simp [posGE_eq_pos h]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.posGT_offset {s : Slice} {p : s.Pos} {h} :
|
||||
s.posGT p.offset h = p.next (by simpa using h) := by
|
||||
rw [posGT_eq_iff, ← Pos.lt_iff]
|
||||
simp [← Pos.lt_iff]
|
||||
|
||||
theorem posGT_eq_next {s : Slice} {p : String.Pos.Raw} {h} (h' : p.IsValidForSlice s) :
|
||||
s.posGT p h = (s.pos p h').next (by simpa [Pos.ext_iff] using Pos.Raw.ne_of_lt h) := by
|
||||
simpa using Pos.posGT_offset (h := h) (p := s.pos p h')
|
||||
|
||||
theorem next_eq_posGT {s : Slice} {p : s.Pos} {h} :
|
||||
p.next h = s.posGT p.offset (by simpa) := by
|
||||
simp
|
||||
|
||||
end Slice
|
||||
|
||||
@[simp]
|
||||
theorem le_offset_posGE {s : String} {p : Pos.Raw} {h : p ≤ s.rawEndPos} :
|
||||
p ≤ (s.posGE p h).offset := by
|
||||
simp [posGE]
|
||||
|
||||
@[simp]
|
||||
theorem posGE_le_iff {s : String} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
s.posGE p h ≤ q ↔ p ≤ q.offset := by
|
||||
simp [posGE, Pos.ofToSlice_le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem lt_posGE_iff {s : String} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
q < s.posGE p h ↔ q.offset < p := by
|
||||
simp [posGE, Pos.lt_ofToSlice_iff]
|
||||
|
||||
theorem posGE_eq_iff {s : String} {p : Pos.Raw} {h : p ≤ s.rawEndPos} {q : s.Pos} :
|
||||
s.posGE p h = q ↔ p ≤ q.offset ∧ ∀ q', p ≤ q'.offset → q ≤ q' :=
|
||||
⟨by rintro rfl; simp, fun ⟨h₁, h₂⟩ => Std.le_antisymm (by simpa) (h₂ _ (by simp))⟩
|
||||
|
||||
theorem posGT_eq_posGE {s : String} {p : Pos.Raw} {h : p < s.rawEndPos} :
|
||||
s.posGT p h = s.posGE p.inc (by simpa) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem posGE_inc {s : String} {p : Pos.Raw} {h : p.inc ≤ s.rawEndPos} :
|
||||
s.posGE p.inc h = s.posGT p (by simpa) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem lt_offset_posGT {s : String} {p : Pos.Raw} {h : p < s.rawEndPos} :
|
||||
p < (s.posGT p h).offset :=
|
||||
Std.lt_of_lt_of_le p.lt_inc (by simp [posGT_eq_posGE, -posGE_inc])
|
||||
|
||||
@[simp]
|
||||
theorem posGT_le_iff {s : String} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
s.posGT p h ≤ q ↔ p < q.offset := by
|
||||
rw [posGT_eq_posGE, posGE_le_iff, Pos.Raw.inc_le]
|
||||
|
||||
@[simp]
|
||||
theorem lt_posGT_iff {s : String} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
q < s.posGT p h ↔ q.offset ≤ p := by
|
||||
rw [posGT_eq_posGE, lt_posGE_iff, Pos.Raw.lt_inc_iff]
|
||||
|
||||
theorem posGT_eq_iff {s : String} {p : Pos.Raw} {h : p < s.rawEndPos} {q : s.Pos} :
|
||||
s.posGT p h = q ↔ p < q.offset ∧ ∀ q', p < q'.offset → q ≤ q' := by
|
||||
simp [posGT_eq_posGE, -posGE_inc, posGE_eq_iff]
|
||||
|
||||
theorem posGE_toSlice {s : String} {p : Pos.Raw} (h : p ≤ s.toSlice.rawEndPos) :
|
||||
s.toSlice.posGE p h = (s.posGE p (by simpa)).toSlice := by
|
||||
simp [posGE]
|
||||
|
||||
theorem posGE_eq_posGE_toSlice {s : String} {p : Pos.Raw} (h : p ≤ s.rawEndPos) :
|
||||
s.posGE p h = Pos.ofToSlice (s.toSlice.posGE p (by simpa)) := by
|
||||
simp [posGE]
|
||||
|
||||
theorem posGT_toSlice {s : String} {p : Pos.Raw} (h : p < s.toSlice.rawEndPos) :
|
||||
s.toSlice.posGT p h = (s.posGT p (by simpa)).toSlice := by
|
||||
simp [posGT]
|
||||
|
||||
theorem posGT_eq_posGT_toSlice {s : String} {p : Pos.Raw} (h : p < s.rawEndPos) :
|
||||
s.posGT p h = Pos.ofToSlice (s.toSlice.posGT p (by simpa)) := by
|
||||
simp [posGT]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.posGE_offset {s : String} {p : s.Pos} : s.posGE p.offset (by simp) = p := by
|
||||
simp [posGE_eq_iff, Pos.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem offset_posGE_eq_self_iff {s : String} {p : String.Pos.Raw} {h} :
|
||||
(s.posGE p h).offset = p ↔ p.IsValid s :=
|
||||
⟨fun h' => by simpa [h'] using (s.posGE p h).isValid,
|
||||
fun h' => by simpa using congrArg Pos.offset (Pos.posGE_offset (p := s.pos p h'))⟩
|
||||
|
||||
theorem posGE_eq_pos {s : String} {p : String.Pos.Raw} (h : p.IsValid s) :
|
||||
s.posGE p h.le_rawEndPos = s.pos p h := by
|
||||
simpa using Pos.posGE_offset (p := s.pos p h)
|
||||
|
||||
theorem pos_eq_posGE {s : String} {p : String.Pos.Raw} {h} :
|
||||
s.pos p h = s.posGE p h.le_rawEndPos := by
|
||||
simp [posGE_eq_pos h]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.posGT_offset {s : String} {p : s.Pos} {h} :
|
||||
s.posGT p.offset h = p.next (by simpa using h) := by
|
||||
rw [posGT_eq_iff, ← Pos.lt_iff]
|
||||
simp [← Pos.lt_iff]
|
||||
|
||||
theorem posGT_eq_next {s : String} {p : String.Pos.Raw} {h} (h' : p.IsValid s) :
|
||||
s.posGT p h = (s.pos p h').next (by simpa [Pos.ext_iff] using Pos.Raw.ne_of_lt h) := by
|
||||
simpa using Pos.posGT_offset (h := h) (p := s.pos p h')
|
||||
|
||||
theorem next_eq_posGT {s : String} {p : s.Pos} {h} :
|
||||
p.next h = s.posGT p.offset (by simpa) := by
|
||||
simp
|
||||
|
||||
end String
|
||||
@@ -1,109 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
import Init.Data.String.OrderInstances
|
||||
import Init.Data.String.Lemmas.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace String
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.next_le_iff_lt {s : Slice} {p q : s.Pos} {h} : p.next h ≤ q ↔ p < q :=
|
||||
⟨fun h => Std.lt_of_lt_of_le lt_next h, next_le_of_lt⟩
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.lt_next_iff_le {s : Slice} {p q : s.Pos} {h} : p < q.next h ↔ p ≤ q := by
|
||||
rw [← Decidable.not_iff_not, Std.not_lt, next_le_iff_lt, Std.not_le]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.next_le_iff_lt {s : String} {p q : s.Pos} {h} : p.next h ≤ q ↔ p < q := by
|
||||
rw [next, Pos.ofToSlice_le_iff, ← Pos.toSlice_lt_toSlice_iff]
|
||||
exact Slice.Pos.next_le_iff_lt
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.le_startPos {s : Slice} (p : s.Pos) : p ≤ s.startPos ↔ p = s.startPos :=
|
||||
⟨fun h => Std.le_antisymm h (startPos_le _), by simp +contextual⟩
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.startPos_lt_iff {s : Slice} (p : s.Pos) : s.startPos < p ↔ p ≠ s.startPos := by
|
||||
simp [← le_startPos, Std.not_le]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.endPos_le {s : Slice} (p : s.Pos) : s.endPos ≤ p ↔ p = s.endPos :=
|
||||
⟨fun h => Std.le_antisymm (le_endPos _) h, by simp +contextual⟩
|
||||
|
||||
@[simp]
|
||||
theorem Pos.le_startPos {s : String} (p : s.Pos) : p ≤ s.startPos ↔ p = s.startPos :=
|
||||
⟨fun h => Std.le_antisymm h (startPos_le _), by simp +contextual⟩
|
||||
|
||||
@[simp]
|
||||
theorem Pos.endPos_le {s : String} (p : s.Pos) : s.endPos ≤ p ↔ p = s.endPos :=
|
||||
⟨fun h => Std.le_antisymm (le_endPos _) h, by simp +contextual [Std.le_refl]⟩
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.not_lt_startPos {s : Slice} {p : s.Pos} : ¬ p < s.startPos :=
|
||||
fun h => Std.lt_irrefl (Std.lt_of_lt_of_le h (Slice.Pos.startPos_le _))
|
||||
|
||||
theorem Slice.Pos.ne_startPos_of_lt {s : Slice} {p q : s.Pos} : p < q → q ≠ s.startPos := by
|
||||
rintro h rfl
|
||||
simp at h
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.next_ne_startPos {s : Slice} {p : s.Pos} {h} :
|
||||
p.next h ≠ s.startPos :=
|
||||
ne_startPos_of_lt lt_next
|
||||
|
||||
theorem Slice.Pos.ofSliceFrom_lt_ofSliceFrom_iff {s : Slice} {p : s.Pos}
|
||||
{q r : (s.sliceFrom p).Pos} : Slice.Pos.ofSliceFrom q < Slice.Pos.ofSliceFrom r ↔ q < r := by
|
||||
simp [Slice.Pos.lt_iff, Pos.Raw.lt_iff]
|
||||
|
||||
theorem Slice.Pos.ofSliceFrom_le_ofSliceFrom_iff {s : Slice} {p : s.Pos}
|
||||
{q r : (s.sliceFrom p).Pos} : Slice.Pos.ofSliceFrom q ≤ Slice.Pos.ofSliceFrom r ↔ q ≤ r := by
|
||||
simp [Slice.Pos.le_iff, Pos.Raw.le_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.offset_le_rawEndPos {s : Slice} {p : s.Pos} :
|
||||
p.offset ≤ s.rawEndPos :=
|
||||
p.isValidForSlice.le_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Pos.offset_le_rawEndPos {s : String} {p : s.Pos} :
|
||||
p.offset ≤ s.rawEndPos :=
|
||||
p.isValid.le_rawEndPos
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.offset_lt_rawEndPos_iff {s : Slice} {p : s.Pos} :
|
||||
p.offset < s.rawEndPos ↔ p ≠ s.endPos := by
|
||||
simp [Std.lt_iff_le_and_ne, p.offset_le_rawEndPos, Pos.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Pos.offset_lt_rawEndPos_iff {s : String} {p : s.Pos} :
|
||||
p.offset < s.rawEndPos ↔ p ≠ s.endPos := by
|
||||
simp [Std.lt_iff_le_and_ne, p.offset_le_rawEndPos, Pos.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem Slice.Pos.getUTF8Byte_offset {s : Slice} {p : s.Pos} {h} :
|
||||
s.getUTF8Byte p.offset h = p.byte (by simpa using h) := by
|
||||
simp [Pos.byte]
|
||||
|
||||
theorem Slice.Pos.isUTF8FirstByte_getUTF8Byte_offset {s : Slice} {p : s.Pos} {h} :
|
||||
(s.getUTF8Byte p.offset h).IsUTF8FirstByte := by
|
||||
simpa [getUTF8Byte_offset] using isUTF8FirstByte_byte
|
||||
|
||||
theorem Pos.getUTF8Byte_offset {s : String} {p : s.Pos} {h} :
|
||||
s.getUTF8Byte p.offset h = p.byte (by simpa using h) := by
|
||||
simp only [getUTF8Byte_eq_getUTF8Byte_toSlice, ← Pos.offset_toSlice,
|
||||
Slice.Pos.getUTF8Byte_offset, byte_toSlice]
|
||||
|
||||
theorem Pos.isUTF8FirstByte_getUTF8Byte_offset {s : String} {p : s.Pos} {h} :
|
||||
(s.getUTF8Byte p.offset h).IsUTF8FirstByte := by
|
||||
simpa [getUTF8Byte_offset] using isUTF8FirstByte_byte
|
||||
|
||||
end String
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.Iterators.Basic
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
@@ -130,24 +129,23 @@ variable [∀ s, Std.Iterator (σ s) Id (SearchStep s)]
|
||||
variable (pat : ρ) [ToForwardSearcher pat σ]
|
||||
|
||||
@[specialize pat]
|
||||
def defaultStartsWith (s : Slice) [Std.IteratorLoop (σ s) Id Id] : Bool :=
|
||||
def defaultStartsWith (s : Slice) : Bool :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
match searcher.first? with
|
||||
| some (.matched start ..) => s.startPos = start
|
||||
match searcher.step with
|
||||
| .yield _ (.matched start ..) _ => s.startPos = start
|
||||
| _ => false
|
||||
|
||||
@[specialize pat]
|
||||
def defaultDropPrefix? (s : Slice) [Std.IteratorLoop (σ s) Id Id] : Option s.Pos :=
|
||||
def defaultDropPrefix? (s : Slice) : Option s.Pos :=
|
||||
let searcher := ToForwardSearcher.toSearcher pat s
|
||||
match searcher.first? with
|
||||
| some (.matched _ endPos) => some endPos
|
||||
match searcher.step with
|
||||
| .yield _ (.matched _ endPos) _ => some endPos
|
||||
| _ => none
|
||||
|
||||
@[always_inline, inline]
|
||||
def defaultImplementation {pat : ρ} [ToForwardSearcher pat σ] [∀ s, Std.IteratorLoop (σ s) Id Id] :
|
||||
ForwardPattern pat where
|
||||
startsWith s := defaultStartsWith pat s
|
||||
dropPrefix? s := defaultDropPrefix? pat s
|
||||
def defaultImplementation {pat : ρ} [ToForwardSearcher pat σ] : ForwardPattern pat where
|
||||
startsWith := defaultStartsWith pat
|
||||
dropPrefix? := defaultDropPrefix? pat
|
||||
|
||||
end ForwardPattern
|
||||
|
||||
@@ -190,24 +188,23 @@ variable [∀ s, Std.Iterator (σ s) Id (SearchStep s)]
|
||||
variable (pat : ρ) [ToBackwardSearcher pat σ]
|
||||
|
||||
@[specialize pat]
|
||||
def defaultEndsWith (s : Slice) [Std.IteratorLoop (σ s) Id Id] : Bool :=
|
||||
def defaultEndsWith (s : Slice) : Bool :=
|
||||
let searcher := ToBackwardSearcher.toSearcher pat s
|
||||
match searcher.first? with
|
||||
| some (.matched _ endPos) => s.endPos = endPos
|
||||
match searcher.step with
|
||||
| .yield _ (.matched _ endPos) _ => s.endPos = endPos
|
||||
| _ => false
|
||||
|
||||
@[specialize pat]
|
||||
def defaultDropSuffix? (s : Slice) [Std.IteratorLoop (σ s) Id Id] : Option s.Pos :=
|
||||
def defaultDropSuffix? (s : Slice) : Option s.Pos :=
|
||||
let searcher := ToBackwardSearcher.toSearcher pat s
|
||||
match searcher.first? with
|
||||
| some (.matched startPos _) => some startPos
|
||||
match searcher.step with
|
||||
| .yield _ (.matched startPos _) _ => some startPos
|
||||
| _ => none
|
||||
|
||||
@[always_inline, inline]
|
||||
def defaultImplementation {pat : ρ} [ToBackwardSearcher pat σ] [∀ s, Std.IteratorLoop (σ s) Id Id] :
|
||||
BackwardPattern pat where
|
||||
endsWith s := defaultEndsWith pat s
|
||||
dropSuffix? s := defaultDropSuffix? pat s
|
||||
def defaultImplementation {pat : ρ} [ToBackwardSearcher pat σ] : BackwardPattern pat where
|
||||
endsWith := defaultEndsWith pat
|
||||
dropSuffix? := defaultDropSuffix? pat
|
||||
|
||||
end ToBackwardSearcher
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Pattern.Basic
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
public import Init.Data.Vector.Basic
|
||||
public import Init.Data.String.FindPos
|
||||
import Init.Data.String.Termination
|
||||
import Init.Data.String.Lemmas.FindPos
|
||||
public import Init.Data.Vector.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
@@ -150,15 +148,15 @@ instance (s : Slice) : Std.Iterator (ForwardSliceSearcher s) Id (SearchStep s) w
|
||||
let basePos := s.pos! stackPos
|
||||
-- Since we report (mis)matches by code point and not by byte, missing in the first byte
|
||||
-- means that we should skip ahead to the next code point.
|
||||
let nextStackPos := s.posGT stackPos h₁
|
||||
let nextStackPos := s.findNextPos stackPos h₁
|
||||
let res := .rejected basePos nextStackPos
|
||||
-- Invariants still satisfied
|
||||
pure (.deflate ⟨.yield ⟨.proper needle table htable nextStackPos.offset 0
|
||||
(by simp [Pos.Raw.lt_iff] at hn ⊢; omega)⟩ res,
|
||||
by simpa using ⟨_, _, ⟨rfl, rfl⟩, by simp [Pos.Raw.lt_iff] at hn ⊢; omega,
|
||||
Or.inl (by
|
||||
have := lt_offset_posGT (h := h₁)
|
||||
have t₀ := (posGT _ _ h₁).isValidForSlice.le_utf8ByteSize
|
||||
have := lt_offset_findNextPos h₁
|
||||
have t₀ := (findNextPos _ _ h₁).isValidForSlice.le_utf8ByteSize
|
||||
simp [nextStackPos, Pos.Raw.lt_iff] at this ⊢; omega)⟩⟩)
|
||||
else
|
||||
let newNeedlePos := table[needlePos.byteIdx - 1]'(by simp [Pos.Raw.lt_iff] at hn; omega)
|
||||
@@ -167,16 +165,19 @@ instance (s : Slice) : Std.Iterator (ForwardSliceSearcher s) Id (SearchStep s) w
|
||||
let basePos := s.pos! (stackPos.unoffsetBy needlePos)
|
||||
-- Since we report (mis)matches by code point and not by byte, missing in the first byte
|
||||
-- means that we should skip ahead to the next code point.
|
||||
let nextStackPos := s.posGE stackPos (Pos.Raw.le_of_lt h₁)
|
||||
let nextStackPos := (s.pos? stackPos).getD (s.findNextPos stackPos h₁)
|
||||
let res := .rejected basePos nextStackPos
|
||||
-- Invariants still satisfied
|
||||
pure (.deflate ⟨.yield ⟨.proper needle table htable nextStackPos.offset 0
|
||||
(by simp [Pos.Raw.lt_iff] at hn ⊢; omega)⟩ res,
|
||||
by simpa using ⟨_, _, ⟨rfl, rfl⟩, by simp [Pos.Raw.lt_iff] at hn ⊢; omega, by
|
||||
have h₂ := le_offset_posGE (h := Pos.Raw.le_of_lt h₁)
|
||||
have h₃ := (s.posGE _ (Pos.Raw.le_of_lt h₁)).isValidForSlice.le_utf8ByteSize
|
||||
simp [Pos.Raw.le_iff, Pos.Raw.lt_iff, Pos.Raw.ext_iff, nextStackPos] at ⊢ h₂
|
||||
omega⟩⟩)
|
||||
simp only [pos?, Pos.Raw.isValidForSlice_eq_true_iff, nextStackPos]
|
||||
split
|
||||
· exact Or.inr (by simp [Pos.Raw.lt_iff]; omega)
|
||||
· refine Or.inl ?_
|
||||
have := lt_offset_findNextPos h₁
|
||||
have t₀ := (findNextPos _ _ h₁).isValidForSlice.le_utf8ByteSize
|
||||
simp [Pos.Raw.lt_iff] at this ⊢; omega⟩⟩)
|
||||
else
|
||||
let oldBasePos := s.pos! (stackPos.decreaseBy needlePos.byteIdx)
|
||||
let newBasePos := s.pos! (stackPos.decreaseBy newNeedlePos)
|
||||
@@ -263,7 +264,8 @@ def startsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
have hs := by
|
||||
simp [Pos.Raw.le_iff] at h ⊢
|
||||
omega
|
||||
have hp := by simp
|
||||
have hp := by
|
||||
simp [Pos.Raw.le_iff]
|
||||
Internal.memcmpSlice s pat s.startPos.offset pat.startPos.offset pat.rawEndPos hs hp
|
||||
else
|
||||
false
|
||||
@@ -299,7 +301,7 @@ def endsWith (pat : Slice) (s : Slice) : Bool :=
|
||||
simp [sStart, Pos.Raw.le_iff] at h ⊢
|
||||
omega
|
||||
have hp := by
|
||||
simp [patStart] at h ⊢
|
||||
simp [patStart, Pos.Raw.le_iff] at h ⊢
|
||||
Internal.memcmpSlice s pat sStart patStart pat.rawEndPos hs hp
|
||||
else
|
||||
false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user