mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-04 03:04:12 +00:00
Compare commits
199 Commits
context-no
...
sofia/asyn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb2954d8d7 | ||
|
|
07f39d40dc | ||
|
|
7b3b323525 | ||
|
|
40a807527a | ||
|
|
5e40283a07 | ||
|
|
9837e4ccea | ||
|
|
94e5b66dfe | ||
|
|
8443600762 | ||
|
|
8b64425033 | ||
|
|
d96fd949ff | ||
|
|
d33aece210 | ||
|
|
9a7bab5f90 | ||
|
|
e2f87ed215 | ||
|
|
e42892cfb6 | ||
|
|
cc5c070328 | ||
|
|
f122454ef6 | ||
|
|
02f482129a | ||
|
|
0807f73171 | ||
|
|
27fa5b0bb5 | ||
|
|
8f9966ba74 | ||
|
|
eabd7309b7 | ||
|
|
795d13ddce | ||
|
|
2b23afdfab | ||
|
|
20b0bd0a20 | ||
|
|
979c2b4af0 | ||
|
|
b3cd5999e7 | ||
|
|
a4dcb25f69 | ||
|
|
85ce814689 | ||
|
|
9fc18b8ab4 | ||
|
|
852a3db447 | ||
|
|
d0d5d4ca39 | ||
|
|
b32f3e8930 | ||
|
|
34f5fba54d | ||
|
|
4c9601e60f | ||
|
|
42be7bb5c7 | ||
|
|
5f68c1662d | ||
|
|
2d14d51935 | ||
|
|
7cbeb14e46 | ||
|
|
cee2886154 | ||
|
|
35764213fc | ||
|
|
6b92cbdfa4 | ||
|
|
72bb7cf364 | ||
|
|
4881c3042e | ||
|
|
ec7add0b48 | ||
|
|
9b842b7554 | ||
|
|
fc718eac88 | ||
|
|
8b3c82cce2 | ||
|
|
0d1b7e6c88 | ||
|
|
d898c9ed17 | ||
|
|
c6abc3c036 | ||
|
|
d07862db2a | ||
|
|
8a79ef3633 | ||
|
|
b1c82f776b | ||
|
|
f278f31469 | ||
|
|
38b4062edb | ||
|
|
ae8dc414c3 | ||
|
|
7822ee4500 | ||
|
|
8f22c56420 | ||
|
|
0e122870be | ||
|
|
13c23877d4 | ||
|
|
7fba12f8f7 | ||
|
|
abb487a0c0 | ||
|
|
1091053824 | ||
|
|
545bd8a96c | ||
|
|
2f9618f76b | ||
|
|
fa36fcd448 | ||
|
|
9a3b4b2716 | ||
|
|
9fb5ab8450 | ||
|
|
a62c0bce77 | ||
|
|
3ce554abd7 | ||
|
|
257c347f9f | ||
|
|
ca1315e3ba | ||
|
|
197bc6cb66 | ||
|
|
02ca710872 | ||
|
|
3fbf080d72 | ||
|
|
4379002d05 | ||
|
|
5d50ec90f9 | ||
|
|
6ca699b1ff | ||
|
|
c2d56fa031 | ||
|
|
b6d590ccc3 | ||
|
|
719765ec5c | ||
|
|
11b0e7d89c | ||
|
|
37f3f0e1e2 | ||
|
|
85645958f9 | ||
|
|
a80169165e | ||
|
|
8dca311ba5 | ||
|
|
e6dfde1ad6 | ||
|
|
e532ce95ce | ||
|
|
e74b81169d | ||
|
|
cf8ffc28d3 | ||
|
|
d625aaa96f | ||
|
|
89e4f9815f | ||
|
|
9002cc8761 | ||
|
|
5a7d663624 | ||
|
|
efb398b040 | ||
|
|
4cbd1a439a | ||
|
|
20873d5d72 | ||
|
|
4c1830e5ae | ||
|
|
7b75db7c6e | ||
|
|
8d418201a6 | ||
|
|
850a4c897f | ||
|
|
186f5a6960 | ||
|
|
917715c862 | ||
|
|
50435417ac | ||
|
|
9deff2751f | ||
|
|
f3d93970dc | ||
|
|
d1577fda7a | ||
|
|
ca10fd7c4f | ||
|
|
a1cd945e82 | ||
|
|
9c372b9bc2 | ||
|
|
38214ac121 | ||
|
|
6d30aeefe5 | ||
|
|
112fa51e08 | ||
|
|
9b53e39804 | ||
|
|
ede1acfb44 | ||
|
|
0799e5c4e9 | ||
|
|
32a4c88986 | ||
|
|
4cf3c0ae67 | ||
|
|
06ba748221 | ||
|
|
d2d32f13c0 | ||
|
|
9aa6448fa9 | ||
|
|
3bea7e209e | ||
|
|
88fa4212d7 | ||
|
|
97464c9d7f | ||
|
|
8df968de01 | ||
|
|
d869c38e7b | ||
|
|
4d8d502754 | ||
|
|
8e1df86939 | ||
|
|
4ff33eaef5 | ||
|
|
22a4cab8c7 | ||
|
|
1e12cdddc0 | ||
|
|
cab33ac1da | ||
|
|
6b97e41650 | ||
|
|
c2521e94e1 | ||
|
|
f771dea78b | ||
|
|
02a4713875 | ||
|
|
7407534eb8 | ||
|
|
3f80e530d3 | ||
|
|
3146f6c651 | ||
|
|
22aab5c3bb | ||
|
|
7e9ea00ac0 | ||
|
|
409cbe1da9 | ||
|
|
3e4fa12c72 | ||
|
|
ed5dc328d9 | ||
|
|
2bbf5db04f | ||
|
|
116b708269 | ||
|
|
4b6eab762f | ||
|
|
9d6f391414 | ||
|
|
245ede65b5 | ||
|
|
2422b9db87 | ||
|
|
3f9f8f094d | ||
|
|
cf18337157 | ||
|
|
3cf7fdcbe0 | ||
|
|
caa0eacea8 | ||
|
|
b8e584a054 | ||
|
|
ae682ed225 | ||
|
|
b64111d5a8 | ||
|
|
72cc6c85eb | ||
|
|
a966ce64ca | ||
|
|
5c88a2bf56 | ||
|
|
73c85b177e | ||
|
|
5c06c79c15 | ||
|
|
c8117a34c1 | ||
|
|
a5f5d793d7 | ||
|
|
61c46fd5f8 | ||
|
|
e7d1cdd36a | ||
|
|
dfcb5bb3a8 | ||
|
|
01ed345643 | ||
|
|
176fb1cf0e | ||
|
|
6b387da032 | ||
|
|
c3667e2861 | ||
|
|
33266b23cd | ||
|
|
a4a2bfa426 | ||
|
|
b7520e7232 | ||
|
|
0b84c3912e | ||
|
|
e96467f500 | ||
|
|
bdab63048a | ||
|
|
30a041902b | ||
|
|
fbcad8f593 | ||
|
|
0a6bd5c0c6 | ||
|
|
de2e935f30 | ||
|
|
57bce526f9 | ||
|
|
b136906939 | ||
|
|
f4c7a0d25c | ||
|
|
3e2124bb48 | ||
|
|
fc6a6cc4e2 | ||
|
|
bb61a2d481 | ||
|
|
2d8de4235d | ||
|
|
a0ecff4610 | ||
|
|
923c3d10a2 | ||
|
|
ac4c752608 | ||
|
|
4d2576362b | ||
|
|
f6a2c6d07c | ||
|
|
1a203c7fe5 | ||
|
|
e75e6fbe9e | ||
|
|
d98b626633 | ||
|
|
fd0177afe3 | ||
|
|
757426b099 | ||
|
|
b81ea5ee9c |
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -4,3 +4,9 @@ RELEASES.md merge=union
|
||||
stage0/** binary linguist-generated
|
||||
# The following file is often manually edited, so do show it in diffs
|
||||
stage0/src/stdlib_flags.h -binary -linguist-generated
|
||||
# These files should not have line endings translated on Windows, because
|
||||
# it throws off parser tests. Later lines override earlier ones, so the
|
||||
# runner code is still treated as ordinary text.
|
||||
tests/lean/docparse/* eol=lf
|
||||
tests/lean/docparse/*.lean eol=auto
|
||||
tests/lean/docparse/*.sh eol=auto
|
||||
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
|
||||
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/check-prelude.yml
vendored
2
.github/workflows/check-prelude.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/check-stage0.yml
vendored
2
.github/workflows/check-stage0.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
check-stage0-on-queue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
filter: blob:none
|
||||
|
||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
# don't schedule nightlies on forks
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
- name: Set Nightly
|
||||
@@ -363,7 +363,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
@@ -388,12 +388,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
|
||||
2
.github/workflows/copyright-header.yml
vendored
2
.github/workflows/copyright-header.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
check-lean-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Verify .lean files start with a copyright header.
|
||||
run: |
|
||||
|
||||
6
.github/workflows/pr-release.yml
vendored
6
.github/workflows/pr-release.yml
vendored
@@ -395,7 +395,7 @@ jobs:
|
||||
# Checkout the Batteries repository with all branches
|
||||
- name: Checkout Batteries repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -454,7 +454,7 @@ jobs:
|
||||
# Checkout the mathlib4 repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -524,7 +524,7 @@ jobs:
|
||||
# Checkout the reference manual repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: leanprover/reference-manual
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
|
||||
12
.github/workflows/update-stage0.yml
vendored
12
.github/workflows/update-stage0.yml
vendored
@@ -21,11 +21,13 @@ jobs:
|
||||
runs-on: nscloud-ubuntu-22.04-amd64-8x16
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
CCACHE_MAXSIZE: 400M
|
||||
steps:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
# https://stackoverflow.com/a/76135647/946226
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||
@@ -72,10 +74,14 @@ jobs:
|
||||
restore-keys: |
|
||||
Linux Lake-build-v3
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: cmake --preset release
|
||||
# sync options with `Linux Lake` to ensure cache reuse
|
||||
run: |
|
||||
mkdir -p build
|
||||
cmake --preset release -B build -DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: make -j$NPROC -C build/release update-stage0-commit
|
||||
run: |
|
||||
make -j$NPROC -C build update-stage0-commit
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: git show --stat
|
||||
|
||||
@@ -2,19 +2,19 @@ This is the repository for **Lean 4**.
|
||||
|
||||
# About
|
||||
|
||||
- [Quickstart](https://lean-lang.org/documentation/setup/)
|
||||
- [Quickstart](https://lean-lang.org/install/)
|
||||
- [Homepage](https://lean-lang.org)
|
||||
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
|
||||
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
|
||||
- [Documentation Overview](https://lean-lang.org/documentation/)
|
||||
- [Documentation Overview](https://lean-lang.org/learn/)
|
||||
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
|
||||
- [Release notes](RELEASES.md) starting at v4.0.0-m3
|
||||
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
|
||||
- [Examples](https://lean-lang.org/examples/)
|
||||
- [External Contribution Guidelines](CONTRIBUTING.md)
|
||||
|
||||
# Installation
|
||||
|
||||
See [Setting Up Lean](https://lean-lang.org/documentation/setup/).
|
||||
See [Install Lean](https://lean-lang.org/install/).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
@@ -99,3 +99,19 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
|
||||
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
|
||||
and will report back to the Lean PR with results from Mathlib CI.
|
||||
|
||||
### Avoiding rebuilds for downstream projects
|
||||
|
||||
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
|
||||
|
||||
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
|
||||
```
|
||||
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
|
||||
```
|
||||
Alternatively, use
|
||||
```
|
||||
export LEAN_GITHASH=$(lean --githash)
|
||||
export ELAN_TOOLCHAIN=lean4
|
||||
```
|
||||
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
|
||||
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build-old",
|
||||
"type": "shell",
|
||||
"command": "make -C build/release -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) LAKE_EXTRA_ARGS=--old",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "build"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"type": "shell",
|
||||
|
||||
@@ -5,6 +5,7 @@ Merge a tag into a branch on a GitHub repository.
|
||||
|
||||
This script checks if a specified tag can be merged cleanly into a branch and performs
|
||||
the merge if possible. If the merge cannot be done cleanly, it prints a helpful message.
|
||||
Merge conflicts in the lean-toolchain file are automatically resolved by accepting the incoming changes.
|
||||
|
||||
Usage:
|
||||
python3 merge_remote.py <org/repo> <branch> <tag>
|
||||
@@ -58,6 +59,32 @@ def clone_repo(repo, temp_dir):
|
||||
return True
|
||||
|
||||
|
||||
def get_conflicted_files():
|
||||
"""Get list of files with merge conflicts."""
|
||||
result = run_command("git diff --name-only --diff-filter=U", check=False)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip().split('\n') if result.stdout.strip() else []
|
||||
return []
|
||||
|
||||
|
||||
def resolve_lean_toolchain_conflict(tag):
|
||||
"""Resolve lean-toolchain conflict by accepting incoming (tag) changes."""
|
||||
print("Resolving lean-toolchain conflict by accepting incoming changes...")
|
||||
# Accept theirs (incoming) version for lean-toolchain
|
||||
result = run_command(f"git checkout --theirs lean-toolchain", check=False)
|
||||
if result.returncode != 0:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
return False
|
||||
|
||||
# Add the resolved file
|
||||
add_result = run_command("git add lean-toolchain", check=False)
|
||||
if add_result.returncode != 0:
|
||||
print("Failed to stage resolved lean-toolchain")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_and_merge(repo, branch, tag, temp_dir):
|
||||
"""Check if tag can be merged into branch and perform the merge if possible."""
|
||||
# Change to the temporary directory
|
||||
@@ -98,12 +125,37 @@ def check_and_merge(repo, branch, tag, temp_dir):
|
||||
# Try merging the tag directly
|
||||
print(f"Merging {tag} into {branch}...")
|
||||
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
|
||||
|
||||
|
||||
if merge_result.returncode != 0:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur. Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
# Check which files have conflicts
|
||||
conflicted_files = get_conflicted_files()
|
||||
|
||||
if conflicted_files == ['lean-toolchain']:
|
||||
# Only lean-toolchain has conflicts, resolve it
|
||||
print("Merge conflict detected only in lean-toolchain.")
|
||||
if resolve_lean_toolchain_conflict(tag):
|
||||
# Continue the merge with the resolved conflict
|
||||
print("Continuing merge with resolved lean-toolchain...")
|
||||
continue_result = run_command(f"git commit --no-edit", check=False)
|
||||
if continue_result.returncode != 0:
|
||||
print("Failed to complete merge after resolving lean-toolchain")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
# Other files have conflicts, or unable to determine
|
||||
if conflicted_files:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print(f"Merge conflicts in: {', '.join(conflicted_files)}")
|
||||
else:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur.")
|
||||
print("Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
|
||||
print(f"Pushing changes to remote...")
|
||||
push_result = run_command(f"git push origin {branch}")
|
||||
|
||||
@@ -52,6 +52,7 @@ def sort_sections_order():
|
||||
return [
|
||||
"Language",
|
||||
"Library",
|
||||
"Tactics",
|
||||
"Compiler",
|
||||
"Pretty Printing",
|
||||
"Documentation",
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
repositories:
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: batteries
|
||||
url: https://github.com/leanprover-community/batteries
|
||||
toolchain-tag: true
|
||||
@@ -7,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
|
||||
@@ -21,20 +35,6 @@ repositories:
|
||||
branch: master
|
||||
dependencies: []
|
||||
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
@@ -96,6 +96,15 @@ repositories:
|
||||
- import-graph
|
||||
- plausible
|
||||
|
||||
- name: cslib
|
||||
url: https://github.com/leanprover/cslib
|
||||
toolchain-tag: true
|
||||
stable-branch: true
|
||||
branch: main
|
||||
bump-branch: true
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: repl
|
||||
url: https://github.com/leanprover-community/repl
|
||||
toolchain-tag: true
|
||||
@@ -103,3 +112,11 @@ repositories:
|
||||
branch: master
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: lean-fro.org
|
||||
url: https://github.com/leanprover/lean-fro.org
|
||||
toolchain-tag: false
|
||||
stable-branch: false
|
||||
branch: master
|
||||
dependencies:
|
||||
- verso
|
||||
|
||||
@@ -377,6 +377,33 @@ def execute_release_steps(repo, version, config):
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
elif repo_name == "lean-fro.org":
|
||||
# Update lean-toolchain in examples/hero
|
||||
print(blue("Updating examples/hero/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "examples" / "hero" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated examples/hero/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
print(blue("Running `lake update`..."))
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
print(blue("Running `lake update` in examples/hero..."))
|
||||
run_command("lake update", cwd=repo_path / "examples" / "hero", stream_output=True)
|
||||
elif repo_name == "cslib":
|
||||
print(blue("Updating lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
print(blue("Updating docs/lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path / "docs")
|
||||
|
||||
# Update lean-toolchain in docs
|
||||
print(blue("Updating docs/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "docs" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated docs/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 24)
|
||||
set(LEAN_VERSION_MINOR 25)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
|
||||
@@ -42,5 +42,8 @@ public import Init.While
|
||||
public import Init.Syntax
|
||||
public import Init.Internal
|
||||
public import Init.Try
|
||||
public meta import Init.Try -- make sure `Try.Config` can be evaluated anywhere
|
||||
public import Init.BinderNameHint
|
||||
public import Init.Task
|
||||
public import Init.MethodSpecsSimp
|
||||
public import Init.LawfulBEqTactics
|
||||
|
||||
@@ -147,7 +147,7 @@ class LawfulMonad (m : Type u → Type v) [Monad m] : Prop extends LawfulApplica
|
||||
|
||||
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
|
||||
attribute [simp] pure_bind bind_assoc bind_pure_comp
|
||||
attribute [grind] pure_bind
|
||||
attribute [grind <=] pure_bind
|
||||
|
||||
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
|
||||
change x >>= (fun a => pure (id a)) = x
|
||||
|
||||
@@ -1580,6 +1580,7 @@ instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) :=
|
||||
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% BitVec
|
||||
gen_injective_theorems% ByteArray
|
||||
gen_injective_theorems% Char
|
||||
gen_injective_theorems% DoResultBC
|
||||
gen_injective_theorems% DoResultPR
|
||||
@@ -2546,7 +2547,3 @@ class Irrefl (r : α → α → Prop) : Prop where
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
end Std
|
||||
|
||||
/-- Deprecated alias for `XorOp`. -/
|
||||
@[deprecated XorOp (since := "2025-07-30")]
|
||||
abbrev Xor := XorOp
|
||||
|
||||
@@ -121,7 +121,7 @@ theorem pmap_eq_map {p : α → Prop} {f : α → β} {xs : Array α} (H) :
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (xs : Array α) {H₁ H₂}
|
||||
(h : ∀ a ∈ xs, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
|
||||
cases xs
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.mem_toArray] at h
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
@@ -176,9 +176,6 @@ theorem attach_map_val (xs : Array α) (f : α → β) :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
|
||||
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
@@ -187,21 +184,18 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {xs : Array α} (H
|
||||
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} {xs : Array α} (H : ∀ a ∈ xs, p a) :
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {xs : Array α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
cases xs
|
||||
@@ -212,12 +206,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
@[simp, grind =]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
@@ -345,7 +340,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
|
||||
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
List.foldl_toArray', List.mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -364,7 +359,7 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
|
||||
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
List.foldr_toArray', List.mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -400,9 +395,6 @@ theorem map_attach_eq_pmap {xs : Array α} {f : { x // x ∈ xs } → β} :
|
||||
cases xs
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
(xs.filterMap f).attach = xs.attach.filterMap
|
||||
@@ -706,7 +698,7 @@ and simplifies these to the function directly taking the value.
|
||||
{f : { x // p x } → Array β} {g : α → Array β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(xs.flatMap f) = xs.unattach.flatMap g := by
|
||||
cases xs
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
mk.injEq]
|
||||
rw [List.flatMap_subtype]
|
||||
simp [hf]
|
||||
|
||||
@@ -40,11 +40,11 @@ namespace Array
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
@[simp, grind =] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
(set xs i v h).size = xs.size :=
|
||||
List.length_set ..
|
||||
|
||||
@[simp, grind] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
@[simp, grind =] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
List.length_concat ..
|
||||
|
||||
theorem ext {xs ys : Array α}
|
||||
@@ -108,13 +108,19 @@ instance : Membership α (Array α) where
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
@[simp, grind =] theorem _root_.List.mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
@[deprecated List.mem_toArray (since := "2025-09-04")]
|
||||
theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l :=
|
||||
List.mem_toArray
|
||||
|
||||
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
@@ -123,19 +129,10 @@ end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[deprecated Array.toArray_toList (since := "2025-02-17")]
|
||||
abbrev toArray_toList := @Array.toArray_toList
|
||||
|
||||
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
|
||||
theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
|
||||
|
||||
@[deprecated toList_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.toList_toArray := @List.toList_toArray
|
||||
|
||||
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
|
||||
@[deprecated size_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.size_toArray := @List.size_toArray
|
||||
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
|
||||
@[simp, grind =] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
|
||||
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
|
||||
@@ -197,7 +194,7 @@ Examples:
|
||||
def pop (xs : Array α) : Array α where
|
||||
toList := xs.toList.dropLast
|
||||
|
||||
@[simp, grind] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
@[simp, grind =] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
match xs with
|
||||
| ⟨[]⟩ => rfl
|
||||
| ⟨a::as⟩ => simp [pop, Nat.succ_sub_succ_eq_sub, size]
|
||||
@@ -406,10 +403,6 @@ that requires a proof the array is non-empty.
|
||||
def back? (xs : Array α) : Option α :=
|
||||
xs[xs.size - 1]?
|
||||
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
|
||||
def get? (xs : Array α) (i : Nat) : Option α :=
|
||||
if h : i < xs.size then some xs[i] else none
|
||||
|
||||
/--
|
||||
Swaps a new element with the element at the given index.
|
||||
|
||||
@@ -1806,7 +1799,6 @@ Examples:
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
|
||||
-/
|
||||
@[grind]
|
||||
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
|
||||
if h : i < xs.size then xs.eraseIdx i h else xs
|
||||
|
||||
|
||||
@@ -24,29 +24,6 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]` instead.
|
||||
|
||||
Access an element from an array without needing a runtime bounds checks,
|
||||
using a `Nat` index and a proof that it is in bounds.
|
||||
|
||||
This function does not use `get_elem_tactic` to automatically find the proof that
|
||||
the index is in bounds. This is because the tactic itself needs to look up values in
|
||||
arrays.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
|
||||
def get {α : Type u} (xs : @& Array α) (i : @& Nat) (h : LT.lt i xs.size) : α :=
|
||||
xs.toList.get ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]!` instead.
|
||||
|
||||
Access an element from an array, or panic if the index is out of bounds.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
|
||||
def get! {α : Type u} [Inhabited α] (xs : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD xs i default
|
||||
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
{f : β → α → m β} {xs : Array α} {i j} (H : xs.size ≤ i + j) {b} :
|
||||
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
|
||||
@@ -108,9 +85,6 @@ abbrev push_toList := @toList_push
|
||||
|
||||
@[simp, grind =] theorem toList_pop {xs : Array α} : xs.pop.toList = xs.toList.dropLast := rfl
|
||||
|
||||
@[deprecated toList_pop (since := "2025-02-17")]
|
||||
abbrev pop_toList := @Array.toList_pop
|
||||
|
||||
@[simp] theorem append_eq_append {xs ys : Array α} : xs.append ys = xs ++ ys := rfl
|
||||
|
||||
@[simp, grind =] theorem toList_append {xs ys : Array α} :
|
||||
|
||||
@@ -91,7 +91,7 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseP
|
||||
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_eraseP_of_neg pa
|
||||
|
||||
@@ -240,7 +240,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_erase (by simpa using h)
|
||||
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
a ∈ xs.erase b ↔ a ∈ xs :=
|
||||
erase_eq_eraseP b xs ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -271,7 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
(xs ++ ys).erase a = if a ∈ xs then xs.erase a ++ ys else xs ++ ys.erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, List.mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
@@ -324,6 +324,13 @@ abbrev erase_mkArray_ne := @erase_replicate_ne
|
||||
|
||||
end erase
|
||||
|
||||
/-! ### eraseIdxIfInBounds -/
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdxIfInBounds_eq {xs : Array α} {i : Nat} :
|
||||
xs.eraseIdxIfInBounds i = if h : i < xs.size then xs.eraseIdx i else xs := by
|
||||
simp [eraseIdxIfInBounds]
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
|
||||
@@ -27,11 +27,11 @@ open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp, grind] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
@[simp, grind =] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind =] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
cases xs; simp [List.findSome?_append]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem findSome?_singleton {a : α} {f : α → Option β} : #[a].findSome? f = f a := by
|
||||
simp
|
||||
|
||||
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ x
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
cases xs; simp
|
||||
@@ -277,9 +278,6 @@ theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = none ↔ ∀ ys ∈ xss, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
|
||||
@@ -305,9 +303,6 @@ theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α → Bool} {a
|
||||
⟨zs.toList, bs.toList.map Array.toList, by simpa using h⟩,
|
||||
by simpa using h₁, by simpa using h₂⟩
|
||||
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem find?_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
@@ -317,17 +312,11 @@ theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
|
||||
|
||||
@[grind =]
|
||||
theorem find?_replicate :
|
||||
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [← List.toArray_replicate, List.find?_replicate]
|
||||
|
||||
@[deprecated find?_replicate (since := "2025-03-18")]
|
||||
abbrev find?_mkArray := @find?_replicate
|
||||
|
||||
@[simp] theorem find?_replicate_of_size_pos (h : 0 < n) :
|
||||
find? p (replicate n a) = if p a then some a else none := by
|
||||
simp [find?_replicate, Nat.ne_of_gt h]
|
||||
@@ -345,34 +334,19 @@ abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
|
||||
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
|
||||
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [← List.toArray_replicate, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
|
||||
|
||||
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_some_iff := @find?_replicate_eq_some_iff
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
|
||||
|
||||
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α → Bool} (h) :
|
||||
((replicate n a).find? p).get h = a := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkArray := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
@@ -395,7 +369,6 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,8 @@ prelude
|
||||
public import Init.Core
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Range.Polymorphic.Iterators
|
||||
import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
import Init.Data.Iterators.Consumers
|
||||
|
||||
public section
|
||||
|
||||
@@ -167,7 +167,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
forIn' as b f = forIn' bs b' g := by
|
||||
cases as <;> cases bs
|
||||
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
simp only [mk.injEq, List.mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
exact List.forIn'_congr w hb h
|
||||
|
||||
/--
|
||||
|
||||
@@ -116,7 +116,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
rw [← List.toArray_range']
|
||||
simp only [List.find?_toArray, mem_toArray]
|
||||
simp only [List.find?_toArray, List.mem_toArray]
|
||||
simp [List.find?_range'_eq_some]
|
||||
|
||||
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.GetElem
|
||||
public import Init.Data.Array.Basic
|
||||
import Init.Data.Array.GetLit
|
||||
public import Init.Data.Slice.Basic
|
||||
|
||||
|
||||
@@ -29,10 +29,6 @@ set_option linter.missingDocs true
|
||||
|
||||
namespace BitVec
|
||||
|
||||
@[inline, deprecated BitVec.ofNatLT (since := "2025-02-13"), inherit_doc BitVec.ofNatLT]
|
||||
protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2 ^ n) : BitVec n :=
|
||||
BitVec.ofNatLT i p
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
@@ -874,4 +870,7 @@ def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
/-- Count the number of leading zeros. -/
|
||||
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
|
||||
/-- Count the number of trailing zeros. -/
|
||||
def ctz (x : BitVec w) : BitVec w := (x.reverse).clz
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -19,7 +19,7 @@ theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
simp only [getLsbD_ofFin]
|
||||
apply Nat.testBit_lt_two_pow
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BitVec
|
||||
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
|
||||
(BitVec.ofFin x)[i] = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
@[simp, grind =] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
rw [getMsbD]
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -74,10 +74,6 @@ theorem some_eq_getElem?_iff {l : BitVec w} : some a = l[n]? ↔ ∃ h : n < w,
|
||||
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a → ∃ h : n < w, l[n] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
|
||||
abbrev getElem?_eq_some := @getElem?_eq_some_iff
|
||||
|
||||
theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
|
||||
simp
|
||||
|
||||
@@ -350,25 +346,14 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
|
||||
@[simp] theorem ofBool_xor_ofBool : ofBool b ^^^ ofBool b' = ofBool (b ^^ b') := by
|
||||
cases b <;> cases b' <;> rfl
|
||||
|
||||
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
|
||||
theorem toNat_ofNatLt (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||||
|
||||
@[simp, grind =] theorem getLsbD_ofNatLT {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
|
||||
getLsbD (x#'lt) i = x.testBit i := by
|
||||
simp [getLsbD, BitVec.ofNatLT]
|
||||
|
||||
@[deprecated getLsbD_ofNatLT (since := "2025-02-13")]
|
||||
theorem getLsbD_ofNatLt {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
|
||||
getLsbD (x#'lt) i = x.testBit i := getLsbD_ofNatLT x lt i
|
||||
|
||||
@[simp, grind =] theorem getMsbD_ofNatLT {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := by
|
||||
simp [getMsbD, getLsbD]
|
||||
|
||||
@[deprecated getMsbD_ofNatLT (since := "2025-02-13")]
|
||||
theorem getMsbD_ofNatLt {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := getMsbD_ofNatLT h
|
||||
|
||||
@[grind =]
|
||||
theorem ofNatLT_eq_ofNat {w : Nat} {n : Nat} (hn) : BitVec.ofNatLT n hn = BitVec.ofNat w n :=
|
||||
eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt hn])
|
||||
@@ -1100,6 +1085,10 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
|
||||
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
|
||||
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
|
||||
|
||||
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w ≤ w') : (b.setWidth w').toNat = b.toNat := by
|
||||
rw [BitVec.toNat_setWidth, Nat.mod_eq_of_lt]
|
||||
exact BitVec.toNat_lt_twoPow_of_le h
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -1287,6 +1276,17 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
|
||||
ext i hi
|
||||
omega
|
||||
|
||||
theorem extractLsb'_setWidth_of_le {b : BitVec w} {start len w' : Nat} (h : start + len ≤ w') :
|
||||
(b.setWidth w').extractLsb' start len = b.extractLsb' start len := by
|
||||
ext i h_i
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem setWidth_extractLsb'_of_le {c : BitVec w} (h : len₁ ≤ len₂) :
|
||||
(c.extractLsb' start len₂).setWidth len₁ = c.extractLsb' start len₁ := by
|
||||
ext i hi
|
||||
simp [show i < len₂ by omega]
|
||||
|
||||
/-! ### allOnes -/
|
||||
|
||||
@[simp, grind =] theorem toNat_allOnes : (allOnes v).toNat = 2^v - 1 := by
|
||||
@@ -1530,6 +1530,12 @@ theorem extractLsb_and {x : BitVec w} {hi lo : Nat} :
|
||||
@[simp, grind =] theorem ofNat_and {x y : Nat} : BitVec.ofNat w (x &&& y) = BitVec.ofNat w x &&& BitVec.ofNat w y :=
|
||||
eq_of_toNat_eq (by simp [Nat.and_mod_two_pow])
|
||||
|
||||
theorem and_or_distrib_left {x y z : BitVec w} : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_left])
|
||||
|
||||
theorem and_or_distrib_right {x y z : BitVec w} : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_right])
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@[simp, grind =] theorem toNat_xor (x y : BitVec v) :
|
||||
@@ -2180,6 +2186,10 @@ theorem msb_ushiftRight {x : BitVec w} {n : Nat} :
|
||||
have := lt_of_getLsbD ha
|
||||
omega
|
||||
|
||||
theorem setWidth_ushiftRight_eq_extractLsb {b : BitVec w} : (b >>> w').setWidth w'' = b.extractLsb' w' w'' := by
|
||||
ext i hi
|
||||
simp
|
||||
|
||||
/-! ### ushiftRight reductions from BitVec to Nat -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -2970,10 +2980,9 @@ theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
|
||||
/-- Combine adjacent `extractLsb'` operations into a single `extractLsb'`. -/
|
||||
theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start₂ = start₁ + len₁) :
|
||||
((x.extractLsb' start₂ len₂) ++ (x.extractLsb' start₁ len₁)) =
|
||||
(x.extractLsb' start₁ (len₁ + len₂)).cast (by omega) := by
|
||||
x.extractLsb' start₁ (len₂ + len₁) := by
|
||||
ext i h
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, getElem_cast, ite_eq_left_iff,
|
||||
Nat.not_lt]
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, ite_eq_left_iff, Nat.not_lt]
|
||||
intro hi
|
||||
congr 1
|
||||
omega
|
||||
@@ -3085,6 +3094,51 @@ theorem extractLsb'_append_eq_of_le {v w} {xhi : BitVec v} {xlo : BitVec w}
|
||||
extractLsb' start len (xhi ++ xlo) = extractLsb' (start - w) len xhi := by
|
||||
simp [extractLsb'_append_eq_ite, show ¬ start < w by omega]
|
||||
|
||||
theorem extractLsb'_append_eq_left {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' w' w = a := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_le]
|
||||
|
||||
theorem extractLsb'_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' 0 w' = b := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_add_le]
|
||||
|
||||
theorem setWidth_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).setWidth w' = b := by
|
||||
ext i hi
|
||||
simp [getLsbD_append, hi]
|
||||
|
||||
theorem append_left_inj {s₁ s₂ : BitVec w} (t : BitVec w') : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, dif_neg] using congrArg (·[i + w']'(by omega)) h
|
||||
|
||||
theorem append_right_inj (s : BitVec w) {t₁ t₂ : BitVec w'} : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, hi] using congrArg (·[i]) h
|
||||
|
||||
theorem setWidth_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} :
|
||||
(b ++ b').setWidth w'' = (b.setWidth w'' <<< w') ||| b'.setWidth w'' := by
|
||||
ext i hi
|
||||
simp only [getElem_setWidth, getElem_or, getElem_shiftLeft]
|
||||
rw [getLsbD_append]
|
||||
split <;> simp_all
|
||||
|
||||
theorem setWidth_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} :
|
||||
(b ++ b' ++ b'').setWidth w''' = (b.setWidth w''' <<< (w' + w'')) ||| (b'.setWidth w''' <<< w'') ||| b''.setWidth w''' := by
|
||||
rw [BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem setWidth_append_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} {b''' : BitVec w'''} :
|
||||
(b ++ b' ++ b'' ++ b''').setWidth w'''' = (b.setWidth w'''' <<< (w' + w'' + w''')) ||| (b'.setWidth w'''' <<< (w'' + w''')) |||
|
||||
(b''.setWidth w'''' <<< w''') ||| b'''.setWidth w'''' := by
|
||||
simp only [BitVec.setWidth_append_eq_shiftLeft_setWidth_or, BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem and_setWidth_allOnes (w' w : Nat) (b : BitVec (w' + w)) :
|
||||
b &&& (BitVec.allOnes w).setWidth (w' + w) = 0#w' ++ b.setWidth w := by
|
||||
ext i hi
|
||||
simp only [getElem_and, getElem_setWidth, getLsbD_allOnes]
|
||||
rw [BitVec.getElem_append]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### rev -/
|
||||
|
||||
@[grind =]
|
||||
@@ -4041,6 +4095,9 @@ instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
|
||||
apply LawfulOrderLT.of_le
|
||||
simpa using fun _ _ => BitVec.lt_asymm
|
||||
|
||||
theorem length_pos_of_lt {b b' : BitVec w} (h : b < b') : 0 < w :=
|
||||
length_pos_of_ne (BitVec.ne_of_lt h)
|
||||
|
||||
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y := by
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
|
||||
apply Nat.mod_lt
|
||||
@@ -4112,6 +4169,14 @@ theorem lt_of_msb_false_of_msb_true {x y : BitVec w} (hx : x.msb = false) (hy :
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem lt_add_one {b : BitVec w} (h : b ≠ allOnes w) : b < b + 1 := by
|
||||
simp only [ne_eq, ← toNat_inj, toNat_allOnes] at h
|
||||
simp only [BitVec.lt_def, ofNat_eq_ofNat, toNat_add, toNat_ofNat, Nat.add_mod_mod]
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
· exact Nat.lt_add_one _
|
||||
· have := b.toNat_lt_twoPow_of_le (Nat.le_refl _)
|
||||
omega
|
||||
|
||||
/-! ### udiv -/
|
||||
|
||||
theorem udiv_def {x y : BitVec n} : x / y = BitVec.ofNat n (x.toNat / y.toNat) := by
|
||||
@@ -5257,7 +5322,7 @@ theorem replicate_succ' {x : BitVec w} :
|
||||
(replicate n x ++ x).cast (by rw [Nat.mul_succ]) := by
|
||||
simp [replicate_append_self]
|
||||
|
||||
theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
theorem setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
rw [toNat_setWidth]
|
||||
simp only [toNat_setWidth, toNat_add, toNat_umod, Nat.add_mod_mod, Nat.mod_add_mod, toNat_twoPow]
|
||||
@@ -5266,6 +5331,14 @@ theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y)
|
||||
· have hk : 2 ^ w < 2 ^ i := Nat.pow_lt_pow_of_lt (by decide) (Nat.lt_of_not_le h)
|
||||
rw [Nat.mod_eq_of_lt hk, Nat.mod_mod_eq_mod_mod_of_dvd (Nat.pow_dvd_pow _ (Nat.le_of_not_le h))]
|
||||
|
||||
theorem setWidth_setWidth_eq_self {a : BitVec w} {w' : Nat} (h : a < BitVec.twoPow w w') : (a.setWidth w').setWidth w = a := by
|
||||
by_cases hw : w' < w
|
||||
· simp only [toNat_eq, toNat_setWidth]
|
||||
rw [Nat.mod_mod_of_dvd' (Nat.pow_dvd_pow _ (Nat.le_of_lt hw)), Nat.mod_eq_of_lt]
|
||||
rwa [BitVec.lt_def, BitVec.toNat_twoPow_of_lt hw] at h
|
||||
· rw [BitVec.lt_def, BitVec.toNat_twoPow_of_le (by omega)] at h
|
||||
simp at h
|
||||
|
||||
/-! ### intMin -/
|
||||
|
||||
@[grind =]
|
||||
@@ -5779,6 +5852,25 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
|
||||
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
|
||||
cases n <;> cases w <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem reverse_eq_zero_iff {x : BitVec w} :
|
||||
x.reverse = 0#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro hrev
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
simp [hrev]
|
||||
· intro hzero
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, getMsbD_reverse]
|
||||
simp [hi, hzero]
|
||||
|
||||
@[simp]
|
||||
theorem reverse_reverse_eq {x : BitVec w} :
|
||||
x.reverse.reverse = x := by
|
||||
ext k hk
|
||||
rw [getElem_reverse, getMsbD_reverse, getLsbD_eq_getElem]
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
@@ -5909,6 +6001,12 @@ theorem getElem_eq_true_of_lt_of_le {x : BitVec w} (hk' : k < w) (hlt: x.toNat <
|
||||
omega
|
||||
· simp [show w ≤ k + k' by omega] at hk'
|
||||
|
||||
theorem not_lt_iff {b : BitVec w} : ~~~b < b ↔ 0 < w ∧ b.msb = true := by
|
||||
refine ⟨fun h => ?_, fun ⟨hw, hb⟩ => ?_⟩
|
||||
· have := length_pos_of_lt h
|
||||
exact ⟨this, by rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)] at h⟩
|
||||
· rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)]
|
||||
|
||||
/-! ### Count leading zeros -/
|
||||
|
||||
theorem clzAuxRec_zero (x : BitVec w) :
|
||||
@@ -6182,16 +6280,70 @@ theorem toNat_lt_two_pow_sub_clz {x : BitVec w} :
|
||||
· simp [show w + 1 ≤ i by omega]
|
||||
· simp; omega
|
||||
|
||||
theorem clz_eq_reverse_ctz {x : BitVec w} :
|
||||
x.clz = (x.reverse).ctz := by
|
||||
simp [ctz]
|
||||
|
||||
/-! ### Deprecations -/
|
||||
/-! ### Count trailing zeros -/
|
||||
|
||||
set_option linter.missingDocs false
|
||||
|
||||
@[deprecated toFin_uShiftRight (since := "2025-02-18")]
|
||||
abbrev toFin_uShiftRight := @toFin_ushiftRight
|
||||
theorem ctz_eq_reverse_clz {x : BitVec w} :
|
||||
x.ctz = (x.reverse).clz := by
|
||||
simp [ctz]
|
||||
|
||||
/-- The number of trailing zeroes is strictly less than the bitwidth iff the bitvector is nonzero. -/
|
||||
@[simp]
|
||||
theorem ctz_lt_iff_ne_zero {x : BitVec w} :
|
||||
ctz x < w ↔ x ≠ 0#w := by
|
||||
simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq]
|
||||
rw [show BitVec.ofNat w w = w by simp, ← reverse_eq_zero_iff (x := x)]
|
||||
apply clz_lt_iff_ne_zero (x := x.reverse)
|
||||
|
||||
/-- If a bitvec is different than zero the bits at indexes lower than `ctz x` are false. -/
|
||||
theorem getLsbD_false_of_lt_ctz {x : BitVec w} (hi : i < x.ctz.toNat) :
|
||||
x.getLsbD i = false := by
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have hiff := ctz_lt_iff_ne_zero (x := x)
|
||||
by_cases hzero : x = 0#w
|
||||
· simp [hzero, getLsbD_reverse]
|
||||
· simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq, hzero, not_false_eq_true,
|
||||
iff_true] at hiff
|
||||
simp only [ctz] at hi
|
||||
have hi' : i < w := by simp [BitVec.lt_def] at hiff; omega
|
||||
simp only [hi', decide_true, Bool.true_and]
|
||||
have : (x.reverse.clzAuxRec (w - 1)).toNat ≤ w := by
|
||||
rw [show ((x.reverse.clzAuxRec (w - 1)).toNat ≤ w) =
|
||||
((x.reverse.clzAuxRec (w - 1)).toNat ≤ (BitVec.ofNat w w).toNat) by simp, ← le_def]
|
||||
apply clzAuxRec_le (x := x.reverse) (n := w - 1)
|
||||
let j := (x.reverse.clzAuxRec (w - 1)).toNat - 1 - i
|
||||
rw [show w - 1 - i = w - (x.reverse.clzAuxRec (w - 1)).toNat + j by
|
||||
subst j
|
||||
rw [Nat.sub_sub (n := (x.reverse.clzAuxRec (w - 1)).toNat),
|
||||
← Nat.add_sub_assoc (by exact Nat.one_add_le_iff.mpr hi)]
|
||||
omega]
|
||||
have hfalse : ∀ (i : Nat), w - 1 < i → x.reverse.getLsbD i = false := by
|
||||
intros i hj
|
||||
simp [show w ≤ i by omega]
|
||||
exact getLsbD_false_of_clzAuxRec (x := x.reverse) (n := w - 1) hfalse (j := j)
|
||||
|
||||
/-- If a bitvec is different than zero, the bit at index `ctz x`, i.e., the first bit after the
|
||||
trailing zeros, is true. -/
|
||||
theorem getLsbD_true_ctz_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
x.getLsbD (ctz x).toNat = true := by
|
||||
simp only [ctz_eq_reverse_clz, clz]
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have := ctz_lt_iff_ne_zero (x := x)
|
||||
simp only [ctz_eq_reverse_clz, clz, natCast_eq_ofNat, lt_def, toNat_ofNat, Nat.mod_two_pow_self,
|
||||
ne_eq] at this
|
||||
simp only [this, hx, not_false_eq_true, decide_true, Bool.true_and]
|
||||
have hnotrev : ¬x.reverse = 0#w := by simp [reverse_eq_zero_iff, hx]
|
||||
apply getLsbD_true_of_eq_clzAuxRec_of_ne_zero (x := x.reverse) (n := w - 1) hnotrev
|
||||
intro i hi
|
||||
simp [show w ≤ i by omega]
|
||||
|
||||
/-- A nonzero bitvector is lower-bounded by its trailing zeroes. -/
|
||||
theorem two_pow_ctz_le_toNat_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
2 ^ (ctz x).toNat ≤ x.toNat := by
|
||||
have hclz := getLsbD_true_ctz_of_ne_zero (x := x) hx
|
||||
exact Nat.ge_two_pow_of_testBit hclz
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -7,6 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.ByteArray.Bootstrap
|
||||
public import Init.Data.ByteArray.Extra
|
||||
public import Init.Data.ByteArray.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -11,16 +11,11 @@ public import Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Option.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
@[expose] public section
|
||||
universe u
|
||||
|
||||
structure ByteArray where
|
||||
data : Array UInt8
|
||||
|
||||
attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
deriving instance BEq for ByteArray
|
||||
@@ -30,29 +25,15 @@ attribute [ext] ByteArray
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[extern "lean_mk_empty_byte_array"]
|
||||
def emptyWithCapacity (c : @& Nat) : ByteArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
def empty : ByteArray := emptyWithCapacity 0
|
||||
|
||||
instance : Inhabited ByteArray where
|
||||
default := empty
|
||||
|
||||
instance : EmptyCollection ByteArray where
|
||||
emptyCollection := ByteArray.empty
|
||||
|
||||
@[extern "lean_byte_array_push"]
|
||||
def push : ByteArray → UInt8 → ByteArray
|
||||
| ⟨bs⟩, b => ⟨bs.push b⟩
|
||||
|
||||
@[extern "lean_byte_array_size"]
|
||||
def size : (@& ByteArray) → Nat
|
||||
| ⟨bs⟩ => bs.size
|
||||
|
||||
@[extern "lean_sarray_size", simp]
|
||||
def usize (a : @& ByteArray) : USize :=
|
||||
a.size.toUSize
|
||||
@@ -106,11 +87,31 @@ def copySlice (src : @& ByteArray) (srcOff : Nat) (dest : ByteArray) (destOff le
|
||||
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
|
||||
a.copySlice b empty 0 (e - b)
|
||||
|
||||
protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
|
||||
b.copySlice 0 a a.size b.size false
|
||||
|
||||
instance : Append ByteArray := ⟨ByteArray.append⟩
|
||||
@[simp]
|
||||
theorem size_data {a : ByteArray} :
|
||||
a.data.size = a.size := rfl
|
||||
|
||||
@[csimp]
|
||||
theorem append_eq_fastAppend : @ByteArray.append = @ByteArray.fastAppend := by
|
||||
funext a b
|
||||
ext1
|
||||
apply Array.ext'
|
||||
simp [ByteArray.fastAppend, copySlice, ← size_data, - Array.append_assoc]
|
||||
|
||||
-- Needs to come after the `csimp` lemma
|
||||
instance : Append ByteArray where
|
||||
append := ByteArray.append
|
||||
|
||||
@[simp]
|
||||
theorem append_eq {a b : ByteArray} : a.append b = a ++ b := rfl
|
||||
|
||||
@[simp]
|
||||
theorem fastAppend_eq {a b : ByteArray} : a.fastAppend b = a ++ b := by
|
||||
simp [← append_eq_fastAppend]
|
||||
|
||||
def toList (bs : ByteArray) : List UInt8 :=
|
||||
let rec loop (i : Nat) (r : List UInt8) :=
|
||||
@@ -350,13 +351,4 @@ def prevn : Iterator → Nat → Iterator
|
||||
end Iterator
|
||||
end ByteArray
|
||||
|
||||
/--
|
||||
Converts a list of bytes into a `ByteArray`.
|
||||
-/
|
||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
let rec loop
|
||||
| [], r => r
|
||||
| b::bs, r => loop bs (r.push b)
|
||||
loop bs ByteArray.empty
|
||||
|
||||
instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
53
src/Init/Data/ByteArray/Bootstrap.lean
Normal file
53
src/Init/Data/ByteArray/Bootstrap.lean
Normal file
@@ -0,0 +1,53 @@
|
||||
/-
|
||||
Copyright (c) 2025 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.Prelude
|
||||
public import Init.Data.List.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem data_push {a : ByteArray} {b : UInt8} : (a.push b).data = a.data.push b := rfl
|
||||
|
||||
@[expose]
|
||||
protected def append (a b : ByteArray) : ByteArray :=
|
||||
⟨⟨a.data.toList ++ b.data.toList⟩⟩
|
||||
|
||||
@[simp]
|
||||
theorem toList_data_append' {a b : ByteArray} :
|
||||
(a.append b).data.toList = a.data.toList ++ b.data.toList := by
|
||||
have ⟨⟨a⟩⟩ := a
|
||||
have ⟨⟨b⟩⟩ := b
|
||||
rfl
|
||||
|
||||
theorem ext : {x y : ByteArray} → x.data = y.data → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
|
||||
end ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem List.toList_data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data.toList = l := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data.toList = b.data.toList ++ a by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all [toList_push]
|
||||
where
|
||||
toList_push {xs : Array UInt8} {x : UInt8} : (xs.push x).toList = xs.toList ++ [x] := by
|
||||
have ⟨xs⟩ := xs
|
||||
simp [Array.push, List.concat_eq_append]
|
||||
|
||||
theorem List.toByteArray_append' {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray.append l'.toByteArray :=
|
||||
ByteArray.ext (ext (by simp))
|
||||
where
|
||||
ext : {x y : Array UInt8} → x.toList = y.toList → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
259
src/Init/Data/ByteArray/Lemmas.lean
Normal file
259
src/Init/Data/ByteArray/Lemmas.lean
Normal file
@@ -0,0 +1,259 @@
|
||||
/-
|
||||
Copyright (c) 2025 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.ByteArray.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
public section
|
||||
|
||||
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
|
||||
@[simp]
|
||||
theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).data = a.data.extract b e := by
|
||||
simp [extract, copySlice]
|
||||
by_cases b ≤ e
|
||||
· rw [(by omega : b + (e - b) = e)]
|
||||
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
ext1
|
||||
simp [Nat.min_le_left]
|
||||
|
||||
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_append {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
|
||||
simp [List.toByteArray_append']
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_data_append {l l' : ByteArray} :
|
||||
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
|
||||
simp [← append_eq]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_append {l l' : ByteArray} :
|
||||
(l ++ l').data = l.data ++ l'.data := by
|
||||
simp [← Array.toList_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data = l.toArray := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all
|
||||
|
||||
@[simp]
|
||||
theorem List.size_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.size = l.length := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ ByteArray.size_empty⟩
|
||||
ext1
|
||||
simp [← Array.size_eq_zero_iff, h]
|
||||
|
||||
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
a[i] = a.data[i]'(by simpa [← size_data]) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_left (by simpa)]
|
||||
|
||||
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hle : a.size ≤ i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_right (by simpa)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
l.toByteArray[i]'h = l[i]'(by simp_all) := by
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
l[i]'h = l.toByteArray[i]'(by simp_all) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).size = min e a.size - b := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
rw [← size_eq_zero_iff, size_extract]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
simp only [extract_eq_empty_iff]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
|
||||
a ++ b = ByteArray.empty ↔ a = ByteArray.empty ∧ b = ByteArray.empty := by
|
||||
simp [← size_eq_zero_iff, size_append]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_eq_empty {l : List UInt8} :
|
||||
l.toByteArray = ByteArray.empty ↔ l = [] := by
|
||||
simp [← ByteArray.size_eq_zero_iff]
|
||||
|
||||
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_right_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
(hi : i ≤ j) (hk : j ≤ k) :
|
||||
a.extract i k = a.extract i j ++ a.extract j k := by
|
||||
simp
|
||||
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
|
||||
|
||||
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
simp only [ByteArray.ext_iff, ← ByteArray.size_data, ByteArray.data_append] at *
|
||||
exact Array.append_inj_left h hl
|
||||
|
||||
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract i (a ++ b).size = b := by
|
||||
subst hi
|
||||
ext1
|
||||
simp [← size_data]
|
||||
|
||||
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract 0 i = a := by
|
||||
subst hi
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
(a ++ b).extract i a.size = a.extract i a.size := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
|
||||
cases h
|
||||
rw [extract_append_size_add]
|
||||
|
||||
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
start + i < xs.size := by
|
||||
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
|
||||
apply Nat.sub_le_sub_right; apply Nat.min_le_right
|
||||
|
||||
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
|
||||
simp [getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
a.extract i j = a.extract i' j ↔ min j a.size - i = min j a.size - i' := by
|
||||
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
|
||||
|
||||
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
a.extract i (i + 1) = [a[i]].toByteArray := by
|
||||
ext
|
||||
· simp
|
||||
omega
|
||||
· rename_i j hj hj'
|
||||
obtain rfl : j = 0 := by simpa using hj'
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_one (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_two (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_three (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
|
||||
simp [ByteArray.toList, ByteArray.toList.loop]
|
||||
|
||||
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
ByteArray.copySlice src srcOff dest destOff len exact =
|
||||
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
|
||||
ext1
|
||||
simp [copySlice]
|
||||
@@ -122,7 +122,7 @@ private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i
|
||||
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
|
||||
else
|
||||
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
|
||||
rw [foldlM_loop_lt]
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
congr; funext
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@@ -3,15 +3,11 @@ Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.Grind.Tactics
|
||||
|
||||
public section
|
||||
|
||||
namespace Function
|
||||
|
||||
/--
|
||||
@@ -34,20 +30,108 @@ Examples:
|
||||
@[inline, expose]
|
||||
def uncurry : (α → β → φ) → α × β → φ := fun f a => f a.1 a.2
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem curry_uncurry (f : α → β → φ) : curry (uncurry f) = f :=
|
||||
rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem uncurry_curry (f : α × β → φ) : uncurry (curry f) = f :=
|
||||
funext fun ⟨_a, _b⟩ => rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem uncurry_apply_pair {α β γ} (f : α → β → γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
|
||||
rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f x y = f (x, y) :=
|
||||
rfl
|
||||
|
||||
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
|
||||
@[expose]
|
||||
def Injective (f : α → β) : Prop :=
|
||||
∀ ⦃a₁ a₂⦄, f a₁ = f a₂ → a₁ = a₂
|
||||
|
||||
theorem Injective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Injective g) (hf : Injective f) :
|
||||
Injective (g ∘ f) := fun _a₁ _a₂ => fun h => hf (hg h)
|
||||
|
||||
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
|
||||
for some `a : α`. -/
|
||||
@[expose]
|
||||
def Surjective (f : α → β) : Prop :=
|
||||
∀ b, Exists fun a => f a = b
|
||||
|
||||
theorem Surjective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Surjective g) (hf : Surjective f) :
|
||||
Surjective (g ∘ f) := fun c : γ =>
|
||||
Exists.elim (hg c) fun b hb =>
|
||||
Exists.elim (hf b) fun a ha =>
|
||||
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
|
||||
|
||||
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
|
||||
@[expose, grind]
|
||||
def LeftInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
∀ x, g (f x) = x
|
||||
|
||||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||||
@[expose]
|
||||
def HasLeftInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => LeftInverse finv f
|
||||
|
||||
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
|
||||
@[expose, grind]
|
||||
def RightInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
LeftInverse f g
|
||||
|
||||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||||
@[expose]
|
||||
def HasRightInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => RightInverse finv f
|
||||
|
||||
theorem LeftInverse.injective {α β} {g : β → α} {f : α → β} : LeftInverse g f → Injective f :=
|
||||
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
|
||||
|
||||
theorem HasLeftInverse.injective {α β} {f : α → β} : HasLeftInverse f → Injective f := fun h =>
|
||||
Exists.elim h fun _finv inv => inv.injective
|
||||
|
||||
theorem rightInverse_of_injective_of_leftInverse {α β} {f : α → β} {g : β → α} (injf : Injective f)
|
||||
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
|
||||
have h : f (g (f x)) = f x := lfg (f x)
|
||||
injf h
|
||||
|
||||
theorem RightInverse.surjective {α β} {f : α → β} {g : β → α} (h : RightInverse g f) : Surjective f :=
|
||||
fun y => ⟨g y, h y⟩
|
||||
|
||||
theorem HasRightInverse.surjective {α β} {f : α → β} : HasRightInverse f → Surjective f
|
||||
| ⟨_finv, inv⟩ => inv.surjective
|
||||
|
||||
theorem leftInverse_of_surjective_of_rightInverse {α β} {f : α → β} {g : β → α} (surjf : Surjective f)
|
||||
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
|
||||
Exists.elim (surjf y) fun x hx => ((hx ▸ rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) ▸ rfl)).trans hx
|
||||
|
||||
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
|
||||
|
||||
theorem surjective_id : Surjective (@id α) := fun a => ⟨a, rfl⟩
|
||||
|
||||
variable {f : α → β}
|
||||
|
||||
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b ↔ a = b :=
|
||||
⟨@I _ _, congrArg f⟩
|
||||
|
||||
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c ↔ a = b :=
|
||||
h ▸ I.eq_iff
|
||||
|
||||
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ ≠ a₂ → f a₁ ≠ f a₂ :=
|
||||
mt fun h ↦ hf h
|
||||
|
||||
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x ≠ f y ↔ x ≠ y :=
|
||||
⟨mt <| congrArg f, hf.ne⟩
|
||||
|
||||
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x ≠ z ↔ x ≠ y :=
|
||||
h ▸ hf.ne_iff
|
||||
|
||||
protected theorem LeftInverse.id {α β} {g : β → α} {f : α → β} (h : LeftInverse g f) : g ∘ f = id :=
|
||||
funext h
|
||||
|
||||
protected theorem RightInverse.id {α β} {g : β → α} {f : α → β} (h : RightInverse g f) : f ∘ g = id :=
|
||||
funext h
|
||||
|
||||
end Function
|
||||
|
||||
@@ -206,9 +206,6 @@ theorem ediv_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : 0 ≤ a / b ↔ 0 ≤ a
|
||||
| Int.ofNat (b+1), _ =>
|
||||
rcases a with ⟨a⟩ <;> simp [Int.ediv, -natCast_ediv]
|
||||
|
||||
@[deprecated ediv_nonneg_iff_of_pos (since := "2025-02-28")]
|
||||
abbrev div_nonneg_iff_of_pos := @ediv_nonneg_iff_of_pos
|
||||
|
||||
/-! ### emod -/
|
||||
|
||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||
|
||||
@@ -17,6 +17,7 @@ import all Init.Data.Int.Gcd
|
||||
public import Init.Data.RArray
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -54,7 +55,7 @@ def Expr.denote (ctx : Context) : Expr → Int
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving @[expose] BEq
|
||||
deriving @[expose] BEq, ReflBEq, LawfulBEq
|
||||
|
||||
@[expose]
|
||||
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
@@ -525,18 +526,6 @@ theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.deno
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go]
|
||||
|
||||
attribute [local simp] Expr.denote_norm
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next ih =>
|
||||
intro _ _ h
|
||||
exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
|
||||
attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm.beq' p) : e.denote ctx = p.denote' ctx := by
|
||||
|
||||
@@ -1347,8 +1347,6 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
|
||||
| 0 => Int.mul_zero _
|
||||
| -[_+1] => Int.mul_neg_one _
|
||||
|
||||
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
|
||||
|
||||
@[simp] theorem sign_mul_self (i : Int) : sign i * i = natAbs i := by
|
||||
rw [Int.mul_comm, mul_sign_self]
|
||||
|
||||
|
||||
@@ -50,14 +50,9 @@ protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := b
|
||||
|
||||
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := ⟨Int.pow_ne_zero (NeZero.ne _)⟩
|
||||
|
||||
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
|
||||
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
-- This can't be removed until the next update-stage0
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp, norm_cast]
|
||||
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
|
||||
|
||||
@@ -19,6 +19,7 @@ universe v u v' u'
|
||||
section ULiftT
|
||||
|
||||
/-- `ULiftT.{v, u}` shrinks a monad on `Type max u v` to a monad on `Type u`. -/
|
||||
@[expose] -- for codegen
|
||||
def ULiftT (n : Type max u v → Type v') (α : Type u) := n (ULift.{v} α)
|
||||
|
||||
/-- Returns the underlying `n`-monadic representation of a `ULiftT n α` value. -/
|
||||
|
||||
@@ -139,7 +139,7 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.size]
|
||||
@[always_inline, inline, expose, inherit_doc IterM.size]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSize.size it.toIterM).run.down
|
||||
|
||||
@@ -57,6 +57,6 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
|
||||
rw [← toArray_toList, ← toArray_toList, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith]
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -53,6 +53,6 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
it.uLift.toArray = it.toArray.map ULift.up := by
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp
|
||||
simp [-toArray_toList]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -44,11 +44,13 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
it.toIter.toListRev = it.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray.toList = it.toList := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.toArray = it.toArray := by
|
||||
|
||||
@@ -14,6 +14,7 @@ public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -43,6 +44,20 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
f out acc) := by
|
||||
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
|
||||
|
||||
@[congr] theorem Iter.forIn'_congr {α β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
{ita itb : Iter (α := α) β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' Id (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -188,6 +203,13 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
obtain ⟨step, h₁, rfl⟩ := h₁
|
||||
simp [heq, IterStep.successor] at h₁
|
||||
|
||||
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toArray ↔ it.IsPlausibleIndirectOutput out := by
|
||||
rw [← Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
|
||||
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -222,6 +244,17 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [ihs h (f := fun out h acc => f out (this ▸ h) acc)]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
simp only [← Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -234,6 +267,18 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [forIn'_toList]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toArray]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -260,6 +305,15 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
|
||||
simp only [← Iter.toArray_toList, List.forIn_toArray, forIn_toList]
|
||||
|
||||
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
@@ -301,6 +355,14 @@ theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [F
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toArray]
|
||||
simp only [Array.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -324,6 +386,12 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
|
||||
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
@@ -344,6 +412,38 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f (it.fold g₁ init) := by
|
||||
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
|
||||
-- w.r.t. the universe of the output.
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
|
||||
|
||||
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom (List.toArray)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
@@ -352,6 +452,14 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
|
||||
it.toList.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
|
||||
@@ -67,15 +67,17 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.toArray = it.toList := by
|
||||
simp [IterM.toList]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.toList = it.toArray := by
|
||||
simp [IterM.toList]
|
||||
simp [IterM.toList, -toList_toArray]
|
||||
|
||||
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
@@ -153,6 +155,6 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq]
|
||||
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -60,6 +60,20 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
simp only [ForIn.forIn, forIn'_eq]
|
||||
|
||||
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m m]
|
||||
{ita itb : IterM (α := α) m β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' m (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
@@ -200,6 +214,23 @@ theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [I
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem IterM.fold_hom {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f <$> (it.fold g₁ init) := by
|
||||
induction it using IterM.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
rw [bind_pure_comp]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
@@ -223,6 +254,15 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
|
||||
simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom]
|
||||
simp
|
||||
|
||||
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=
|
||||
|
||||
@@ -149,9 +149,6 @@ theorem attach_map_val {l : List α} {f : α → β} :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
rw [attach, attachWith, map_pmap]; exact pmap_eq_map _
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
-- The argument `l : List α` is explicit to allow rewriting from right to left.
|
||||
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
|
||||
attach_map_val.trans (List.map_id _)
|
||||
@@ -160,21 +157,18 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {l : List α} (H :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
rw [attachWith, map_pmap]; exact pmap_eq_map _
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} {l : List α} (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_val _).trans (List.map_id _)
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {l : List α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
induction l with
|
||||
@@ -192,12 +186,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f l H, a ∈ l
|
||||
|
||||
@[simp, grind =]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
@@ -253,13 +248,6 @@ theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} (h
|
||||
· simp
|
||||
· simp only [pmap, getElem?_cons_succ, hl]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated List.getElem?_pmap (since := "2025-02-12")]
|
||||
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
|
||||
simp only [get?_eq_getElem?]
|
||||
simp [getElem?_pmap]
|
||||
|
||||
-- The argument `f` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind =]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {i : Nat}
|
||||
@@ -276,15 +264,6 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
|
||||
· simp
|
||||
· simp [hl]
|
||||
|
||||
@[deprecated getElem_pmap (since := "2025-02-13")]
|
||||
theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||
(hn : n < (pmap f l h).length) :
|
||||
get (pmap f l h) ⟨n, hn⟩ =
|
||||
f (get l ⟨n, @length_pmap _ _ p f l h ▸ hn⟩)
|
||||
(h _ (getElem_mem (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
@@ -370,13 +349,13 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach.tail = xs.tail.attach.map (fun ⟨x, h⟩ => ⟨x, mem_of_mem_tail h⟩) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem foldl_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem foldr_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
@@ -465,9 +444,6 @@ theorem map_attach_eq_pmap {l : List α} {f : { x // x ∈ l } → β} :
|
||||
apply pmap_congr_left
|
||||
simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
|
||||
@@ -80,17 +80,17 @@ namespace List
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
@[simp, grind] theorem length_nil : length ([] : List α) = 0 :=
|
||||
@[simp, grind =] theorem length_nil : length ([] : List α) = 0 :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_singleton {a : α} : length [a] = 1 := rfl
|
||||
|
||||
@[simp, grind] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
@[simp, grind =] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
rfl
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[simp, grind] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
@[simp, grind =] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
induction as generalizing i with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
@@ -101,8 +101,8 @@ namespace List
|
||||
/-! ### foldl -/
|
||||
|
||||
-- As `List.foldl` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@[simp, grind] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
@[simp, grind =] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind =] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
|
||||
/-! ### concat -/
|
||||
|
||||
@@ -289,16 +289,6 @@ theorem cons_lex_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false :
|
||||
@[simp] theorem lex_nil [BEq α] {as : List α} : lex as [] lt = false := by
|
||||
cases as <;> simp [nil_lex_nil, cons_lex_nil]
|
||||
|
||||
@[deprecated nil_lex_nil (since := "2025-02-10")]
|
||||
theorem lex_nil_nil [BEq α] : lex ([] : List α) [] lt = false := rfl
|
||||
@[deprecated nil_lex_cons (since := "2025-02-10")]
|
||||
theorem lex_nil_cons [BEq α] {b} {bs : List α} : lex [] (b :: bs) lt = true := rfl
|
||||
@[deprecated cons_lex_nil (since := "2025-02-10")]
|
||||
theorem lex_cons_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false := rfl
|
||||
@[deprecated cons_lex_cons (since := "2025-02-10")]
|
||||
theorem lex_cons_cons [BEq α] {a b} {as bs : List α} :
|
||||
lex (a :: as) (b :: bs) lt = (lt a b || (a == b && lex as bs lt)) := rfl
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
/-! ### getLast -/
|
||||
@@ -332,7 +322,7 @@ def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
|
||||
@[simp, grind] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
|
||||
/-! ### getLastD -/
|
||||
|
||||
@@ -365,7 +355,7 @@ Returns the first element of a non-empty list.
|
||||
def head : (as : List α) → as ≠ [] → α
|
||||
| a::_, _ => a
|
||||
|
||||
@[simp, grind] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
@[simp, grind =] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
|
||||
/-! ### head? -/
|
||||
|
||||
@@ -383,8 +373,8 @@ def head? : List α → Option α
|
||||
| [] => none
|
||||
| a::_ => some a
|
||||
|
||||
@[simp, grind] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
@[simp, grind =] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
|
||||
/-! ### headD -/
|
||||
|
||||
@@ -420,8 +410,8 @@ def tail : List α → List α
|
||||
| [] => []
|
||||
| _::as => as
|
||||
|
||||
@[simp, grind] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
@[simp, grind =] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind =] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
|
||||
/-! ### tail? -/
|
||||
|
||||
@@ -441,8 +431,8 @@ def tail? : List α → Option (List α)
|
||||
| [] => none
|
||||
| _::as => some as
|
||||
|
||||
@[simp, grind] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
@[simp, grind =] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
|
||||
/-! ### tailD -/
|
||||
|
||||
@@ -475,23 +465,8 @@ We define the basic functional programming operations on `List`:
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
/--
|
||||
Applies a function to each element of the list, returning the resulting list of values.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].map f = [f a, f b, f c]`
|
||||
* `[].map Nat.succ = []`
|
||||
* `["one", "two", "three"].map (·.length) = [3, 3, 5]`
|
||||
* `["one", "two", "three"].map (·.reverse) = ["eno", "owt", "eerht"]`
|
||||
-/
|
||||
@[specialize] def map (f : α → β) : (l : List α) → List β
|
||||
| [] => []
|
||||
| a::as => f a :: map f as
|
||||
|
||||
@[simp, grind] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
@[simp, grind =] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind =] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@@ -511,7 +486,7 @@ def filter (p : α → Bool) : (l : List α) → List α
|
||||
| true => a :: filter p as
|
||||
| false => filter p as
|
||||
|
||||
@[simp, grind] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
@[simp, grind =] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@@ -537,8 +512,8 @@ Example:
|
||||
| none => filterMap f as
|
||||
| some b => b :: filterMap f as
|
||||
|
||||
@[simp, grind] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
@[simp, grind =] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind =] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
filterMap f (a :: l) =
|
||||
match f a with
|
||||
| none => filterMap f l
|
||||
@@ -561,8 +536,8 @@ Examples:
|
||||
| [] => init
|
||||
| a :: l => f a (foldr f init l)
|
||||
|
||||
@[simp, grind] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
@[simp, grind =] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind =] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
(a :: l).foldr f b = f a (l.foldr f b) := rfl
|
||||
|
||||
/-! ### reverse -/
|
||||
@@ -591,7 +566,7 @@ Examples:
|
||||
@[expose] def reverse (as : List α) : List α :=
|
||||
reverseAux as []
|
||||
|
||||
@[simp, grind] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
@[simp, grind =] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
|
||||
theorem reverseAux_reverseAux {as bs cs : List α} :
|
||||
reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
|
||||
@@ -606,20 +581,6 @@ Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
|
||||
* `[] ++ [4, 5] = [4, 5]`.
|
||||
* `[1, 2, 3] ++ [] = [1, 2, 3]`.
|
||||
-/
|
||||
protected def append : (xs ys : List α) → List α
|
||||
| [], bs => bs
|
||||
| a::as, bs => a :: List.append as bs
|
||||
|
||||
/--
|
||||
Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
This is a tail-recursive version of `List.append`.
|
||||
|
||||
Examples:
|
||||
@@ -645,10 +606,10 @@ instance : Append (List α) := ⟨List.append⟩
|
||||
|
||||
@[simp] theorem append_eq {as bs : List α} : List.append as bs = as ++ bs := rfl
|
||||
|
||||
@[simp, grind] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind =] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind _=_] theorem cons_append {a : α} {as bs : List α} : (a::as) ++ bs = a::(as ++ bs) := rfl
|
||||
|
||||
@[simp, grind] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
@[simp, grind =] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
@@ -658,7 +619,7 @@ instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
|
||||
left_id := nil_append
|
||||
right_id := append_nil
|
||||
|
||||
@[simp, grind] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
@[simp, grind =] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons _ as ih => simp [ih, Nat.succ_add]
|
||||
@@ -685,27 +646,15 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
|
||||
rw [ih (bs := a :: bs), ih (bs := [a]), append_assoc]
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
@[simp, grind =] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
simp [reverse, reverseAux]
|
||||
rw [← reverseAux_eq_append]
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
/--
|
||||
Concatenates a list of lists into a single list, preserving the order of the elements.
|
||||
|
||||
`O(|flatten L|)`.
|
||||
|
||||
Examples:
|
||||
* `[["a"], ["b", "c"]].flatten = ["a", "b", "c"]`
|
||||
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flatten = ["a", "b", "c", "d", "e", "f"]`
|
||||
-/
|
||||
def flatten : List (List α) → List α
|
||||
| [] => []
|
||||
| l :: L => l ++ flatten L
|
||||
|
||||
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
@[simp, grind =] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind =] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
|
||||
/-! ### singleton -/
|
||||
|
||||
@@ -721,20 +670,14 @@ Examples:
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
/--
|
||||
Applies a function that returns a list to each element of a list, and concatenates the resulting
|
||||
lists.
|
||||
|
||||
Examples:
|
||||
* `[2, 3, 2].flatMap List.range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
* `["red", "blue"].flatMap String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
@[simp, grind] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind =] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
|
||||
@[simp, grind _=_] theorem flatMap_append {xs ys : List α} {f : α → List β} :
|
||||
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
|
||||
induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
/--
|
||||
@@ -748,10 +691,10 @@ def replicate : (n : Nat) → (a : α) → List α
|
||||
| 0, _ => []
|
||||
| n+1, a => a :: replicate n a
|
||||
|
||||
@[simp, grind] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
@[simp, grind =] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind =] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
|
||||
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
@[simp, grind =] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp only [ih, replicate_succ, length_cons]
|
||||
@@ -819,8 +762,8 @@ def isEmpty : List α → Bool
|
||||
| [] => true
|
||||
| _ :: _ => false
|
||||
|
||||
@[simp, grind] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
@[simp, grind =] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind =] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
|
||||
/-! ### elem -/
|
||||
|
||||
@@ -842,7 +785,7 @@ def elem [BEq α] (a : α) : (l : List α) → Bool
|
||||
| true => true
|
||||
| false => elem a bs
|
||||
|
||||
@[simp, grind] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
@[simp, grind =] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
@@ -958,9 +901,9 @@ def take : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, a::as => a :: take n as
|
||||
|
||||
@[simp, grind] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
@[simp, grind =] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind =] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind =] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
|
||||
/-! ### drop -/
|
||||
|
||||
@@ -980,10 +923,10 @@ def drop : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, _::as => drop n as
|
||||
|
||||
@[simp, grind] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
@[simp, grind =] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
cases i <;> rfl
|
||||
@[simp, grind] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
@[simp, grind =] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind =] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
|
||||
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length ≤ i) : as.drop i = [] := by
|
||||
match as, i with
|
||||
@@ -1094,13 +1037,13 @@ def dropLast {α} : List α → List α
|
||||
| [_] => []
|
||||
| a::as => a :: dropLast as
|
||||
|
||||
@[simp, grind] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
|
||||
@[deprecated dropLast_singleton (since := "2025-04-16")]
|
||||
theorem dropLast_single : [x].dropLast = [] := dropLast_singleton
|
||||
|
||||
@[simp, grind] theorem dropLast_cons₂ :
|
||||
@[simp, grind =] theorem dropLast_cons₂ :
|
||||
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
|
||||
|
||||
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
|
||||
@@ -1439,8 +1382,8 @@ def replace [BEq α] : (l : List α) → (a : α) → (b : α) → List α
|
||||
| true => c::as
|
||||
| false => a :: replace as b c
|
||||
|
||||
@[simp, grind] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind] theorem replace_cons [BEq α] {a : α} :
|
||||
@[simp, grind =] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind =] theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
@@ -1648,8 +1591,8 @@ def findSome? (f : α → Option β) : List α → Option β
|
||||
| some b => some b
|
||||
| none => findSome? f as
|
||||
|
||||
@[simp, grind] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind] theorem findSome?_cons {f : α → Option β} :
|
||||
@[simp, grind =] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind =] theorem findSome?_cons {f : α → Option β} :
|
||||
(a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f :=
|
||||
rfl
|
||||
|
||||
@@ -1906,8 +1849,8 @@ def any : (l : List α) → (p : α → Bool) → Bool
|
||||
| [], _ => false
|
||||
| h :: t, p => p h || any t p
|
||||
|
||||
@[simp, grind] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
@[simp, grind =] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind =] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
|
||||
/-! ### all -/
|
||||
|
||||
@@ -1925,8 +1868,8 @@ def all : List α → (α → Bool) → Bool
|
||||
| [], _ => true
|
||||
| h :: t, p => p h && all t p
|
||||
|
||||
@[simp, grind] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
@[simp, grind =] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind =] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
|
||||
/-! ### or -/
|
||||
|
||||
@@ -2066,8 +2009,8 @@ Examples:
|
||||
def sum {α} [Add α] [Zero α] : List α → α :=
|
||||
foldr (· + ·) 0
|
||||
|
||||
@[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
|
||||
@[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
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
|
||||
@@ -21,65 +21,6 @@ namespace List
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
/-! ### get? -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
|
||||
Also see `get`, `getD` and `get!`.
|
||||
-/
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
|
||||
def get? : (as : List α) → (i : Nat) → Option α
|
||||
| a::_, 0 => some a
|
||||
| _::as, n+1 => get? as n
|
||||
| _, _ => none
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_nil : @get? α [] n = none := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_cons_zero : @get? α (a::l) 0 = some a := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_cons_succ : @get? α (a::l) (n+1) = get? l n := rfl
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `List.ext_getElem?`." (since := "2025-02-12")]
|
||||
theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n) → l₁ = l₂
|
||||
| [], [], _ => rfl
|
||||
| _ :: _, [], h => nomatch h 0
|
||||
| [], _ :: _, h => nomatch h 0
|
||||
| a :: l₁, a' :: l₂, h => by
|
||||
have h0 : some a = some a' := h 0
|
||||
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
|
||||
|
||||
/-! ### get! -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function panics when executed, and returns
|
||||
`default`. See `get?` and `getD` for safer alternatives.
|
||||
-/
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12"), expose]
|
||||
def get! [Inhabited α] : (as : List α) → (i : Nat) → α
|
||||
| a::_, 0 => a
|
||||
| _::as, n+1 => get! as n
|
||||
| _, _ => panic! "invalid index"
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_nil [Inhabited α] (n : Nat) : [].get! n = (default : α) := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_cons_succ [Inhabited α] (l : List α) (a : α) (n : Nat) :
|
||||
(a::l).get! (n+1) = get! l n := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
/--
|
||||
@@ -281,17 +222,6 @@ theorem getElem_append_right {as bs : List α} {i : Nat} (h₁ : as.length ≤ i
|
||||
cases i with simp [Nat.succ_sub_succ] <;> simp at h₁
|
||||
| succ i => apply ih; simp [h₁]
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2025-02-13")]
|
||||
theorem get_last {as : List α} {i : Fin (length (as ++ [a]))} (h : ¬ i.1 < as.length) : (as ++ [a] : List _).get i = a := by
|
||||
cases i; rename_i i h'
|
||||
induction as generalizing i with
|
||||
| nil => cases i with
|
||||
| zero => simp [List.get]
|
||||
| succ => simp +arith at h'
|
||||
| cons a as ih =>
|
||||
cases i with simp at h
|
||||
| succ i => apply ih; simp [h]
|
||||
|
||||
theorem sizeOf_lt_of_mem [SizeOf α] {as : List α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
||||
induction h with
|
||||
| head => simp +arith
|
||||
|
||||
@@ -223,7 +223,7 @@ variable [BEq α]
|
||||
|
||||
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_cons {a b : α} {l : List α} :
|
||||
count a (b :: l) = count a l + if b == a then 1 else 0 := by
|
||||
simp [count, countP_cons]
|
||||
@@ -237,7 +237,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
|
||||
simp [count, countP_eq_length_filter]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_tail : ∀ {l : List α} {a : α},
|
||||
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
|
||||
| [], a => by simp
|
||||
@@ -380,7 +380,7 @@ theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List
|
||||
theorem count_flatMap {α} [BEq β] {l : List α} {f : α → List β} {x : β} :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem count_erase {a b : α} :
|
||||
∀ {l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||
| [] => by simp
|
||||
|
||||
@@ -130,7 +130,7 @@ theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length :=
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset ·)
|
||||
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
refine ⟨mem_of_mem_eraseP, fun al => ?_⟩
|
||||
match exists_or_eq_self_of_eraseP p l with
|
||||
| .inl h => rw [h]; assumption
|
||||
@@ -265,14 +265,18 @@ theorem eraseP_eq_iff {p} {l : List α} :
|
||||
subst p
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) :=
|
||||
Pairwise.sublist <| eraseP_sublist
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
|
||||
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
|
||||
|
||||
theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) :=
|
||||
Pairwise.eraseP p
|
||||
|
||||
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
|
||||
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
|
||||
@@ -393,7 +397,7 @@ theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤
|
||||
@[grind →]
|
||||
theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset h
|
||||
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
a ∈ l.erase b ↔ a ∈ l :=
|
||||
erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -508,10 +512,12 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
|
||||
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
|
||||
grind_pattern List.Nodup.not_mem_erase => a ∈ l.erase a, l.Nodup
|
||||
|
||||
@[grind]
|
||||
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l → Nodup (l.erase a) :=
|
||||
Pairwise.erase a
|
||||
|
||||
grind_pattern Nodup.erase => Nodup (l.erase a)
|
||||
grind_pattern Nodup.erase => Nodup l, l.erase a
|
||||
|
||||
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs :=
|
||||
erase_sublist.head_mem h
|
||||
|
||||
@@ -578,21 +584,21 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
| [a]
|
||||
| a::b::l => simp
|
||||
|
||||
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
| [], _ => by simp
|
||||
| a::l, 0 => by simp
|
||||
| a::l, k + 1 => by simp [eraseIdx_sublist]
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ <+ l
|
||||
|
||||
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a ∈ l.eraseIdx i) : a ∈ l :=
|
||||
(eraseIdx_sublist _ _).mem h
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k ⊆ l :=
|
||||
(eraseIdx_sublist _ _).subset
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ ⊆ l
|
||||
|
||||
@[simp]
|
||||
theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k
|
||||
| [], _ => by simp
|
||||
@@ -649,15 +655,18 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
exact m.2
|
||||
· rw [eraseIdx_of_length_le (by simpa using h)]
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) :=
|
||||
Pairwise.sublist <| eraseIdx_sublist _ _
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
|
||||
|
||||
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) :=
|
||||
Pairwise.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
|
||||
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
|
||||
|
||||
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
eraseIdx l k <+: eraseIdx l' k := by
|
||||
rcases h with ⟨t, rfl⟩
|
||||
@@ -667,6 +676,10 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
rw [Nat.not_lt] at hkl
|
||||
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
|
||||
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
|
||||
|
||||
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
|
||||
-- `Init/Data/List/Nat/Basic.lean`.
|
||||
|
||||
@@ -686,6 +699,4 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -293,7 +293,6 @@ theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
|
||||
· exact H ▸ .head _
|
||||
· exact .tail _ (mem_of_find?_eq_some H)
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h ∈ xs := by
|
||||
induction xs with
|
||||
| nil => simp at h
|
||||
@@ -305,6 +304,8 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
right
|
||||
apply ih
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : List α} {p : α → Bool} {q : α → Bool} :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
induction xs with
|
||||
@@ -359,9 +360,6 @@ theorem find?_flatten_eq_none_iff {xs : List (List α)} {p : α → Bool} :
|
||||
xs.flatten.find? p = none ↔ ∀ ys ∈ xs, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some list in `xs` contains `a`, and no earlier element of that list satisfies `p`.
|
||||
@@ -402,9 +400,6 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
|
||||
· exact h₁ l ml a m
|
||||
· exact h₂ a m
|
||||
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem find?_flatMap {xs : List α} {f : α → List β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
simp [flatMap_def, findSome?_map]; rfl
|
||||
@@ -433,16 +428,10 @@ theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_replicate_eq_none := @find?_replicate_eq_none_iff
|
||||
|
||||
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_replicate_eq_some := @find?_replicate_eq_some_iff
|
||||
|
||||
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α → Bool} (h) : ((replicate n a).find? p).get h = a := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
@@ -558,7 +547,6 @@ where
|
||||
@[simp] theorem findIdx_singleton {a : α} {p : α → Bool} : [a].findIdx p = if p a then 0 else 1 := by
|
||||
simp [findIdx_cons, findIdx_nil]
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
@@ -836,9 +824,6 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
simp_all only [findIdx?_cons]
|
||||
split at w <;> cases i <;> simp_all
|
||||
|
||||
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
|
||||
|
||||
theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p = none) :
|
||||
∀ i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
|
||||
intro i
|
||||
@@ -854,9 +839,6 @@ theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
apply ih
|
||||
split at w <;> simp_all
|
||||
|
||||
@[deprecated of_findIdx?_eq_none (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
|
||||
|
||||
@[simp, grind _=_] theorem findIdx?_map {f : β → α} {l : List β} : findIdx? p (l.map f) = l.findIdx? (p ∘ f) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -105,9 +105,6 @@ theorem length_leftpad {n : Nat} {a : α} {l : List α} :
|
||||
(leftpad n a l).length = max n l.length := by
|
||||
simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max]
|
||||
|
||||
@[deprecated length_leftpad (since := "2025-02-24")]
|
||||
abbrev leftpad_length := @length_leftpad
|
||||
|
||||
theorem length_rightpad {n : Nat} {a : α} {l : List α} :
|
||||
(rightpad n a l).length = max n l.length := by
|
||||
simp [rightpad]
|
||||
|
||||
@@ -196,9 +196,6 @@ theorem getElem_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (hn : i < j)
|
||||
| zero => omega
|
||||
| succ j => simp
|
||||
|
||||
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
|
||||
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (l.insertIdx i x).length) :
|
||||
(l.insertIdx i x)[j] =
|
||||
@@ -261,9 +258,6 @@ theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (h : i < j)
|
||||
(l.insertIdx i x)[j]? = l[j - 1]? := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
|
||||
|
||||
@[deprecated getElem?_insertIdx_of_gt (since := "2025-02-04")]
|
||||
abbrev getElem?_insertIdx_of_ge := @getElem?_insertIdx_of_gt
|
||||
|
||||
end InsertIdx
|
||||
|
||||
end List
|
||||
|
||||
@@ -248,11 +248,10 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem nodup_range {n : Nat} : Nodup (range n) := by
|
||||
simp +decide only [range_eq_range', nodup_range']
|
||||
|
||||
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[grind]
|
||||
theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp
|
||||
|
||||
@@ -117,9 +117,6 @@ theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
|
||||
next h' => rw [getElem?_set_ne (by omega)]
|
||||
· rfl
|
||||
|
||||
@[deprecated take_set_of_le (since := "2025-02-04")]
|
||||
abbrev take_set_of_lt := @take_set_of_le
|
||||
|
||||
@[simp, grind =] theorem take_replicate {a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
|
||||
| n, 0 => by simp
|
||||
| 0, m => by simp
|
||||
@@ -165,9 +162,6 @@ theorem take_eq_take_iff :
|
||||
| x :: xs, 0, j + 1 => by simp [succ_min_succ]
|
||||
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take_iff]
|
||||
|
||||
@[deprecated take_eq_take_iff (since := "2025-02-16")]
|
||||
abbrev take_eq_take := @take_eq_take_iff
|
||||
|
||||
@[grind =]
|
||||
theorem take_add {l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j := by
|
||||
suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
|
||||
@@ -567,9 +561,10 @@ theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
|
||||
f (l[i]'(lt_length_left_of_zipWith h))
|
||||
(l'[i]'(lt_length_right_of_zipWith h)) := by
|
||||
rw [← Option.some_inj, ← getElem?_eq_getElem, getElem?_zipWith_eq_some]
|
||||
have := lt_length_right_of_zipWith h
|
||||
exact
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact ⟨rfl, rfl⟩⟩
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i],
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem this]; exact ⟨rfl, rfl⟩⟩
|
||||
|
||||
theorem zipWith_eq_zipWith_take_min : ∀ {l₁ : List α} {l₂ : List β},
|
||||
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||||
|
||||
@@ -43,7 +43,7 @@ theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l →
|
||||
(pairwise_cons.1 p).2
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
@[grind] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
@[grind ←] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
| [], h => h
|
||||
| _ :: _, h => h.of_cons
|
||||
|
||||
@@ -103,7 +103,7 @@ theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pa
|
||||
· exact h₃.1 _ hx
|
||||
· exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy
|
||||
|
||||
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
@[grind ←] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
|
||||
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp
|
||||
|
||||
@@ -117,7 +117,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
(p : Pairwise S (map f l)) : Pairwise R l :=
|
||||
(pairwise_map.1 p).imp (H _ _)
|
||||
|
||||
@[grind] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
@[grind <=] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
(p : Pairwise R l) : Pairwise S (map f l) :=
|
||||
pairwise_map.2 <| p.imp (H _ _)
|
||||
|
||||
@@ -136,7 +136,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
simpa [IH, e] using fun _ =>
|
||||
⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩
|
||||
|
||||
@[grind] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
@[grind <=] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
(H : ∀ a a' : α, R a a' → ∀ b, f a = some b → ∀ b', f a' = some b' → S b b') {l : List α} (p : Pairwise R l) :
|
||||
Pairwise S (filterMap f l) :=
|
||||
pairwise_filterMap.2 <| p.imp (H _ _)
|
||||
@@ -146,7 +146,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
rw [← filterMap_eq_filter, pairwise_filterMap]
|
||||
simp
|
||||
|
||||
@[grind] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
@[grind ←] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
Pairwise.sublist filter_sublist
|
||||
|
||||
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
|
||||
@@ -171,7 +171,7 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
induction L with
|
||||
| nil => simp
|
||||
| cons l L IH =>
|
||||
simp only [flatten, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
simp only [flatten_cons, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
pairwise_cons, and_assoc, and_congr_right_iff]
|
||||
rw [and_comm, and_congr_left_iff]
|
||||
intros; exact ⟨fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e⟩
|
||||
@@ -207,10 +207,10 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
simp
|
||||
· exact ⟨fun _ => h, Or.inr h⟩
|
||||
|
||||
@[grind] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
@[grind ←] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
h.sublist (drop_sublist _ _)
|
||||
|
||||
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
@[grind ←] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
h.sublist (take_sublist _ _)
|
||||
|
||||
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
|
||||
@@ -266,7 +266,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
rintro H _ b hb rfl
|
||||
exact H b hb _ _
|
||||
|
||||
@[grind] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
@[grind <=] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
(h : ∀ x ∈ l, p x) {S : β → β → Prop}
|
||||
(hS : ∀ ⦃x⦄ (hx : p x) ⦃y⦄ (hy : p y), R x y → S (f x hx) (f y hy)) :
|
||||
Pairwise S (l.pmap f h) := by
|
||||
@@ -277,10 +277,12 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
|
||||
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l ↔ List.Pairwise (· ≠ ·) l := Iff.rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem nodup_nil : @Nodup α [] :=
|
||||
Pairwise.nil
|
||||
|
||||
grind_pattern nodup_nil => @Nodup α []
|
||||
|
||||
@[simp, grind =]
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
@@ -151,11 +151,11 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
|
||||
|
||||
/-! ### Sublist and isSublist -/
|
||||
|
||||
@[simp, grind] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
@[simp, grind ←] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (nil_sublist l).cons a
|
||||
|
||||
@[simp, grind] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
@[simp, grind ←] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (Sublist.refl l).cons₂ a
|
||||
|
||||
@@ -172,7 +172,7 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
|
||||
|
||||
instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩
|
||||
|
||||
attribute [simp, grind] Sublist.cons
|
||||
attribute [simp, grind ←] Sublist.cons
|
||||
|
||||
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
|
||||
|
||||
@@ -202,12 +202,18 @@ theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l
|
||||
protected theorem Sublist.mem (hx : a ∈ l₁) (hl : l₁ <+ l₂) : a ∈ l₂ :=
|
||||
hl.subset hx
|
||||
|
||||
@[grind] theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
s.mem (List.head_mem h)
|
||||
|
||||
@[grind] theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
grind_pattern Sublist.head_mem => ys <+ xs, ys.head h
|
||||
grind_pattern Sublist.head_mem => ys.head h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
s.mem (List.getLast_mem h)
|
||||
|
||||
grind_pattern Sublist.getLast_mem => ys <+ xs, ys.getLast h
|
||||
grind_pattern Sublist.getLast_mem => ys.getLast h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
instance : Trans (@Sublist α) Subset Subset :=
|
||||
⟨fun h₁ h₂ => trans h₁.subset h₂⟩
|
||||
|
||||
@@ -248,12 +254,13 @@ theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l
|
||||
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ ↔ l₁ = l₂ :=
|
||||
⟨s.eq_of_length, congrArg _⟩
|
||||
|
||||
@[grind]
|
||||
theorem tail_sublist : ∀ l : List α, tail l <+ l
|
||||
| [] => .slnil
|
||||
| a::l => sublist_cons_self a l
|
||||
|
||||
@[grind]
|
||||
grind_pattern tail_sublist => tail l <+ _
|
||||
|
||||
@[grind ←]
|
||||
protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂
|
||||
| _, _, slnil => .slnil
|
||||
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
|
||||
@@ -263,7 +270,7 @@ protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tai
|
||||
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
|
||||
h.tail
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
|
||||
induction s with
|
||||
| slnil => simp
|
||||
@@ -275,7 +282,7 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
filterMap f l₁ <+ filterMap f l₂ := by
|
||||
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons]
|
||||
@@ -283,7 +290,7 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₁
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₂
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
|
||||
rw [← filterMap_eq_filter]; apply s.filterMap
|
||||
|
||||
@@ -481,7 +488,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
|
||||
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
|
||||
simp_all
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
|
||||
rw [sublist_append_iff] at h
|
||||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||||
@@ -624,22 +631,28 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
|
||||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||||
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀ i, l₁.drop i <+ l₂.drop i
|
||||
| _, _, h, 0 => h
|
||||
| _, _, h, i + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop i
|
||||
|
||||
/-! ### IsPrefix / IsSuffix / IsInfix -/
|
||||
|
||||
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
|
||||
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
grind_pattern prefix_append => l₁ <+: l₁ ++ l₂
|
||||
|
||||
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
|
||||
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
|
||||
|
||||
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩
|
||||
|
||||
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
rw [← List.append_assoc]; apply infix_append
|
||||
|
||||
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
|
||||
|
||||
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := ⟨[], l₂, rfl⟩
|
||||
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := ⟨l₁, [], by simp⟩
|
||||
|
||||
@@ -651,22 +664,24 @@ theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ =>
|
||||
|
||||
grind_pattern IsSuffix.isInfix => l₁ <:+ l₂, IsInfix
|
||||
|
||||
@[simp, grind] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
@[simp, grind ←] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
|
||||
@[simp, grind] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
@[simp, grind ←] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
|
||||
@[simp, grind] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
@[simp, grind ←] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
|
||||
theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩
|
||||
@[simp, grind] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
@[simp, grind ←] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
|
||||
theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
@[simp, grind] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
@[simp, grind ←] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
|
||||
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
|
||||
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
@[simp, grind ←] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
|
||||
@[simp, grind] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
|
||||
grind_pattern suffix_cons => _ <:+ a :: l
|
||||
|
||||
theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨l₁', l₂', h⟩ => ⟨a :: l₁', l₂', h ▸ rfl⟩
|
||||
|
||||
@@ -1108,24 +1123,36 @@ theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flat
|
||||
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ :=
|
||||
prefix_append_right_inj [a]
|
||||
|
||||
@[grind] theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
@[grind] theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
grind_pattern take_prefix => take i l <+: _
|
||||
|
||||
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
@[grind] theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
grind_pattern drop_suffix => drop i l <+: _
|
||||
|
||||
theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
(take_prefix i l).sublist
|
||||
|
||||
@[grind] theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
grind_pattern take_sublist => take i l <+ l
|
||||
|
||||
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
(drop_suffix i l).sublist
|
||||
|
||||
grind_pattern drop_sublist => drop i l <+ l
|
||||
|
||||
theorem take_subset (i) (l : List α) : take i l ⊆ l :=
|
||||
(take_sublist i l).subset
|
||||
|
||||
grind_pattern take_subset => take i l ⊆ l
|
||||
|
||||
theorem drop_subset (i) (l : List α) : drop i l ⊆ l :=
|
||||
(drop_sublist i l).subset
|
||||
|
||||
grind_pattern drop_subset => drop i l ⊆ l
|
||||
|
||||
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take i) : a ∈ l :=
|
||||
take_subset _ _ h
|
||||
|
||||
@@ -1138,64 +1165,84 @@ theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l
|
||||
|
||||
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
|
||||
|
||||
@[grind] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
@[grind ←] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
(drop_suffix_drop_left l h).sublist
|
||||
|
||||
@[grind] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
@[grind ←] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
(drop_sublist_drop_left l h).subset
|
||||
|
||||
@[grind] theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
⟨l.dropWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
@[grind] theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
grind_pattern takeWhile_prefix => l.takeWhile p <+: _
|
||||
|
||||
theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
⟨l.takeWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
@[grind] theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
grind_pattern dropWhile_suffix => l.dropWhile p <+: _
|
||||
|
||||
theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
(takeWhile_prefix p).sublist
|
||||
|
||||
@[grind] theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
grind_pattern takeWhile_sublist => l.takeWhile p <+ _
|
||||
|
||||
theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
(dropWhile_suffix p).sublist
|
||||
|
||||
grind_pattern dropWhile_sublist => l.dropWhile p <+ _
|
||||
|
||||
theorem takeWhile_subset {l : List α} (p : α → Bool) : l.takeWhile p ⊆ l :=
|
||||
(takeWhile_sublist p).subset
|
||||
|
||||
grind_pattern takeWhile_subset => l.takeWhile p ⊆ _
|
||||
|
||||
theorem dropWhile_subset {l : List α} (p : α → Bool) : l.dropWhile p ⊆ l :=
|
||||
(dropWhile_sublist p).subset
|
||||
|
||||
@[grind] theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
grind_pattern dropWhile_subset => l.dropWhile p ⊆ _
|
||||
|
||||
theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
| [] => ⟨nil, by rw [dropLast, List.append_nil]⟩
|
||||
| a :: l => ⟨_, dropLast_concat_getLast (cons_ne_nil a l)⟩
|
||||
|
||||
@[grind] theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
grind_pattern dropLast_prefix => l.dropLast <+: _
|
||||
|
||||
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
(dropLast_prefix l).sublist
|
||||
|
||||
grind_pattern dropLast_sublist => l.dropLast <+ _
|
||||
|
||||
theorem dropLast_subset (l : List α) : l.dropLast ⊆ l :=
|
||||
(dropLast_sublist l).subset
|
||||
|
||||
@[grind] theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
grind_pattern dropLast_subset => l.dropLast ⊆ _
|
||||
|
||||
@[grind] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
|
||||
grind_pattern tail_suffix => tail l <+: _
|
||||
|
||||
@[grind ←] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply prefix_append
|
||||
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₁.map f
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
@[grind ←] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply suffix_append
|
||||
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₁.map f
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
@[grind ←] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
obtain ⟨r₁, r₂, rfl⟩ := h
|
||||
rw [map_append, map_append]; apply infix_append
|
||||
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₁.map f
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
|
||||
@[grind] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind ←] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
l₁.filter p <+: l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply prefix_append
|
||||
@@ -1203,7 +1250,7 @@ grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₁.filter p
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind ←] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
l₁.filter p <:+ l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply suffix_append
|
||||
@@ -1211,7 +1258,7 @@ grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₁.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind ←] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
l₁.filter p <:+: l₂.filter p := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filter_append, filter_append]; apply infix_append _
|
||||
@@ -1219,7 +1266,7 @@ grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₁.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
|
||||
@[grind] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind ←] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
filterMap f l₁ <+: filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply prefix_append
|
||||
@@ -1227,7 +1274,7 @@ grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₁
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
|
||||
@[grind] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind ←] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
filterMap f l₁ <:+ filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply suffix_append
|
||||
@@ -1235,7 +1282,7 @@ grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₁
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₂
|
||||
|
||||
@[grind] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind ←] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
filterMap f l₁ <:+: filterMap f l₂ := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filterMap_append, filterMap_append]; apply infix_append
|
||||
|
||||
@@ -165,9 +165,6 @@ theorem take_set {l : List α} {i j : Nat} {a : α} :
|
||||
| nil => simp
|
||||
| cons hd tl => cases j <;> simp_all
|
||||
|
||||
@[deprecated take_set (since := "2025-02-17")]
|
||||
abbrev set_take := @take_set
|
||||
|
||||
theorem drop_set {l : List α} {i j : Nat} {a : α} :
|
||||
(l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a := by
|
||||
induction i generalizing l j with
|
||||
|
||||
@@ -791,18 +791,6 @@ protected theorem pow_le_pow_right {n : Nat} (hx : n > 0) {i : Nat} : ∀ {j}, i
|
||||
| Or.inr h =>
|
||||
h.symm ▸ Nat.le_refl _
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp] theorem zero_pow_of_pos (n : Nat) (h : 0 < n) : 0 ^ n = 0 := by
|
||||
cases n with
|
||||
| zero => cases h
|
||||
@@ -882,9 +870,6 @@ protected theorem ne_zero_of_lt (h : b < a) : a ≠ 0 := by
|
||||
exact absurd h (Nat.not_lt_zero _)
|
||||
apply Nat.noConfusion
|
||||
|
||||
@[deprecated Nat.ne_zero_of_lt (since := "2025-02-06")]
|
||||
theorem not_eq_zero_of_lt (h : b < a) : a ≠ 0 := Nat.ne_zero_of_lt h
|
||||
|
||||
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
|
||||
pred_lt (Nat.ne_zero_of_lt h)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.ByCases
|
||||
public import Init.Data.Prod
|
||||
public import Init.Data.RArray
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -138,21 +139,7 @@ structure PolyCnstr where
|
||||
eq : Bool
|
||||
lhs : Poly
|
||||
rhs : Poly
|
||||
deriving BEq
|
||||
|
||||
-- TODO: implement LawfulBEq generator companion for BEq
|
||||
instance : LawfulBEq PolyCnstr where
|
||||
eq_of_beq {a b} h := by
|
||||
cases a; rename_i eq₁ lhs₁ rhs₁
|
||||
cases b; rename_i eq₂ lhs₂ rhs₂
|
||||
have h : eq₁ == eq₂ && (lhs₁ == lhs₂ && rhs₁ == rhs₂) := h
|
||||
simp at h
|
||||
have ⟨h₁, h₂, h₃⟩ := h
|
||||
rw [h₁, h₂, h₃]
|
||||
rfl {a} := by
|
||||
cases a; rename_i eq lhs rhs
|
||||
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
simp
|
||||
deriving BEq, ReflBEq, LawfulBEq
|
||||
|
||||
structure ExprCnstr where
|
||||
eq : Bool
|
||||
|
||||
@@ -15,30 +15,30 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
forIn' o.toArray b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toArray b f = forIn o b f := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind =] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toArray.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind =] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toArray.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind =] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toArray.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind =] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -75,9 +75,6 @@ theorem attach_map_val (o : Option α) (f : α → β) :
|
||||
(o.attach.map fun (i : {i // o = some i}) => f i) = o.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
@[simp, grind =]theorem attach_map_subtype_val (o : Option α) :
|
||||
o.attach.map Subtype.val = o :=
|
||||
(attach_map_val _ _).trans (congrFun Option.map_id _)
|
||||
@@ -86,9 +83,6 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
|
||||
((o.attachWith p H).map fun (i : { i // p i}) => f i.val) = o.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
@[simp, grind =] theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
(o.attachWith p H).map Subtype.val = o :=
|
||||
(attachWith_map_val _ _ _).trans (congrFun Option.map_id _)
|
||||
@@ -97,7 +91,7 @@ theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach =
|
||||
| none, ⟨x, h⟩ => by simp at h
|
||||
| some a, ⟨x, h⟩ => by simpa using h
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach :=
|
||||
attach_eq_some
|
||||
|
||||
@@ -187,9 +181,6 @@ theorem toArray_attachWith {p : α → Prop} {o : Option α} {h} :
|
||||
o.attach.map f = o.pmap (fun a (h : o = some a) => f ⟨a, h⟩) (fun _ h => h) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[simp, grind =] theorem map_attachWith {l : Option α} {P : α → Prop} {H : ∀ (a : α), l = some a → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f = l.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
|
||||
@@ -18,27 +18,27 @@ namespace Option
|
||||
deriving instance DecidableEq for Option
|
||||
deriving instance BEq for Option
|
||||
|
||||
@[simp, grind] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
|
||||
@[simp, grind =] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind =] theorem getD_some : getD (some a) b = a := rfl
|
||||
|
||||
@[simp, grind] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
@[simp, grind =] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind =] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
|
||||
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
|
||||
def getM [Alternative m] : Option α → m α
|
||||
| none => failure
|
||||
| some a => pure a
|
||||
|
||||
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
@[simp, grind =] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind =] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@[inline] def isSome : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[simp, grind] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind] theorem isSome_some : isSome (some a) = true := rfl
|
||||
@[simp, grind =] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind =] theorem isSome_some : isSome (some a) = true := rfl
|
||||
|
||||
/--
|
||||
Returns `true` on `none` and `false` on `some x`.
|
||||
@@ -53,8 +53,8 @@ Examples:
|
||||
| some _ => false
|
||||
| none => true
|
||||
|
||||
@[simp, grind] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind] theorem isNone_some : isNone (some a) = false := rfl
|
||||
@[simp, grind =] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind =] theorem isNone_some : isNone (some a) = false := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is both present and equal to some other value.
|
||||
@@ -89,8 +89,8 @@ Examples:
|
||||
| none, _ => none
|
||||
| some a, f => f a
|
||||
|
||||
@[simp, grind] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
@[simp, grind =] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind =] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
|
||||
@[deprecated bind_none (since := "2025-05-03")]
|
||||
abbrev none_bind := @bind_none
|
||||
@@ -125,8 +125,8 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
|
||||
| none => pure none
|
||||
| some x => some <$> f x
|
||||
|
||||
@[simp, grind] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
@[simp, grind =] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind =] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
|
||||
/--
|
||||
Applies a function in some applicative functor to an optional value, returning `none` with no
|
||||
@@ -138,9 +138,9 @@ This is an alias for `Option.mapM`, which already works for applicative functors
|
||||
Option.mapM f
|
||||
|
||||
/-- For verification purposes, we replace `mapA` with `mapM`. -/
|
||||
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
@[simp, grind =] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem map_id : (Option.map id : Option α → Option α) = id :=
|
||||
funext (fun o => match o with | none => rfl | some _ => rfl)
|
||||
|
||||
@@ -182,8 +182,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => true
|
||||
|
||||
@[simp, grind] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
@[simp, grind =] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind =] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
|
||||
@@ -197,8 +197,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => false
|
||||
|
||||
@[simp, grind] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
@[simp, grind =] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind =] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
|
||||
@@ -210,8 +210,8 @@ See also `or` for a version that is strict in the second argument.
|
||||
| some a, _ => some a
|
||||
| none, b => b ()
|
||||
|
||||
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
|
||||
@[simp, grind =] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind =] theorem orElse_none : none.orElse b = b () := rfl
|
||||
|
||||
instance : OrElse (Option α) where
|
||||
orElse := Option.orElse
|
||||
@@ -351,9 +351,9 @@ Extracts the value from an option that can be proven to be `some`.
|
||||
@[inline] def get {α : Type u} : (o : Option α) → isSome o → α
|
||||
| some x, _ => x
|
||||
|
||||
@[simp, grind] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
@[simp, grind =] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
| some _, _ => rfl
|
||||
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
@[simp, grind =] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
|
||||
/--
|
||||
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
|
||||
@@ -431,8 +431,8 @@ Examples:
|
||||
-/
|
||||
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
|
||||
|
||||
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind] theorem join_some : (some o).join = o := rfl
|
||||
@[simp, grind =] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind =] theorem join_some : (some o).join = o := rfl
|
||||
|
||||
/--
|
||||
Converts an optional monadic computation into a monadic computation of an optional value.
|
||||
@@ -457,8 +457,8 @@ some "world"
|
||||
| none => pure none
|
||||
| some f => some <$> f
|
||||
|
||||
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
@[simp, grind =] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind =] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
|
||||
/--
|
||||
A monadic case analysis function for `Option`.
|
||||
@@ -483,8 +483,8 @@ This is the monadic analogue of `Option.getD`.
|
||||
| some a => pure a
|
||||
| none => y
|
||||
|
||||
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
@[simp, grind =] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind =] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
|
||||
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
|
||||
rfl {x} := private
|
||||
@@ -520,10 +520,10 @@ protected def min [Min α] : Option α → Option α → Option α
|
||||
|
||||
instance [Min α] : Min (Option α) where min := Option.min
|
||||
|
||||
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
@[simp, grind =] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind =] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
@[simp, grind =] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated min_none_right (since := "2025-05-12")]
|
||||
@@ -553,10 +553,10 @@ protected def max [Max α] : Option α → Option α → Option α
|
||||
|
||||
instance [Max α] : Max (Option α) where max := Option.max
|
||||
|
||||
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
@[simp, grind =] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind =] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
@[simp, grind =] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated max_none_right (since := "2025-05-12")]
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Option
|
||||
@[deprecated mem_def (since := "2025-04-07")]
|
||||
theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
@[grind] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
@[grind =] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
|
||||
theorem mem_some_iff {a b : α} : a ∈ some b ↔ b = a := mem_some
|
||||
|
||||
@@ -52,7 +52,7 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
|
||||
theorem get_of_eq_some : ∀ {o : Option α} (h : isSome o), o = some a → o.get h = a
|
||||
| _, _, rfl => rfl
|
||||
|
||||
@[simp, grind] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
@[simp, grind ←] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
|
||||
theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.getD y) = x := by
|
||||
cases x; {contradiction}; rw [getD_some]
|
||||
|
||||
@@ -16,38 +16,38 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
@[simp, grind =] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toList b f = forIn o b f := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind =] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind =] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind =] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toList.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind =] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toList.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem pairwise_toList {P : α → α → Prop} {o : Option α} : o.toList.Pairwise P := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem head?_toList {o : Option α} : o.toList.head? = o := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -16,20 +16,20 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
@[simp, grind =] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind =] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
simp [Option.bindM]
|
||||
|
||||
-- We simplify `Option.forM` to `forM`.
|
||||
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
|
||||
|
||||
@[simp, grind] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
@[simp, grind =] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
forM none f = pure .unit := rfl
|
||||
|
||||
@[simp, grind] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
@[simp, grind =] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
forM (some a) f = f a := rfl
|
||||
|
||||
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
forM (o.map g) f = forM o (fun a => f (g a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -37,11 +37,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
forM o.join f = forM o (forM · f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
forIn' none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -49,11 +49,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
funext x
|
||||
split <;> simp
|
||||
|
||||
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind =] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn, forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -106,7 +106,7 @@ theorem forIn'_id_yield_eq_pelim
|
||||
o.pelim b (fun a h => f a h b) :=
|
||||
forIn'_pure_yield_eq_pelim _ _ _
|
||||
|
||||
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : (b : β) → b ∈ o.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
|
||||
cases o <;> simp
|
||||
@@ -149,7 +149,7 @@ theorem forIn_id_yield_eq_elim
|
||||
o.elim b (fun a => f a b) :=
|
||||
forIn_pure_yield_eq_elim _ _ _
|
||||
|
||||
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -349,13 +349,13 @@ theorem LawfulEqCmp.compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
|
||||
beq_iff_eq.trans compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_eq_iff_eq` -/
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem LawfulEqOrd.compare_eq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b = .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_beq_iff_eq` -/
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem LawfulEqOrd.compare_beq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b == .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_beq_iff_eq
|
||||
|
||||
@@ -12,6 +12,8 @@ public import Init.Data.Range.Polymorphic.Stream
|
||||
public import Init.Data.Range.Polymorphic.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Int
|
||||
public import Init.Data.Range.Polymorphic.BitVec
|
||||
public import Init.Data.Range.Polymorphic.UInt
|
||||
public import Init.Data.Range.Polymorphic.NatLemmas
|
||||
public import Init.Data.Range.Polymorphic.GetElemTactic
|
||||
|
||||
|
||||
88
src/Init/Data/Range/Polymorphic/BitVec.lean
Normal file
88
src/Init/Data/Range/Polymorphic/BitVec.lean
Normal file
@@ -0,0 +1,88 @@
|
||||
/-
|
||||
Copyright (c) 2025 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.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.UInt
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
|
||||
open Std Std.PRange
|
||||
|
||||
namespace BitVec
|
||||
|
||||
variable {n : Nat}
|
||||
|
||||
instance : UpwardEnumerable (BitVec n) where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? m i := if h : i.toNat + m < 2 ^ n then some (.ofNatLT _ h) else none
|
||||
|
||||
instance : LawfulUpwardEnumerable (BitVec n) where
|
||||
ne_of_lt := by
|
||||
simp +contextual [UpwardEnumerable.LT, ← BitVec.toNat_inj, succMany?] at ⊢
|
||||
omega
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?, BitVec.toNat_lt_twoPow_of_le]
|
||||
succMany?_succ? a b := by
|
||||
simp +contextual [← BitVec.toNat_inj, succMany?, succ?]
|
||||
split <;> split
|
||||
· rename_i h
|
||||
simp [← BitVec.toNat_inj, Nat.mod_eq_of_lt (a := b.toNat + a + 1) ‹_›]
|
||||
all_goals omega
|
||||
· omega
|
||||
· have : b.toNat + a + 1 = 2 ^ n := by omega
|
||||
simp [this]
|
||||
· simp
|
||||
|
||||
instance : LawfulUpwardEnumerableLE (BitVec n) where
|
||||
le_iff x y := by
|
||||
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, BitVec.le_def]
|
||||
apply Iff.intro
|
||||
· intro hle
|
||||
refine ⟨y.toNat - x.toNat, ?_⟩
|
||||
apply Exists.intro <;> simp [Nat.add_sub_cancel' hle, BitVec.toNat_lt_twoPow_of_le]
|
||||
· rintro ⟨n, hn, rfl⟩
|
||||
simp [BitVec.ofNatLT]
|
||||
|
||||
instance : LawfulOrderLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open (BitVec n) := inferInstance
|
||||
|
||||
instance : RangeSize .closed (BitVec n) where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
instance : RangeSize .open (BitVec n) := RangeSize.openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed (BitVec n) where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simp [SupportsUpperBound.IsSatisfied, BitVec.not_le, RangeSize.size, BitVec.lt_def]
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
have := BitVec.toNat_lt_twoPow_of_le (Nat.le_refl _) (x := bound)
|
||||
have (h : (x.toNat + 1) % 2 ^ n = 0) : x.toNat = 2 ^ n - 1 := by
|
||||
apply Classical.not_not.mp
|
||||
intro _
|
||||
simp [Nat.mod_eq_of_lt (a := x.toNat + 1) (b := 2 ^ n) (by omega)] at h
|
||||
simp [RangeSize.size, BitVec.le_def, ← BitVec.toNat_inj, succ?]
|
||||
omega
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
have (h : ¬ (init.toNat + 1) % 2 ^ n = 0) : ¬ (init.toNat + 1 ≥ 2 ^ n) := by
|
||||
intro _
|
||||
have : init.toNat + 1 = 2 ^ n := by omega
|
||||
simp_all
|
||||
simp_all +contextual [RangeSize.size, BitVec.le_def, ← BitVec.toNat_inj,
|
||||
Nat.mod_eq_of_lt (a := init.toNat + 1) (b := 2 ^ n), succ?]
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open (BitVec n) := inferInstance
|
||||
|
||||
end BitVec
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Int.Order
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
@@ -23,7 +24,7 @@ instance : LawfulUpwardEnumerable Int where
|
||||
simp only [UpwardEnumerable.LT, UpwardEnumerable.succMany?, Option.some.injEq]
|
||||
omega
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by
|
||||
succMany?_succ? := by
|
||||
simp only [UpwardEnumerable.succMany?, UpwardEnumerable.succ?,
|
||||
Option.bind_some, Option.some.injEq]
|
||||
omega
|
||||
@@ -36,6 +37,14 @@ instance : LawfulUpwardEnumerableLE Int where
|
||||
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, Int.le_def, Int.nonneg_def,
|
||||
Int.sub_eq_iff_eq_add', eq_comm (a := y)]
|
||||
|
||||
instance : LawfulOrderLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Int := inferInstance
|
||||
|
||||
instance : RangeSize .closed Int where
|
||||
size bound a := (bound + 1 - a).toNat
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def Internal.iter {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl
|
||||
|
||||
/--
|
||||
Returns the elements of the given range as a list in ascending order, given that ranges of the given
|
||||
type and shape support this function and the range is finite.
|
||||
type and shape are finite and support this function.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
@@ -37,6 +37,18 @@ def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[IteratorCollect (RangeIterator su α) Id Id] : List α :=
|
||||
PRange.Internal.iter r |>.toList
|
||||
|
||||
/--
|
||||
Returns the elements of the given range as an array in ascending order, given that ranges of the
|
||||
given type and shape are finite and support this function.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def toArray {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α]
|
||||
(r : PRange ⟨sl, su⟩ α)
|
||||
[Iterator (RangeIterator su α) Id α] [Finite (RangeIterator su α) Id]
|
||||
[IteratorCollect (RangeIterator su α) Id Id] : Array α :=
|
||||
PRange.Internal.iter r |>.toArray
|
||||
|
||||
/--
|
||||
Iterators for ranges implementing `RangeSize` support the `size` function.
|
||||
-/
|
||||
|
||||
@@ -16,6 +16,7 @@ public import Init.Data.Range.Polymorphic.Iterators
|
||||
import all Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -44,6 +45,12 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
r.toList = (Internal.iter r).toList := by
|
||||
rfl
|
||||
|
||||
private theorem Internal.toArray_eq_toArray_iter {sl su} [UpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α] {r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = (Internal.iter r).toArray := by
|
||||
rfl
|
||||
|
||||
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -61,6 +68,35 @@ public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
· simp [*]
|
||||
· split <;> rename_i heq' <;> simp [*]
|
||||
|
||||
public theorem RangeIterator.toArray_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{it : Iter (α := RangeIterator su α) α} :
|
||||
it.toArray = match it.internalState.next with
|
||||
| none => #[]
|
||||
| some a => if SupportsUpperBound.IsSatisfied it.internalState.upperBound a then
|
||||
#[a] ++ (⟨⟨UpwardEnumerable.succ? a, it.internalState.upperBound⟩⟩ : Iter (α := RangeIterator su α) α).toArray
|
||||
else
|
||||
#[] := by
|
||||
rw [← Iter.toArray_toList, toList_eq_match]
|
||||
split
|
||||
· rfl
|
||||
· split <;> simp
|
||||
|
||||
@[simp]
|
||||
public theorem toList_toArray {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray.toList = r.toList := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_toList {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList.toArray = r.toArray := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
|
||||
|
||||
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -73,6 +109,18 @@ public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnume
|
||||
[] := by
|
||||
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
|
||||
|
||||
public theorem toArray_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = match init? r.lower with
|
||||
| none => #[]
|
||||
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
|
||||
#[a] ++ (PRange.mk (shape := ⟨.open, su⟩) a r.upper).toArray
|
||||
else
|
||||
#[] := by
|
||||
rw [Internal.toArray_eq_toArray_iter, RangeIterator.toArray_eq_match]; rfl
|
||||
|
||||
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -90,6 +138,14 @@ public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerab
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
|
||||
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
|
||||
|
||||
public theorem toArray_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toArray =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toArray := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
|
||||
|
||||
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -101,6 +157,14 @@ public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
simp only
|
||||
split <;> rename_i heq <;> simp [heq]
|
||||
|
||||
public theorem toArray_eq_empty_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = #[] ↔
|
||||
¬ (∃ a, init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
rw [← toArray_toList, List.toArray_eq_iff, Array.toList_empty, toList_eq_nil_iff]
|
||||
|
||||
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -110,6 +174,15 @@ public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
public theorem mem_toArray_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{a : α} : a ∈ r.toArray ↔ a ∈ r := by
|
||||
rw [Internal.toArray_eq_toArray_iter, Iter.mem_toArray_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
@@ -301,6 +374,17 @@ public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [Support
|
||||
(lower...upper).toList.map succ :=
|
||||
toList_Rco_succ_succ_eq_map
|
||||
|
||||
public theorem toArray_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toArray =
|
||||
(lower...upper).toArray.map succ := by
|
||||
simp only [← toArray_toList]
|
||||
rw [toList_Rco_succ_succ_eq_map]
|
||||
simp only [List.map_toArray]
|
||||
|
||||
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -324,6 +408,18 @@ public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
|
||||
Iter.forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem forIn'_eq_forIn'_toArray [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → a ∈ r → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r init f =
|
||||
ForIn'.forIn' r.toArray init (fun a ha acc => f a (mem_toArray_iff_mem.mp ha) acc) := by
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toArray_eq_toArray_iter,
|
||||
Iter.forIn'_eq_forIn'_toArray]
|
||||
|
||||
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -335,6 +431,17 @@ public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem forIn'_toArray_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → _ → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r.toArray init f =
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toArray_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toArray]
|
||||
|
||||
public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -431,6 +538,20 @@ public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
public theorem length_toList {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[HasFiniteRanges su α] [LawfulRangeSize su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList.length = r.size := by
|
||||
simp [PRange.toList, PRange.size]
|
||||
|
||||
public theorem size_toArray {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[HasFiniteRanges su α] [LawfulRangeSize su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray.size = r.size := by
|
||||
simp [PRange.toArray, PRange.size]
|
||||
|
||||
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -455,4 +576,94 @@ public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulU
|
||||
(Option.some_get hi).symm
|
||||
exact h ((init? r.lower).get hi) ⟨hl, hu⟩
|
||||
|
||||
theorem Std.PRange.getElem?_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} :
|
||||
r.toList[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
|
||||
induction i generalizing r
|
||||
· rw [PRange.toList_eq_match, UpwardEnumerable.succMany?_zero]
|
||||
simp only [Option.filter_some, decide_eq_true_eq]
|
||||
split <;> simp
|
||||
· rename_i n ih
|
||||
rw [PRange.toList_eq_match]
|
||||
simp only
|
||||
split
|
||||
· simp [UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?]
|
||||
cases hs : UpwardEnumerable.succ? r.lower
|
||||
· rw [PRange.toList_eq_match]
|
||||
simp [BoundedUpwardEnumerable.init?, hs]
|
||||
· rw [toList_Rox_eq_toList_Rcx_of_isSome_succ? (by simp [hs])]
|
||||
rw [ih]
|
||||
simp [hs]
|
||||
· simp only [List.length_nil, Nat.not_lt_zero, not_false_eq_true, getElem?_neg]
|
||||
cases hs : UpwardEnumerable.succMany? (n + 1) r.lower
|
||||
· simp
|
||||
· rename_i hl a
|
||||
simp only [Option.filter_some, decide_eq_true_eq, right_eq_ite_iff]
|
||||
have : UpwardEnumerable.LE r.lower a := ⟨n + 1, hs⟩
|
||||
intro ha
|
||||
exact hl.elim <| LawfulUpwardEnumerableUpperBound.isSatisfied_of_le r.upper _ _ ha this (α := α)
|
||||
|
||||
theorem Std.PRange.getElem?_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} :
|
||||
r.toArray[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
|
||||
rw [← toArray_toList, List.getElem?_toArray, getElem?_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.isSome_succMany?_of_lt_length_toList_Rcx [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} (h : i < r.toList.length) :
|
||||
(UpwardEnumerable.succMany? i r.lower).isSome := by
|
||||
have : r.toList[i]?.isSome := by simp [h]
|
||||
simp only [getElem?_toList_Rcx_eq, Option.isSome_filter] at this
|
||||
exact Option.isSome_of_any this
|
||||
|
||||
theorem Std.PRange.isSome_succMany?_of_lt_size_toArray_Rcx [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} (h : i < r.toArray.size) :
|
||||
(UpwardEnumerable.succMany? i r.lower).isSome := by
|
||||
have : r.toArray[i]?.isSome := by simp [h]
|
||||
simp only [getElem?_toArray_Rcx_eq, Option.isSome_filter] at this
|
||||
exact Option.isSome_of_any this
|
||||
|
||||
theorem Std.PRange.getElem_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i h} :
|
||||
r.toList[i]'h = (UpwardEnumerable.succMany? i r.lower).get
|
||||
(isSome_succMany?_of_lt_length_toList_Rcx h) := by
|
||||
simp [List.getElem_eq_getElem?_get, getElem?_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.getElem_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i h} :
|
||||
r.toArray[i]'h = (UpwardEnumerable.succMany? i r.lower).get
|
||||
(isSome_succMany?_of_lt_size_toArray_Rcx h) := by
|
||||
simp [Array.getElem_eq_getElem?_get, getElem?_toArray_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.eq_succMany?_of_toList_Rcx_eq_append_cons [LE α]
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {pref suff : List α} {cur : α} (h : r.toList = pref ++ cur :: suff) :
|
||||
cur = (UpwardEnumerable.succMany? pref.length r.lower).get
|
||||
(isSome_succMany?_of_lt_length_toList_Rcx (by simp [h])) := by
|
||||
have : cur = (pref ++ cur :: suff)[pref.length] := by simp
|
||||
simp only [← h] at this
|
||||
simp [this, getElem_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.eq_succMany?_of_toArray_Rcx_eq_append_append [LE α]
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {pref suff : Array α} {cur : α} (h : r.toArray = pref ++ #[cur] ++ suff) :
|
||||
cur = (UpwardEnumerable.succMany? pref.size r.lower).get
|
||||
(isSome_succMany?_of_lt_size_toArray_Rcx (by simp [h, Nat.add_assoc, Nat.add_comm 1])) := by
|
||||
have : cur = (pref ++ #[cur] ++ suff)[pref.size] := by simp
|
||||
simp only [← h] at this
|
||||
simp [this, getElem_toArray_Rcx_eq]
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -10,10 +10,12 @@ import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std PRange
|
||||
|
||||
namespace Std.PRange
|
||||
|
||||
instance : UpwardEnumerable Nat where
|
||||
@@ -39,7 +41,7 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
succMany?_succ? := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
@@ -76,8 +78,7 @@ instance : LawfulRangeSize .closed Nat where
|
||||
instance : LawfulRangeSize .open Nat := inferInstance
|
||||
instance : HasFiniteRanges .closed Nat := inferInstance
|
||||
instance : HasFiniteRanges .open Nat := inferInstance
|
||||
instance : LinearlyUpwardEnumerable Nat := by
|
||||
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
|
||||
instance : LinearlyUpwardEnumerable Nat := inferInstance
|
||||
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
|
||||
@@ -25,4 +25,17 @@ theorem toList_Rco_succ_succ {m n : Nat} :
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
|
||||
|
||||
@[simp]
|
||||
theorem Nat.size_Rco {a b : Nat} :
|
||||
(a...b).size = b - a := by
|
||||
simp only [size, Iterators.Iter.size, Iterators.IteratorSize.size, Iterators.Iter.toIterM,
|
||||
Internal.iter, init?, RangeSize.size, Id.run_pure]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem Nat.size_Rcc {a b : Nat} :
|
||||
(a...=b).size = b + 1- a := by
|
||||
simp [Std.PRange.size, Std.Iterators.Iter.size, Std.Iterators.IteratorSize.size,
|
||||
Std.PRange.Internal.iter, Std.Iterators.Iter.toIterM, Std.PRange.RangeSize.size]
|
||||
|
||||
end Std.PRange.Nat
|
||||
|
||||
382
src/Init/Data/Range/Polymorphic/UInt.lean
Normal file
382
src/Init/Data/Range/Polymorphic/UInt.lean
Normal file
@@ -0,0 +1,382 @@
|
||||
/-
|
||||
Copyright (c) 2025 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.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.UInt
|
||||
import Init.Omega
|
||||
public import Init.Data.Range.Polymorphic.BitVec
|
||||
|
||||
public section
|
||||
|
||||
open Std Std.PRange
|
||||
|
||||
namespace UInt8
|
||||
|
||||
instance : UpwardEnumerable UInt8 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt8.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 8} :
|
||||
UpwardEnumerable.succ? (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt8.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 8} :
|
||||
UpwardEnumerable.succMany? k (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 8} :
|
||||
UpwardEnumerable.LE (UInt8.ofBitVec x) (UInt8.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 8} :
|
||||
UpwardEnumerable.LT (UInt8.ofBitVec x) (UInt8.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt8 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt8 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt8.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt8 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt8 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt8} {x : BitVec 8} :
|
||||
RangeSize.size bound (UInt8.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt8 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 8) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 8) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, ← UInt8.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 8) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt8 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt8 := inferInstance
|
||||
|
||||
end UInt8
|
||||
|
||||
namespace UInt16
|
||||
|
||||
instance : UpwardEnumerable UInt16 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt16.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 16} :
|
||||
UpwardEnumerable.succ? (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt16.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 16} :
|
||||
UpwardEnumerable.succMany? k (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 16} :
|
||||
UpwardEnumerable.LE (UInt16.ofBitVec x) (UInt16.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 16} :
|
||||
UpwardEnumerable.LT (UInt16.ofBitVec x) (UInt16.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt16 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt16 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt16.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt16 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt16 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt16} {x : BitVec 16} :
|
||||
RangeSize.size bound (UInt16.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt16 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 16) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 16) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, ← UInt16.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 16) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt16 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt16 := inferInstance
|
||||
|
||||
end UInt16
|
||||
|
||||
namespace UInt32
|
||||
|
||||
instance : UpwardEnumerable UInt32 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt32.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 32} :
|
||||
UpwardEnumerable.succ? (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt32.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 32} :
|
||||
UpwardEnumerable.succMany? k (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 32} :
|
||||
UpwardEnumerable.LE (UInt32.ofBitVec x) (UInt32.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 32} :
|
||||
UpwardEnumerable.LT (UInt32.ofBitVec x) (UInt32.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt32 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt32 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt32.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt32 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt32 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt32} {x : BitVec 32} :
|
||||
RangeSize.size bound (UInt32.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt32 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 32) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 32) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, ← UInt32.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 32) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt32 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt32 := inferInstance
|
||||
|
||||
end UInt32
|
||||
|
||||
namespace UInt64
|
||||
|
||||
instance : UpwardEnumerable UInt64 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt64.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 64} :
|
||||
UpwardEnumerable.succ? (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt64.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 64} :
|
||||
UpwardEnumerable.succMany? k (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 64} :
|
||||
UpwardEnumerable.LE (UInt64.ofBitVec x) (UInt64.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 64} :
|
||||
UpwardEnumerable.LT (UInt64.ofBitVec x) (UInt64.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt64 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt64 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt64.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt64 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt64 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt64} {x : BitVec 64} :
|
||||
RangeSize.size bound (UInt64.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt64 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 64) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 64) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, ← UInt64.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 64) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt64 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt64 := inferInstance
|
||||
|
||||
end UInt64
|
||||
|
||||
namespace USize
|
||||
|
||||
instance : UpwardEnumerable USize where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < USize.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.succ? (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← USize.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.succMany? k (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.LE (USize.ofBitVec x) (USize.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.LT (USize.ofBitVec x) (USize.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable USize where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE USize where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, USize.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open USize := inferInstance
|
||||
|
||||
instance : RangeSize .closed USize where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed USize} {x : BitVec System.Platform.numBits} :
|
||||
RangeSize.size bound (USize.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed USize where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec System.Platform.numBits) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec System.Platform.numBits) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, ← USize.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec System.Platform.numBits) _ _ _
|
||||
|
||||
instance : RangeSize .open USize := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open USize := inferInstance
|
||||
|
||||
end USize
|
||||
@@ -40,7 +40,6 @@ class UpwardEnumerable (α : Type u) where
|
||||
-/
|
||||
succMany? (n : Nat) (a : α) : Option α := Nat.repeat (· >>= succ?) n (some a)
|
||||
|
||||
attribute [simp] UpwardEnumerable.succ? UpwardEnumerable.succMany?
|
||||
export UpwardEnumerable (succ? succMany?)
|
||||
|
||||
/--
|
||||
@@ -80,7 +79,6 @@ class Least? (α : Type u) where
|
||||
-/
|
||||
least? : Option α
|
||||
|
||||
attribute [simp] Least?.least?
|
||||
export Least? (least?)
|
||||
|
||||
/--
|
||||
@@ -95,7 +93,7 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
The `n + 1`-th successor of `a` is the successor of the `n`-th successor, given that said
|
||||
successors actually exist.
|
||||
-/
|
||||
succMany?_succ (n : Nat) (a : α) :
|
||||
succMany?_succ? (n : Nat) (a : α) :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ?
|
||||
|
||||
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
@@ -105,7 +103,7 @@ theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnume
|
||||
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
LawfulUpwardEnumerable.succMany?_succ n a
|
||||
LawfulUpwardEnumerable.succMany?_succ? n a
|
||||
|
||||
@[deprecated succMany?_succ? (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
|
||||
@@ -96,8 +96,7 @@ theorem Int8.toBitVec.inj : {x y : Int8} → x.toBitVec = y.toBitVec → x = y
|
||||
|
||||
/-- Obtains the `Int8` that is 2's complement equivalent to the `UInt8`. -/
|
||||
@[inline] def UInt8.toInt8 (i : UInt8) : Int8 := Int8.ofUInt8 i
|
||||
@[inline, deprecated UInt8.toInt8 (since := "2025-02-13"), inherit_doc UInt8.toInt8]
|
||||
def Int8.mk (i : UInt8) : Int8 := UInt8.toInt8 i
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision integer to an 8-bit integer, wrapping on overflow or underflow.
|
||||
|
||||
@@ -159,8 +158,7 @@ Converts an 8-bit signed integer to a natural number, mapping all negative numbe
|
||||
Use `Int8.toBitVec` to obtain the two's complement representation.
|
||||
-/
|
||||
@[inline] def Int8.toNatClampNeg (i : Int8) : Nat := i.toInt.toNat
|
||||
@[inline, deprecated Int8.toNatClampNeg (since := "2025-02-13"), inherit_doc Int8.toNatClampNeg]
|
||||
def Int8.toNat (i : Int8) : Nat := i.toInt.toNat
|
||||
|
||||
/-- Obtains the `Int8` whose 2's complement representation is the given `BitVec 8`. -/
|
||||
@[inline] def Int8.ofBitVec (b : BitVec 8) : Int8 := ⟨⟨b⟩⟩
|
||||
/--
|
||||
@@ -449,8 +447,7 @@ theorem Int16.toBitVec.inj : {x y : Int16} → x.toBitVec = y.toBitVec → x = y
|
||||
|
||||
/-- Obtains the `Int16` that is 2's complement equivalent to the `UInt16`. -/
|
||||
@[inline] def UInt16.toInt16 (i : UInt16) : Int16 := Int16.ofUInt16 i
|
||||
@[inline, deprecated UInt16.toInt16 (since := "2025-02-13"), inherit_doc UInt16.toInt16]
|
||||
def Int16.mk (i : UInt16) : Int16 := UInt16.toInt16 i
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision integer to a 16-bit signed integer, wrapping on overflow or underflow.
|
||||
|
||||
@@ -514,8 +511,7 @@ Converts a 16-bit signed integer to a natural number, mapping all negative numbe
|
||||
Use `Int16.toBitVec` to obtain the two's complement representation.
|
||||
-/
|
||||
@[inline] def Int16.toNatClampNeg (i : Int16) : Nat := i.toInt.toNat
|
||||
@[inline, deprecated Int16.toNatClampNeg (since := "2025-02-13"), inherit_doc Int16.toNatClampNeg]
|
||||
def Int16.toNat (i : Int16) : Nat := i.toInt.toNat
|
||||
|
||||
/-- Obtains the `Int16` whose 2's complement representation is the given `BitVec 16`. -/
|
||||
@[inline] def Int16.ofBitVec (b : BitVec 16) : Int16 := ⟨⟨b⟩⟩
|
||||
/--
|
||||
@@ -820,8 +816,7 @@ theorem Int32.toBitVec.inj : {x y : Int32} → x.toBitVec = y.toBitVec → x = y
|
||||
|
||||
/-- Obtains the `Int32` that is 2's complement equivalent to the `UInt32`. -/
|
||||
@[inline] def UInt32.toInt32 (i : UInt32) : Int32 := Int32.ofUInt32 i
|
||||
@[inline, deprecated UInt32.toInt32 (since := "2025-02-13"), inherit_doc UInt32.toInt32]
|
||||
def Int32.mk (i : UInt32) : Int32 := UInt32.toInt32 i
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision integer to a 32-bit integer, wrapping on overflow or underflow.
|
||||
|
||||
@@ -886,8 +881,7 @@ Converts a 32-bit signed integer to a natural number, mapping all negative numbe
|
||||
Use `Int32.toBitVec` to obtain the two's complement representation.
|
||||
-/
|
||||
@[inline] def Int32.toNatClampNeg (i : Int32) : Nat := i.toInt.toNat
|
||||
@[inline, deprecated Int32.toNatClampNeg (since := "2025-02-13"), inherit_doc Int32.toNatClampNeg]
|
||||
def Int32.toNat (i : Int32) : Nat := i.toInt.toNat
|
||||
|
||||
/-- Obtains the `Int32` whose 2's complement representation is the given `BitVec 32`. -/
|
||||
@[inline] def Int32.ofBitVec (b : BitVec 32) : Int32 := ⟨⟨b⟩⟩
|
||||
/--
|
||||
@@ -1207,8 +1201,7 @@ theorem Int64.toBitVec.inj : {x y : Int64} → x.toBitVec = y.toBitVec → x = y
|
||||
|
||||
/-- Obtains the `Int64` that is 2's complement equivalent to the `UInt64`. -/
|
||||
@[inline] def UInt64.toInt64 (i : UInt64) : Int64 := Int64.ofUInt64 i
|
||||
@[inline, deprecated UInt64.toInt64 (since := "2025-02-13"), inherit_doc UInt64.toInt64]
|
||||
def Int64.mk (i : UInt64) : Int64 := UInt64.toInt64 i
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision integer to a 64-bit integer, wrapping on overflow or underflow.
|
||||
|
||||
@@ -1278,8 +1271,7 @@ Converts a 64-bit signed integer to a natural number, mapping all negative numbe
|
||||
Use `Int64.toBitVec` to obtain the two's complement representation.
|
||||
-/
|
||||
@[inline] def Int64.toNatClampNeg (i : Int64) : Nat := i.toInt.toNat
|
||||
@[inline, deprecated Int64.toNatClampNeg (since := "2025-02-13"), inherit_doc Int64.toNatClampNeg]
|
||||
def Int64.toNat (i : Int64) : Nat := i.toInt.toNat
|
||||
|
||||
/-- Obtains the `Int64` whose 2's complement representation is the given `BitVec 64`. -/
|
||||
@[inline] def Int64.ofBitVec (b : BitVec 64) : Int64 := ⟨⟨b⟩⟩
|
||||
/--
|
||||
@@ -1613,8 +1605,7 @@ theorem ISize.toBitVec.inj : {x y : ISize} → x.toBitVec = y.toBitVec → x = y
|
||||
|
||||
/-- Obtains the `ISize` that is 2's complement equivalent to the `USize`. -/
|
||||
@[inline] def USize.toISize (i : USize) : ISize := ISize.ofUSize i
|
||||
@[inline, deprecated USize.toISize (since := "2025-02-13"), inherit_doc USize.toISize]
|
||||
def ISize.mk (i : USize) : ISize := USize.toISize i
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision integer to a word-sized signed integer, wrapping around on over- or
|
||||
underflow.
|
||||
@@ -1647,8 +1638,7 @@ Converts a word-sized signed integer to a natural number, mapping all negative n
|
||||
Use `ISize.toBitVec` to obtain the two's complement representation.
|
||||
-/
|
||||
@[inline] def ISize.toNatClampNeg (i : ISize) : Nat := i.toInt.toNat
|
||||
@[inline, deprecated ISize.toNatClampNeg (since := "2025-02-13"), inherit_doc ISize.toNatClampNeg]
|
||||
def ISize.toNat (i : ISize) : Nat := i.toInt.toNat
|
||||
|
||||
/-- Obtains the `ISize` whose 2's complement representation is the given `BitVec`. -/
|
||||
@[inline] def ISize.ofBitVec (b : BitVec System.Platform.numBits) : ISize := ⟨⟨b⟩⟩
|
||||
/--
|
||||
|
||||
@@ -10,7 +10,7 @@ public import Init.Core
|
||||
public import Init.Data.Slice.Array.Basic
|
||||
import Init.Data.Iterators.Combinators.Attach
|
||||
import Init.Data.Iterators.Combinators.FilterMap
|
||||
import Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Consumers.Collect
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
@@ -31,7 +31,6 @@ open Std Slice PRange Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
@[no_expose]
|
||||
instance {s : Subarray α} : ToIterator s Id α :=
|
||||
.of _
|
||||
(PRange.Internal.iter (s.internalRepresentation.start...<s.internalRepresentation.stop)
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Decode
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
|
||||
@@ -9,11 +9,370 @@ prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.String.Decode
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
universe u
|
||||
|
||||
section
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_nil : List.utf8Encode [] = ByteArray.empty := by simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_singleton {c : Char} : [c].utf8Encode = (String.utf8EncodeChar c).toByteArray := by
|
||||
simp [utf8Encode]
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_append {l l' : List Char} :
|
||||
(l ++ l').utf8Encode = l.utf8Encode ++ l'.utf8Encode := by
|
||||
simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_cons {c : Char} {l : List Char} : (c :: l).utf8Encode = [c].utf8Encode ++ l.utf8Encode := by
|
||||
rw [← singleton_append, List.utf8Encode_append]
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8EncodeChar_ne_nil {c : Char} : String.utf8EncodeChar c ≠ [] := by
|
||||
fun_cases String.utf8EncodeChar with simp
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_eq_empty {l : List Char} : l.utf8Encode = ByteArray.empty ↔ l = [] := by
|
||||
simp [utf8Encode, ← List.eq_nil_iff_forall_not_mem]
|
||||
|
||||
theorem ByteArray.isValidUtf8_utf8Encode {l : List Char} : IsValidUtf8 l.utf8Encode :=
|
||||
.intro l rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.isValidUtf8_empty : IsValidUtf8 ByteArray.empty :=
|
||||
.intro [] (by simp)
|
||||
|
||||
theorem Char.isValidUtf8_toByteArray_utf8EncodeChar {c : Char} :
|
||||
ByteArray.IsValidUtf8 (String.utf8EncodeChar c).toByteArray :=
|
||||
.intro [c] (by simp [List.utf8Encode_singleton])
|
||||
|
||||
theorem ByteArray.IsValidUtf8.append {b b' : ByteArray} (h : IsValidUtf8 b) (h' : IsValidUtf8 b') :
|
||||
IsValidUtf8 (b ++ b') := by
|
||||
rcases h with ⟨m, rfl⟩
|
||||
rcases h' with ⟨m', rfl⟩
|
||||
exact .intro (m ++ m') (by simp)
|
||||
|
||||
theorem ByteArray.isValidUtf8_utf8Encode_singleton_append_iff {b : ByteArray} {c : Char} :
|
||||
IsValidUtf8 ([c].utf8Encode ++ b) ↔ IsValidUtf8 b := by
|
||||
refine ⟨?_, fun h => IsValidUtf8.append isValidUtf8_utf8Encode h⟩
|
||||
rintro ⟨l, hl⟩
|
||||
match l with
|
||||
| [] => simp at hl
|
||||
| d::l =>
|
||||
obtain rfl : c = d := by
|
||||
replace hl := congrArg (fun l => utf8DecodeChar? l 0) hl
|
||||
simpa [List.utf8DecodeChar?_utf8Encode_singleton_append,
|
||||
List.utf8DecodeChar?_utf8Encode_cons] using hl
|
||||
rw [← List.singleton_append (l := l), List.utf8Encode_append,
|
||||
ByteArray.append_right_inj] at hl
|
||||
exact hl ▸ isValidUtf8_utf8Encode
|
||||
|
||||
@[expose]
|
||||
def ByteArray.utf8Decode? (b : ByteArray) : Option (Array Char) :=
|
||||
go (b.size + 1) 0 #[] (by simp) (by simp)
|
||||
where
|
||||
go (fuel : Nat) (i : Nat) (acc : Array Char) (hi : i ≤ b.size) (hf : b.size - i < fuel) : Option (Array Char) :=
|
||||
match fuel, hf with
|
||||
| fuel + 1, _ =>
|
||||
if i = b.size then
|
||||
some acc
|
||||
else
|
||||
match h : utf8DecodeChar? b i with
|
||||
| none => none
|
||||
| some c => go fuel (i + c.utf8Size) (acc.push c)
|
||||
(le_size_of_utf8DecodeChar?_eq_some h)
|
||||
(have := c.utf8Size_pos; have := le_size_of_utf8DecodeChar?_eq_some h; by omega)
|
||||
termination_by structural fuel
|
||||
|
||||
theorem ByteArray.utf8Decode?.go.congr {b b' : ByteArray} {fuel fuel' i i' : Nat} {acc acc' : Array Char} {hi hi' hf hf'}
|
||||
(hbb' : b = b') (hii' : i = i') (hacc : acc = acc') :
|
||||
ByteArray.utf8Decode?.go b fuel i acc hi hf = ByteArray.utf8Decode?.go b' fuel' i' acc' hi' hf' := by
|
||||
subst hbb' hii' hacc
|
||||
fun_induction ByteArray.utf8Decode?.go b fuel i acc hi hf generalizing fuel' with
|
||||
| case1 =>
|
||||
rw [go.eq_def]
|
||||
split
|
||||
simp
|
||||
| case2 =>
|
||||
rw [go.eq_def]
|
||||
split <;> split
|
||||
· simp_all
|
||||
· split <;> simp_all
|
||||
| case3 =>
|
||||
conv => rhs; rw [go.eq_def]
|
||||
split <;> split
|
||||
· simp_all
|
||||
· split
|
||||
· simp_all
|
||||
· rename_i c₁ hc₁ ih _ _ _ _ _ c₂ hc₂
|
||||
obtain rfl : c₁ = c₂ := by rw [← Option.some_inj, ← hc₁, ← hc₂]
|
||||
apply ih
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.utf8Decode?_empty : ByteArray.empty.utf8Decode? = some #[] := by
|
||||
simp [utf8Decode?, utf8Decode?.go]
|
||||
|
||||
private theorem ByteArray.isSome_utf8Decode?go_iff {b : ByteArray} {fuel i : Nat} {hi : i ≤ b.size} {hf} {acc : Array Char} :
|
||||
(ByteArray.utf8Decode?.go b fuel i acc hi hf).isSome ↔ IsValidUtf8 (b.extract i b.size) := by
|
||||
fun_induction ByteArray.utf8Decode?.go with
|
||||
| case1 => simp
|
||||
| case2 fuel i hi hf acc h₁ h₂ =>
|
||||
simp only [Option.isSome_none, Bool.false_eq_true, false_iff]
|
||||
rintro ⟨l, hl⟩
|
||||
have : l ≠ [] := by
|
||||
rintro rfl
|
||||
simp at hl
|
||||
omega
|
||||
rw [← l.cons_head_tail this] at hl
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract, hl, List.utf8DecodeChar?_utf8Encode_cons] at h₂
|
||||
simp at h₂
|
||||
| case3 i acc hi fuel hf h₁ c h₂ ih =>
|
||||
rw [ih]
|
||||
have h₂' := h₂
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂'
|
||||
obtain ⟨l, hl⟩ := exists_of_utf8DecodeChar?_eq_some h₂'
|
||||
rw [ByteArray.extract_eq_extract_append_extract (i := i) (i + c.utf8Size) (by omega)
|
||||
(le_size_of_utf8DecodeChar?_eq_some h₂)] at hl ⊢
|
||||
rw [ByteArray.append_inj_left hl (by have := le_size_of_utf8DecodeChar?_eq_some h₂; simp; omega),
|
||||
← List.utf8Encode_singleton, isValidUtf8_utf8Encode_singleton_append_iff]
|
||||
|
||||
theorem ByteArray.isSome_utf8Decode?_iff {b : ByteArray} :
|
||||
b.utf8Decode?.isSome ↔ IsValidUtf8 b := by
|
||||
rw [utf8Decode?, isSome_utf8Decode?go_iff, extract_zero_size]
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_empty : "".bytes = ByteArray.empty := (rfl)
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
The internal implementation will perform destructive updates if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".append "def" = "abcdef"`
|
||||
* `"abc" ++ "def" = "abcdef"`
|
||||
* `"" ++ "" = ""`
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def String.append (s t : String) : String where
|
||||
bytes := s.bytes ++ t.bytes
|
||||
isValidUtf8 := s.isValidUtf8.append t.isValidUtf8
|
||||
|
||||
instance : Append String where
|
||||
append s t := s.append t
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_append {s t : String} : (s ++ t).bytes = s.bytes ++ t.bytes := (rfl)
|
||||
|
||||
theorem String.bytes_inj {s t : String} : s.bytes = t.bytes ↔ s = t := by
|
||||
refine ⟨fun h => ?_, (· ▸ rfl)⟩
|
||||
rcases s with ⟨s⟩
|
||||
rcases t with ⟨t⟩
|
||||
subst h
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.empty_append {s : String} : "" ++ s = s := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem String.append_empty {s : String} : s ++ "" = s := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp] theorem List.bytes_asString {l : List Char} : l.asString.bytes = l.utf8Encode := by
|
||||
simp [List.asString, String.mk]
|
||||
|
||||
@[simp]
|
||||
theorem List.asString_nil : List.asString [] = "" := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem List.asString_append {l₁ l₂ : List Char} : (l₁ ++ l₂).asString = l₁.asString ++ l₂.asString := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[expose]
|
||||
def String.Internal.toArray (b : String) : Array Char :=
|
||||
b.bytes.utf8Decode?.get (b.bytes.isSome_utf8Decode?_iff.2 b.isValidUtf8)
|
||||
|
||||
@[simp]
|
||||
theorem String.Internal.toArray_empty : String.Internal.toArray "" = #[] := by
|
||||
simp [toArray]
|
||||
|
||||
@[extern "lean_string_data", expose]
|
||||
def String.data (b : String) : List Char :=
|
||||
(String.Internal.toArray b).toList
|
||||
|
||||
@[simp]
|
||||
theorem String.data_empty : "".data = [] := by
|
||||
simp [data]
|
||||
|
||||
/--
|
||||
Returns the length of a string in Unicode code points.
|
||||
|
||||
Examples:
|
||||
* `"".length = 0`
|
||||
* `"abc".length = 3`
|
||||
* `"L∃∀N".length = 4`
|
||||
-/
|
||||
@[extern "lean_string_length"]
|
||||
def String.length (b : String) : Nat :=
|
||||
b.data.length
|
||||
|
||||
@[simp]
|
||||
theorem String.Internal.size_toArray {b : String} : (String.Internal.toArray b).size = b.length :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem String.length_data {b : String} : b.data.length = b.length := (rfl)
|
||||
|
||||
theorem String.exists_eq_asString (s : String) :
|
||||
∃ l : List Char, s = l.asString := by
|
||||
rcases s with ⟨_, ⟨l, rfl⟩⟩
|
||||
refine ⟨l, by simp [← String.bytes_inj]⟩
|
||||
|
||||
private theorem ByteArray.utf8Decode?go_eq_utf8Decode?go_extract {b : ByteArray} {fuel i : Nat} {hi : i ≤ b.size} {hf} {acc : Array Char} :
|
||||
utf8Decode?.go b fuel i acc hi hf = (utf8Decode?.go (b.extract i b.size) fuel 0 #[] (by simp) (by simp [hf])).map (acc ++ ·) := by
|
||||
fun_cases utf8Decode?.go b fuel i acc hi hf with
|
||||
| case1 =>
|
||||
rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_pos (by omega)]
|
||||
simp
|
||||
| case2 fuel hf₁ h₁ h₂ hf₂ =>
|
||||
rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_neg (by omega)]
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
|
||||
split <;> simp_all
|
||||
| case3 fuel hf₁ h₁ c h₂ hf₂ =>
|
||||
conv => rhs; rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_neg (by omega)]
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
|
||||
split
|
||||
· simp_all
|
||||
· rename_i c' hc'
|
||||
obtain rfl : c = c' := by
|
||||
rw [← Option.some_inj, ← h₂, hc']
|
||||
have := c.utf8Size_pos
|
||||
conv => lhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
|
||||
conv => rhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Option.map_map, ByteArray.extract_extract]
|
||||
have : (fun x => acc ++ x) ∘ (fun x => #[c] ++ x) = fun x => acc.push c ++ x := by funext; simp
|
||||
simp [(by omega : i + (b.size - i) = b.size), this]
|
||||
|
||||
theorem ByteArray.utf8Decode?_utf8Encode_singleton_append {l : ByteArray} {c : Char} :
|
||||
([c].utf8Encode ++ l).utf8Decode? = l.utf8Decode?.map (#[c] ++ ·) := by
|
||||
rw [utf8Decode?, utf8Decode?.go,
|
||||
if_neg (by simp [List.utf8Encode_singleton]; have := c.utf8Size_pos; omega)]
|
||||
split
|
||||
· simp_all [List.utf8DecodeChar?_utf8Encode_singleton_append]
|
||||
· rename_i d h
|
||||
obtain rfl : c = d := by simpa [List.utf8DecodeChar?_utf8Encode_singleton_append] using h
|
||||
rw [utf8Decode?go_eq_utf8Decode?go_extract, utf8Decode?]
|
||||
simp only [List.push_toArray, List.nil_append, Nat.zero_add]
|
||||
congr 1
|
||||
apply ByteArray.utf8Decode?.go.congr _ rfl rfl
|
||||
apply extract_append_eq_right
|
||||
simp [List.utf8Encode_singleton]
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Decode?_utf8Encode {l : List Char} :
|
||||
l.utf8Encode.utf8Decode? = some l.toArray := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons c l ih =>
|
||||
rw [← List.singleton_append, List.utf8Encode_append]
|
||||
simp only [ByteArray.utf8Decode?_utf8Encode_singleton_append, cons_append, nil_append,
|
||||
Option.map_eq_some_iff, Array.append_eq_toArray_iff, cons.injEq, true_and]
|
||||
refine ⟨l.toArray, ih, by simp⟩
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.utf8Encode_get_utf8Decode? {b : ByteArray} {h} :
|
||||
(b.utf8Decode?.get h).toList.utf8Encode = b := by
|
||||
obtain ⟨l, rfl⟩ := isSome_utf8Decode?_iff.1 h
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.data_asString {l : List Char} : l.asString.data = l := by
|
||||
simp [String.data, String.Internal.toArray]
|
||||
|
||||
@[simp]
|
||||
theorem String.asString_data {b : String} : b.data.asString = b := by
|
||||
obtain ⟨l, rfl⟩ := String.exists_eq_asString b
|
||||
rw [List.data_asString]
|
||||
|
||||
theorem List.asString_injective {l₁ l₂ : List Char} (h : l₁.asString = l₂.asString) : l₁ = l₂ := by
|
||||
simpa using congrArg String.data h
|
||||
|
||||
theorem List.asString_inj {l₁ l₂ : List Char} : l₁.asString = l₂.asString ↔ l₁ = l₂ :=
|
||||
⟨asString_injective, (· ▸ rfl)⟩
|
||||
|
||||
theorem String.data_injective {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ := by
|
||||
simpa using congrArg List.asString h
|
||||
|
||||
theorem String.data_inj {s₁ s₂ : String} : s₁.data = s₂.data ↔ s₁ = s₂ :=
|
||||
⟨data_injective, (· ▸ rfl)⟩
|
||||
|
||||
@[simp]
|
||||
theorem String.data_append {l₁ l₂ : String} : (l₁ ++ l₂).data = l₁.data ++ l₂.data := by
|
||||
apply List.asString_injective
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8encode_data {b : String} : b.data.utf8Encode = b.bytes := by
|
||||
have := congrArg String.bytes (String.asString_data (b := b))
|
||||
rwa [← List.bytes_asString]
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_empty : "".utf8ByteSize = 0 := (rfl)
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_append {s t : String} :
|
||||
(s ++ t).utf8ByteSize = s.utf8ByteSize + t.utf8ByteSize := by
|
||||
simp [utf8ByteSize]
|
||||
|
||||
@[simp]
|
||||
theorem String.size_bytes {s : String} : s.bytes.size = s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_push {s : String} {c : Char} : (s.push c).bytes = s.bytes ++ [c].utf8Encode := by
|
||||
simp [push]
|
||||
|
||||
-- This is just to keep the proof of `set_next_add` below from breaking; if that lemma goes away
|
||||
-- or the proof is rewritten, it can be removed.
|
||||
private noncomputable def String.utf8ByteSize' : String → Nat
|
||||
| s => go s.data
|
||||
where
|
||||
go : List Char → Nat
|
||||
| [] => 0
|
||||
| c::cs => go cs + c.utf8Size
|
||||
|
||||
private theorem String.utf8ByteSize'_eq (s : String) : s.utf8ByteSize' = s.utf8ByteSize := by
|
||||
suffices ∀ l, utf8ByteSize'.go l = l.asString.utf8ByteSize by
|
||||
obtain ⟨m, rfl⟩ := s.exists_eq_asString
|
||||
rw [utf8ByteSize', this, asString_data]
|
||||
intro l
|
||||
induction l with
|
||||
| nil => simp [utf8ByteSize'.go]
|
||||
| cons c cs ih =>
|
||||
rw [utf8ByteSize'.go, ih, ← List.singleton_append, List.asString_append,
|
||||
utf8ByteSize_append, Nat.add_comm]
|
||||
congr
|
||||
rw [← size_bytes, List.bytes_asString, List.utf8Encode_singleton,
|
||||
List.size_toByteArray, length_utf8EncodeChar]
|
||||
|
||||
end
|
||||
|
||||
namespace String
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
@@ -54,8 +413,6 @@ instance : LT String :=
|
||||
instance decidableLT (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
|
||||
List.decidableLT s₁.data s₂.data
|
||||
|
||||
|
||||
|
||||
/--
|
||||
Non-strict inequality on strings, typically used via the `≤` operator.
|
||||
|
||||
@@ -69,32 +426,6 @@ instance : LE String :=
|
||||
instance decLE (s₁ s₂ : String) : Decidable (s₁ ≤ s₂) :=
|
||||
inferInstanceAs (Decidable (Not _))
|
||||
|
||||
/--
|
||||
Returns the length of a string in Unicode code points.
|
||||
|
||||
Examples:
|
||||
* `"".length = 0`
|
||||
* `"abc".length = 3`
|
||||
* `"L∃∀N".length = 4`
|
||||
-/
|
||||
@[extern "lean_string_length", expose]
|
||||
def length : (@& String) → Nat
|
||||
| ⟨s⟩ => s.length
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
The internal implementation will perform destructive updates if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".append "def" = "abcdef"`
|
||||
* `"abc" ++ "def" = "abcdef"`
|
||||
* `"" ++ "" = ""`
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def append : String → (@& String) → String
|
||||
| ⟨a⟩, ⟨b⟩ => ⟨a ++ b⟩
|
||||
|
||||
/--
|
||||
Converts a string to a list of characters.
|
||||
|
||||
@@ -153,8 +484,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_get", expose]
|
||||
def get (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
utf8GetAux s.data 0 p
|
||||
|
||||
def utf8GetAux? : List Char → Pos → Pos → Option Char
|
||||
| [], _, _ => none
|
||||
@@ -175,7 +505,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_get_opt"]
|
||||
def get? : (@& String) → (@& Pos) → Option Char
|
||||
| ⟨s⟩, p => utf8GetAux? s 0 p
|
||||
| s, p => utf8GetAux? s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the character at position `p` of a string. Panics if `p` is not a valid position.
|
||||
@@ -191,7 +521,7 @@ Examples
|
||||
@[extern "lean_string_utf8_get_bang", expose]
|
||||
def get! (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
| s => utf8GetAux s.data 0 p
|
||||
|
||||
def utf8SetAux (c' : Char) : List Char → Pos → Pos → List Char
|
||||
| [], _, _ => []
|
||||
@@ -214,7 +544,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_set"]
|
||||
def set : String → (@& Pos) → Char → String
|
||||
| ⟨s⟩, i, c => ⟨utf8SetAux c s 0 i⟩
|
||||
| s, i, c => (utf8SetAux c s.data 0 i).asString
|
||||
|
||||
/--
|
||||
Replaces the character at position `p` in the string `s` with the result of applying `f` to that
|
||||
@@ -270,7 +600,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_prev", expose]
|
||||
def prev : (@& String) → (@& Pos) → Pos
|
||||
| ⟨s⟩, p => utf8PrevAux s 0 p
|
||||
| s, p => utf8PrevAux s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the first character in `s`. If `s = ""`, returns `(default : Char)`.
|
||||
@@ -336,7 +666,7 @@ Examples:
|
||||
@[extern "lean_string_utf8_get_fast", expose]
|
||||
def get' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
| s => utf8GetAux s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the next position in a string after position `p`. The result is unspecified if `p` is not a
|
||||
@@ -360,16 +690,6 @@ def next' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Pos :=
|
||||
let c := get s p
|
||||
p + c
|
||||
|
||||
theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
repeat first | apply iteInduction (motive := (0 < ·)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size ≤ 4 := by
|
||||
repeat first | apply iteInduction (motive := (· ≤ 4)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
|
||||
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
|
||||
|
||||
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
@@ -534,7 +854,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_extract", expose]
|
||||
def extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
| ⟨s⟩, b, e => if b.byteIdx ≥ e.byteIdx then "" else ⟨go₁ s 0 b e⟩
|
||||
| s, b, e => if b.byteIdx ≥ e.byteIdx then "" else (go₁ s.data 0 b e).asString
|
||||
where
|
||||
go₁ : List Char → Pos → Pos → Pos → List Char
|
||||
| [], _, _, _ => []
|
||||
@@ -1030,37 +1350,31 @@ theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p
|
||||
theorem set_next_add (s : String) (i : Pos) (c : Char) (b₁ b₂)
|
||||
(h : (s.next i).1 + b₁ = s.endPos.1 + b₂) :
|
||||
((s.set i c).next i).1 + b₁ = (s.set i c).endPos.1 + b₂ := by
|
||||
simp [next, get, set, endPos, utf8ByteSize] at h ⊢
|
||||
simp [next, get, set, endPos, ← utf8ByteSize'_eq, utf8ByteSize'] at h ⊢
|
||||
rw [Nat.add_comm i.1, Nat.add_assoc] at h ⊢
|
||||
let rec foo : ∀ cs a b₁ b₂,
|
||||
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize.go cs + b₂ →
|
||||
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
|
||||
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize'.go cs + b₂ →
|
||||
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize'.go (utf8SetAux c cs a i) + b₂
|
||||
| [], _, _, _, h => h
|
||||
| c'::cs, a, b₁, b₂, h => by
|
||||
unfold utf8SetAux
|
||||
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize.go] at h ⊢
|
||||
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize'.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize'.go] at h ⊢
|
||||
next =>
|
||||
rw [Nat.add_assoc, Nat.add_left_comm] at h ⊢; rw [Nat.add_left_cancel h]
|
||||
next =>
|
||||
rw [Nat.add_assoc] at h ⊢
|
||||
refine foo cs (a + c') b₁ (c'.utf8Size + b₂) h
|
||||
exact foo s.1 0 _ _ h
|
||||
exact foo s.data 0 _ _ h
|
||||
|
||||
theorem mapAux_lemma (s : String) (i : Pos) (c : Char) (h : ¬s.atEnd i) :
|
||||
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 :=
|
||||
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 := by
|
||||
suffices (s.set i c).endPos.1 - ((s.set i c).next i).1 = s.endPos.1 - (s.next i).1 by
|
||||
rw [this]
|
||||
apply Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next ..)
|
||||
Nat.sub.elim (motive := (_ = ·)) _ _
|
||||
(fun _ k e =>
|
||||
have := set_next_add _ _ _ k 0 e.symm
|
||||
Nat.sub_eq_of_eq_add <| this.symm.trans <| Nat.add_comm ..)
|
||||
(fun h => by
|
||||
have ⟨k, e⟩ := Nat.le.dest h
|
||||
rw [Nat.succ_add] at e
|
||||
have : ((s.set i c).next i).1 = _ := set_next_add _ _ c 0 k.succ e.symm
|
||||
exact Nat.sub_eq_zero_of_le (this ▸ Nat.le_add_right ..))
|
||||
have := set_next_add s i c (s.endPos.byteIdx - (s.next i).byteIdx) 0
|
||||
have := set_next_add s i c 0 ((s.next i).byteIdx - s.endPos.byteIdx)
|
||||
omega
|
||||
|
||||
@[specialize] def mapAux (f : Char → Char) (i : Pos) (s : String) : String :=
|
||||
if h : s.atEnd i then s
|
||||
@@ -2044,40 +2358,51 @@ def stripSuffix (s : String) (suff : String) : String :=
|
||||
|
||||
end String
|
||||
|
||||
namespace Char
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
|
||||
|
||||
end Char
|
||||
|
||||
namespace String
|
||||
|
||||
@[ext]
|
||||
theorem ext {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ :=
|
||||
show ⟨s₁.data⟩ = (⟨s₂.data⟩ : String) from h ▸ rfl
|
||||
|
||||
theorem ext_iff {s₁ s₂ : String} : s₁ = s₂ ↔ s₁.data = s₂.data := ⟨fun h => h ▸ rfl, ext⟩
|
||||
data_injective h
|
||||
|
||||
@[simp] theorem default_eq : default = "" := rfl
|
||||
|
||||
@[simp] theorem length_mk (s : List Char) : (String.mk s).length = s.length := rfl
|
||||
@[simp]
|
||||
theorem String.mk_eq_asString (s : List Char) : String.mk s = List.asString s := rfl
|
||||
|
||||
@[simp] theorem length_empty : "".length = 0 := rfl
|
||||
@[simp]
|
||||
theorem _root_.List.length_asString (s : List Char) : (List.asString s).length = s.length := by
|
||||
rw [← length_data, List.data_asString]
|
||||
|
||||
@[simp] theorem length_singleton (c : Char) : (String.singleton c).length = 1 := rfl
|
||||
@[simp] theorem length_empty : "".length = 0 := by simp [← length_data, data_empty]
|
||||
|
||||
@[simp]
|
||||
theorem bytes_singleton {c : Char} : (String.singleton c).bytes = [c].utf8Encode := by
|
||||
simp [singleton]
|
||||
|
||||
theorem singleton_eq {c : Char} : String.singleton c = [c].asString := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp] theorem data_singleton (c : Char) : (String.singleton c).data = [c] := by
|
||||
simp [singleton_eq]
|
||||
|
||||
@[simp]
|
||||
theorem length_singleton {c : Char} : (String.singleton c).length = 1 := by
|
||||
simp [← length_data]
|
||||
|
||||
theorem push_eq_append (c : Char) : String.push s c = s ++ singleton c := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp] theorem data_push (c : Char) : (String.push s c).data = s.data ++ [c] := by
|
||||
simp [push_eq_append]
|
||||
|
||||
@[simp] theorem length_push (c : Char) : (String.push s c).length = s.length + 1 := by
|
||||
rw [push, length_mk, List.length_append, List.length_singleton, Nat.succ.injEq]
|
||||
rfl
|
||||
simp [← length_data]
|
||||
|
||||
@[simp] theorem length_pushn (c : Char) (n : Nat) : (pushn s c n).length = s.length + n := by
|
||||
unfold pushn; induction n <;> simp [Nat.repeat, Nat.add_assoc, *]
|
||||
|
||||
@[simp] theorem length_append (s t : String) : (s ++ t).length = s.length + t.length := by
|
||||
simp only [length, append, List.length_append]
|
||||
|
||||
@[simp] theorem data_push (s : String) (c : Char) : (s.push c).data = s.data ++ [c] := rfl
|
||||
|
||||
@[simp] theorem data_append (s t : String) : (s ++ t).data = s.data ++ t.data := rfl
|
||||
simp [← length_data]
|
||||
|
||||
attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas
|
||||
|
||||
@@ -2161,10 +2486,8 @@ end Pos
|
||||
theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
|
||||
|
||||
@[simp] theorem prev_zero (s : String) : prev s 0 = 0 := by
|
||||
cases s with | mk cs
|
||||
cases cs
|
||||
next => rfl
|
||||
next => simp [prev, utf8PrevAux, Pos.le_iff]
|
||||
rw [prev]
|
||||
cases s.data <;> simp [utf8PrevAux, Pos.le_iff]
|
||||
|
||||
@[simp] theorem get'_eq (s : String) (p : Pos) (h) : get' s p h = get s p := rfl
|
||||
|
||||
@@ -2174,19 +2497,20 @@ theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
|
||||
-- so for proving can be unfolded.
|
||||
attribute [simp] toSubstring'
|
||||
|
||||
theorem singleton_eq (c : Char) : singleton c = ⟨[c]⟩ := rfl
|
||||
|
||||
@[simp] theorem data_singleton (c : Char) : (singleton c).data = [c] := rfl
|
||||
|
||||
@[simp] theorem append_empty (s : String) : s ++ "" = s := ext (List.append_nil _)
|
||||
|
||||
@[simp] theorem empty_append (s : String) : "" ++ s = s := rfl
|
||||
|
||||
theorem append_assoc (s₁ s₂ s₃ : String) : (s₁ ++ s₂) ++ s₃ = s₁ ++ (s₂ ++ s₃) :=
|
||||
ext (List.append_assoc ..)
|
||||
ext (by simp [data_append])
|
||||
|
||||
end String
|
||||
|
||||
namespace Char
|
||||
|
||||
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := by
|
||||
simp [toString_eq_singleton]
|
||||
|
||||
end Char
|
||||
|
||||
open String
|
||||
|
||||
namespace Substring
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.ByteArray.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -31,7 +32,11 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
| ⟨b, h⟩, c => ⟨b.append (List.utf8Encode [c]), ?pf⟩
|
||||
where finally
|
||||
have ⟨m, hm⟩ := h
|
||||
cases hm
|
||||
exact .intro (m ++ [c]) (by simp [List.utf8Encode, List.toByteArray_append'])
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
@@ -124,8 +129,21 @@ Examples:
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
@[extern "lean_string_mk", expose]
|
||||
def String.mk (data : List Char) : String :=
|
||||
⟨List.utf8Encode data,.intro data rfl⟩
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
@[expose]
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
String.mk s
|
||||
|
||||
namespace Substring.Internal
|
||||
|
||||
|
||||
1238
src/Init/Data/String/Decode.lean
Normal file
1238
src/Init/Data/String/Decode.lean
Normal file
File diff suppressed because it is too large
Load Diff
@@ -104,8 +104,7 @@ where
|
||||
|
||||
/--
|
||||
Decodes an array of bytes that encode a string as [UTF-8](https://en.wikipedia.org/wiki/UTF-8) into
|
||||
the corresponding string. Invalid UTF-8 characters in the byte array result in `(default : Char)`,
|
||||
or `'A'`, in the string.
|
||||
the corresponding string.
|
||||
-/
|
||||
@[extern "lean_string_from_utf8_unchecked"]
|
||||
def fromUTF8 (a : @& ByteArray) (h : validateUTF8 a) : String :=
|
||||
@@ -133,92 +132,15 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
|
||||
@[inline] def fromUTF8! (a : ByteArray) : String :=
|
||||
if h : validateUTF8 a then fromUTF8 a h else panic! "invalid UTF-8 string"
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def utf8EncodeCharFast (c : Char) : List UInt8 :=
|
||||
let v := c.val
|
||||
if v ≤ 0x7f then
|
||||
[v.toUInt8]
|
||||
else if v ≤ 0x7ff then
|
||||
[(v >>> 6).toUInt8 &&& 0x1f ||| 0xc0,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else if v ≤ 0xffff then
|
||||
[(v >>> 12).toUInt8 &&& 0x0f ||| 0xe0,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else
|
||||
[(v >>> 18).toUInt8 &&& 0x07 ||| 0xf0,
|
||||
(v >>> 12).toUInt8 &&& 0x3f ||| 0x80,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
private theorem Nat.add_two_pow_eq_or_of_lt {b : Nat} (i : Nat) (b_lt : b < 2 ^ i) (a : Nat) :
|
||||
b + 2 ^ i * a = b ||| 2 ^ i * a := by
|
||||
rw [Nat.add_comm, Nat.or_comm, Nat.two_pow_add_eq_or_of_lt b_lt]
|
||||
|
||||
@[csimp]
|
||||
theorem utf8EncodeChar_eq_utf8EncodeCharFast : @utf8EncodeChar = @utf8EncodeCharFast := by
|
||||
funext c
|
||||
simp only [utf8EncodeChar, utf8EncodeCharFast, UInt8.ofNat_uInt32ToNat, UInt8.ofNat_add,
|
||||
UInt8.reduceOfNat, UInt32.le_iff_toNat_le, UInt32.reduceToNat]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 5 (by omega) 6,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 5, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 4 (by omega) 14,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 4, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 3 (by omega) 30,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 3, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 12) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
|
||||
simp [Char.utf8Size, utf8EncodeChar_eq_utf8EncodeCharFast, utf8EncodeCharFast]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
/--
|
||||
Encodes a string in UTF-8 as an array of bytes.
|
||||
-/
|
||||
@[extern "lean_string_to_utf8"]
|
||||
def toUTF8 (a : @& String) : ByteArray :=
|
||||
⟨⟨a.data.flatMap utf8EncodeChar⟩⟩
|
||||
a.bytes
|
||||
|
||||
@[simp] theorem size_toUTF8 (s : String) : s.toUTF8.size = s.utf8ByteSize := by
|
||||
simp [toUTF8, ByteArray.size, Array.size, utf8ByteSize, List.flatMap]
|
||||
induction s.data <;> simp [List.map, utf8ByteSize.go, Nat.add_comm, *]
|
||||
rfl
|
||||
|
||||
/--
|
||||
Accesses the indicated byte in the UTF-8 encoding of a string.
|
||||
|
||||
@@ -142,9 +142,9 @@ inductive LiftRel (r : α → γ → Prop) (s : β → δ → Prop) : α ⊕ β
|
||||
@[simp, grind =] theorem liftRel_inl_inl : LiftRel r s (inl a) (inl c) ↔ r a c :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inl⟩
|
||||
|
||||
@[simp, grind] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
|
||||
@[simp, grind ←] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
|
||||
|
||||
@[simp, grind] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
|
||||
@[simp, grind ←] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
|
||||
|
||||
@[simp, grind =] theorem liftRel_inr_inr : LiftRel r s (inr b) (inr d) ↔ s b d :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inr⟩
|
||||
@@ -179,7 +179,7 @@ attribute [simp] Lex.sep
|
||||
@[simp, grind =] theorem lex_inr_inr : Lex r s (inr b₁) (inr b₂) ↔ s b₁ b₂ :=
|
||||
⟨fun h => by cases h; assumption, Lex.inr⟩
|
||||
|
||||
@[simp, grind] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
|
||||
@[simp, grind ←] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
|
||||
|
||||
instance instDecidableRelSumLex [DecidableRel r] [DecidableRel s] : DecidableRel (Lex r s)
|
||||
| inl _, inl _ => decidable_of_iff' _ lex_inl_inl
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Extra
|
||||
public import Init.Data.String.Extra
|
||||
|
||||
/-!
|
||||
Here we give the. implementation of `Name.toString`. There is also a private implementation in
|
||||
|
||||
@@ -21,12 +21,7 @@ open Nat
|
||||
|
||||
/-- Converts a `Fin UInt8.size` into the corresponding `UInt8`. -/
|
||||
@[inline] def UInt8.ofFin (a : Fin UInt8.size) : UInt8 := ⟨⟨a⟩⟩
|
||||
@[deprecated UInt8.ofBitVec (since := "2025-02-12"), inherit_doc UInt8.ofBitVec]
|
||||
def UInt8.mk (bitVec : BitVec 8) : UInt8 :=
|
||||
UInt8.ofBitVec bitVec
|
||||
@[inline, deprecated UInt8.ofNatLT (since := "2025-02-13"), inherit_doc UInt8.ofNatLT]
|
||||
def UInt8.ofNatCore (n : Nat) (h : n < UInt8.size) : UInt8 :=
|
||||
UInt8.ofNatLT n h
|
||||
|
||||
|
||||
/-- Converts an `Int` to a `UInt8` by taking the (non-negative remainder of the division by `2 ^ 8`. -/
|
||||
def UInt8.ofInt (x : Int) : UInt8 := ofNat (x % 2 ^ 8).toNat
|
||||
@@ -190,12 +185,6 @@ instance : Min UInt8 := minOfLe
|
||||
|
||||
/-- Converts a `Fin UInt16.size` into the corresponding `UInt16`. -/
|
||||
@[inline] def UInt16.ofFin (a : Fin UInt16.size) : UInt16 := ⟨⟨a⟩⟩
|
||||
@[deprecated UInt16.ofBitVec (since := "2025-02-12"), inherit_doc UInt16.ofBitVec]
|
||||
def UInt16.mk (bitVec : BitVec 16) : UInt16 :=
|
||||
UInt16.ofBitVec bitVec
|
||||
@[inline, deprecated UInt16.ofNatLT (since := "2025-02-13"), inherit_doc UInt16.ofNatLT]
|
||||
def UInt16.ofNatCore (n : Nat) (h : n < UInt16.size) : UInt16 :=
|
||||
UInt16.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt16` by taking the (non-negative remainder of the division by `2 ^ 16`. -/
|
||||
def UInt16.ofInt (x : Int) : UInt16 := ofNat (x % 2 ^ 16).toNat
|
||||
@@ -406,12 +395,6 @@ instance : Min UInt16 := minOfLe
|
||||
|
||||
/-- Converts a `Fin UInt32.size` into the corresponding `UInt32`. -/
|
||||
@[inline] def UInt32.ofFin (a : Fin UInt32.size) : UInt32 := ⟨⟨a⟩⟩
|
||||
@[deprecated UInt32.ofBitVec (since := "2025-02-12"), inherit_doc UInt32.ofBitVec]
|
||||
def UInt32.mk (bitVec : BitVec 32) : UInt32 :=
|
||||
UInt32.ofBitVec bitVec
|
||||
@[inline, deprecated UInt32.ofNatLT (since := "2025-02-13"), inherit_doc UInt32.ofNatLT]
|
||||
def UInt32.ofNatCore (n : Nat) (h : n < UInt32.size) : UInt32 :=
|
||||
UInt32.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt32` by taking the (non-negative remainder of the division by `2 ^ 32`. -/
|
||||
def UInt32.ofInt (x : Int) : UInt32 := ofNat (x % 2 ^ 32).toNat
|
||||
@@ -585,12 +568,6 @@ def Bool.toUInt32 (b : Bool) : UInt32 := if b then 1 else 0
|
||||
|
||||
/-- Converts a `Fin UInt64.size` into the corresponding `UInt64`. -/
|
||||
@[inline] def UInt64.ofFin (a : Fin UInt64.size) : UInt64 := ⟨⟨a⟩⟩
|
||||
@[deprecated UInt64.ofBitVec (since := "2025-02-12"), inherit_doc UInt64.ofBitVec]
|
||||
def UInt64.mk (bitVec : BitVec 64) : UInt64 :=
|
||||
UInt64.ofBitVec bitVec
|
||||
@[inline, deprecated UInt64.ofNatLT (since := "2025-02-13"), inherit_doc UInt64.ofNatLT]
|
||||
def UInt64.ofNatCore (n : Nat) (h : n < UInt64.size) : UInt64 :=
|
||||
UInt64.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `UInt64` by taking the (non-negative remainder of the division by `2 ^ 64`. -/
|
||||
def UInt64.ofInt (x : Int) : UInt64 := ofNat (x % 2 ^ 64).toNat
|
||||
@@ -799,12 +776,6 @@ instance : Min UInt64 := minOfLe
|
||||
|
||||
/-- Converts a `Fin USize.size` into the corresponding `USize`. -/
|
||||
@[inline] def USize.ofFin (a : Fin USize.size) : USize := ⟨⟨a⟩⟩
|
||||
@[deprecated USize.ofBitVec (since := "2025-02-12"), inherit_doc USize.ofBitVec]
|
||||
def USize.mk (bitVec : BitVec System.Platform.numBits) : USize :=
|
||||
USize.ofBitVec bitVec
|
||||
@[inline, deprecated USize.ofNatLT (since := "2025-02-13"), inherit_doc USize.ofNatLT]
|
||||
def USize.ofNatCore (n : Nat) (h : n < USize.size) : USize :=
|
||||
USize.ofNatLT n h
|
||||
|
||||
/-- Converts an `Int` to a `USize` by taking the (non-negative remainder of the division by `2 ^ numBits`. -/
|
||||
def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toNat
|
||||
@@ -812,14 +783,6 @@ def USize.ofInt (x : Int) : USize := ofNat (x % 2 ^ System.Platform.numBits).toN
|
||||
@[simp] theorem USize.le_size : 2 ^ 32 ≤ USize.size := by cases USize.size_eq <;> simp_all
|
||||
@[simp] theorem USize.size_le : USize.size ≤ 2 ^ 64 := by cases USize.size_eq <;> simp_all
|
||||
|
||||
@[deprecated USize.size_le (since := "2025-02-24")]
|
||||
theorem usize_size_le : USize.size ≤ 18446744073709551616 :=
|
||||
USize.size_le
|
||||
|
||||
@[deprecated USize.le_size (since := "2025-02-24")]
|
||||
theorem le_usize_size : 4294967296 ≤ USize.size :=
|
||||
USize.le_size
|
||||
|
||||
/--
|
||||
Multiplies two word-sized unsigned integers, wrapping around on overflow. Usually accessed via the
|
||||
`*` operator.
|
||||
|
||||
@@ -26,8 +26,6 @@ open Nat
|
||||
|
||||
/-- Converts a `UInt8` into the corresponding `Fin UInt8.size`. -/
|
||||
def UInt8.toFin (x : UInt8) : Fin UInt8.size := x.toBitVec.toFin
|
||||
@[deprecated UInt8.toFin (since := "2025-02-12"), inherit_doc UInt8.toFin]
|
||||
def UInt8.val (x : UInt8) : Fin UInt8.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to an 8-bit unsigned integer, returning the largest representable value if
|
||||
@@ -67,8 +65,6 @@ instance UInt8.instOfNat : OfNat UInt8 n := ⟨UInt8.ofNat n⟩
|
||||
|
||||
/-- Converts a `UInt16` into the corresponding `Fin UInt16.size`. -/
|
||||
def UInt16.toFin (x : UInt16) : Fin UInt16.size := x.toBitVec.toFin
|
||||
@[deprecated UInt16.toFin (since := "2025-02-12"), inherit_doc UInt16.toFin]
|
||||
def UInt16.val (x : UInt16) : Fin UInt16.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to a 16-bit unsigned integer, wrapping on overflow.
|
||||
@@ -134,8 +130,6 @@ instance UInt16.instOfNat : OfNat UInt16 n := ⟨UInt16.ofNat n⟩
|
||||
|
||||
/-- Converts a `UInt32` into the corresponding `Fin UInt32.size`. -/
|
||||
def UInt32.toFin (x : UInt32) : Fin UInt32.size := x.toBitVec.toFin
|
||||
@[deprecated UInt32.toFin (since := "2025-02-12"), inherit_doc UInt32.toFin]
|
||||
def UInt32.val (x : UInt32) : Fin UInt32.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to a 32-bit unsigned integer, wrapping on overflow.
|
||||
@@ -149,8 +143,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_uint32_of_nat"]
|
||||
def UInt32.ofNat (n : @& Nat) : UInt32 := ⟨BitVec.ofNat 32 n⟩
|
||||
@[inline, deprecated UInt32.ofNatLT (since := "2025-02-13"), inherit_doc UInt32.ofNatLT]
|
||||
def UInt32.ofNat' (n : Nat) (h : n < UInt32.size) : UInt32 := UInt32.ofNatLT n h
|
||||
|
||||
/--
|
||||
Converts a natural number to a 32-bit unsigned integer, returning the largest representable value if
|
||||
the number is too large.
|
||||
@@ -210,23 +203,14 @@ theorem UInt32.ofNatLT_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UIn
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat,
|
||||
Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.ofNatLT_lt_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.ofNat'_lt_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
n < m → UInt32.ofNatLT n h1 < UInt32.ofNat m := UInt32.ofNatLT_lt_of_lt h1 h2
|
||||
|
||||
theorem UInt32.lt_ofNatLT_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
m < n → UInt32.ofNat m < UInt32.ofNatLT n h1 := by
|
||||
simp only [(· < ·), BitVec.toNat, ofNatLT, BitVec.ofNatLT, ofNat, BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat,
|
||||
Fin.ofNat, Nat.mod_eq_of_lt h2, imp_self]
|
||||
|
||||
@[deprecated UInt32.lt_ofNatLT_of_lt (since := "2025-02-13")]
|
||||
theorem UInt32.lt_ofNat'_of_lt {n m : Nat} (h1 : n < UInt32.size) (h2 : m < UInt32.size) :
|
||||
m < n → UInt32.ofNat m < UInt32.ofNatLT n h1 := UInt32.lt_ofNatLT_of_lt h1 h2
|
||||
|
||||
/-- Converts a `UInt64` into the corresponding `Fin UInt64.size`. -/
|
||||
def UInt64.toFin (x : UInt64) : Fin UInt64.size := x.toBitVec.toFin
|
||||
@[deprecated UInt64.toFin (since := "2025-02-12"), inherit_doc UInt64.toFin]
|
||||
def UInt64.val (x : UInt64) : Fin UInt64.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts a natural number to a 64-bit unsigned integer, wrapping on overflow.
|
||||
|
||||
@@ -315,18 +299,9 @@ def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨⟨a.toNat, Nat.lt_trans a.toBit
|
||||
|
||||
instance UInt64.instOfNat : OfNat UInt64 n := ⟨UInt64.ofNat n⟩
|
||||
|
||||
@[deprecated USize.size_eq (since := "2025-02-24")]
|
||||
theorem usize_size_eq : USize.size = 4294967296 ∨ USize.size = 18446744073709551616 :=
|
||||
USize.size_eq
|
||||
|
||||
@[deprecated USize.size_pos (since := "2025-02-24")]
|
||||
theorem usize_size_pos : 0 < USize.size :=
|
||||
USize.size_pos
|
||||
|
||||
/-- Converts a `USize` into the corresponding `Fin USize.size`. -/
|
||||
def USize.toFin (x : USize) : Fin USize.size := x.toBitVec.toFin
|
||||
@[deprecated USize.toFin (since := "2025-02-12"), inherit_doc USize.toFin]
|
||||
def USize.val (x : USize) : Fin USize.size := x.toFin
|
||||
|
||||
/--
|
||||
Converts an arbitrary-precision natural number to an unsigned word-sized integer, wrapping around on
|
||||
overflow.
|
||||
|
||||
@@ -1327,3 +1327,14 @@ theorem UInt64.right_le_or {a b : UInt64} : b ≤ a ||| b := by
|
||||
simpa [UInt64.le_iff_toNat_le] using Nat.right_le_or
|
||||
theorem USize.right_le_or {a b : USize} : b ≤ a ||| b := by
|
||||
simpa [USize.le_iff_toNat_le] using Nat.right_le_or
|
||||
|
||||
theorem UInt8.and_lt_add_one {b c : UInt8} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt8.lt_of_le_of_lt UInt8.and_le_right (UInt8.lt_add_one h)
|
||||
theorem UInt16.and_lt_add_one {b c : UInt16} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt16.lt_of_le_of_lt UInt16.and_le_right (UInt16.lt_add_one h)
|
||||
theorem UInt32.and_lt_add_one {b c : UInt32} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt32.lt_of_le_of_lt UInt32.and_le_right (UInt32.lt_add_one h)
|
||||
theorem UInt64.and_lt_add_one {b c : UInt64} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt64.lt_of_le_of_lt UInt64.and_le_right (UInt64.lt_add_one h)
|
||||
theorem USize.and_lt_add_one {b c : USize} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
USize.lt_of_le_of_lt USize.and_le_right (USize.lt_add_one h)
|
||||
|
||||
@@ -42,9 +42,6 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
|
||||
@[simp] theorem toNat_ofBitVec : (ofBitVec a).toNat = a.toNat := (rfl)
|
||||
|
||||
@[deprecated toNat_ofBitVec (since := "2025-02-12")]
|
||||
theorem toNat_mk : (ofBitVec a).toNat = a.toNat := (rfl)
|
||||
|
||||
@[simp] theorem toNat_ofNat' {n : Nat} : (ofNat n).toNat = n % 2 ^ $bits := BitVec.toNat_ofNat ..
|
||||
|
||||
-- Not `simp` because we have simprocs which will avoid the modulo.
|
||||
@@ -52,34 +49,14 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
|
||||
@[simp] theorem toNat_ofNatLT {n : Nat} {h : n < size} : (ofNatLT n h).toNat = n := BitVec.toNat_ofNatLT ..
|
||||
|
||||
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
|
||||
theorem toNat_ofNatCore {n : Nat} {h : n < size} : (ofNatLT n h).toNat = n := BitVec.toNat_ofNatLT ..
|
||||
|
||||
@[simp] theorem toFin_val (x : $typeName) : x.toFin.val = x.toNat := (rfl)
|
||||
@[deprecated toFin_val (since := "2025-02-12")]
|
||||
theorem val_val_eq_toNat (x : $typeName) : x.toFin.val = x.toNat := (rfl)
|
||||
|
||||
@[simp] theorem toNat_toBitVec (x : $typeName) : x.toBitVec.toNat = x.toNat := (rfl)
|
||||
@[simp] theorem toFin_toBitVec (x : $typeName) : x.toBitVec.toFin = x.toFin := (rfl)
|
||||
|
||||
@[deprecated toNat_toBitVec (since := "2025-02-21")]
|
||||
theorem toNat_toBitVec_eq_toNat (x : $typeName) : x.toBitVec.toNat = x.toNat := (rfl)
|
||||
|
||||
@[simp] theorem ofBitVec_toBitVec : ∀ (a : $typeName), ofBitVec a.toBitVec = a
|
||||
| ⟨_, _⟩ => rfl
|
||||
|
||||
@[deprecated ofBitVec_toBitVec (since := "2025-02-21")]
|
||||
theorem ofBitVec_toBitVec_eq : ∀ (a : $typeName), ofBitVec a.toBitVec = a :=
|
||||
ofBitVec_toBitVec
|
||||
|
||||
@[deprecated ofBitVec_toBitVec_eq (since := "2025-02-12")]
|
||||
theorem mk_toBitVec_eq : ∀ (a : $typeName), ofBitVec a.toBitVec = a
|
||||
| ⟨_, _⟩ => rfl
|
||||
|
||||
@[deprecated "Use `toNat_toBitVec` and `toNat_ofNat_of_lt`." (since := "2025-03-05")]
|
||||
theorem toBitVec_eq_of_lt {a : Nat} : a < size → (ofNat a).toBitVec.toNat = a :=
|
||||
Nat.mod_eq_of_lt
|
||||
|
||||
theorem toBitVec_ofNat' (n : Nat) : (ofNat n).toBitVec = BitVec.ofNat _ n := (rfl)
|
||||
|
||||
theorem toNat_ofNat_of_lt' {n : Nat} (h : n < size) : (ofNat n).toNat = n := by
|
||||
@@ -140,17 +117,10 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
protected theorem eq_of_toFin_eq {a b : $typeName} (h : a.toFin = b.toFin) : a = b := by
|
||||
rcases a with ⟨⟨_⟩⟩; rcases b with ⟨⟨_⟩⟩; simp_all [toFin]
|
||||
open $typeName (eq_of_toFin_eq) in
|
||||
@[deprecated eq_of_toFin_eq (since := "2025-02-12")]
|
||||
protected theorem eq_of_val_eq {a b : $typeName} (h : a.toFin = b.toFin) : a = b :=
|
||||
eq_of_toFin_eq h
|
||||
|
||||
open $typeName (eq_of_toFin_eq) in
|
||||
protected theorem toFin_inj {a b : $typeName} : a.toFin = b.toFin ↔ a = b :=
|
||||
Iff.intro eq_of_toFin_eq (congrArg toFin)
|
||||
open $typeName (toFin_inj) in
|
||||
@[deprecated toFin_inj (since := "2025-02-12")]
|
||||
protected theorem val_inj {a b : $typeName} : a.toFin = b.toFin ↔ a = b :=
|
||||
toFin_inj
|
||||
|
||||
open $typeName (eq_of_toBitVec_eq) in
|
||||
protected theorem toBitVec_ne_of_ne {a b : $typeName} (h : a ≠ b) : a.toBitVec ≠ b.toBitVec :=
|
||||
@@ -236,8 +206,6 @@ instance : LawfulOrderLT $typeName where
|
||||
|
||||
@[simp]
|
||||
theorem toFin_ofNat (n : Nat) : toFin (no_index (OfNat.ofNat n)) = OfNat.ofNat n := (rfl)
|
||||
@[deprecated toFin_ofNat (since := "2025-02-12")]
|
||||
theorem val_ofNat (n : Nat) : toFin (no_index (OfNat.ofNat n)) = OfNat.ofNat n := (rfl)
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem toBitVec_ofNat (n : Nat) : toBitVec (no_index (OfNat.ofNat n)) = BitVec.ofNat _ n := (rfl)
|
||||
@@ -245,9 +213,6 @@ instance : LawfulOrderLT $typeName where
|
||||
@[simp]
|
||||
theorem ofBitVec_ofNat (n : Nat) : ofBitVec (BitVec.ofNat _ n) = OfNat.ofNat n := (rfl)
|
||||
|
||||
@[deprecated ofBitVec_ofNat (since := "2025-02-12")]
|
||||
theorem mk_ofNat (n : Nat) : ofBitVec (BitVec.ofNat _ n) = OfNat.ofNat n := (rfl)
|
||||
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_add {a b : $typeName} : (a + b).toBitVec = a.toBitVec + b.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_sub {a b : $typeName} : (a - b).toBitVec = a.toBitVec - b.toBitVec := (rfl)
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_mul {a b : $typeName} : (a * b).toBitVec = a.toBitVec * b.toBitVec := (rfl)
|
||||
@@ -311,6 +276,13 @@ theorem UInt64.ofNat_mod_size : ofNat (x % 2 ^ 64) = ofNat x := by
|
||||
theorem USize.ofNat_mod_size : ofNat (x % 2 ^ System.Platform.numBits) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat]
|
||||
|
||||
theorem UInt8.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt16.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt32.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt64.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem USize.ofNat_size : ofNat size = 0 := by
|
||||
simp [ofNat, BitVec.ofNat, USize.eq_iff_toBitVec_eq]
|
||||
|
||||
theorem UInt8.lt_ofNat_iff {n : UInt8} {m : Nat} (h : m < size) : n < ofNat m ↔ n.toNat < m := by
|
||||
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
|
||||
theorem UInt8.ofNat_lt_iff {n : UInt8} {m : Nat} (h : m < size) : ofNat m < n ↔ m < n.toNat := by
|
||||
@@ -3156,3 +3128,15 @@ protected theorem USize.sub_lt {a b : USize} (hb : 0 < b) (hab : b ≤ a) : a -
|
||||
rw [lt_iff_toNat_lt, USize.toNat_sub_of_le _ _ hab]
|
||||
refine Nat.sub_lt ?_ (USize.lt_iff_toNat_lt.1 hb)
|
||||
exact USize.lt_iff_toNat_lt.1 (USize.lt_of_lt_of_le hb hab)
|
||||
|
||||
theorem UInt8.lt_add_one {c : UInt8} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt8.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt8.toBitVec_inj] using h))
|
||||
theorem UInt16.lt_add_one {c : UInt16} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt16.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt16.toBitVec_inj] using h))
|
||||
theorem UInt32.lt_add_one {c : UInt32} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt32.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt32.toBitVec_inj] using h))
|
||||
theorem UInt64.lt_add_one {c : UInt64} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt64.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt64.toBitVec_inj] using h))
|
||||
theorem USize.lt_add_one {c : USize} (h : c ≠ -1) : c < c + 1 :=
|
||||
USize.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one
|
||||
(by simpa [← USize.toBitVec_inj, BitVec.neg_one_eq_allOnes] using h))
|
||||
|
||||
@@ -172,9 +172,6 @@ theorem attach_map_val (xs : Vector α n) (f : α → β) :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
-- The argument `xs : Vector α n` is explicit to allow rewriting from right to left.
|
||||
theorem attach_map_subtype_val (xs : Vector α n) : xs.attach.map Subtype.val = xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -185,22 +182,19 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {xs : Vector α n}
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} {xs : Vector α n} (H : ∀ a ∈ xs, p a) :
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (xs : Vector α n) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem mem_attachWith {xs : Vector α n} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -211,12 +205,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
theorem pmap_eq_self {xs : Vector α n} {p : α → Prop} {hp : ∀ (a : α), a ∈ xs → p a}
|
||||
{f : (a : α) → p a → α} : xs.pmap f hp = xs ↔ ∀ a (h : a ∈ xs), f a (hp a h) = a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -344,9 +339,6 @@ theorem map_attach_eq_pmap {xs : Vector α n} {f : { x // x ∈ xs } → β} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f : ∀ b, q b → γ} {xs : Vector α n} (H₁ H₂) :
|
||||
pmap f (pmap g xs H₁) H₂ =
|
||||
|
||||
@@ -36,7 +36,7 @@ structure Vector (α : Type u) (n : Nat) where
|
||||
size_toArray : toArray.size = n
|
||||
deriving Repr, DecidableEq
|
||||
|
||||
attribute [simp, grind] Vector.size_toArray
|
||||
attribute [simp, grind =] Vector.size_toArray
|
||||
|
||||
/--
|
||||
Converts an array to a vector. The resulting vector's size is the array's size.
|
||||
|
||||
@@ -32,11 +32,11 @@ open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp, grind] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
|
||||
@[simp, grind] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
@[simp, grind =] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
|
||||
@[simp, grind =] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem findSome?_singleton {a : α} {f : α → Option β} : #v[a].findSome? f = f a := by
|
||||
simp
|
||||
|
||||
@@ -228,11 +228,12 @@ theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a
|
||||
simp at h
|
||||
simpa using Array.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [Array.get_find?_mem]
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_map {f : β → α} {xs : Vector β n} :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@@ -266,12 +266,12 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
|
||||
|
||||
/-! ### toArray lemmas -/
|
||||
|
||||
@[simp, grind] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
|
||||
@[simp, grind =] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
|
||||
xs.toArray[i] = xs[i]'(by simpa using h) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
|
||||
xs.toArray[i]? = xs[i]? := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -280,45 +280,45 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
|
||||
(xs ++ ys).toArray = xs.toArray ++ ys.toArray := rfl
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
@[simp, grind] theorem toArray_drop {xs : Vector α n} {i} :
|
||||
@[simp, grind =] theorem toArray_drop {xs : Vector α n} {i} :
|
||||
(xs.drop i).toArray = xs.toArray.extract i n := by
|
||||
simp [drop]
|
||||
|
||||
@[simp, grind =] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_emptyWithCapacity {cap} :
|
||||
@[simp, grind =] theorem toArray_emptyWithCapacity {cap} :
|
||||
(Vector.emptyWithCapacity (α := α) cap).toArray = Array.emptyWithCapacity cap := rfl
|
||||
|
||||
@[deprecated toArray_emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev toArray_mkEmpty := @toArray_emptyWithCapacity
|
||||
|
||||
@[simp, grind] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
|
||||
@[simp, grind =] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
|
||||
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
|
||||
@[simp, grind =] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
|
||||
(xs.eraseIdx! i).toArray = xs.toArray.eraseIdx! i := by
|
||||
cases xs; simp_all [Array.eraseIdx!]
|
||||
|
||||
@[simp, grind] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
|
||||
@[simp, grind =] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
|
||||
(xs.insertIdx i x h).toArray = xs.toArray.insertIdx i x (by simp [h]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i ≤ n) :
|
||||
@[simp, grind =] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i ≤ n) :
|
||||
(xs.insertIdx! i x).toArray = xs.toArray.insertIdx! i x := by
|
||||
cases xs; simp_all [Array.insertIdx!]
|
||||
|
||||
@[simp, grind] theorem toArray_cast {xs : Vector α n} (h : n = m) :
|
||||
@[simp, grind =] theorem toArray_cast {xs : Vector α n} (h : n = m) :
|
||||
(xs.cast h).toArray = xs.toArray := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_extract {xs : Vector α n} {start stop} :
|
||||
@[simp, grind =] theorem toArray_extract {xs : Vector α n} {start stop} :
|
||||
(xs.extract start stop).toArray = xs.toArray.extract start stop := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_map {f : α → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_map {f : α → β} {xs : Vector α n} :
|
||||
(xs.map f).toArray = xs.toArray.map f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_mapIdx {f : Nat → α → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapIdx {f : Nat → α → β} {xs : Vector α n} :
|
||||
(xs.mapIdx f).toArray = xs.toArray.mapIdx f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_mapFinIdx {f : (i : Nat) → α → (h : i < n) → β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapFinIdx {f : (i : Nat) → α → (h : i < n) → β} {xs : Vector α n} :
|
||||
(xs.mapFinIdx f).toArray =
|
||||
xs.toArray.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) :=
|
||||
rfl
|
||||
@@ -336,42 +336,42 @@ private theorem toArray_mapM_go [Monad m] [LawfulMonad m] {f : α → m β} {xs
|
||||
rfl
|
||||
· simp
|
||||
|
||||
@[simp, grind] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α → m β} {xs : Vector α n} :
|
||||
toArray <$> xs.mapM f = xs.toArray.mapM f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
unfold mapM
|
||||
rw [toArray_mapM_go]
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem toArray_ofFn {f : Fin n → α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
|
||||
@[simp, grind =] theorem toArray_ofFn {f : Fin n → α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
|
||||
@[simp, grind =] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
|
||||
@[simp, grind =] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
|
||||
@[simp, grind =] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
|
||||
(xs.toArray == ys.toArray) = (xs == ys) := by
|
||||
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
|
||||
|
||||
@[simp, grind] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
|
||||
@[simp, grind =] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
|
||||
@[simp, grind =] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_set {xs : Vector α n} {i x} (h) :
|
||||
@[simp, grind =] theorem toArray_set {xs : Vector α n} {i x} (h) :
|
||||
(xs.set i x).toArray = xs.toArray.set i x (by simpa using h):= rfl
|
||||
|
||||
@[simp, grind] theorem toArray_set! {xs : Vector α n} {i x} :
|
||||
@[simp, grind =] theorem toArray_set! {xs : Vector α n} {i x} :
|
||||
(xs.set! i x).toArray = xs.toArray.set! i x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
|
||||
@[simp, grind =] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
|
||||
(xs.setIfInBounds i x).toArray = xs.toArray.setIfInBounds i x := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
|
||||
@[simp, grind =] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
|
||||
@[simp, grind =] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
|
||||
xs.toArray.swap i j (by simp [hj]) (by simp [hi]) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
|
||||
@[simp, grind =] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
|
||||
(xs.swapIfInBounds i j).toArray = xs.toArray.swapIfInBounds i j := rfl
|
||||
|
||||
theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
|
||||
@@ -383,98 +383,98 @@ theorem toArray_swapAt! {xs : Vector α n} {i x} :
|
||||
((xs.swapAt! i x).fst, (xs.swapAt! i x).snd.toArray) =
|
||||
((xs.toArray.swapAt! i x).fst, (xs.toArray.swapAt! i x).snd) := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
|
||||
@[simp, grind =] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
@[simp, grind =] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
(xs.zipIdx k).toArray = xs.toArray.zipIdx k := rfl
|
||||
|
||||
@[simp, grind] theorem toArray_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
@[simp, grind =] theorem toArray_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
(Vector.zipWith f as bs).toArray = Array.zipWith f as.toArray bs.toArray := rfl
|
||||
|
||||
@[simp, grind] theorem anyM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem anyM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.anyM p = xs.anyM p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem allM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem allM_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.allM p = xs.allM p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem any_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem any_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.any p = xs.any p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem all_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.all p = xs.all p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem countP_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem countP_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.countP p = xs.countP p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
xs.toArray.count a = xs.count a := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
|
||||
@[simp, grind =] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
|
||||
xs.toArray.replace a b = (xs.replace a b).toArray := rfl
|
||||
|
||||
@[simp, grind] theorem find?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem find?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.find? p = xs.find? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSome?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSome?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
xs.toArray.findSome? f = xs.findSome? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findRev?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findRev?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.findRev? p = xs.findRev? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeRev?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeRev?_toArray {f : α → Option β} {xs : Vector α n} :
|
||||
xs.toArray.findSomeRev? f = xs.findSomeRev? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.findM? p = xs.findM? p := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
xs.toArray.findSomeM? f = xs.findSomeM? f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findRevM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findRevM?_toArray [Monad m] {p : α → m Bool} {xs : Vector α n} :
|
||||
xs.toArray.findRevM? p = xs.findRevM? p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findSomeRevM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSomeRevM?_toArray [Monad m] {f : α → m (Option β)} {xs : Vector α n} :
|
||||
xs.toArray.findSomeRevM? f = xs.findSomeRevM? f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
|
||||
xs.toArray.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast xs.size_toArray.symm) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem findFinIdx?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findFinIdx?_toArray {p : α → Bool} {xs : Vector α n} :
|
||||
xs.toArray.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast xs.size_toArray.symm) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
|
||||
@[simp, grind =] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
|
||||
|
||||
@[deprecated toArray_replicate (since := "2025-03-18")]
|
||||
abbrev toArray_mkVector := @toArray_replicate
|
||||
@@ -503,13 +503,13 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x
|
||||
|
||||
/-! ### toList -/
|
||||
|
||||
@[simp, grind] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
|
||||
@[simp, grind =] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [toList]
|
||||
|
||||
@[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
|
||||
|
||||
@[simp, grind] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
|
||||
@[simp, grind =] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
|
||||
|
||||
@[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) :
|
||||
xs.toList[i] = xs[i]'(by simpa using h) := by
|
||||
@@ -784,12 +784,12 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@[simp, grind] theorem replicate_zero : replicate 0 a = #v[] := rfl
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #v[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev replicate_mkVector := @replicate_zero
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
simp [replicate, Array.replicate_succ]
|
||||
|
||||
@@ -895,26 +895,37 @@ theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some
|
||||
theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a else none := by
|
||||
simp [List.getElem?_singleton]
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
@[simp] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
|
||||
@[grind ←]
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
|
||||
|
||||
@[simp] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
@[simp, grind =] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
|
||||
theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
|
||||
a ∈ xs.push b → a ∈ xs ∨ a = b := Vector.mem_push.mp
|
||||
|
||||
@[grind] theorem mem_push_self {xs : Vector α n} {x : α} : x ∈ xs.push x :=
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of vectors,
|
||||
-- and constructing a list via `push`, even if the elements are unrelated.
|
||||
-- Nevertheless in practice it is quite helpful!
|
||||
grind_pattern mem_or_eq_of_mem_push => xs.push b, a ∈ xs
|
||||
|
||||
|
||||
theorem mem_push_self {xs : Vector α n} {x : α} : x ∈ xs.push x :=
|
||||
mem_push.2 (Or.inr rfl)
|
||||
|
||||
theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
|
||||
@@ -926,7 +937,7 @@ theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
|
||||
obtain rfl := h
|
||||
exact ⟨_, _, as.toVector, bs.toVector, by simp, by simp, by simpa using w⟩
|
||||
|
||||
@[grind] theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
mem_push.2 (Or.inl h)
|
||||
|
||||
theorem exists_mem_of_size_pos {xs : Vector α n} (h : 0 < n) : ∃ x, x ∈ xs := by
|
||||
@@ -1213,9 +1224,9 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff contains_iff
|
||||
|
||||
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
|
||||
@[grind =] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = decide (a ∈ as) := by
|
||||
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
|
||||
|
||||
@@ -1236,7 +1247,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[grind] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
|
||||
@[grind =] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
|
||||
(xs.set i x hi)[j] = if i = j then x else xs[j] := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1249,7 +1260,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
|
||||
@[simp] theorem getElem_set_ne {xs : Vector α n} {x : α} (hi : i < n) (hj : j < n) (h : i ≠ j) :
|
||||
(xs.set i x hi)[j] = xs[j] := by simp [getElem_set, h]
|
||||
|
||||
@[grind] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
|
||||
@[grind =] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
|
||||
(xs.set i x hi)[j]? = if i = j then some x else xs[j]? := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1294,10 +1305,10 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
|
||||
/-! ### setIfInBounds -/
|
||||
|
||||
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
#v[].setIfInBounds i a = #v[] := rfl
|
||||
|
||||
@[grind] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
|
||||
@[grind =] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
|
||||
(xs.setIfInBounds i x)[j] = if i = j then x else xs[j] := by
|
||||
cases xs
|
||||
split <;> simp_all
|
||||
@@ -1310,7 +1321,7 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
|
||||
@[simp] theorem getElem_setIfInBounds_ne {xs : Vector α n} {x : α} (hj : j < n) (h : i ≠ j) :
|
||||
(xs.setIfInBounds i x)[j] = xs[j] := by simp [getElem_setIfInBounds, h]
|
||||
|
||||
@[grind] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
|
||||
@[grind =] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
|
||||
(xs.setIfInBounds i x)[j]? = if i = j then if i < n then some x else none else xs[j]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_setIfInBounds]
|
||||
@@ -1347,7 +1358,7 @@ theorem mem_setIfInBounds {xs : Vector α n} {a : α} (hi : i < n) :
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1410,16 +1421,16 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
|
||||
|
||||
/-! ### back -/
|
||||
|
||||
@[grind] theorem back_singleton {a : α} : #v[a].back = a := by simp
|
||||
@[grind =] theorem back_singleton {a : α} : #v[a].back = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by have := NeZero.ne n; omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.back_eq_getElem]
|
||||
|
||||
@[grind] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
|
||||
@[grind =] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
|
||||
|
||||
@[grind] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
|
||||
@[grind =] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.back?_eq_getElem?]
|
||||
|
||||
@@ -1430,22 +1441,22 @@ theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by
|
||||
/-! ### map -/
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {xs : Vector α n} (hi : i < n) :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {xs : Vector α n} (hi : i < n) :
|
||||
(xs.map f)[i] = f xs[i] := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} {xs : Vector α n} {i : Nat}:
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} {xs : Vector α n} {i : Nat}:
|
||||
(xs.map f)[i]? = xs[i]?.map f := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-- The empty vector maps to the empty vector. -/
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_empty {f : α → β} : map f #v[] = #v[] := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
|
||||
@[simp, grind =] theorem map_push {f : α → β} {as : Vector α n} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
cases as
|
||||
simp
|
||||
@@ -1620,7 +1631,7 @@ theorem append_push {as : Vector α n} {bs : Vector α m} {a : α} :
|
||||
|
||||
theorem singleton_eq_toVector_singleton {a : α} : #v[a] = #[a].toVector := rfl
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1656,16 +1667,16 @@ theorem forall_mem_append {p : α → Prop} {xs : Vector α n} {ys : Vector α m
|
||||
(∀ (x) (_ : x ∈ xs ++ ys), p x) ↔ (∀ (x) (_ : x ∈ xs), p x) ∧ (∀ (x) (_ : x ∈ ys), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem empty_append {xs : Vector α n} : (#v[] : Vector α 0) ++ xs = xs.cast (by omega) := by
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem append_empty {xs : Vector α n} : xs ++ (#v[] : Vector α 0) = xs := by
|
||||
rw [← toArray_inj, toArray_append, Array.append_empty]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem_append {xs : Vector α n} {ys : Vector α m} (hi : i < n + m) :
|
||||
(xs ++ ys)[i] = if h : i < n then xs[i] else ys[i - n] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -1692,7 +1703,7 @@ theorem getElem?_append_right {xs : Vector α n} {ys : Vector α m} (h : n ≤ i
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.getElem?_append_right, h]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_append {xs : Vector α n} {ys : Vector α m} {i : Nat} :
|
||||
(xs ++ ys)[i]? = if i < n then xs[i]? else ys[i - n]? := by
|
||||
split <;> rename_i h
|
||||
@@ -1771,7 +1782,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
right
|
||||
refine ⟨cs.toArray, ha, rfl⟩
|
||||
|
||||
@[simp, grind] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
@[simp, grind =] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
(xs ++ ys) ++ zs = (xs ++ (ys ++ zs)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -1779,14 +1790,14 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
simp [Array.append_assoc]
|
||||
|
||||
-- Variant for rewriting the other direction: we can't use `append_assoc` as it has a `cast` on the right-hand side.
|
||||
@[grind] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
@[grind =] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
|
||||
xs ++ (ys ++ zs) = ((xs ++ ys) ++ zs).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
rcases zs with ⟨zs, rfl⟩
|
||||
simp [Array.append_assoc]
|
||||
|
||||
@[grind] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
|
||||
@[grind =] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
|
||||
(xs ++ ys).set i x =
|
||||
if h' : i < n then
|
||||
xs.set i x ++ ys
|
||||
@@ -1806,7 +1817,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
(xs ++ ys).set i x = xs ++ ys.set (i - n) x := by
|
||||
rw [set_append, dif_neg (by omega)]
|
||||
|
||||
@[grind] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
|
||||
@[grind =] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
|
||||
(xs ++ ys).setIfInBounds i x =
|
||||
if i < n then
|
||||
xs.setIfInBounds i x ++ ys
|
||||
@@ -1826,7 +1837,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
|
||||
(xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - n) x := by
|
||||
rw [setIfInBounds_append, if_neg (by omega)]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem map_append {f : α → β} {xs : Vector α n} {ys : Vector α m} :
|
||||
map f (xs ++ ys) = map f xs ++ map f ys := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -1895,7 +1906,7 @@ theorem getElem?_flatten {xss : Vector (Vector β m) n} {i : Nat} :
|
||||
none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[simp, grind] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
|
||||
@[simp, grind =] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
|
||||
simp [flatten]
|
||||
|
||||
set_option linter.listVariables false in
|
||||
@@ -1922,17 +1933,17 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Vector (Vector α n) m} :
|
||||
induction xss using vector₂_induction with
|
||||
| of xss h₁ h₂ => simp
|
||||
|
||||
@[simp, grind] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
@[simp, grind =] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
flatten (xss₁ ++ xss₂) = (flatten xss₁ ++ flatten xss₂).cast (by simp [Nat.add_mul]) := by
|
||||
induction xss₁ using vector₂_induction
|
||||
induction xss₂ using vector₂_induction
|
||||
simp
|
||||
|
||||
@[grind] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
@[grind =] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
|
||||
flatten xss₁ ++ flatten xss₂ = (flatten (xss₁ ++ xss₂)).cast (by simp [Nat.add_mul]) := by
|
||||
simp
|
||||
|
||||
@[grind] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
|
||||
@[grind =] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
|
||||
flatten (xss.push xs) = (flatten xss ++ xs).cast (by simp [Nat.add_mul]) := by
|
||||
induction xss using vector₂_induction
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -1982,10 +1993,10 @@ theorem flatMap_def {xs : Vector α n} {f : α → Vector β m} : xs.flatMap f =
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.flatMap_def, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem flatMap_empty {f : α → Vector β m} :
|
||||
@[simp, grind =] theorem flatMap_empty {f : α → Vector β m} :
|
||||
(#v[] : Vector α 0).flatMap f = #v[].cast (by simp) := rfl
|
||||
|
||||
@[simp, grind] theorem flatMap_push {xs : Vector α n} {x : α} {f : α → Vector β m} :
|
||||
@[simp, grind =] theorem flatMap_push {xs : Vector α n} {x : α} {f : α → Vector β m} :
|
||||
(xs.push x).flatMap f = (xs.flatMap f ++ f x).cast (by simp [Nat.add_mul]) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2011,7 +2022,7 @@ theorem getElem?_flatMap {xs : Vector α n} {f : α → Vector β m} {i : Nat} :
|
||||
|
||||
@[simp] theorem flatMap_id' {xss : Vector (Vector α m) n} : xss.flatMap (fun xs => xs) = xss.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → Vector β m} {b} {xs : Vector α n} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → Vector β m} {b} {xs : Vector α n} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
|
||||
|
||||
@@ -2074,7 +2085,7 @@ theorem replicate_succ' : replicate (n + 1) a = (#v[a] ++ replicate n a).cast (b
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkVector_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [mem_mk]
|
||||
simp
|
||||
@@ -2094,14 +2105,14 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[deprecated forall_mem_replicate (since := "2025-03-18")]
|
||||
abbrev forall_mem_mkVector := @forall_mem_replicate
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
|
||||
@[simp, grind =] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
|
||||
rw [replicate_eq_mk_replicate, getElem_mk]
|
||||
simp
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkVector := @getElem_replicate
|
||||
|
||||
@[grind] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
@[grind =] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[deprecated getElem?_replicate (since := "2025-03-18")]
|
||||
@@ -2227,16 +2238,16 @@ abbrev sum_mkVector := @sum_replicate_nat
|
||||
|
||||
theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
|
||||
|
||||
@[simp, grind] theorem reverse_push {as : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem reverse_push {as : Vector α n} {a : α} :
|
||||
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp [Array.reverse_push]
|
||||
|
||||
@[simp, grind] theorem mem_reverse {x : α} {as : Vector α n} : x ∈ as.reverse ↔ x ∈ as := by
|
||||
@[simp, grind =] theorem mem_reverse {x : α} {as : Vector α n} : x ∈ as.reverse ↔ x ∈ as := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
|
||||
@[simp, grind =] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
|
||||
(xs.reverse)[i] = xs[n - 1 - i] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2252,14 +2263,14 @@ theorem getElem?_reverse' {xs : Vector α n} {i j : Nat} (h : i + j + 1 = n) : x
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simpa using Array.getElem?_reverse' h
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {xs : Vector α n} {i} (h : i < n) :
|
||||
xs.reverse[i]? = xs[n - 1 - i]? := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
-- The argument `xs : Vector α n` is explicit so we can rewrite from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
|
||||
@[simp, grind =] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.reverse_reverse]
|
||||
|
||||
@@ -2279,13 +2290,13 @@ theorem reverse_eq_iff {xs ys : Vector α n} : xs.reverse = ys ↔ xs = ys.rever
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.map_reverse]
|
||||
|
||||
@[simp, grind] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).reverse = (ys.reverse ++ xs.reverse).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.reverse_append]
|
||||
|
||||
@[grind] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
|
||||
@[grind =] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
|
||||
ys.reverse ++ xs.reverse = (xs ++ ys).reverse.cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -2320,7 +2331,7 @@ theorem flatMap_reverse {xs : Vector α n} {f : α → Vector β m} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.flatMap_reverse, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
|
||||
rw [← toArray_inj]
|
||||
simp
|
||||
|
||||
@@ -2345,7 +2356,7 @@ set_option linter.indexVariables false in
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind] theorem extract_empty {start stop : Nat} :
|
||||
@[grind =] theorem extract_empty {start stop : Nat} :
|
||||
(#v[] : Vector α 0).extract start stop = #v[].cast (by simp) := by
|
||||
simp
|
||||
|
||||
@@ -2361,11 +2372,11 @@ theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
|
||||
foldlM f init #v[] = return init := by
|
||||
simp
|
||||
|
||||
@[grind] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} :
|
||||
@[grind =] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} :
|
||||
foldrM f init #v[] = return init := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β → α → m β} {b} :
|
||||
@[simp, grind =] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β → α → m β} {b} :
|
||||
(xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2410,16 +2421,16 @@ theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldrM_push [Monad m] {f : α → β → m β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#v[].foldl f init) = init := rfl
|
||||
@[grind =] theorem foldl_empty {f : β → α → β} {init : β} : (#v[].foldl f init) = init := rfl
|
||||
|
||||
@[grind] theorem foldr_empty {f : α → β → β} {init : β} : (#v[].foldr f init) = init := rfl
|
||||
@[grind =] theorem foldr_empty {f : α → β → β} {init : β} : (#v[].foldr f init) = init := rfl
|
||||
|
||||
@[congr]
|
||||
theorem foldl_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : β → α → β} (h₁ : f = g)
|
||||
@@ -2433,12 +2444,12 @@ theorem foldr_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : α → β →
|
||||
xs.foldr f a = ys.foldr g b := by
|
||||
congr
|
||||
|
||||
@[simp, grind] theorem foldl_push {f : β → α → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldl_push {f : β → α → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldl f init = f (xs.foldl f init) a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldr_push {f : α → β → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
@[simp, grind =] theorem foldr_push {f : α → β → β} {init : β} {xs : Vector α n} {a : α} :
|
||||
(xs.push a).foldr f init = xs.foldr f (f a init) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2490,21 +2501,21 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
@[simp, grind _=_] theorem foldr_append {f : α → β → β} {b} {xs : Vector α n} {ys : Vector α k} :
|
||||
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := foldrM_append
|
||||
|
||||
@[simp, grind] theorem foldl_flatten {f : β → α → β} {b} {xss : Vector (Vector α m) n} :
|
||||
@[simp, grind =] theorem foldl_flatten {f : β → α → β} {b} {xss : Vector (Vector α m) n} :
|
||||
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
|
||||
cases xss using vector₂_induction
|
||||
simp [Array.foldl_flatten', Array.foldl_map']
|
||||
|
||||
@[simp, grind] theorem foldr_flatten {f : α → β → β} {b} {xss : Vector (Vector α m) n} :
|
||||
@[simp, grind =] theorem foldr_flatten {f : α → β → β} {b} {xss : Vector (Vector α m) n} :
|
||||
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
|
||||
cases xss using vector₂_induction
|
||||
simp [Array.foldr_flatten', Array.foldr_map']
|
||||
|
||||
@[simp, grind] theorem foldl_reverse {xs : Vector α n} {f : β → α → β} {b} :
|
||||
@[simp, grind =] theorem foldl_reverse {xs : Vector α n} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse
|
||||
|
||||
@[simp, grind] theorem foldr_reverse {xs : Vector α n} {f : α → β → β} {b} :
|
||||
@[simp, grind =] theorem foldr_reverse {xs : Vector α n} {f : α → β → β} {b} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
@@ -2598,7 +2609,7 @@ theorem back?_eq_some_iff {xs : Vector α n} {a : α} :
|
||||
simp only [mk_append_mk, back_mk]
|
||||
rw [Array.back_append_of_size_pos]
|
||||
|
||||
@[grind] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
|
||||
@[grind =] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
|
||||
(xs ++ ys).back =
|
||||
if h' : m = 0 then
|
||||
have : NeZero n := by subst h'; simp_all
|
||||
@@ -2629,7 +2640,7 @@ theorem back_append_left {xs : Vector α n} {ys : Vector α 0} [NeZero n] :
|
||||
simp only [mk_append_mk, back_mk]
|
||||
rw [Array.back_append_left _ h]
|
||||
|
||||
@[simp, grind] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
@[simp, grind =] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
@@ -2681,24 +2692,28 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Vector α n} {a : α} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.contains_iff_exists_mem_beq]
|
||||
|
||||
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
|
||||
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
|
||||
grind_pattern contains_iff_exists_mem_beq => xs.contains a
|
||||
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Vector α n} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_toList [BEq α] {xs : Vector α n} {x : α} :
|
||||
xs.toList.contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_toArray [BEq α] {xs : Vector α n} {x : α} :
|
||||
xs.toArray.contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_map [BEq β] {xs : Vector α n} {x : β} {f : α → β} :
|
||||
(xs.map f).contains x = xs.any (fun a => x == f a) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -2723,19 +2738,19 @@ theorem contains_append [BEq α] {xs : Vector α n} {ys : Vector α m} {x : α}
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatten [BEq α] {xs : Vector (Vector α n) m} {x : α} :
|
||||
(xs.flatten).contains x = xs.any fun xs => xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_reverse [BEq α] {xs : Vector α n} {x : α} :
|
||||
(xs.reverse).contains x = xs.contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x : β} :
|
||||
(xs.flatMap f).contains x = xs.any fun a => (f a).contains x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -2747,7 +2762,7 @@ theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x
|
||||
|
||||
@[simp] theorem pop_push {xs : Vector α n} {x : α} : (xs.push x).pop = xs := by simp [pop]
|
||||
|
||||
@[simp, grind] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
|
||||
@[simp, grind =] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
|
||||
xs.pop[i] = xs[i] := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -2760,7 +2775,7 @@ defeq issues in the implicit size argument.
|
||||
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt xs.pop i h = xs[i] :=
|
||||
getElem_pop h
|
||||
|
||||
@[grind] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
|
||||
@[grind =] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
|
||||
xs.pop[i]? = if i < n - 1 then xs[i]? else none := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_pop]
|
||||
@@ -2908,15 +2923,15 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
unfold all
|
||||
apply allM_congr w h
|
||||
|
||||
@[simp, grind] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
|
||||
@[simp, grind =] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
|
||||
@[simp, grind =] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
|
||||
cases xss using vector₂_induction
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem any_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
@[simp, grind =] theorem any_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).any p = xs.any fun a => (f a).any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, any_mk, Array.size_flatMap, size_toArray, Array.any_flatMap']
|
||||
@@ -2925,7 +2940,7 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp, grind] theorem all_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
@[simp, grind =] theorem all_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).all p = xs.all fun a => (f a).all p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [flatMap_mk, all_mk, Array.size_flatMap, size_toArray, Array.all_flatMap']
|
||||
@@ -2934,11 +2949,11 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
|
||||
congr
|
||||
simp [Vector.size_toArray]
|
||||
|
||||
@[simp, grind] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
|
||||
@[simp, grind =] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
|
||||
@[simp, grind =] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@@ -2974,9 +2989,9 @@ variable [BEq α]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
|
||||
@[simp, grind =] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
|
||||
|
||||
@[grind] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
|
||||
@[grind =] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
|
||||
simp
|
||||
|
||||
-- This hypothesis could probably be dropped from some of the lemmas below,
|
||||
@@ -2987,7 +3002,7 @@ variable [LawfulBEq α]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.getElem?_replace, -beq_iff_eq]
|
||||
@@ -2996,7 +3011,7 @@ theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? ≠ some
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
@[grind =] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
(xs.replace a b)[i] = if xs[i] == a then if a ∈ xs.take i then a else b else xs[i] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_replace]
|
||||
@@ -3007,7 +3022,7 @@ theorem getElem_replace_of_ne {xs : Vector α n} {i : Nat} {h : i < n} (h' : xs[
|
||||
rw [getElem_replace h]
|
||||
simp [h']
|
||||
|
||||
@[grind] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
|
||||
@[grind =] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
@@ -3022,7 +3037,7 @@ theorem replace_append_right {xs : Vector α n} {ys : Vector α m} (h : ¬ a ∈
|
||||
(xs ++ ys).replace a b = xs ++ ys.replace a b := by
|
||||
simp [replace_append, h]
|
||||
|
||||
@[grind] theorem replace_push {xs : Vector α n} {a b c : α} :
|
||||
@[grind =] theorem replace_push {xs : Vector α n} {a b c : α} :
|
||||
(xs.push a).replace b c = if b ∈ xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp only [push_mk, replace_mk, Array.replace_push, mem_mk]
|
||||
@@ -3091,7 +3106,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
|
||||
/-! ### swap -/
|
||||
|
||||
@[grind] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
|
||||
@[grind =] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
|
||||
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
|
||||
cases xs
|
||||
simp_all [Array.getElem_swap]
|
||||
@@ -3108,7 +3123,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
|
||||
(hi' : k ≠ i) (hj' : k ≠ j) : (xs.swap i j hi hj)[k] = xs[k] := by
|
||||
simp_all [getElem_swap]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
|
||||
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user