mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-30 08:44:07 +00:00
Compare commits
89 Commits
context-no
...
release_up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43f1fe2797 | ||
|
|
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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -377,6 +377,17 @@ 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 == "cslib":
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
# 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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -201,7 +201,7 @@ theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
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 +212,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 +346,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 +365,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
|
||||
@@ -706,7 +707,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
|
||||
@@ -132,7 +138,7 @@ 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]
|
||||
@[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
|
||||
@@ -197,7 +203,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]
|
||||
|
||||
@@ -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 =]
|
||||
|
||||
@@ -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
|
||||
@@ -395,7 +396,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)
|
||||
|
||||
@@ -61,7 +61,7 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by
|
||||
@[simp] theorem empty_eq {xs : Array α} : #[] = xs ↔ xs = #[] := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind] theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
@[grind =] theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
/-! ### size -/
|
||||
|
||||
@@ -88,7 +88,7 @@ theorem eq_empty_iff_size_eq_zero : xs = #[] ↔ xs.size = 0 :=
|
||||
|
||||
theorem size_pos_of_mem {a : α} {xs : Array α} (h : a ∈ xs) : 0 < xs.size := by
|
||||
cases xs
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.mem_toArray] at h
|
||||
simpa using List.length_pos_of_mem h
|
||||
|
||||
grind_pattern size_pos_of_mem => a ∈ xs, xs.size
|
||||
@@ -196,7 +196,7 @@ theorem getElem?_push_size {xs : Array α} {x} : (xs.push x)[xs.size]? = some x
|
||||
theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : #[a][i] = a := by
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : #[a][i]? = if i = 0 then some a else none := by
|
||||
simp [List.getElem?_singleton]
|
||||
|
||||
@@ -211,12 +211,12 @@ theorem ext_getElem? {xs ys : Array α} (h : ∀ i : Nat, xs[i]? = ys[i]?) : xs
|
||||
|
||||
@[simp] theorem pop_push {xs : Array α} {x : α} : (xs.push x).pop = xs := by simp [pop]
|
||||
|
||||
@[simp, grind] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
|
||||
@[simp, grind =] theorem getElem_pop {xs : Array α} {i : Nat} (h : i < xs.pop.size) :
|
||||
xs.pop[i] = xs[i]'(by simp at h; omega) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getElem_dropLast]
|
||||
|
||||
@[grind] theorem getElem?_pop {xs : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_pop {xs : Array α} {i : Nat} :
|
||||
xs.pop[i]? = if i < xs.size - 1 then xs[i]? else none := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getElem?_dropLast]
|
||||
@@ -331,7 +331,7 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@[simp, grind] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
List.length_replicate ..
|
||||
|
||||
@[deprecated size_replicate (since := "2025-03-18")]
|
||||
@@ -343,12 +343,12 @@ abbrev size_mkArray := @size_replicate
|
||||
@[deprecated toList_replicate (since := "2025-03-18")]
|
||||
abbrev toList_mkArray := @toList_replicate
|
||||
|
||||
@[simp, grind] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev mkArray_zero := @replicate_zero
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
apply toList_inj.1
|
||||
simp [List.replicate_succ']
|
||||
@@ -356,13 +356,13 @@ theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
@[deprecated replicate_succ (since := "2025-03-18")]
|
||||
abbrev mkArray_succ := @replicate_succ
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
(replicate n v)[i] = v := by simp [← getElem_toList]
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkArray := @getElem_replicate
|
||||
|
||||
@[grind] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
(replicate n v)[i]? = if i < n then some v else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@@ -373,14 +373,20 @@ abbrev getElem?_mkArray := @getElem?_replicate
|
||||
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #[] := by simp
|
||||
|
||||
@[simp] theorem mem_push {xs : Array α} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
@[simp, grind =] theorem mem_push {xs : Array α} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
simp only [mem_def]
|
||||
simp
|
||||
|
||||
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
|
||||
theorem mem_or_eq_of_mem_push {a b : α} {xs : Array α} :
|
||||
a ∈ xs.push b → a ∈ xs ∨ a = b := Array.mem_push.mp
|
||||
|
||||
@[grind] theorem mem_push_self {xs : Array α} {x : α} : x ∈ xs.push x :=
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of arrays,
|
||||
-- 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 : Array α} {x : α} : x ∈ xs.push x :=
|
||||
mem_push.2 (Or.inr rfl)
|
||||
|
||||
theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x ∈ xs) :
|
||||
@@ -391,7 +397,7 @@ theorem eq_push_append_of_mem {xs : Array α} {x : α} (h : x ∈ xs) :
|
||||
obtain rfl := h
|
||||
exact ⟨as.toArray, bs.toArray, by simp, by simpa using w⟩
|
||||
|
||||
@[grind] theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
theorem mem_push_of_mem {xs : Array α} {x : α} (y : α) (h : x ∈ xs) : x ∈ xs.push y :=
|
||||
mem_push.2 (Or.inl h)
|
||||
|
||||
-- The argument `xs : Array α` is intentionally explicit,
|
||||
@@ -459,7 +465,7 @@ theorem mem_singleton_self (a : α) : a ∈ #[a] := by simp
|
||||
|
||||
theorem mem_of_mem_push_of_mem {a b : α} {xs : Array α} : a ∈ xs.push b → b ∈ xs → a ∈ xs := by
|
||||
cases xs
|
||||
simp only [List.push_toArray, mem_toArray, List.mem_append, List.mem_singleton]
|
||||
simp only [List.push_toArray, List.mem_toArray, List.mem_append, List.mem_singleton]
|
||||
rintro (h | rfl)
|
||||
· intro _
|
||||
exact h
|
||||
@@ -520,8 +526,8 @@ theorem forall_getElem {xs : Array α} {p : α → Prop} :
|
||||
|
||||
/-! ### isEmpty -/
|
||||
|
||||
@[grind] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
|
||||
@[simp, grind] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
|
||||
@[grind =] theorem isEmpty_empty : (#[] : Array α).isEmpty = true := rfl
|
||||
@[simp, grind =] theorem isEmpty_push {xs : Array α} : (xs.push x).isEmpty = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@@ -728,18 +734,18 @@ theorem all_eq_true_iff_forall_mem {xs : Array α} : xs.all p ↔ ∀ x, x ∈ x
|
||||
subst h
|
||||
rw [all_toList]
|
||||
|
||||
@[grind] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.anyM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
l.toArray.anyM p = l.anyM p := by
|
||||
rw [← anyM_toList]
|
||||
|
||||
@[grind] theorem _root_.List.any_toArray {p : α → Bool} {l : List α} : l.toArray.any p = l.any p := by
|
||||
@[grind =] theorem _root_.List.any_toArray {p : α → Bool} {l : List α} : l.toArray.any p = l.any p := by
|
||||
rw [any_toList]
|
||||
|
||||
@[grind] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.allM_toArray [Monad m] [LawfulMonad m] {p : α → m Bool} {l : List α} :
|
||||
l.toArray.allM p = l.allM p := by
|
||||
rw [← allM_toList]
|
||||
|
||||
@[grind] theorem _root_.List.all_toArray {p : α → Bool} {l : List α} : l.toArray.all p = l.all p := by
|
||||
@[grind =] theorem _root_.List.all_toArray {p : α → Bool} {l : List α} : l.toArray.all p = l.all p := by
|
||||
rw [all_toList]
|
||||
|
||||
/-- Variant of `any_eq_true` in terms of membership rather than an array index. -/
|
||||
@@ -846,7 +852,7 @@ theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (
|
||||
elem a xs = xs.contains a := by
|
||||
simp [elem]
|
||||
|
||||
@[grind] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
|
||||
@[grind =] theorem contains_empty [BEq α] : (#[] : Array α).contains a = false := by simp
|
||||
|
||||
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
@@ -860,14 +866,14 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Array α) : Decidable (a ∈ as)
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = decide (a ∈ xs) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = decide (a ∈ xs) := by rw [← elem_eq_contains, elem_eq_mem]
|
||||
|
||||
@[grind] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[grind] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
@[grind =] theorem any_empty [BEq α] {p : α → Bool} : (#[] : Array α).any p = false := by simp
|
||||
@[grind =] theorem all_empty [BEq α] {p : α → Bool} : (#[] : Array α).all p = true := by simp
|
||||
|
||||
/-- Variant of `any_push` with a side condition on `stop`. -/
|
||||
@[simp, grind] theorem any_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
@[simp, grind =] theorem any_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
(xs.push a).any p 0 stop = (xs.any p || p a) := by
|
||||
cases xs
|
||||
rw [List.push_toArray]
|
||||
@@ -878,7 +884,7 @@ theorem any_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
any_push' (by simp)
|
||||
|
||||
/-- Variant of `all_push` with a side condition on `stop`. -/
|
||||
@[simp, grind] theorem all_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
@[simp, grind =] theorem all_push' {xs : Array α} {a : α} {p : α → Bool} (h : stop = xs.size + 1) :
|
||||
(xs.push a).all p 0 stop = (xs.all p && p a) := by
|
||||
cases xs
|
||||
rw [List.push_toArray]
|
||||
@@ -911,13 +917,13 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(ne : i ≠ j) : (xs.set i v)[j]? = xs[j]? := by
|
||||
by_cases h : j < xs.size <;> simp [ne, h]
|
||||
|
||||
@[grind] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
@[grind =] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(h : j < (xs.set i v).size) :
|
||||
(xs.set i v)[j] = if i = j then v else xs[j]'(by simpa using h) := by
|
||||
simp at h
|
||||
by_cases p : i = j <;> simp [p, h]
|
||||
|
||||
@[grind] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
|
||||
@[grind =] theorem getElem?_set {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat} :
|
||||
(xs.set i v)[j]? = if i = j then some v else xs[j]? := by
|
||||
split <;> simp_all
|
||||
|
||||
@@ -983,23 +989,23 @@ 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 : α} :
|
||||
#[].setIfInBounds i a = #[] := rfl
|
||||
|
||||
@[simp, grind =] theorem set!_eq_setIfInBounds : set! xs i v = setIfInBounds xs i v := rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
|
||||
|
||||
@[simp, grind] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem size_setIfInBounds {xs : Array α} {i : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a).size = xs.size := by
|
||||
if h : i < xs.size then
|
||||
simp [setIfInBounds, h]
|
||||
else
|
||||
simp [setIfInBounds, h]
|
||||
|
||||
@[grind] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
@[grind =] theorem getElem_setIfInBounds {xs : Array α} {i : Nat} {a : α} {j : Nat}
|
||||
(hj : j < xs.size) :
|
||||
(xs.setIfInBounds i a)[j]'(by simp [hj]) = if i = j then a else xs[j] := by
|
||||
simp only [setIfInBounds]
|
||||
@@ -1018,7 +1024,7 @@ theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
(xs.setIfInBounds i a)[j]'(by simpa using hj) = xs[j] := by
|
||||
simp [getElem_setIfInBounds, hj, h]
|
||||
|
||||
@[grind] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
|
||||
@[grind =] theorem getElem?_setIfInBounds {xs : Array α} {i j : Nat} {a : α} :
|
||||
(xs.setIfInBounds i a)[j]? = if i = j then if i < xs.size then some a else none else xs[j]? := by
|
||||
cases xs
|
||||
simp [List.getElem?_set]
|
||||
@@ -1082,11 +1088,11 @@ theorem mem_or_eq_of_mem_setIfInBounds
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
|
||||
@[simp, grind =] theorem beq_empty_eq [BEq α] {xs : Array α} : (xs == #[]) = xs.isEmpty := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
|
||||
@[simp, grind =] theorem empty_beq_eq [BEq α] {xs : Array α} : (#[] == xs) = xs.isEmpty := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -1096,7 +1102,7 @@ abbrev beq_empty_iff := @beq_empty_eq
|
||||
@[deprecated empty_beq_eq (since := "2025-04-04")]
|
||||
abbrev empty_beq_iff := @empty_beq_eq
|
||||
|
||||
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
cases ys
|
||||
@@ -1156,16 +1162,16 @@ private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a ==
|
||||
|
||||
/-! ### back -/
|
||||
|
||||
@[grind] theorem back_singleton {a : α} : #[a].back = a := by simp
|
||||
@[grind =] theorem back_singleton {a : α} : #[a].back = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem back_eq_getElem {xs : Array α} (h : 0 < xs.size) : xs.back = xs[xs.size - 1] := by
|
||||
cases xs
|
||||
simp [List.getLast_eq_getElem]
|
||||
|
||||
@[grind] theorem back?_empty : (#[] : Array α).back? = none := by simp
|
||||
@[grind =] theorem back?_empty : (#[] : Array α).back? = none := by simp
|
||||
|
||||
@[grind] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
|
||||
@[grind =] theorem back?_eq_getElem? {xs : Array α} : xs.back? = xs[xs.size - 1]? := by
|
||||
cases xs
|
||||
simp [List.getLast?_eq_getElem?]
|
||||
|
||||
@@ -1202,17 +1208,17 @@ where
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem size_map {f : α → β} {xs : Array α} : (xs.map f).size = xs.size := by
|
||||
@[simp, grind =] theorem size_map {f : α → β} {xs : Array α} : (xs.map f).size = xs.size := by
|
||||
simp only [← length_toList]
|
||||
simp
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {xs : Array α} {i : Nat} (hi : i < (xs.map f).size) :
|
||||
(xs.map f)[i] = f (xs[i]'(by simpa using hi)) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} {xs : Array α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} {xs : Array α} {i : Nat} :
|
||||
(xs.map f)[i]? = xs[i]?.map f := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@@ -1220,9 +1226,9 @@ where
|
||||
@[simp] theorem mapM_empty [Monad m] (f : α → m β) : mapM f #[] = pure #[] := by
|
||||
rw [mapM, mapM.map]; rfl
|
||||
|
||||
@[grind] theorem map_empty {f : α → β} : map f #[] = #[] := by simp
|
||||
@[grind =] theorem map_empty {f : α → β} : map f #[] = #[] := by simp
|
||||
|
||||
@[simp, grind] theorem map_push {f : α → β} {as : Array α} {x : α} :
|
||||
@[simp, grind =] theorem map_push {f : α → β} {as : Array α} {x : α} :
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
ext
|
||||
· simp
|
||||
@@ -1271,7 +1277,9 @@ theorem forall_mem_map {f : α → β} {xs : Array α} {P : β → Prop} :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
-- This would be helpful as a `grind` lemma if
|
||||
-- we could have it fire only once `map f l` and `#[]` are the same equivalence class.
|
||||
-- Otherwise it is too aggressive.
|
||||
theorem eq_empty_of_map_eq_empty {f : α → β} {xs : Array α} (h : map f xs = #[]) : xs = #[] :=
|
||||
map_eq_empty_iff.mp h
|
||||
|
||||
@@ -1383,7 +1391,7 @@ theorem array₃_induction (P : Array (Array (Array α)) → Prop)
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@[grind] theorem filter_empty {p : α → Bool} : #[].filter p = #[] := rfl
|
||||
@[grind =] theorem filter_empty {p : α → Bool} : #[].filter p = #[] := rfl
|
||||
|
||||
@[congr]
|
||||
theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
@@ -1404,7 +1412,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
induction xs with simp
|
||||
| cons => split <;> simp [*]
|
||||
|
||||
@[grind] theorem toList_filter {p : α → Bool} {xs : Array α} :
|
||||
@[grind =] theorem toList_filter {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p).toList = xs.toList.filter p := by
|
||||
simp
|
||||
|
||||
@@ -1413,7 +1421,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
apply ext'
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem _root_.List.filter_toArray {p : α → Bool} {l : List α} :
|
||||
@[grind =] theorem _root_.List.filter_toArray {p : α → Bool} {l : List α} :
|
||||
l.toArray.filter p = (l.filter p).toArray := by
|
||||
simp
|
||||
|
||||
@@ -1431,7 +1439,7 @@ theorem filter_congr {xs ys : Array α} (h : xs = ys)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem filter_push {p : α → Bool} {a : α} {xs : Array α} :
|
||||
@[grind =] theorem filter_push {p : α → Bool} {a : α} {xs : Array α} :
|
||||
(xs.push a).filter p = if p a then (xs.filter p).push a else xs.filter p := by
|
||||
split <;> simp [*]
|
||||
|
||||
@@ -1452,7 +1460,7 @@ grind_pattern Array.size_filter_le => (xs.filter p).size
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_filter {p : α → Bool} {xs : Array α} {a : α} :
|
||||
@[simp, grind =] theorem mem_filter {p : α → Bool} {xs : Array α} {a : α} :
|
||||
a ∈ xs.filter p ↔ a ∈ xs ∧ p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -1472,7 +1480,7 @@ theorem forall_mem_filter {p : α → Bool} {xs : Array α} {P : α → Prop} :
|
||||
|
||||
theorem getElem?_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
rw [getElem?_eq_getElem h] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
@@ -1514,7 +1522,7 @@ theorem map_filter_eq_foldl {f : α → β} {p : α → Bool} {xs : Array α} :
|
||||
simp only [List.filter_cons, List.foldr_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind] theorem filter_append {p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
@[simp, grind =] theorem filter_append {p : α → Bool} {xs ys : Array α} {stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
filter p (xs ++ ys) 0 stop = filter p xs ++ filter p ys := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -1568,7 +1576,7 @@ theorem size_filter_lt_size_iff_exists {xs : Array α} {p : α → Bool} :
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@[simp, grind] theorem filterMap_empty {f : α → Option β} : filterMap f #[] = #[] := rfl
|
||||
@[simp, grind =] theorem filterMap_empty {f : α → Option β} : filterMap f #[] = #[] := rfl
|
||||
|
||||
@[congr]
|
||||
theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
@@ -1591,7 +1599,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
· simp_all [List.filterMap_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind] theorem toList_filterMap {f : α → Option β} {xs : Array α} :
|
||||
@[grind =] theorem toList_filterMap {f : α → Option β} {xs : Array α} :
|
||||
(xs.filterMap f).toList = xs.toList.filterMap f := by
|
||||
simp [toList_filterMap']
|
||||
|
||||
@@ -1601,7 +1609,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
apply ext'
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem _root_.List.filterMap_toArray {f : α → Option β} {l : List α} :
|
||||
@[grind =] theorem _root_.List.filterMap_toArray {f : α → Option β} {l : List α} :
|
||||
l.toArray.filterMap f = (l.filterMap f).toArray := by
|
||||
simp
|
||||
|
||||
@@ -1619,7 +1627,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem filterMap_push {f : α → Option β} {a : α} {xs : Array α}
|
||||
@[grind =] theorem filterMap_push {f : α → Option β} {a : α} {xs : Array α}
|
||||
(w : stop = xs.size + 1) :
|
||||
filterMap f (xs.push a) 0 stop =
|
||||
match f a with
|
||||
@@ -1644,7 +1652,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
@[simp, grind =] theorem filterMap_some {xs : Array α} : filterMap some xs = xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -1672,19 +1680,19 @@ theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {xs : Array α} :
|
||||
filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
|
||||
cases xs
|
||||
simp [List.filterMap_filterMap]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_filterMap {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
|
||||
cases xs
|
||||
simp [List.map_filterMap]
|
||||
|
||||
@[simp, grind] theorem filterMap_map {f : α → β} {g : β → Option γ} {xs : Array α} :
|
||||
@[simp, grind =] theorem filterMap_map {f : α → β} {g : β → Option γ} {xs : Array α} :
|
||||
filterMap g (map f xs) = filterMap (g ∘ f) xs := by
|
||||
cases xs
|
||||
simp [List.filterMap_map]
|
||||
@@ -1699,7 +1707,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {xs : Array α
|
||||
cases xs
|
||||
simp [List.filterMap_filter]
|
||||
|
||||
@[simp, grind] theorem mem_filterMap {f : α → Option β} {xs : Array α} {b : β} :
|
||||
@[simp, grind =] theorem mem_filterMap {f : α → Option β} {xs : Array α} {b : β} :
|
||||
b ∈ filterMap f xs ↔ ∃ a, a ∈ xs ∧ f a = some b := by
|
||||
simp only [mem_def, toList_filterMap, List.mem_filterMap]
|
||||
|
||||
@@ -1711,7 +1719,7 @@ theorem forall_mem_filterMap {f : α → Option β} {xs : Array α} {P : β →
|
||||
intro a
|
||||
rw [forall_comm]
|
||||
|
||||
@[simp, grind] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α → Option β}
|
||||
@[simp, grind =] theorem filterMap_append {α β : Type _} {xs ys : Array α} {f : α → Option β}
|
||||
{stop : Nat} (w : stop = xs.size + ys.size) :
|
||||
filterMap f (xs ++ ys) 0 stop = filterMap f xs ++ filterMap f ys := by
|
||||
subst w
|
||||
@@ -1770,7 +1778,7 @@ theorem size_filterMap_lt_size_iff_exists {xs : Array α} {f : α → Option β}
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
@[simp, grind] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
|
||||
@[simp, grind =] theorem size_append {xs ys : Array α} : (xs ++ ys).size = xs.size + ys.size := by
|
||||
simp only [size, toList_append, List.length_append]
|
||||
|
||||
@[simp, grind _=_] theorem push_append {a : α} {xs ys : Array α} : (xs ++ ys).push a = xs ++ ys.push a := by
|
||||
@@ -1807,7 +1815,7 @@ theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
|
||||
funext ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
@[simp, grind =] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
simp only [mem_def, toList_append, List.mem_append]
|
||||
|
||||
theorem mem_append_left {a : α} {xs : Array α} (ys : Array α) (h : a ∈ xs) : a ∈ xs ++ ys :=
|
||||
@@ -1835,7 +1843,7 @@ theorem forall_mem_append {p : α → Prop} {xs ys : Array α} :
|
||||
(∀ (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]
|
||||
|
||||
@[grind] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
|
||||
@[grind =] theorem getElem_append {xs ys : Array α} (h : i < (xs ++ ys).size) :
|
||||
(xs ++ ys)[i] = if h' : i < xs.size then xs[i] else ys[i - xs.size]'(by simp at h; omega) := by
|
||||
cases xs; cases ys
|
||||
simp [List.getElem_append]
|
||||
@@ -1869,7 +1877,7 @@ theorem getElem?_append_right {xs ys : Array α} {i : Nat} (h : xs.size ≤ i) :
|
||||
simp at h
|
||||
simp [List.getElem?_append_right, h]
|
||||
|
||||
@[grind] theorem getElem?_append {xs ys : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_append {xs ys : Array α} {i : Nat} :
|
||||
(xs ++ ys)[i]? = if i < xs.size then xs[i]? else ys[i - xs.size]? := by
|
||||
split <;> rename_i h
|
||||
· exact getElem?_append_left h
|
||||
@@ -1950,7 +1958,6 @@ theorem append_left_inj {xs₁ xs₂ : Array α} (ys) : xs₁ ++ ys = xs₂ ++ y
|
||||
@[simp] theorem append_eq_empty_iff {xs ys : Array α} : xs ++ ys = #[] ↔ xs = #[] ∧ ys = #[] := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind →]
|
||||
theorem eq_empty_of_append_eq_empty {xs ys : Array α} (h : xs ++ ys = #[]) : xs = #[] ∧ ys = #[] :=
|
||||
append_eq_empty_iff.mp h
|
||||
|
||||
@@ -2012,7 +2019,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
· left; exact ⟨as.toList, by simp⟩
|
||||
· right; exact ⟨cs.toList, by simp⟩
|
||||
|
||||
@[grind] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
|
||||
@[grind =] theorem set_append {xs ys : Array α} {i : Nat} {x : α} (h : i < (xs ++ ys).size) :
|
||||
(xs ++ ys).set i x =
|
||||
if h' : i < xs.size then
|
||||
xs.set i x ++ ys
|
||||
@@ -2032,7 +2039,7 @@ theorem append_eq_append_iff {ws xs ys zs : Array α} :
|
||||
(xs ++ ys).set i x = xs ++ ys.set (i - xs.size) x (by simp at h'; omega) := by
|
||||
rw [set_append, dif_neg (by omega)]
|
||||
|
||||
@[grind] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
|
||||
@[grind =] theorem setIfInBounds_append {xs ys : Array α} {i : Nat} {x : α} :
|
||||
(xs ++ ys).setIfInBounds i x =
|
||||
if i < xs.size then
|
||||
xs.setIfInBounds i x ++ ys
|
||||
@@ -2069,7 +2076,7 @@ theorem append_eq_filterMap_iff {f : α → Option β} :
|
||||
∃ as bs, zs = as ++ bs ∧ filterMap f as = xs ∧ filterMap f bs = ys := by
|
||||
rw [eq_comm, filterMap_eq_append_iff]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} {xs ys : Array α} :
|
||||
@[simp, grind =] theorem map_append {f : α → β} {xs ys : Array α} :
|
||||
map f (xs ++ ys) = map f xs ++ map f ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
@@ -2085,9 +2092,9 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
@[simp, grind] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
|
||||
@[simp, grind =] theorem flatten_empty : (#[] : Array (Array α)).flatten = #[] := by simp [flatten]; rfl
|
||||
|
||||
@[simp, grind] theorem toList_flatten {xss : Array (Array α)} :
|
||||
@[simp, grind =] theorem toList_flatten {xss : Array (Array α)} :
|
||||
xss.flatten.toList = (xss.toList.map toList).flatten := by
|
||||
dsimp [flatten]
|
||||
simp only [← foldl_toList]
|
||||
@@ -2113,11 +2120,11 @@ theorem flatten_map_toArray {L : List (List α)} :
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
|
||||
@[simp, grind =] theorem size_flatten {xss : Array (Array α)} : xss.flatten.size = (xss.map size).sum := by
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
|
||||
@[simp, grind =] theorem flatten_singleton {xs : Array α} : #[xs].flatten = xs := by simp [flatten]; rfl
|
||||
|
||||
theorem mem_flatten : ∀ {xss : Array (Array α)}, a ∈ xss.flatten ↔ ∃ xs, xs ∈ xss ∧ a ∈ xs := by
|
||||
simp only [mem_def, toList_flatten, List.mem_flatten, List.mem_map]
|
||||
@@ -2160,7 +2167,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
|
||||
Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
|
||||
@[simp, grind] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
@[simp, grind =] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
@@ -2168,7 +2175,7 @@ theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap
|
||||
List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
|
||||
@[simp, grind] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
@[simp, grind =] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
@@ -2192,7 +2199,7 @@ theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]]
|
||||
induction xss₂ using array₂_induction
|
||||
simp [← List.map_append]
|
||||
|
||||
@[grind] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
|
||||
@[grind =] theorem flatten_push {xss : Array (Array α)} {xs : Array α} :
|
||||
flatten (xss.push xs) = flatten xss ++ xs := by
|
||||
induction xss using array₂_induction
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -2283,7 +2290,7 @@ theorem flatMap_def {xs : Array α} {f : α → Array β} : xs.flatMap f = flatt
|
||||
rcases xs with ⟨l⟩
|
||||
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
|
||||
|
||||
@[simp, grind] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
|
||||
@[simp, grind =] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
|
||||
|
||||
theorem flatMap_toList {xs : Array α} {f : α → List β} :
|
||||
xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
|
||||
@@ -2319,7 +2326,7 @@ theorem size_flatMap {xs : Array α} {f : α → Array β} :
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : 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₂⟩⟩
|
||||
|
||||
@@ -2347,7 +2354,7 @@ theorem flatMap_singleton {f : α → Array β} {x : α} : #[x].flatMap f = f x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem flatMap_push {xs : Array α} {x : α} {f : α → Array β} :
|
||||
@[simp, grind =] theorem flatMap_push {xs : Array α} {x : α} {f : α → Array β} :
|
||||
(xs.push x).flatMap f = xs.flatMap f ++ f x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -2416,9 +2423,9 @@ theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkArray_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_toArray, List.mem_replicate]
|
||||
simp only [List.mem_toArray, List.mem_replicate]
|
||||
|
||||
@[deprecated mem_replicate (since := "2025-03-18")]
|
||||
abbrev mem_mkArray := @mem_replicate
|
||||
@@ -2532,7 +2539,7 @@ abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
|
||||
@[deprecated map_replicate (since := "2025-03-18")]
|
||||
abbrev map_mkArray := @map_replicate
|
||||
|
||||
@[grind] theorem filter_replicate (w : stop = n) :
|
||||
@[grind =] theorem filter_replicate (w : stop = n) :
|
||||
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
|
||||
apply Array.ext'
|
||||
simp only [w]
|
||||
@@ -2631,14 +2638,14 @@ abbrev sum_mkArray_nat := @sum_replicate_nat
|
||||
|
||||
/-! ### Preliminaries about `swap` needed for `reverse`. -/
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_swap {xs : Array α} {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
|
||||
simp [swap_def, getElem?_set]
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp, grind] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
|
||||
@[simp, grind =] theorem size_reverse {xs : Array α} : xs.reverse.size = xs.size := by
|
||||
let rec go (as : Array α) (i j) : (reverse.loop as i j).size = as.size := by
|
||||
rw [reverse.loop]
|
||||
if h : i < j then
|
||||
@@ -2647,7 +2654,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
termination_by j - i
|
||||
simp only [reverse]; split <;> simp [go]
|
||||
|
||||
@[simp, grind] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
|
||||
@[simp, grind =] theorem reverse_empty : reverse (#[] : Array α) = #[] := rfl
|
||||
|
||||
@[simp] theorem toList_reverse {xs : Array α} : xs.reverse.toList = xs.toList.reverse := by
|
||||
let rec go (as : Array α) (i j hj)
|
||||
@@ -2702,7 +2709,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
|
||||
@[simp, grind =] theorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) :
|
||||
(xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega) := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -2731,14 +2738,14 @@ theorem getElem?_reverse' {xs : Array α} {i j} (h : i + j + 1 = xs.size) : xs.r
|
||||
simp only [List.reverse_toArray, List.getElem?_toArray]
|
||||
rw [List.getElem?_reverse' h]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {xs : Array α} {i} (h : i < xs.size) :
|
||||
xs.reverse[i]? = xs[xs.size - 1 - i]? := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
|
||||
@[simp, grind =] theorem reverse_reverse (xs : Array α) : xs.reverse.reverse = xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@@ -2777,7 +2784,7 @@ theorem reverse_eq_iff {xs ys : Array α} : xs.reverse = ys ↔ xs = ys.reverse
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
|
||||
@[simp, grind =] theorem reverse_append {xs ys : Array α} : (xs ++ ys).reverse = ys.reverse ++ xs.reverse := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
@@ -2801,17 +2808,17 @@ theorem flatten_reverse {xss : Array (Array α)} :
|
||||
cases xss using array₂_induction
|
||||
simp [flatten_toArray, List.flatten_reverse, Function.comp_def]
|
||||
|
||||
@[grind] theorem reverse_flatMap {β} {xs : Array α} {f : α → Array β} :
|
||||
@[grind =] theorem reverse_flatMap {β} {xs : Array α} {f : α → Array β} :
|
||||
(xs.flatMap f).reverse = xs.reverse.flatMap (reverse ∘ f) := by
|
||||
cases xs
|
||||
simp [List.reverse_flatMap, Function.comp_def]
|
||||
|
||||
@[grind] theorem flatMap_reverse {β} {xs : Array α} {f : α → Array β} :
|
||||
@[grind =] theorem flatMap_reverse {β} {xs : Array α} {f : α → Array β} :
|
||||
(xs.reverse.flatMap f) = (xs.flatMap (reverse ∘ f)).reverse := by
|
||||
cases xs
|
||||
simp [List.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 [← toList_inj]
|
||||
simp
|
||||
|
||||
@@ -2972,10 +2979,10 @@ theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : x
|
||||
simp only [extract, Nat.sub_eq, emptyWithCapacity_eq]
|
||||
rw [←Nat.sub_min_sub_right, Nat.sub_eq_zero_of_le h, Nat.min_zero, extract_loop_zero]
|
||||
|
||||
@[simp, grind] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
|
||||
@[simp, grind =] theorem extract_empty {start stop : Nat} : (#[] : Array α).extract start stop = #[] :=
|
||||
extract_empty_of_size_le_start (Nat.zero_le _)
|
||||
|
||||
@[simp, grind] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
|
||||
@[simp, grind =] theorem extract_zero {xs : Array α} : xs.extract start 0 = #[] := by
|
||||
ext i h₁ h₂
|
||||
· simp
|
||||
· simp at h₁
|
||||
@@ -3169,7 +3176,7 @@ theorem foldlM_append [Monad m] [LawfulMonad m] {f : β → α → m β} {b} {xs
|
||||
· rfl
|
||||
· simp at h₂
|
||||
|
||||
@[simp, grind] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} {start stop : Nat} :
|
||||
@[simp, grind =] theorem foldrM_empty [Monad m] {f : α → β → m β} {init : β} {start stop : Nat} :
|
||||
foldrM f init #[] start stop = return init := by
|
||||
simp [foldrM]
|
||||
|
||||
@@ -3243,6 +3250,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
(xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
|
||||
simp [← foldrM_push, h]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ (← l.reverse.mapM f).toArray := by
|
||||
induction l with
|
||||
@@ -3255,15 +3263,16 @@ rather than `(arr.push a).size` as the argument.
|
||||
funext x
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ (← l.mapM f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-! ### foldl / foldr -/
|
||||
|
||||
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
|
||||
@[grind =] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
|
||||
|
||||
@[grind] theorem foldr_empty {f : α → β → β} {init : β} : (#[].foldr f init) = init := rfl
|
||||
@[grind =] theorem foldr_empty {f : α → β → β} {init : β} : (#[].foldr f init) = init := rfl
|
||||
|
||||
theorem foldl_induction
|
||||
{as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → β}
|
||||
@@ -3311,7 +3320,7 @@ theorem foldl_push {f : β → α → β} {init : β} {xs : Array α} {a : α} :
|
||||
foldlM_push ..
|
||||
|
||||
/-- Variant of `foldl_push` with a side condition for the `stop` argument. -/
|
||||
@[simp, grind] theorem foldl_push' {f : β → α → β} {init : β} {xs : Array α} {a : α} {stop : Nat}
|
||||
@[simp, grind =] theorem foldl_push' {f : β → α → β} {init : β} {xs : Array α} {a : α} {stop : Nat}
|
||||
(h : stop = xs.size + 1) :
|
||||
(xs.push a).foldl f init 0 stop = f (xs.foldl f init) a := by
|
||||
subst h
|
||||
@@ -3324,10 +3333,11 @@ theorem foldr_push {f : α → β → β} {init : β} {xs : Array α} {a : α} :
|
||||
Variant of `foldr_push` with the `h : start = arr.size + 1`
|
||||
rather than `(arr.push a).size` as the argument.
|
||||
-/
|
||||
@[simp, grind] theorem foldr_push' {f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat}
|
||||
@[simp, grind =] theorem foldr_push' {f : α → β → β} {init : β} {xs : Array α} {a : α} {start : Nat}
|
||||
(h : start = xs.size + 1) : (xs.push a).foldr f init start = xs.foldr f (f a init) :=
|
||||
foldrM_push' h
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f := by
|
||||
subst w
|
||||
@@ -3336,12 +3346,14 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp only [List.foldl_toArray']
|
||||
induction as generalizing bs <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : start = as.size) :
|
||||
as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs := by
|
||||
subst w
|
||||
@@ -3349,27 +3361,29 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp
|
||||
|
||||
/-- Variant of `foldr_cons_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
|
||||
@[simp, grind =] theorem foldr_cons_eq_append' {as : Array α} {bs : List α} (w : start = as.size) :
|
||||
as.foldr List.cons bs start 0 = as.toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldr_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
|
||||
@[simp, grind =] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldr (fun x xs => xs.push x) xs = xs ++ l.reverse.toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
/-- Variant of `List.foldl_push_eq_append` specialized to `f = id`. -/
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
|
||||
@[simp, grind =] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
|
||||
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
|
||||
simpa using List.foldl_push_eq_append (f := id)
|
||||
|
||||
@@ -3381,24 +3395,28 @@ theorem _root_.List.foldl_push {l : List α} {as : Array α} : l.foldl Array.pus
|
||||
theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
|
||||
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys:= by
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -3527,12 +3545,12 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldr_flatten, List.foldr_map]
|
||||
|
||||
@[grind] theorem foldl_flatten {f : β → α → β} {b} {xss : Array (Array α)} :
|
||||
@[grind =] theorem foldl_flatten {f : β → α → β} {b} {xss : Array (Array α)} :
|
||||
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldl_flatten, List.foldl_map]
|
||||
|
||||
@[grind] theorem foldr_flatten {f : α → β → β} {b} {xss : Array (Array α)} :
|
||||
@[grind =] theorem foldr_flatten {f : α → β → β} {b} {xss : Array (Array α)} :
|
||||
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.foldr_flatten, List.foldr_map]
|
||||
@@ -3549,11 +3567,11 @@ theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b} {xs
|
||||
xs.reverse.foldr f b start 0 = xs.foldl (fun x y => f y x) b :=
|
||||
foldrM_reverse' w
|
||||
|
||||
@[grind] theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
@[grind =] theorem foldl_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
|
||||
foldlM_reverse
|
||||
|
||||
@[grind] theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
@[grind =] theorem foldr_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
|
||||
foldrM_reverse
|
||||
|
||||
@@ -3658,7 +3676,7 @@ theorem mem_of_back? {xs : Array α} {a : α} (h : xs.back? = some a) : a ∈ xs
|
||||
simp only [List.append_toArray, List.back_toArray]
|
||||
rw [List.getLast_append_of_ne_nil]
|
||||
|
||||
@[grind] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
|
||||
@[grind =] theorem back_append {xs : Array α} (h : 0 < (xs ++ ys).size) :
|
||||
(xs ++ ys).back h =
|
||||
if h' : ys.isEmpty then
|
||||
xs.back (by simp_all)
|
||||
@@ -3689,7 +3707,7 @@ theorem back_append_left {xs ys : Array α} (w : 0 < (xs ++ ys).size) (h : ys.si
|
||||
rw [List.getLast_append_left]
|
||||
simpa using h
|
||||
|
||||
@[simp, grind] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
@[simp, grind =] theorem back?_append {xs ys : Array α} : (xs ++ ys).back? = ys.back?.or xs.back? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.back?_toArray]
|
||||
@@ -3761,6 +3779,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.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 : Array α} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
@@ -4003,10 +4025,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
cases xss using array₂_induction
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[grind] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
|
||||
@[grind =] theorem any_flatten {xss : Array (Array α)} : xss.flatten.any f = xss.any (any · f) := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
|
||||
@[grind =] theorem all_flatten {xss : Array (Array α)} : xss.flatten.all f = xss.all (all · f) := by
|
||||
simp
|
||||
|
||||
/-- Variant of `any_flatMap` with a side condition for the `stop` argument. -/
|
||||
@@ -4025,11 +4047,11 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
rw [List.flatMap_toArray]
|
||||
simp [List.all_flatMap]
|
||||
|
||||
@[grind] theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[grind =] theorem any_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).any p 0 = xs.any fun a => (f a).any p := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[grind =] theorem all_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).all p 0 = xs.all fun a => (f a).all p := by
|
||||
simp
|
||||
|
||||
@@ -4047,10 +4069,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
rw [List.reverse_toArray]
|
||||
simp [List.all_reverse]
|
||||
|
||||
@[grind] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
|
||||
@[grind =] theorem any_reverse {xs : Array α} : xs.reverse.any f 0 = xs.any f := by
|
||||
simp
|
||||
|
||||
@[grind] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
|
||||
@[grind =] theorem all_reverse {xs : Array α} : xs.reverse.all f 0 = xs.all f := by
|
||||
simp
|
||||
|
||||
@[simp] theorem any_replicate {n : Nat} {a : α} :
|
||||
@@ -4121,7 +4143,7 @@ theorem getElem_swap' {xs : Array α} {i j : Nat} {hi hj} {k : Nat} (hk : k < xs
|
||||
· simp_all only [getElem_swap_left]
|
||||
· split <;> simp_all
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} (hk : k < (xs.swap i j hi hj).size) :
|
||||
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k]'(by simp_all) := by
|
||||
apply getElem_swap'
|
||||
@@ -4172,13 +4194,13 @@ theorem swapAt!_def {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
section replace
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
|
||||
@[simp, grind =] theorem replace_empty : (#[] : Array α).replace a b = #[] := by simp [replace]
|
||||
|
||||
@[simp, grind] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
|
||||
@[simp, grind =] theorem replace_singleton {a b c : α} : #[a].replace b c = #[if a == b then c else a] := by
|
||||
simp only [replace, List.finIdxOf?_toArray, List.finIdxOf?]
|
||||
by_cases h : a == b <;> simp [h]
|
||||
|
||||
@[simp, grind] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
|
||||
@[simp, grind =] theorem size_replace {xs : Array α} : (xs.replace a b).size = xs.size := by
|
||||
simp only [replace]
|
||||
split <;> simp
|
||||
|
||||
@@ -4190,17 +4212,17 @@ variable [LawfulBEq α]
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace {xs : Array α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace {xs : Array α} {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⟩
|
||||
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
|
||||
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, mem_toArray]
|
||||
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, List.mem_toArray]
|
||||
|
||||
theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? ≠ some a) :
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
@[grind =] theorem getElem_replace {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
(xs.replace a b)[i]'(by simpa) = 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]
|
||||
@@ -4211,14 +4233,14 @@ theorem getElem_replace_of_ne {xs : Array α} {i : Nat} {h : i < xs.size} (h' :
|
||||
rw [getElem_replace h]
|
||||
simp [h']
|
||||
|
||||
@[grind] theorem replace_append {xs ys : Array α} :
|
||||
@[grind =] theorem replace_append {xs ys : Array α} :
|
||||
(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⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.replace_toArray, List.replace_append, mem_toArray]
|
||||
simp only [List.append_toArray, List.replace_toArray, List.replace_append, List.mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem replace_push {xs : Array α} {a b c : α} :
|
||||
@[grind =] theorem replace_push {xs : Array α} {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⟩
|
||||
simp [List.replace_append]
|
||||
@@ -4369,7 +4391,7 @@ theorem getElem?_range {n : Nat} {i : Nat} : (Array.range n)[i]? = if i < n then
|
||||
|
||||
/-! ### sum -/
|
||||
|
||||
@[simp, grind] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
|
||||
@[simp, grind =] theorem sum_empty [Add α] [Zero α] : (#[] : Array α).sum = 0 := rfl
|
||||
|
||||
-- Without further algebraic hypotheses, there's no useful `sum_push` lemma.
|
||||
|
||||
@@ -4442,7 +4464,7 @@ theorem getElem_mem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]
|
||||
theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default := by
|
||||
simp [back!, back?, getElem!_def, Option.getD]; rfl
|
||||
|
||||
@[simp, grind] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
|
||||
@[simp, grind =] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
|
||||
simp [back?]
|
||||
|
||||
@[simp] theorem back!_push [Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x := by
|
||||
@@ -4450,10 +4472,10 @@ theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD
|
||||
|
||||
theorem getElem?_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
|
||||
(xs.push x)[i]? = some xs[i] := by
|
||||
rw [getElem?_pos, getElem_push_lt]
|
||||
rw [getElem?_pos (xs.push x) i (size_push _ ▸ Nat.lt_succ_of_lt h), getElem_push_lt]
|
||||
|
||||
theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x := by
|
||||
rw [getElem?_pos, getElem_push_eq]
|
||||
rw [getElem?_pos (xs.push x) xs.size (size_push _ ▸ Nat.lt_succ_self xs.size), getElem_push_eq]
|
||||
|
||||
@[simp] theorem getElem?_size {xs : Array α} : xs[xs.size]? = none := by
|
||||
simp only [getElem?_def, Nat.lt_irrefl, dite_false]
|
||||
|
||||
@@ -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} :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -34,20 +34,104 @@ 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`. -/
|
||||
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 : α`. -/
|
||||
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`. -/
|
||||
@[grind]
|
||||
def LeftInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
∀ x, g (f x) = x
|
||||
|
||||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||||
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`. -/
|
||||
@[grind]
|
||||
def RightInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
LeftInverse f g
|
||||
|
||||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||||
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
|
||||
|
||||
@@ -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) :=
|
||||
|
||||
@@ -174,7 +174,7 @@ theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
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 +192,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
|
||||
@@ -370,13 +371,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
|
||||
|
||||
@@ -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 -/
|
||||
|
||||
@@ -332,7 +332,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 +365,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 +383,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 +420,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 +441,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 -/
|
||||
|
||||
@@ -490,8 +490,8 @@ Examples:
|
||||
| [] => []
|
||||
| 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 +511,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 +537,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 +561,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 +591,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
|
||||
@@ -645,10 +645,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 +658,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,7 +685,7 @@ 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]
|
||||
|
||||
@@ -704,8 +704,8 @@ 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 -/
|
||||
|
||||
@@ -731,8 +731,8 @@ Examples:
|
||||
-/
|
||||
@[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]
|
||||
|
||||
/-! ### replicate -/
|
||||
@@ -748,10 +748,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 +819,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 +842,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 +958,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 +980,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 +1094,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 +1439,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 +1648,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 +1906,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 +1925,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 +2066,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 -/
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -558,7 +559,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
|
||||
|
||||
@@ -306,7 +306,7 @@ theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getElem?_singleton {a : α} {i : Nat} : [a][i]? = if i = 0 then some a else none := by
|
||||
simp [getElem?_cons]
|
||||
|
||||
@@ -382,14 +382,20 @@ theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! :=
|
||||
|
||||
@[simp] theorem not_mem_nil {a : α} : ¬ a ∈ [] := nofun
|
||||
|
||||
@[simp] theorem mem_cons : a ∈ b :: l ↔ a = b ∨ a ∈ l :=
|
||||
@[simp, grind =] theorem mem_cons : a ∈ b :: l ↔ a = b ∨ a ∈ l :=
|
||||
⟨fun h => by cases h <;> simp [Membership.mem, *],
|
||||
fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption⟩
|
||||
|
||||
@[grind] theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
|
||||
theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
|
||||
a ∈ b :: l → a = b ∨ a ∈ l := List.mem_cons.mp
|
||||
|
||||
@[grind] theorem mem_cons_self {a : α} {l : List α} : a ∈ a :: l := .head ..
|
||||
-- This pattern may be excessively general:
|
||||
-- it fires anytime we ae thinking about membership of lists,
|
||||
-- and constructing a list via `cons`, even if the elements are unrelated.
|
||||
-- Nevertheless in practice it is quite helpful!
|
||||
grind_pattern eq_or_mem_of_mem_cons => b :: l, a ∈ l
|
||||
|
||||
theorem mem_cons_self {a : α} {l : List α} : a ∈ a :: l := .head ..
|
||||
|
||||
theorem mem_concat_self {xs : List α} {a : α} : a ∈ xs ++ [a] :=
|
||||
mem_append_right xs mem_cons_self
|
||||
@@ -411,7 +417,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
· obtain ⟨as, bs, rfl, h⟩ := ih h
|
||||
exact ⟨x :: as, bs, rfl, by simp_all⟩
|
||||
|
||||
@[grind] theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l := .tail _
|
||||
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l := .tail _
|
||||
|
||||
-- The argument `l : List α` is intentionally explicit,
|
||||
-- as a tactic may generate `h` without determining `l`.
|
||||
@@ -547,10 +553,10 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
|
||||
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
|
||||
as.contains a = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
|
||||
|
||||
@[simp, grind] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
|
||||
@[simp, grind =] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
|
||||
(a :: l).contains b = (b == a || l.contains b) := by
|
||||
simp only [contains, elem_cons]
|
||||
split <;> simp_all
|
||||
@@ -605,7 +611,7 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
@[simp] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
|
||||
simp [all_eq]
|
||||
|
||||
@[grind] theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
|
||||
induction l <;> simp_all [contains_cons]
|
||||
|
||||
/-- Variant of `any_beq` with `==` reversed. -/
|
||||
@@ -613,7 +619,7 @@ theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
(l.any fun x => x == a) = l.contains a := by
|
||||
simp only [BEq.comm, any_beq]
|
||||
|
||||
@[grind] theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
|
||||
induction l <;> simp_all [bne]
|
||||
|
||||
/-- Variant of `all_bne` with `!=` reversed. -/
|
||||
@@ -624,10 +630,10 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
/-! ### set -/
|
||||
|
||||
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@[simp, grind] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
|
||||
@[simp, grind] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
|
||||
@[simp, grind =] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
|
||||
@[simp, grind =] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
|
||||
(x :: xs).set 0 a = a :: xs := rfl
|
||||
@[simp, grind] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
|
||||
(x :: xs).set (i + 1) a = x :: xs.set i a := rfl
|
||||
|
||||
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
|
||||
@@ -670,14 +676,14 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
simp_all
|
||||
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
|
||||
|
||||
@[grind] theorem getElem_set {l : List α} {i j} {a} (h) :
|
||||
@[grind =] theorem getElem_set {l : List α} {i j} {a} (h) :
|
||||
(set l i a)[j]'h = if i = j then a else l[j]'(length_set .. ▸ h) := by
|
||||
if h : i = j then
|
||||
subst h; simp only [getElem_set_self, ↓reduceIte]
|
||||
else
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
|
||||
@[grind =] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
|
||||
(l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
|
||||
if h : i = j then
|
||||
subst h
|
||||
@@ -747,10 +753,10 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.s
|
||||
|
||||
/-! ### BEq -/
|
||||
|
||||
@[simp, grind] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
@[simp, grind =] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
@[simp, grind =] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[deprecated beq_nil_eq (since := "2025-04-04")]
|
||||
@@ -759,7 +765,7 @@ abbrev beq_nil_iff := @beq_nil_eq
|
||||
@[deprecated nil_beq_eq (since := "2025-04-04")]
|
||||
abbrev nil_beq_iff := @nil_beq_eq
|
||||
|
||||
@[simp, grind] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
@[simp, grind =] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
@@ -825,7 +831,7 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
|
||||
|
||||
/-! ### getLast -/
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast_eq_getElem : ∀ {l : List α} (h : l ≠ []),
|
||||
getLast l h = l[l.length - 1]'(by
|
||||
match l with
|
||||
@@ -839,7 +845,7 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@[simp, grind] theorem getLast_cons_cons {a : α} {l : List α} :
|
||||
@[simp, grind =] theorem getLast_cons_cons {a : α} {l : List α} :
|
||||
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) :=
|
||||
rfl
|
||||
|
||||
@@ -852,10 +858,10 @@ theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
|
||||
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
|
||||
@[simp, grind =] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp, grind] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
|
||||
@[simp, grind =] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
|
||||
|
||||
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
simp [getLast!, getLast_eq_getLastD]
|
||||
@@ -888,7 +894,7 @@ theorem getLast?_eq_getLast : ∀ {l : List α} h, l.getLast? = some (l.getLast
|
||||
| [], h => nomatch h rfl
|
||||
| _ :: _, _ => rfl
|
||||
|
||||
@[grind] theorem getLast?_eq_getElem? : ∀ {l : List α}, l.getLast? = l[l.length - 1]?
|
||||
@[grind =] theorem getLast?_eq_getElem? : ∀ {l : List α}, l.getLast? = l[l.length - 1]?
|
||||
| [] => rfl
|
||||
| a::l => by
|
||||
rw [getLast?_eq_getLast (l := a :: l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
|
||||
@@ -901,14 +907,14 @@ theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
|
||||
-- `getLast?_eq_none_iff`, `getLast?_eq_some_iff`, `getLast?_isSome`, and `getLast_mem`
|
||||
-- are proved later once more `reverse` theorems are available.
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast?_cons {a : α} : (a::l).getLast? = some (l.getLast?.getD a) := by
|
||||
cases l <;> simp [getLast?, getLast]
|
||||
|
||||
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
|
||||
simp [getLast?_cons]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast?_concat {l : List α} {a : α} : (l ++ [a]).getLast? = some a := by
|
||||
simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
|
||||
|
||||
@@ -927,14 +933,14 @@ theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons _ _ =>
|
||||
apply getLast!_of_getLast?
|
||||
rw [getElem!_pos, getElem_cons_length (h := by simp)]
|
||||
rfl
|
||||
rw [getLast?_eq_getElem?]
|
||||
simp
|
||||
|
||||
/-! ## Head and tail -/
|
||||
|
||||
@@ -955,7 +961,7 @@ theorem head?_eq_getElem? : ∀ {l : List α}, l.head? = l[0]?
|
||||
|
||||
theorem head_singleton {a : α} : head [a] (by simp) = a := by simp
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem head_eq_getElem {l : List α} (h : l ≠ []) : head l h = l[0]'(length_pos_iff.mpr h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
@@ -1017,18 +1023,18 @@ theorem head_of_mem_head? {l : List α} {x} (hx : x ∈ l.head?) :
|
||||
/-! ### headD -/
|
||||
|
||||
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
|
||||
@[simp, grind] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
|
||||
@[simp, grind =] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
|
||||
cases l <;> simp [headD]
|
||||
|
||||
/-! ### tailD -/
|
||||
|
||||
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
|
||||
@[simp, grind] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
|
||||
@[simp, grind =] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
|
||||
cases l <;> rfl
|
||||
|
||||
/-! ### tail -/
|
||||
|
||||
@[simp, grind] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
|
||||
@[simp, grind =] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
|
||||
|
||||
theorem tail_eq_tailD {l : List α} : l.tail = tailD l [] := by cases l <;> rfl
|
||||
|
||||
@@ -1040,13 +1046,13 @@ theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := b
|
||||
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail ≠ [] → l ≠ [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
|
||||
@[simp, grind =] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
|
||||
(tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ l => simp
|
||||
|
||||
@[simp, grind] theorem getElem?_tail {l : List α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_tail {l : List α} {i : Nat} :
|
||||
(tail l)[i]? = l[i + 1]? := by
|
||||
cases l <;> simp
|
||||
|
||||
@@ -1070,7 +1076,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
|
||||
@[simp] theorem head?_tail {l : List α} : (tail l).head? = l[1]? := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[simp, grind] theorem getLast_tail {l : List α} (h : l.tail ≠ []) :
|
||||
@[simp, grind =] theorem getLast_tail {l : List α} (h : l.tail ≠ []) :
|
||||
(tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
|
||||
simp only [getLast_eq_getElem, length_tail, getElem_tail]
|
||||
congr
|
||||
@@ -1096,7 +1102,7 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
@[simp, grind] theorem length_map {as : List α} (f : α → β) : (as.map f).length = as.length := by
|
||||
@[simp, grind =] theorem length_map {as : List α} (f : α → β) : (as.map f).length = as.length := by
|
||||
induction as with
|
||||
| nil => simp [List.map]
|
||||
| cons _ as ih => simp [List.map, ih]
|
||||
@@ -1104,13 +1110,13 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
|
||||
@[simp] theorem isEmpty_map {l : List α} {f : α → β} : (l.map f).isEmpty = l.isEmpty := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem?_map {f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
|
||||
@[simp, grind =] theorem getElem?_map {f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
|
||||
| [], _ => rfl
|
||||
| _ :: _, 0 => by simp
|
||||
| _ :: l, i+1 => by simp [getElem?_map]
|
||||
|
||||
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
|
||||
@[simp, grind] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
@[simp, grind =] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
(map f l)[i] = f (l[i]'(length_map f ▸ h)) :=
|
||||
Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
|
||||
|
||||
@@ -1156,7 +1162,9 @@ theorem forall_mem_map {f : α → β} {l : List α} {P : β → Prop} :
|
||||
@[simp] theorem map_eq_nil_iff {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
@[grind →]
|
||||
-- This would be helpful as a `grind` lemma if
|
||||
-- we could have it fire only once `map f l` and `[]` are the same equivalence class.
|
||||
-- Otherwise it is too aggressive.
|
||||
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
|
||||
map_eq_nil_iff.mp h
|
||||
|
||||
@@ -1276,7 +1284,7 @@ theorem getLastD_map {f : α → β} {l : List α} {a : α} : (map f l).getLastD
|
||||
@[simp] theorem filter_cons_of_neg {p : α → Bool} {a : α} {l} (pa : ¬ p a) :
|
||||
filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
|
||||
|
||||
@[grind] theorem filter_cons :
|
||||
@[grind =] theorem filter_cons :
|
||||
(x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
|
||||
split <;> simp [*]
|
||||
|
||||
@@ -1315,7 +1323,7 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
|
||||
@[deprecated length_filter_eq_length_iff (since := "2025-04-04")]
|
||||
abbrev filter_length_eq_length := @length_filter_eq_length_iff
|
||||
|
||||
@[simp, grind] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
@[simp, grind =] theorem mem_filter : x ∈ filter p as ↔ x ∈ as ∧ p x := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
@@ -1330,13 +1338,15 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
|
||||
(∀ (i) (_ : i ∈ l.filter p), P i) ↔ ∀ (j) (_ : j ∈ l), p j → P j := by
|
||||
simp
|
||||
|
||||
@[grind] theorem getElem_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length) :
|
||||
theorem getElem_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length) :
|
||||
p (xs.filter p)[i] :=
|
||||
(mem_filter.mp (getElem_mem h)).2
|
||||
|
||||
grind_pattern getElem_filter => (xs.filter p)[i]
|
||||
|
||||
theorem getElem?_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
rw [getElem?_eq_getElem h] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
@@ -1377,7 +1387,7 @@ theorem map_filter_eq_foldr {f : α → β} {p : α → Bool} {as : List α} :
|
||||
simp only [foldr]
|
||||
cases hp : p head <;> simp [filter, *]
|
||||
|
||||
@[simp, grind] theorem filter_append {p : α → Bool} :
|
||||
@[simp, grind =] theorem filter_append {p : α → Bool} :
|
||||
∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
|
||||
| [], _ => rfl
|
||||
| a :: l₁, l₂ => by simp only [cons_append, filter]; split <;> simp [filter_append l₁]
|
||||
@@ -1442,7 +1452,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
|
||||
erw [filterMap_eq_map]
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
@[simp, grind =] theorem filterMap_some {l : List α} : filterMap some l = l := by
|
||||
rw [filterMap_some_fun, id]
|
||||
|
||||
theorem map_filterMap_some_eq_filter_map_isSome {f : α → Option β} {l : List α} :
|
||||
@@ -1477,19 +1487,19 @@ theorem filterMap_eq_filter {p : α → Bool} :
|
||||
| nil => rfl
|
||||
| cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, ← IH]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {l : List α} :
|
||||
filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons a l IH => cases h : f a <;> simp [filterMap_cons, *]
|
||||
|
||||
@[grind]
|
||||
@[grind =]
|
||||
theorem map_filterMap {f : α → Option β} {g : β → γ} {l : List α} :
|
||||
map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by
|
||||
simp only [← filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem filterMap_map {f : α → β} {g : β → Option γ} {l : List α} :
|
||||
filterMap g (map f l) = filterMap (g ∘ f) l := by
|
||||
rw [← filterMap_eq_map, filterMap_filterMap]; rfl
|
||||
@@ -1504,7 +1514,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {l : List α}
|
||||
rw [← filterMap_eq_filter, filterMap_filterMap]
|
||||
congr; funext x; by_cases h : p x <;> simp [Option.guard, h]
|
||||
|
||||
@[simp, grind] theorem mem_filterMap {f : α → Option β} {l : List α} {b : β} :
|
||||
@[simp, grind =] theorem mem_filterMap {f : α → Option β} {l : List α} {b : β} :
|
||||
b ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b := by
|
||||
induction l <;> simp [filterMap_cons]; split <;> simp [*, eq_comm]
|
||||
|
||||
@@ -1516,7 +1526,7 @@ theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Pr
|
||||
intro a
|
||||
rw [forall_comm]
|
||||
|
||||
@[simp, grind] theorem filterMap_append {l l' : List α} {f : α → Option β} :
|
||||
@[simp, grind =] theorem filterMap_append {l l' : List α} {f : α → Option β} :
|
||||
filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by
|
||||
induction l <;> simp [filterMap_cons]; split <;> simp [*]
|
||||
|
||||
@@ -1588,7 +1598,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
@[simp] theorem cons_append_fun {a : α} {as : List α} :
|
||||
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
||||
|
||||
@[simp, grind] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
@[simp, grind =] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
induction s <;> simp_all [or_assoc]
|
||||
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
@@ -1611,7 +1621,7 @@ theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
|
||||
(∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
@[grind] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
|
||||
@[grind =] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
|
||||
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
split <;> rename_i h'
|
||||
· rw [getElem_append_left h']
|
||||
@@ -1630,7 +1640,7 @@ theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length
|
||||
rw [cons_append]
|
||||
simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
|
||||
|
||||
@[grind] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
(l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
|
||||
split <;> rename_i h
|
||||
· exact getElem?_append_left h
|
||||
@@ -1709,7 +1719,6 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
|
||||
theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem eq_nil_of_append_eq_nil {l₁ l₂ : List α} (h : l₁ ++ l₂ = []) : l₁ = [] ∧ l₂ = [] :=
|
||||
append_eq_nil_iff.mp h
|
||||
|
||||
@@ -1739,12 +1748,12 @@ theorem append_eq_append_iff {ws xs ys zs : List α} :
|
||||
| nil => simp_all
|
||||
| cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
|
||||
|
||||
@[simp, grind] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
|
||||
@[simp, grind =] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
|
||||
head (l ++ l') w₁ = head l w₂ := by
|
||||
match l, w₂ with
|
||||
| a :: l, _ => rfl
|
||||
|
||||
@[grind] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) :
|
||||
@[grind =] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) :
|
||||
head (l₁ ++ l₂) w =
|
||||
if h : l₁.isEmpty then
|
||||
head l₂ (by simp_all [isEmpty_iff])
|
||||
@@ -1765,28 +1774,28 @@ theorem head_append_right {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l
|
||||
head (l₁ ++ l₂) w = head l₂ (by simp_all) := by
|
||||
rw [head_append, dif_pos (by simp_all)]
|
||||
|
||||
@[simp, grind] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
|
||||
@[simp, grind =] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
|
||||
cases l <;> simp
|
||||
|
||||
-- Note:
|
||||
-- `getLast_append_of_ne_nil`, `getLast_append` and `getLast?_append`
|
||||
-- are stated and proved later in the `reverse` section.
|
||||
|
||||
@[grind] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
|
||||
@[grind =] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem tail?_append_of_ne_nil {l l' : List α} (_ : l ≠ []) : (l ++ l').tail? = some (l.tail ++ l') :=
|
||||
match l with
|
||||
| _ :: _ => by simp
|
||||
|
||||
@[grind] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
|
||||
@[grind =] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem tail_append_of_ne_nil {xs ys : List α} (h : xs ≠ []) :
|
||||
(xs ++ ys).tail = xs.tail ++ ys := by
|
||||
simp_all [tail_append]
|
||||
|
||||
@[grind] theorem set_append {s t : List α} :
|
||||
@[grind =] theorem set_append {s t : List α} :
|
||||
(s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
|
||||
induction s generalizing i with
|
||||
| nil => simp
|
||||
@@ -1844,7 +1853,7 @@ theorem append_eq_filter_iff {p : α → Bool} :
|
||||
L₁ ++ L₂ = filter p l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂ := by
|
||||
rw [eq_comm, filter_eq_append_iff]
|
||||
|
||||
@[simp, grind] theorem map_append {f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
@[simp, grind =] theorem map_append {f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
intro l₁; induction l₁ <;> intros <;> simp_all
|
||||
|
||||
theorem map_eq_append_iff {f : α → β} :
|
||||
@@ -1917,7 +1926,7 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ l' b, l = concat l' b
|
||||
| cons =>
|
||||
simp [flatten, length_append, *]
|
||||
|
||||
@[grind] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
|
||||
@[grind =] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
|
||||
|
||||
@[simp] theorem mem_flatten : ∀ {L : List (List α)}, a ∈ L.flatten ↔ ∃ l, l ∈ L ∧ a ∈ l
|
||||
| [] => by simp
|
||||
@@ -2092,7 +2101,7 @@ theorem length_flatMap {l : List α} {f : α → List β} :
|
||||
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||
@[simp, grind =] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ 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₂⟩⟩
|
||||
|
||||
@@ -2119,7 +2128,7 @@ theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
|
||||
@[simp] theorem flatMap_singleton' (l : List α) : (l.flatMap fun x => [x]) = l := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[grind] theorem head?_flatMap {l : List α} {f : α → List β} :
|
||||
@[grind =] theorem head?_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).head? = l.findSome? fun a => (f a).head? := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -2172,7 +2181,7 @@ theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
|
||||
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
|
||||
induction n <;> simp_all [replicate_succ, ← cons_append]
|
||||
|
||||
@[simp, grind] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
|
||||
| 0 => by simp
|
||||
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
|
||||
|
||||
@@ -2197,11 +2206,11 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicate n a = [] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp, grind] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
|
||||
@[simp, grind =] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
|
||||
(replicate n a)[i] = a :=
|
||||
eq_of_mem_replicate (getElem_mem _)
|
||||
|
||||
@[grind] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
@[grind =] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
|
||||
by_cases h : i < n
|
||||
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
|
||||
· rw [getElem?_eq_none (by simpa using h), if_neg h]
|
||||
@@ -2209,7 +2218,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
|
||||
@[grind =] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
|
||||
cases n <;> simp [replicate_succ]
|
||||
|
||||
@[simp] theorem head_replicate (w : replicate n a ≠ []) : (replicate n a).head w = a := by
|
||||
@@ -2298,7 +2307,7 @@ theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
|
||||
simp only [getElem?_map, getElem?_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
|
||||
@[grind =] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
@@ -2401,7 +2410,7 @@ termination_by l.length
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp, grind] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
|
||||
@[simp, grind =] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih => simp [ih]
|
||||
@@ -2410,7 +2419,7 @@ theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈
|
||||
| [], _ => ⟨.inr, fun | .inr h => h⟩
|
||||
| a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons]
|
||||
|
||||
@[simp, grind] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as := by
|
||||
@[simp, grind =] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as := by
|
||||
simp [reverse, mem_reverseAux]
|
||||
|
||||
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] ↔ xs = [] := by
|
||||
@@ -2434,14 +2443,14 @@ theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
|
||||
rw [getElem?_append_left, getElem?_reverse' this]
|
||||
rw [length_reverse, ← this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
|
||||
l.reverse[i]? = l[l.length - 1 - i]? :=
|
||||
getElem?_reverse' <| by
|
||||
rw [Nat.add_sub_of_le (Nat.le_sub_one_of_lt h),
|
||||
Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
|
||||
l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h)) := by
|
||||
apply Option.some.inj
|
||||
@@ -2454,7 +2463,7 @@ theorem reverseAux_reverseAux_nil {as bs : List α} : reverseAux (reverseAux as
|
||||
| cons a as ih => simp [reverseAux, ih]
|
||||
|
||||
-- The argument `as : List α` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
|
||||
@[simp, grind =] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
|
||||
simp only [reverse]; rw [reverseAux_reverseAux_nil]; rfl
|
||||
|
||||
theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse := by
|
||||
@@ -2467,10 +2476,10 @@ theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse :
|
||||
xs.reverse = a :: ys ↔ xs = ys.reverse ++ [a] := by
|
||||
rw [reverse_eq_iff, reverse_cons]
|
||||
|
||||
@[simp, grind] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
|
||||
@[simp, grind =] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
|
||||
cases l <;> simp [getLast?_concat]
|
||||
|
||||
@[simp, grind] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
|
||||
@[simp, grind =] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
|
||||
rw [← getLast?_reverse, reverse_reverse]
|
||||
|
||||
theorem getLast?_eq_head?_reverse {xs : List α} : xs.getLast? = xs.reverse.head? := by
|
||||
@@ -2534,16 +2543,16 @@ theorem flatten_reverse {L : List (List α)} :
|
||||
L.reverse.flatten = (L.map reverse).flatten.reverse := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[grind] theorem reverse_flatMap {β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f) := by
|
||||
@[grind =] theorem reverse_flatMap {β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[grind] theorem flatMap_reverse {β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse := by
|
||||
@[grind =] theorem flatMap_reverse {β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem reverseAux_eq {as bs : List α} : reverseAux as bs = reverse as ++ bs :=
|
||||
reverseAux_eq_append ..
|
||||
|
||||
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
|
||||
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
|
||||
eq_replicate_iff.2
|
||||
⟨by rw [length_reverse, length_replicate],
|
||||
fun _ h => eq_of_mem_replicate (mem_reverse.1 h)⟩
|
||||
@@ -2555,7 +2564,7 @@ theorem flatten_reverse {L : List (List α)} :
|
||||
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
|
||||
induction l generalizing b <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} :
|
||||
@[simp, grind =] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} :
|
||||
(a :: l).foldrM f b = l.foldrM f b >>= f a := by
|
||||
simp only [foldrM]
|
||||
induction l <;> simp_all
|
||||
@@ -2599,37 +2608,37 @@ theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
|
||||
/-! ### foldl and foldr -/
|
||||
|
||||
@[simp, grind] theorem foldr_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
@[simp] theorem foldr_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
|
||||
@[simp, grind] theorem foldr_cons_eq_append' {l l' : List β} :
|
||||
@[simp, grind =] theorem foldr_cons_eq_append' {l l' : List β} :
|
||||
l.foldr cons l' = l ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_flip_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
@[simp] theorem foldl_flip_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
|
||||
l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
/-- Variant of `foldl_flip_cons_eq_append` specalized to `f = id`. -/
|
||||
@[grind] theorem foldl_flip_cons_eq_append' {l l' : List α} :
|
||||
theorem foldl_flip_cons_eq_append' {l l' : List α} :
|
||||
l.foldl (fun xs y => y :: xs) l' = l.reverse ++ l' := by
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem foldr_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldr_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l' := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldl_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten := by
|
||||
induction l generalizing l'<;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldr_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldr_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
@[simp, grind] theorem foldl_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
@[simp] theorem foldl_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
|
||||
l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
|
||||
induction l generalizing l' <;> simp [*]
|
||||
|
||||
@@ -2683,19 +2692,19 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
@[simp, grind _=_] theorem foldr_append {f : α → β → β} {b : β} {l l' : List α} :
|
||||
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM, -foldrM_pure]
|
||||
|
||||
@[grind] theorem foldl_flatten {f : β → α → β} {b : β} {L : List (List α)} :
|
||||
@[grind =] theorem foldl_flatten {f : β → α → β} {b : β} {L : List (List α)} :
|
||||
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
|
||||
induction L generalizing b <;> simp_all
|
||||
|
||||
@[grind] theorem foldr_flatten {f : α → β → β} {b : β} {L : List (List α)} :
|
||||
@[grind =] theorem foldr_flatten {f : α → β → β} {b : β} {L : List (List α)} :
|
||||
(flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[simp, grind] theorem foldl_reverse {l : List α} {f : β → α → β} {b : β} :
|
||||
@[simp, grind =] theorem foldl_reverse {l : List α} {f : β → α → β} {b : β} :
|
||||
l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by
|
||||
simp [foldl_eq_foldlM, foldr_eq_foldrM, -foldrM_pure]
|
||||
|
||||
@[simp, grind] theorem foldr_reverse {l : List α} {f : α → β → β} {b : β} :
|
||||
@[simp, grind =] theorem foldr_reverse {l : List α} {f : α → β → β} {b : β} :
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
@@ -2849,7 +2858,7 @@ theorem foldr_rel {l : List α} {f : α → β → β} {g : α → γ → γ} {a
|
||||
|
||||
/-! #### Further results about `getLast` and `getLast?` -/
|
||||
|
||||
@[simp, grind] theorem head_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
@[simp, grind =] theorem head_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
l.reverse.head h = getLast l (by simp_all) := by
|
||||
induction l with
|
||||
| nil => contradiction
|
||||
@@ -2879,7 +2888,7 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
|
||||
rw [getLast?_eq_head?_reverse, isSome_head?]
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
@[simp, grind =] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
l.reverse.getLast h = l.head (by simp_all) := by
|
||||
simp [getLast_eq_head_reverse]
|
||||
|
||||
@@ -2892,7 +2901,7 @@ theorem head_eq_getLast_reverse {l : List α} (h : l ≠ []) :
|
||||
simp only [getLast_eq_head_reverse, reverse_append]
|
||||
rw [head_append_of_ne_nil]
|
||||
|
||||
@[grind] theorem getLast_append {l : List α} (h : l ++ l' ≠ []) :
|
||||
@[grind =] theorem getLast_append {l : List α} (h : l ++ l' ≠ []) :
|
||||
(l ++ l').getLast h =
|
||||
if h' : l'.isEmpty then
|
||||
l.getLast (by simp_all [isEmpty_iff])
|
||||
@@ -2913,7 +2922,7 @@ theorem getLast_append_left {l : List α} (w : l ++ l' ≠ []) (h : l' = []) :
|
||||
(l ++ l').getLast w = l.getLast (by simp_all) := by
|
||||
rw [getLast_append, dif_pos (by simp_all)]
|
||||
|
||||
@[simp, grind] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
|
||||
@[simp, grind =] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
|
||||
simp [← head?_reverse]
|
||||
|
||||
theorem getLast_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p (getLast l w) = true) :
|
||||
@@ -2949,7 +2958,7 @@ theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n
|
||||
/-! ### leftpad -/
|
||||
|
||||
-- We unfold `leftpad` and `rightpad` for verification purposes.
|
||||
attribute [simp, grind] leftpad rightpad
|
||||
attribute [simp, grind =] leftpad rightpad
|
||||
|
||||
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
|
||||
|
||||
@@ -2978,17 +2987,21 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ ∃ a' ∈ l, a == a' := by
|
||||
induction l <;> simp_all
|
||||
|
||||
-- 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 => l.contains a
|
||||
|
||||
@[grind _=_]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_map [BEq β] {l : List α} {x : β} {f : α → β} :
|
||||
(l.map f).contains x = l.any (fun a => x == f a) := by
|
||||
induction l with simp_all
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
|
||||
(l.filter p).contains x = l.any (fun a => x == a && p a) := by
|
||||
induction l with
|
||||
@@ -2997,7 +3010,7 @@ theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
|
||||
simp only [filter_cons, any_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_filterMap [BEq β] {l : List α} {x : β} {f : α → Option β} :
|
||||
(l.filterMap f).contains x = l.any (fun a => (f a).any fun b => x == b) := by
|
||||
induction l with
|
||||
@@ -3013,21 +3026,21 @@ theorem contains_append [BEq α] {l₁ l₂ : List α} {x : α} :
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Bool.or_assoc]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatten [BEq α] {l : List (List α)} {x : α} :
|
||||
l.flatten.contains x = l.any fun l => l.contains x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [ih]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_reverse [BEq α] {l : List α} {x : α} :
|
||||
(l.reverse).contains x = l.contains x := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Bool.or_comm]
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem contains_flatMap [BEq β] {l : List α} {f : α → List β} {x : β} :
|
||||
(l.flatMap f).contains x = l.any fun a => (f a).contains x := by
|
||||
induction l with
|
||||
@@ -3042,7 +3055,7 @@ Because we immediately simplify `partition` into two `filter`s for verification
|
||||
we do not separately develop much theory about it.
|
||||
-/
|
||||
|
||||
@[simp, grind] theorem partition_eq_filter_filter {p : α → Bool} {l : List α} :
|
||||
@[simp, grind =] theorem partition_eq_filter_filter {p : α → Bool} {l : List α} :
|
||||
partition p l = (filter p l, filter (not ∘ p) l) := by simp [partition, aux]
|
||||
where
|
||||
aux : ∀ l {as bs}, partition.loop p l (as, bs) =
|
||||
@@ -3062,16 +3075,16 @@ grind_pattern mem_partition => a ∈ (partition p l).2
|
||||
are often used for theorems about `Array.pop`.
|
||||
-/
|
||||
|
||||
@[simp, grind] theorem length_dropLast : ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
|
||||
@[simp, grind =] theorem length_dropLast : ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
|
||||
| [] => rfl
|
||||
| x::xs => by simp
|
||||
|
||||
@[simp, grind] theorem getElem_dropLast : ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
|
||||
@[simp, grind =] theorem getElem_dropLast : ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
|
||||
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
|
||||
| _ :: _ :: _, 0, _ => rfl
|
||||
| _ :: _ :: _, _ + 1, h => getElem_dropLast (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[grind] theorem getElem?_dropLast {xs : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_dropLast {xs : List α} {i : Nat} :
|
||||
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
|
||||
split
|
||||
· rw [getElem?_eq_getElem, getElem?_eq_getElem, getElem_dropLast]
|
||||
@@ -3269,24 +3282,24 @@ theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!
|
||||
| nil => rfl
|
||||
| cons h t ih => simp_all [Bool.and_assoc]
|
||||
|
||||
@[simp, grind] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
|
||||
@[simp, grind =] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
|
||||
@[simp, grind =] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem any_flatMap {l : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem any_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).any p = l.any fun a => (f a).any p := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem all_flatMap {l : List α} {f : α → List β} :
|
||||
@[simp, grind =] theorem all_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).all p = l.all fun a => (f a).all p := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp, grind] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
|
||||
@[simp, grind =] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
|
||||
induction l <;> simp_all [Bool.or_comm]
|
||||
|
||||
@[simp, grind] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
|
||||
@[simp, grind =] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
|
||||
induction l <;> simp_all [Bool.and_comm]
|
||||
|
||||
@[simp] theorem any_replicate {n : Nat} {a : α} :
|
||||
@@ -3336,14 +3349,14 @@ variable [BEq α]
|
||||
simp only [replace_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
|
||||
@[simp, grind =] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih =>
|
||||
simp only [replace_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
|
||||
(l.replace a b)[i]? = if l[i]? == some a then if a ∈ l.take i then some a else some b else l[i]? := by
|
||||
induction l generalizing i with
|
||||
| nil => cases i <;> simp
|
||||
@@ -3356,7 +3369,7 @@ theorem getElem?_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} (h : l[i]?
|
||||
(l.replace a b)[i]? = l[i]? := by
|
||||
simp_all [getElem?_replace]
|
||||
|
||||
@[grind] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
|
||||
@[grind =] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
|
||||
(l.replace a b)[i]'(by simpa) = if l[i] == a then if a ∈ l.take i then a else b else l[i] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_replace]
|
||||
@@ -3386,7 +3399,7 @@ theorem head_replace {l : List α} {a b : α} (w) :
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_replace, head?_eq_head]
|
||||
|
||||
@[grind] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
|
||||
@[grind =] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).replace a b = if a ∈ l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b := by
|
||||
induction l₁ with
|
||||
| nil => simp
|
||||
@@ -3430,9 +3443,9 @@ end replace
|
||||
section insert
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind] theorem insert_nil (a : α) : [].insert a = [a] := rfl
|
||||
@[simp, grind =] theorem insert_nil (a : α) : [].insert a = [a] := rfl
|
||||
|
||||
@[simp, grind] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
|
||||
@[simp, grind =] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
|
||||
(l.insert a).contains x = (x == a || l.contains x) := by
|
||||
simp only [List.insert]
|
||||
split <;> rename_i h
|
||||
@@ -3449,7 +3462,7 @@ variable [LawfulBEq α]
|
||||
@[simp] theorem insert_of_not_mem {l : List α} (h : a ∉ l) : l.insert a = a :: l := by
|
||||
simp [List.insert, h]
|
||||
|
||||
@[simp, grind] theorem mem_insert_iff {l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l := by
|
||||
@[simp, grind =] theorem mem_insert_iff {l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l := by
|
||||
if h : b ∈ l then
|
||||
rw [insert_of_mem h]
|
||||
constructor; {apply Or.inr}
|
||||
@@ -3473,7 +3486,7 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b ∨
|
||||
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a ∉ l) :
|
||||
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
|
||||
|
||||
@[grind] theorem length_insert {l : List α} :
|
||||
@[grind =] theorem length_insert {l : List α} :
|
||||
(l.insert a).length = l.length + if a ∈ l then 0 else 1 := by
|
||||
split <;> simp_all
|
||||
|
||||
@@ -3508,13 +3521,13 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
|
||||
simp only [insert_eq]
|
||||
split <;> simp
|
||||
|
||||
@[grind] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
|
||||
@[grind =] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
|
||||
(l.insert a)[i]? = if a ∈ l then l[i]? else if i = 0 then some a else l[i-1]? := by
|
||||
cases i
|
||||
· simp [getElem?_insert_zero]
|
||||
· simp [getElem?_insert_succ]
|
||||
|
||||
@[grind] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
|
||||
@[grind =] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
|
||||
(l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) =
|
||||
if a ∈ l then l[i] else if i = 0 then a else l[i-1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h) := by
|
||||
apply Option.some.inj
|
||||
@@ -3538,7 +3551,7 @@ theorem head_insert {l : List α} {a : α} (w) :
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_insert]
|
||||
|
||||
@[grind] theorem insert_append {l₁ l₂ : List α} {a : α} :
|
||||
@[grind =] theorem insert_append {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).insert a = if a ∈ l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂ := by
|
||||
simp only [insert_eq, mem_append]
|
||||
(repeat split) <;> simp_all
|
||||
@@ -3551,7 +3564,7 @@ theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂)
|
||||
(l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
|
||||
simp [insert_append, h]
|
||||
|
||||
@[simp, grind] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
|
||||
@[simp, grind =] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
|
||||
cases n <;> simp_all
|
||||
|
||||
@[simp] theorem insert_replicate_ne {a b : α} (h : !b == a) :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -567,9 +567,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 α} :
|
||||
@@ -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]
|
||||
|
||||
@@ -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⟩
|
||||
|
||||
@@ -666,7 +679,9 @@ theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
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 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -97,7 +97,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -16,30 +16,30 @@ 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
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Option
|
||||
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 α]
|
||||
|
||||
@@ -311,6 +311,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
|
||||
|
||||
@@ -200,7 +200,7 @@ theorem mem_attach (xs : Vector α n) : ∀ x, x ∈ xs.attach
|
||||
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 +211,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⟩
|
||||
|
||||
@@ -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,35 @@ 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
|
||||
|
||||
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 +935,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 +1222,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 +1245,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 +1258,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 +1303,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 +1319,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 +1356,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 +1419,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 +1439,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 +1629,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 +1665,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 +1701,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 +1780,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 +1788,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 +1815,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 +1835,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 +1904,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 +1931,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 +1991,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 +2020,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 +2083,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 +2103,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 +2236,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 +2261,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 +2288,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 +2329,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 +2354,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 +2370,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 +2419,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 +2442,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 +2499,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 +2607,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 +2638,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 +2690,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 +2736,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 +2760,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 +2773,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 +2921,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 +2938,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 +2947,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 +2987,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 +3000,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 +3009,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 +3020,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 +3035,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 +3104,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 +3121,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⟩
|
||||
|
||||
@@ -166,25 +166,25 @@ export LawfulGetElem (getElem?_def getElem!_def)
|
||||
instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
|
||||
LawfulGetElem coll idx elem valid where
|
||||
|
||||
@[simp, grind] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : dom c i) : c[i]? = some (c[i]'h) := by
|
||||
have : Decidable (dom c i) := .isTrue h
|
||||
rw [getElem?_def]
|
||||
exact dif_pos h
|
||||
|
||||
@[simp, grind] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : ¬dom c i) : c[i]? = none := by
|
||||
have : Decidable (dom c i) := .isFalse h
|
||||
rw [getElem?_def]
|
||||
exact dif_neg h
|
||||
|
||||
@[simp, grind] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) :
|
||||
c[i]! = c[i]'h := by
|
||||
have : Decidable (dom c i) := .isTrue h
|
||||
simp [getElem!_def, h]
|
||||
|
||||
@[simp, grind] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
@[simp, grind =] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) : c[i]! = default := by
|
||||
have : Decidable (dom c i) := .isFalse h
|
||||
simp [getElem!_def, h]
|
||||
@@ -291,18 +291,20 @@ namespace List
|
||||
instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
getElem as i h := as.get ⟨i, h⟩
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) :
|
||||
getElem (a :: as) 0 h = a := rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind =]
|
||||
theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
grind_pattern getElem_mem => l[n]'h ∈ l
|
||||
|
||||
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
|
||||
@@ -4,13 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Poly
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ring.Envelope
|
||||
public import Init.Grind.Ring.OfSemiring
|
||||
public import Init.Grind.Ring.CommSolver
|
||||
public import Init.Grind.Ring.CommSemiringAdapter
|
||||
public import Init.Grind.Ring.ToInt
|
||||
|
||||
public section
|
||||
|
||||
@@ -179,6 +179,20 @@ theorem ofNat_mul (a b : Nat) : OfNat.ofNat (α := α) (a * b) = OfNat.ofNat a *
|
||||
theorem natCast_mul (a b : Nat) : ((a * b : Nat) : α) = ((a : α) * (b : α)) := by
|
||||
rw [← ofNat_eq_natCast, ofNat_mul, ofNat_eq_natCast, ofNat_eq_natCast]
|
||||
|
||||
theorem natCast_mul_comm (a : Nat) (b : α) : a * b = b * a := by
|
||||
induction a
|
||||
next => simp [Semiring.natCast_zero, mul_zero, zero_mul]
|
||||
next ih =>
|
||||
rw [Semiring.natCast_succ, Semiring.left_distrib, Semiring.right_distrib, ih]
|
||||
simp [Semiring.mul_one, Semiring.one_mul]
|
||||
|
||||
theorem natCast_mul_left_comm (a : α) (b : Nat) (c : α) : a * (b * c) = b * (a * c) := by
|
||||
induction b
|
||||
next => simp [Semiring.natCast_zero, mul_zero, zero_mul]
|
||||
next ih =>
|
||||
rw [Semiring.natCast_succ, Semiring.right_distrib, Semiring.left_distrib, ih,
|
||||
Semiring.right_distrib, Semiring.one_mul, Semiring.one_mul]
|
||||
|
||||
theorem pow_one (a : α) : a ^ 1 = a := by
|
||||
rw [pow_succ, pow_zero, one_mul]
|
||||
|
||||
@@ -331,6 +345,18 @@ theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :
|
||||
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_mul_aux,
|
||||
intCast_natCast, intCast_natCast]
|
||||
|
||||
theorem intCast_mul_comm (a : Int) (b : α) : a * b = b * a := by
|
||||
have : a = a.natAbs ∨ a = -a.natAbs := by exact Int.natAbs_eq a
|
||||
cases this
|
||||
next h => rw [h, Ring.intCast_natCast, Semiring.natCast_mul_comm]
|
||||
next h => rw [h, Ring.intCast_neg, Ring.intCast_natCast, Ring.mul_neg, Ring.neg_mul, Semiring.natCast_mul_comm]
|
||||
|
||||
theorem intCast_mul_left_comm (a : α) (b : Int) (c : α) : a * (b * c) = b * (a * c) := by
|
||||
have : b = b.natAbs ∨ b = -b.natAbs := by exact Int.natAbs_eq b
|
||||
cases this
|
||||
next h => rw [h, Ring.intCast_natCast, Semiring.natCast_mul_left_comm]
|
||||
next h => rw [h, Ring.intCast_neg, Ring.intCast_natCast, Ring.neg_mul, Ring.neg_mul, Ring.mul_neg, Semiring.natCast_mul_left_comm]
|
||||
|
||||
theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k := by
|
||||
induction k
|
||||
next => simp [pow_zero, Int.pow_zero, intCast_one]
|
||||
|
||||
@@ -4,15 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Envelope
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.RArray
|
||||
public import Init.Grind.Ring.Poly
|
||||
|
||||
public import Init.Grind.Ring.CommSolver
|
||||
@[expose] public section
|
||||
|
||||
namespace Lean.Grind.Ring.OfSemiring
|
||||
/-!
|
||||
Helper definitions and theorems for converting `Semiring` expressions into `Ring` ones.
|
||||
@@ -4,27 +4,29 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.Ord.Basic
|
||||
import all Init.Data.Ord.Basic
|
||||
public import Init.Data.RArray
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ordered.Ring
|
||||
public import Init.GrindInstances.Ring.Int
|
||||
|
||||
import all Init.Data.Ord.Basic
|
||||
@[expose] public section
|
||||
namespace Lean.Grind.CommRing
|
||||
/-!
|
||||
Data-structures, definitions and theorems for implementing the
|
||||
`grind` solver and normalizer for commutative rings and its extensions (e.g., fields,
|
||||
commutative semirings, etc.)
|
||||
|
||||
The solver uses proof-by-reflection.
|
||||
-/
|
||||
open Std
|
||||
|
||||
namespace Lean.Grind
|
||||
-- These are no longer global instances, so we need to turn them on here.
|
||||
attribute [local instance] Semiring.natCast Ring.intCast
|
||||
namespace CommRing
|
||||
abbrev Var := Nat
|
||||
|
||||
inductive Expr where
|
||||
@@ -41,18 +43,15 @@ inductive Expr where
|
||||
|
||||
abbrev Context (α : Type u) := RArray α
|
||||
|
||||
@[expose]
|
||||
def Var.denote {α} (ctx : Context α) (v : Var) : α :=
|
||||
ctx.get v
|
||||
|
||||
@[expose]
|
||||
noncomputable def denoteInt {α} [Ring α] (k : Int) : α :=
|
||||
Bool.rec
|
||||
(OfNat.ofNat (α := α) k.natAbs)
|
||||
(- OfNat.ofNat (α := α) k.natAbs)
|
||||
(Int.blt' k 0)
|
||||
|
||||
@[expose]
|
||||
noncomputable def Expr.denote {α} [Ring α] (ctx : Context α) (e : Expr) : α :=
|
||||
Expr.rec
|
||||
(fun k => denoteInt k)
|
||||
@@ -81,11 +80,9 @@ protected noncomputable def Power.beq' (pw₁ pw₂ : Power) : Bool :=
|
||||
@[simp] theorem Power.beq'_eq (pw₁ pw₂ : Power) : pw₁.beq' pw₂ = (pw₁ = pw₂) := by
|
||||
cases pw₁; cases pw₂; simp [Power.beq']
|
||||
|
||||
@[expose]
|
||||
def Power.varLt (p₁ p₂ : Power) : Bool :=
|
||||
p₁.x.blt p₂.x
|
||||
|
||||
@[expose]
|
||||
def Power.denote {α} [Semiring α] (ctx : Context α) : Power → α
|
||||
| {x, k} =>
|
||||
match k with
|
||||
@@ -121,12 +118,10 @@ protected noncomputable def Mon.beq' (m₁ : Mon) : Mon → Bool :=
|
||||
simp [← ih m₂, ← Bool.and'_eq_and]
|
||||
rfl
|
||||
|
||||
@[expose]
|
||||
def Mon.denote {α} [Semiring α] (ctx : Context α) : Mon → α
|
||||
| unit => 1
|
||||
| .mult p m => p.denote ctx * denote ctx m
|
||||
|
||||
@[expose]
|
||||
def Mon.denote' {α} [Semiring α] (ctx : Context α) (m : Mon) : α :=
|
||||
match m with
|
||||
| .unit => 1
|
||||
@@ -137,17 +132,14 @@ where
|
||||
| .unit => acc
|
||||
| .mult pw m => go m (acc * (pw.denote ctx))
|
||||
|
||||
@[expose]
|
||||
def Mon.ofVar (x : Var) : Mon :=
|
||||
.mult { x, k := 1 } .unit
|
||||
|
||||
@[expose]
|
||||
def Mon.concat (m₁ m₂ : Mon) : Mon :=
|
||||
match m₁ with
|
||||
| .unit => m₂
|
||||
| .mult pw m₁ => .mult pw (concat m₁ m₂)
|
||||
|
||||
@[expose]
|
||||
def Mon.mulPow (pw : Power) (m : Mon) : Mon :=
|
||||
match m with
|
||||
| .unit =>
|
||||
@@ -160,15 +152,23 @@ def Mon.mulPow (pw : Power) (m : Mon) : Mon :=
|
||||
else
|
||||
.mult { x := pw.x, k := pw.k + pw'.k } m
|
||||
|
||||
@[expose]
|
||||
-- **Note**: We use the `_nc` suffix for functions for the non-commutative case
|
||||
|
||||
def Mon.mulPow_nc (pw : Power) (m : Mon) : Mon :=
|
||||
match m with
|
||||
| .unit => .mult pw .unit
|
||||
| .mult pw' m =>
|
||||
bif pw.x == pw'.x then
|
||||
.mult { x := pw.x, k := pw.k + pw'.k } m
|
||||
else
|
||||
.mult pw (.mult pw' m)
|
||||
|
||||
def Mon.length : Mon → Nat
|
||||
| .unit => 0
|
||||
| .mult _ m => 1 + length m
|
||||
|
||||
@[expose]
|
||||
def hugeFuel := 1000000
|
||||
|
||||
@[expose]
|
||||
def Mon.mul (m₁ m₂ : Mon) : Mon :=
|
||||
-- We could use `m₁.length + m₂.length` to avoid hugeFuel
|
||||
go hugeFuel m₁ m₂
|
||||
@@ -188,18 +188,21 @@ where
|
||||
else
|
||||
.mult { x := pw₁.x, k := pw₁.k + pw₂.k } (go fuel m₁ m₂)
|
||||
|
||||
@[expose]
|
||||
def Mon.mul_nc (m₁ m₂ : Mon) : Mon :=
|
||||
match m₁ with
|
||||
| .unit => m₂
|
||||
| .mult pw .unit => m₂.mulPow_nc pw
|
||||
| .mult pw m₁ => .mult pw (mul_nc m₁ m₂)
|
||||
|
||||
def Mon.degree : Mon → Nat
|
||||
| .unit => 0
|
||||
| .mult pw m => pw.k + degree m
|
||||
|
||||
@[expose]
|
||||
def Var.revlex (x y : Var) : Ordering :=
|
||||
bif x.blt y then .gt
|
||||
else bif y.blt x then .lt
|
||||
else .eq
|
||||
|
||||
@[expose]
|
||||
def powerRevlex (k₁ k₂ : Nat) : Ordering :=
|
||||
bif k₁.blt k₂ then .gt
|
||||
else bif k₂.blt k₁ then .lt
|
||||
@@ -212,11 +215,9 @@ theorem powerRevlex_k_eq_powerRevlex (k₁ k₂ : Nat) : powerRevlex_k k₁ k₂
|
||||
simp [powerRevlex_k, powerRevlex, cond] <;> split <;> simp [*]
|
||||
split <;> simp [*]
|
||||
|
||||
@[expose]
|
||||
def Power.revlex (p₁ p₂ : Power) : Ordering :=
|
||||
p₁.x.revlex p₂.x |>.then (powerRevlex p₁.k p₂.k)
|
||||
|
||||
@[expose]
|
||||
def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
|
||||
match m₁, m₂ with
|
||||
| .unit, .unit => .eq
|
||||
@@ -230,7 +231,6 @@ def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
|
||||
else
|
||||
revlexWF (.mult pw₁ m₁) m₂ |>.then .gt
|
||||
|
||||
@[expose]
|
||||
def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
|
||||
match fuel with
|
||||
| 0 =>
|
||||
@@ -250,11 +250,9 @@ def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
|
||||
else
|
||||
revlexFuel fuel (.mult pw₁ m₁) m₂ |>.then .gt
|
||||
|
||||
@[expose]
|
||||
def Mon.revlex (m₁ m₂ : Mon) : Ordering :=
|
||||
revlexFuel hugeFuel m₁ m₂
|
||||
|
||||
@[expose]
|
||||
def Mon.grevlex (m₁ m₂ : Mon) : Ordering :=
|
||||
compare m₁.degree m₂.degree |>.then (revlex m₁ m₂)
|
||||
|
||||
@@ -360,13 +358,11 @@ instance : LawfulBEq Poly where
|
||||
change m == m ∧ p == p
|
||||
simp [ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.denote [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
| .add k m p => k • (m.denote ctx) + denote ctx p
|
||||
|
||||
@[expose]
|
||||
def Poly.denote' [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
@@ -384,21 +380,17 @@ where
|
||||
| .num k => acc + Int.cast k
|
||||
| .add k m p => go p (acc + denoteTerm k m)
|
||||
|
||||
@[expose]
|
||||
def Poly.ofMon (m : Mon) : Poly :=
|
||||
.add 1 m (.num 0)
|
||||
|
||||
@[expose]
|
||||
def Poly.ofVar (x : Var) : Poly :=
|
||||
ofMon (Mon.ofVar x)
|
||||
|
||||
@[expose]
|
||||
def Poly.isSorted : Poly → Bool
|
||||
| .num _ => true
|
||||
| .add _ _ (.num _) => true
|
||||
| .add _ m₁ (.add k m₂ p) => m₁.grevlex m₂ == .gt && (Poly.add k m₂ p).isSorted
|
||||
|
||||
@[expose]
|
||||
def Poly.addConst (p : Poly) (k : Int) : Poly :=
|
||||
bif k == 0 then
|
||||
p
|
||||
@@ -424,7 +416,6 @@ theorem Poly.addConst_k_eq_addConst (p : Poly) (k : Int) : addConst_k p k = addC
|
||||
induction p <;> simp [addConst.go]
|
||||
next ih => rw [← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.insert (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
p
|
||||
@@ -446,13 +437,11 @@ where
|
||||
| .gt => .add k m (.add k' m' p)
|
||||
| .lt => .add k' m' (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.concat (p₁ p₂ : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k₁ => p₂.addConst k₁
|
||||
| .add k m p₁ => .add k m (concat p₁ p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulConst (k : Int) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
@@ -491,7 +480,6 @@ noncomputable def Poly.mulConst_k (k : Int) (p : Poly) : Poly :=
|
||||
next => rfl
|
||||
next k m p ih => simp [mulConst.go, ← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMon (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
@@ -545,7 +533,19 @@ noncomputable def Poly.mulMon_k (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
simp [h]
|
||||
next ih => simp [← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMon_nc (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else bif m == .unit then
|
||||
p.mulConst k
|
||||
else
|
||||
go p (.num 0)
|
||||
where
|
||||
go (p : Poly) (acc : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => acc.insert (k*k') m
|
||||
| .add k' m' p => go p (acc.insert (k*k') (m.mul_nc m'))
|
||||
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
go hugeFuel p₁ p₂
|
||||
where
|
||||
@@ -609,7 +609,6 @@ noncomputable def Poly.combine_k : Poly → Poly → Poly :=
|
||||
next h => simp [h]; rw [← ih p₁ (add k₂ m₂ p₂)]; rfl
|
||||
next h => simp [h]; rw [← ih (add k₁ m₁ p₁) p₂]; rfl
|
||||
|
||||
@[expose]
|
||||
def Poly.mul (p₁ : Poly) (p₂ : Poly) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
@@ -618,14 +617,26 @@ where
|
||||
| .num k => acc.combine (p₂.mulConst k)
|
||||
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon k m))
|
||||
|
||||
@[expose]
|
||||
def Poly.mul_nc (p₁ : Poly) (p₂ : Poly) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combine (p₂.mulConst k)
|
||||
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon_nc k m))
|
||||
|
||||
def Poly.pow (p : Poly) (k : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mul (pow p k)
|
||||
|
||||
@[expose]
|
||||
def Poly.pow_nc (p : Poly) (k : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => (pow_nc p k).mul_nc p
|
||||
|
||||
def Expr.toPoly : Expr → Poly
|
||||
| .num k => .num k
|
||||
| .intCast k => .num k
|
||||
@@ -645,7 +656,7 @@ def Expr.toPoly : Expr → Poly
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly.pow k
|
||||
|
||||
@[expose] noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
|
||||
noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
|
||||
Expr.rec
|
||||
(fun k => .num k) (fun k => .num k) (fun k => .num k)
|
||||
(fun x => .ofVar x)
|
||||
@@ -691,6 +702,25 @@ def Expr.toPoly : Expr → Poly
|
||||
| x => a.toPoly.pow k
|
||||
cases a <;> try simp [*]
|
||||
|
||||
def Expr.toPoly_nc : Expr → Poly
|
||||
| .num k => .num k
|
||||
| .intCast k => .num k
|
||||
| .natCast k => .num k
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => a.toPoly_nc.combine b.toPoly_nc
|
||||
| .mul a b => a.toPoly_nc.mul_nc b.toPoly_nc
|
||||
| .neg a => a.toPoly_nc.mulConst (-1)
|
||||
| .sub a b => a.toPoly_nc.combine (b.toPoly_nc.mulConst (-1))
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
| .num n => .num (n^k)
|
||||
| .intCast n => .num (n^k)
|
||||
| .natCast n => .num (n^k)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly_nc.pow_nc k
|
||||
|
||||
def Poly.normEq0 (p : Poly) (c : Nat) : Poly :=
|
||||
match p with
|
||||
| .num a =>
|
||||
@@ -707,13 +737,11 @@ Once we can specialize definitions before they reach the kernel,
|
||||
we can merge the two versions. Until then, the `IsCharP` definitions will carry the `C` suffix.
|
||||
We use them whenever we can infer the characteristic using type class instance synthesis.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.addConstC (p : Poly) (k : Int) (c : Nat) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num ((k' + k) % c)
|
||||
| .add k' m p => .add k' m (addConstC p k c)
|
||||
|
||||
@[expose]
|
||||
def Poly.insertC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -734,7 +762,6 @@ where
|
||||
| .gt => .add k m (.add k' m' p)
|
||||
| .lt => .add k' m' (go k p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulConstC (k : Int) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -753,7 +780,6 @@ where
|
||||
else
|
||||
.add k m (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMonC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -777,7 +803,20 @@ where
|
||||
else
|
||||
.add k (m.mul m') (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMonC_nc (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else bif m == .unit then
|
||||
p.mulConstC k c
|
||||
else
|
||||
go p (.num 0)
|
||||
where
|
||||
go (p : Poly) (acc : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => acc.insert (k*k' % c) m
|
||||
| .add k' m' p => go p (acc.insert (k*k' % c) (m.mul_nc m'))
|
||||
|
||||
def Poly.combineC (p₁ p₂ : Poly) (c : Nat) : Poly :=
|
||||
go hugeFuel p₁ p₂
|
||||
where
|
||||
@@ -799,7 +838,6 @@ where
|
||||
| .gt => .add k₁ m₁ (go fuel p₁ (.add k₂ m₂ p₂))
|
||||
| .lt => .add k₂ m₂ (go fuel (.add k₁ m₁ p₁) p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulC (p₁ : Poly) (p₂ : Poly) (c : Nat) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
@@ -808,14 +846,26 @@ where
|
||||
| .num k => acc.combineC (p₂.mulConstC k c) c
|
||||
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC k m c) c)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulC_nc (p₁ : Poly) (p₂ : Poly) (c : Nat) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combineC (p₂.mulConstC k c) c
|
||||
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC_nc k m c) c)
|
||||
|
||||
def Poly.powC (p : Poly) (k : Nat) (c : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mulC (powC p k c) c
|
||||
|
||||
@[expose]
|
||||
def Poly.powC_nc (p : Poly) (k : Nat) (c : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => (powC_nc p k c).mulC_nc p c
|
||||
|
||||
def Expr.toPolyC (e : Expr) (c : Nat) : Poly :=
|
||||
go e
|
||||
where
|
||||
@@ -836,6 +886,26 @@ where
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => (go a).powC k c
|
||||
|
||||
def Expr.toPolyC_nc (e : Expr) (c : Nat) : Poly :=
|
||||
go e
|
||||
where
|
||||
go : Expr → Poly
|
||||
| .num k => .num (k % c)
|
||||
| .natCast k => .num (k % c)
|
||||
| .intCast k => .num (k % c)
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => (go a).combineC (go b) c
|
||||
| .mul a b => (go a).mulC_nc (go b) c
|
||||
| .neg a => (go a).mulConstC (-1) c
|
||||
| .sub a b => (go a).combineC ((go b).mulConstC (-1) c) c
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
| .num n => .num ((n^k) % c)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => (go a).powC_nc k c
|
||||
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings in `grind`.
|
||||
-/
|
||||
@@ -845,7 +915,7 @@ open Semiring hiding add_zero add_comm add_assoc
|
||||
open Ring hiding sub_eq_add_neg
|
||||
open CommSemiring
|
||||
|
||||
theorem denoteInt_eq {α} [CommRing α] (k : Int) : denoteInt (α := α) k = k := by
|
||||
theorem denoteInt_eq {α} [Ring α] (k : Int) : denoteInt (α := α) k = k := by
|
||||
simp [denoteInt] <;> cases h : k.blt' 0 <;> simp <;> simp at h
|
||||
next h => rw [ofNat_eq_natCast, ← intCast_natCast, ← Int.eq_natAbs_of_nonneg h]
|
||||
next h => rw [ofNat_eq_natCast, ← intCast_natCast, ← Ring.intCast_neg, ← Int.eq_neg_natAbs_of_nonpos (Int.le_of_lt h)]
|
||||
@@ -888,6 +958,13 @@ theorem Mon.denote_mulPow {α} [CommSemiring α] (ctx : Context α) (p : Power)
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [Power.denote_eq, pow_add, mul_assoc, this]
|
||||
|
||||
theorem Mon.denote_mulPow_nc {α} [Semiring α] (ctx : Context α) (p : Power) (m : Mon)
|
||||
: denote ctx (mulPow_nc p m) = p.denote ctx * m.denote ctx := by
|
||||
fun_cases mulPow_nc <;> simp [denote, *]
|
||||
next h =>
|
||||
simp at h
|
||||
simp [Power.denote_eq, pow_add, mul_assoc, h]
|
||||
|
||||
theorem Mon.denote_mul {α} [CommSemiring α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (mul m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
unfold mul
|
||||
@@ -899,6 +976,10 @@ theorem Mon.denote_mul {α} [CommSemiring α] (ctx : Context α) (m₁ m₂ : Mo
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [Power.denote_eq, pow_add, this]
|
||||
|
||||
theorem Mon.denote_mul_nc {α} [Semiring α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (mul_nc m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
fun_induction mul_nc <;> simp [denote, Semiring.one_mul, Semiring.mul_one, denote_mulPow_nc, Semiring.mul_assoc, *]
|
||||
|
||||
theorem Var.eq_of_revlex {x₁ x₂ : Var} : x₁.revlex x₂ = .eq → x₁ = x₂ := by
|
||||
simp [revlex, cond_eq_if] <;> split <;> simp
|
||||
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
|
||||
@@ -954,15 +1035,15 @@ theorem Poly.denote'_eq_denote {α} [Ring α] (ctx : Context α) (p : Poly) : p.
|
||||
fun_induction denote'.go <;> simp [denote, *, Ring.intCast_zero, Semiring.add_zero, denoteTerm_eq]
|
||||
next ih => simp [denoteTerm_eq] at ih; simp [ih, Semiring.add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_ofMon {α} [CommRing α] (ctx : Context α) (m : Mon)
|
||||
theorem Poly.denote_ofMon {α} [Ring α] (ctx : Context α) (m : Mon)
|
||||
: denote ctx (ofMon m) = m.denote ctx := by
|
||||
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_ofVar {α} [CommRing α] (ctx : Context α) (x : Var)
|
||||
theorem Poly.denote_ofVar {α} [Ring α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
simp [ofVar, denote_ofMon, Mon.denote_ofVar]
|
||||
|
||||
theorem Poly.denote_addConst {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
|
||||
theorem Poly.denote_addConst {α} [Ring α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
|
||||
simp [addConst, cond_eq_if]; split
|
||||
next => simp [*, intCast_zero, add_zero]
|
||||
next =>
|
||||
@@ -970,7 +1051,7 @@ theorem Poly.denote_addConst {α} [CommRing α] (ctx : Context α) (p : Poly) (k
|
||||
next => rw [intCast_add]
|
||||
next => simp [add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_insert {α} [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
theorem Poly.denote_insert {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insert k m p).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
simp [insert, cond_eq_if] <;> split
|
||||
next => simp [*, intCast_zero, zero_mul, zero_add]
|
||||
@@ -987,13 +1068,13 @@ theorem Poly.denote_insert {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next =>
|
||||
rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_concat {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_concat {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (concat p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
fun_induction concat <;> simp [*, denote_addConst, denote]
|
||||
next => rw [add_comm]
|
||||
next => rw [add_assoc]
|
||||
|
||||
theorem Poly.denote_mulConst {α} [CommRing α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
theorem Poly.denote_mulConst {α} [Ring α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConst k p).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConst, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
@@ -1017,7 +1098,28 @@ theorem Poly.denote_mulMon {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next => simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next => simp [Mon.denote_mul, intCast_mul, left_distrib, mul_left_comm, mul_assoc]
|
||||
|
||||
theorem Poly.denote_combine {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_mulMon_nc_go {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p acc : Poly)
|
||||
: (mulMon_nc.go k m p acc).denote ctx = k * m.denote ctx * p.denote ctx + acc.denote ctx := by
|
||||
fun_induction mulMon_nc.go <;> simp [denote, denote_insert, zsmul_eq_intCast_mul]
|
||||
next => rw [Ring.intCast_mul, Semiring.mul_assoc, Semiring.mul_assoc, ← Ring.intCast_mul_comm]
|
||||
next ih =>
|
||||
rw [ih, denote_insert, Mon.denote_mul_nc, Semiring.left_distrib, Ring.intCast_mul]
|
||||
rw [Ring.intCast_mul_left_comm]; simp [← Semiring.mul_assoc]
|
||||
conv => enter [1, 2, 1, 1, 1]; rw [Ring.intCast_mul_comm]
|
||||
simp [Semiring.add_assoc, Semiring.add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulMon_nc {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMon_nc k m p).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMon_nc, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
split
|
||||
next h =>
|
||||
simp at h; simp [*, Mon.denote, mul_one, denote_mulConst]
|
||||
next =>
|
||||
rw [denote_mulMon_nc_go]; simp [denote, Ring.intCast_zero, add_zero]
|
||||
|
||||
theorem Poly.denote_combine {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combine p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combine; generalize hugeFuel = fuel
|
||||
fun_induction combine.go
|
||||
@@ -1038,6 +1140,15 @@ theorem Poly.denote_mul {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mul, denote_mul_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_mul_nc_go {α} [Ring α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mul_nc.go p₂ p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mul_nc.go
|
||||
<;> simp [denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon_nc, add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_mul_nc {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul_nc p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mul_nc, denote_mul_nc_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_pow {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (pow p k).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction pow
|
||||
@@ -1045,6 +1156,13 @@ theorem Poly.denote_pow {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Na
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mul, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Poly.denote_pow_nc {α} [Ring α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (pow_nc p k).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction pow_nc
|
||||
next => simp [denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mul_nc, *, pow_succ]
|
||||
|
||||
theorem Expr.denote_toPoly {α} [CommRing α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly.denote ctx = e.denote ctx := by
|
||||
fun_induction toPoly
|
||||
@@ -1056,21 +1174,37 @@ theorem Expr.denote_toPoly {α} [CommRing α] (ctx : Context α) (e : Expr)
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.denote_toPoly_nc {α} [Ring α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly_nc.denote ctx = e.denote ctx := by
|
||||
fun_induction toPoly_nc
|
||||
<;> simp [denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combine,
|
||||
Poly.denote_mul_nc, Poly.denote_mulConst, Poly.denote_pow_nc, intCast_pow, intCast_neg, intCast_one,
|
||||
neg_mul, one_mul, sub_eq_add_neg, denoteInt_eq, *]
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero]
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.eq_of_toPoly_eq {α} [CommRing α] (ctx : Context α) (a b : Expr) (h : a.toPoly == b.toPoly) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPoly] at h
|
||||
assumption
|
||||
|
||||
theorem Expr.eq_of_toPoly_nc_eq {α} [Ring α] (ctx : Context α) (a b : Expr) (h : a.toPoly_nc == b.toPoly_nc) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPoly_nc] at h
|
||||
assumption
|
||||
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings with a characteristic in `grind`.
|
||||
-/
|
||||
|
||||
theorem Poly.denote_addConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
|
||||
theorem Poly.denote_addConstC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
|
||||
fun_induction addConstC <;> simp [denote, *]
|
||||
next => rw [IsCharP.intCast_emod, intCast_add]
|
||||
next => simp [add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
theorem Poly.denote_insertC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insertC k m p c).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
simp [insertC, cond_eq_if] <;> split
|
||||
next =>
|
||||
@@ -1087,7 +1221,7 @@ theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
|
||||
theorem Poly.denote_mulConstC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConstC k p c).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConstC, cond_eq_if] <;> split
|
||||
next =>
|
||||
@@ -1136,7 +1270,29 @@ theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
simp +zetaDelta [*, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
|
||||
mul_left_comm, mul_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_mulMonC_nc_go {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p acc : Poly)
|
||||
: (mulMonC_nc.go k m c p acc).denote ctx = k * m.denote ctx * p.denote ctx + acc.denote ctx := by
|
||||
fun_induction mulMonC_nc.go <;> simp [denote, denote_insert, zsmul_eq_intCast_mul]
|
||||
next => rw [IsCharP.intCast_emod (x := k * _) (p := c), Ring.intCast_mul, Semiring.mul_assoc, Semiring.mul_assoc, ← Ring.intCast_mul_comm]
|
||||
next ih =>
|
||||
rw [ih, denote_insert, Mon.denote_mul_nc, IsCharP.intCast_emod (x := k * _) (p := c),
|
||||
Semiring.left_distrib, Ring.intCast_mul]
|
||||
rw [Ring.intCast_mul_left_comm]; simp [← Semiring.mul_assoc]
|
||||
conv => enter [1, 2, 1, 1, 1]; rw [Ring.intCast_mul_comm]
|
||||
simp [Semiring.add_assoc, Semiring.add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulMonC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMonC_nc k m p c).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMonC_nc, cond_eq_if] <;> split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
split
|
||||
next h => simp at h; simp [*, Mon.denote, mul_one, denote_mulConstC, IsCharP.intCast_emod]
|
||||
next => rw [Poly.denote_mulMonC_nc_go, denote, Ring.intCast_zero, add_zero]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combineC p₁ p₂ c).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combineC; generalize hugeFuel = fuel
|
||||
fun_induction combineC.go
|
||||
@@ -1160,6 +1316,15 @@ theorem Poly.denote_mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α)
|
||||
: (mulC p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mulC, denote_mulC_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_mulC_nc_go {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mulC_nc.go p₂ c p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mulC_nc.go
|
||||
<;> simp [denote_combineC, denote_mulConstC, denote, *, right_distrib, denote_mulMonC_nc, add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_mulC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mulC_nc p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mulC_nc, denote_mulC_nc_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (powC p k c).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction powC
|
||||
@@ -1167,6 +1332,13 @@ theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α)
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mulC, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Poly.denote_powC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (powC_nc p k c).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction powC_nc
|
||||
next => simp [denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mulC_nc, *, pow_succ]
|
||||
|
||||
theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (e : Expr)
|
||||
: (e.toPolyC c).denote ctx = e.denote ctx := by
|
||||
unfold toPolyC
|
||||
@@ -1182,17 +1354,37 @@ theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.denote_toPolyC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (e : Expr)
|
||||
: (e.toPolyC_nc c).denote ctx = e.denote ctx := by
|
||||
unfold toPolyC_nc
|
||||
fun_induction toPolyC_nc.go
|
||||
<;> simp [denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combineC,
|
||||
Poly.denote_mulC_nc, Poly.denote_mulConstC, Poly.denote_powC_nc, denoteInt_eq, *]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [IsCharP.intCast_emod, Ring.intCast_natCast]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul, sub_eq_add_neg]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero, Ring.intCast_one]
|
||||
next => rw [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.eq_of_toPolyC_eq {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (a b : Expr)
|
||||
(h : a.toPolyC c == b.toPolyC c) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPolyC] at h
|
||||
assumption
|
||||
|
||||
theorem Expr.eq_of_toPolyC_nc_eq {α c} [Ring α] [IsCharP α c] (ctx : Context α) (a b : Expr)
|
||||
(h : a.toPolyC_nc c == b.toPolyC_nc c) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPolyC_nc] at h
|
||||
assumption
|
||||
|
||||
namespace Stepwise
|
||||
/-!
|
||||
Theorems for stepwise proof-term construction
|
||||
-/
|
||||
@[expose]
|
||||
noncomputable def core_cert (lhs rhs : Expr) (p : Poly) : Bool :=
|
||||
(lhs.sub rhs).toPoly_k.beq' p
|
||||
|
||||
@@ -1202,7 +1394,6 @@ theorem core {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
simp [Expr.denote_toPoly, Expr.denote]
|
||||
simp [sub_eq_zero_iff]
|
||||
|
||||
@[expose]
|
||||
noncomputable def superpose_cert (k₁ : Int) (m₁ : Mon) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
(p₁.mulMon_k k₁ m₁).combine_k (p₂.mulMon_k k₂ m₂) |>.beq' p
|
||||
|
||||
@@ -1211,7 +1402,6 @@ theorem superpose {α} [CommRing α] (ctx : Context α) (k₁ : Int) (m₁ : Mon
|
||||
simp [superpose_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def simp_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
(p₁.mulConst_k k₁).combine_k (p₂.mulMon_k k₂ m₂) |>.beq' p
|
||||
|
||||
@@ -1220,32 +1410,26 @@ theorem simp {α} [CommRing α] (ctx : Context α) (k₁ : Int) (p₁ : Poly) (k
|
||||
simp [simp_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, Poly.denote_mulConst, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def mul_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
p₁.mulConst_k k |>.beq' p
|
||||
|
||||
@[expose]
|
||||
def mul {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [mul_cert]; intro _ h; subst p
|
||||
simp [Poly.denote_mulConst, *, mul_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def div_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (p.mulConst_k k |>.beq' p₁)
|
||||
|
||||
@[expose]
|
||||
def div {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_cert]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConst, ← zsmul_eq_intCast_mul] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
noncomputable def unsat_eq_cert (p : Poly) (k : Int) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (p.beq' (.num k))
|
||||
|
||||
@[expose]
|
||||
def unsat_eq {α} [CommRing α] (ctx : Context α) [IsCharP α 0] (p : Poly) (k : Int)
|
||||
: unsat_eq_cert p k → p.denote ctx = 0 → False := by
|
||||
simp [unsat_eq_cert]; intro h _; subst p; simp [Poly.denote]
|
||||
@@ -1256,7 +1440,6 @@ def unsat_eq {α} [CommRing α] (ctx : Context α) [IsCharP α 0] (p : Poly) (k
|
||||
theorem d_init {α} [CommRing α] (ctx : Context α) (p : Poly) : (1:Int) * p.denote ctx = p.denote ctx := by
|
||||
rw [intCast_one, one_mul]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_step1_cert (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
p.beq' (p₁.combine_k (p₂.mulMon_k k₂ m₂))
|
||||
|
||||
@@ -1265,7 +1448,6 @@ theorem d_step1 {α} [CommRing α] (ctx : Context α) (k : Int) (init : Poly) (p
|
||||
simp [d_step1_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, h₂, mul_zero, add_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_stepk_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
p.beq' ((p₁.mulConst_k k₁).combine_k (p₂.mulMon_k k₂ m₂))
|
||||
|
||||
@@ -1275,7 +1457,6 @@ theorem d_stepk {α} [CommRing α] (ctx : Context α) (k₁ : Int) (k : Int) (in
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, Poly.denote_mulConst, h₂, mul_zero, add_zero]
|
||||
rw [intCast_mul, mul_assoc, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_1eq_cert (lhs rhs : Expr) (p₁ p₂ : Poly) : Bool :=
|
||||
(lhs.sub rhs).toPoly_k.beq' p₁ |>.and' (p₂.beq' (.num 0))
|
||||
|
||||
@@ -1284,7 +1465,6 @@ theorem imp_1eq {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p₁ p
|
||||
simp [imp_1eq_cert, intCast_one, one_mul]; intro _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPoly, Expr.denote, sub_eq_zero_iff, Poly.denote, intCast_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_keq_cert (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) : Bool :=
|
||||
!Int.beq' k 0 |>.and' ((lhs.sub rhs).toPoly_k.beq' p₁ |>.and' (p₂.beq' (.num 0)))
|
||||
|
||||
@@ -1295,7 +1475,6 @@ theorem imp_keq {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (k
|
||||
intro h; replace h := no_int_zero_divisors hnz h
|
||||
rw [← sub_eq_zero_iff, h]
|
||||
|
||||
@[expose]
|
||||
noncomputable def core_certC (lhs rhs : Expr) (p : Poly) (c : Nat) : Bool :=
|
||||
(lhs.sub rhs).toPolyC c |>.beq' p
|
||||
|
||||
@@ -1305,7 +1484,6 @@ theorem coreC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (lhs rhs :
|
||||
simp [Expr.denote_toPolyC, Expr.denote]
|
||||
simp [sub_eq_zero_iff]
|
||||
|
||||
@[expose]
|
||||
noncomputable def superpose_certC (k₁ : Int) (m₁ : Mon) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
(p₁.mulMonC k₁ m₁ c).combineC (p₂.mulMonC k₂ m₂ c) c |>.beq' p
|
||||
|
||||
@@ -1314,28 +1492,23 @@ theorem superposeC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁
|
||||
simp [superpose_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def mul_certC (p₁ : Poly) (k : Int) (p : Poly) (c : Nat) : Bool :=
|
||||
p₁.mulConstC k c |>.beq' p
|
||||
|
||||
@[expose]
|
||||
def mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_certC p₁ k p c → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [mul_certC]; intro _ h; subst p
|
||||
simp [Poly.denote_mulConstC, *, mul_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def div_certC (p₁ : Poly) (k : Int) (p : Poly) (c : Nat) : Bool :=
|
||||
!Int.beq' k 0 |>.and' ((p.mulConstC k c).beq' p₁)
|
||||
|
||||
@[expose]
|
||||
def divC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_certC p₁ k p c → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_certC]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConstC, ← zsmul_eq_intCast_mul] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
noncomputable def simp_certC (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
(p₁.mulConstC k₁ c).combineC (p₂.mulMonC k₂ m₂ c) c |>.beq' p
|
||||
|
||||
@@ -1344,11 +1517,9 @@ theorem simpC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁ : Int
|
||||
simp [simp_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, Poly.denote_mulConstC, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def unsat_eq_certC (p : Poly) (k : Int) (c : Nat) : Bool :=
|
||||
!Int.beq' (k % c) 0 |>.and' (p.beq' (.num k))
|
||||
|
||||
@[expose]
|
||||
def unsat_eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int)
|
||||
: unsat_eq_certC p k c → p.denote ctx = 0 → False := by
|
||||
simp [unsat_eq_certC]; intro h _; subst p; simp [Poly.denote]
|
||||
@@ -1356,7 +1527,6 @@ def unsat_eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly)
|
||||
simp [h] at this
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_step1_certC (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
p.beq' (p₁.combineC (p₂.mulMonC k₂ m₂ c) c)
|
||||
|
||||
@@ -1365,7 +1535,6 @@ theorem d_step1C {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int
|
||||
simp [d_step1_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, h₂, mul_zero, add_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_stepk_certC (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
p.beq' ((p₁.mulConstC k₁ c).combineC (p₂.mulMonC k₂ m₂ c) c)
|
||||
|
||||
@@ -1375,7 +1544,6 @@ theorem d_stepkC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁ :
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, Poly.denote_mulConstC, h₂, mul_zero, add_zero]
|
||||
rw [intCast_mul, mul_assoc, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_1eq_certC (lhs rhs : Expr) (p₁ p₂ : Poly) (c : Nat) : Bool :=
|
||||
((lhs.sub rhs).toPolyC c).beq' p₁ |>.and' (p₂.beq' (.num 0))
|
||||
|
||||
@@ -1384,7 +1552,6 @@ theorem imp_1eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (lhs rhs
|
||||
simp [imp_1eq_certC, intCast_one, one_mul]; intro _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPolyC, Expr.denote, sub_eq_zero_iff, Poly.denote, intCast_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_keq_certC (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) (c : Nat) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (((lhs.sub rhs).toPolyC c).beq' p₁ |>.and' (p₂.beq' (.num 0)))
|
||||
|
||||
@@ -1399,7 +1566,6 @@ end Stepwise
|
||||
|
||||
/-! IntModule interface -/
|
||||
|
||||
@[expose]
|
||||
def Mon.denoteAsIntModule [CommRing α] (ctx : Context α) (m : Mon) : α :=
|
||||
match m with
|
||||
| .unit => One.one
|
||||
@@ -1410,7 +1576,6 @@ where
|
||||
| .unit => acc
|
||||
| .mult pw m => go m (acc * pw.denote ctx)
|
||||
|
||||
@[expose]
|
||||
def Poly.denoteAsIntModule [CommRing α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => k • (One.one : α)
|
||||
@@ -1511,7 +1676,6 @@ theorem inv_split {α} [Field α] (a : α) : if a = 0 then a⁻¹ = 0 else a * a
|
||||
next h => simp [h, Field.inv_zero]
|
||||
next h => rw [Field.mul_inv_cancel h]
|
||||
|
||||
@[expose]
|
||||
noncomputable def one_eq_zero_unsat_cert (p : Poly) :=
|
||||
p.beq' (.num 1) || p.beq' (.num (-1))
|
||||
|
||||
@@ -1551,7 +1715,6 @@ theorem Poly.normEq0_eq {α} [CommRing α] (ctx : Context α) (p : Poly) (c : Na
|
||||
simp [denote, normEq0, cond_eq_if]; split <;> simp [denote, zsmul_eq_intCast_mul, *]
|
||||
next h' => rw [of_mod_eq_0 h h', Semiring.zero_mul, zero_add]
|
||||
|
||||
@[expose]
|
||||
noncomputable def eq_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₁.beq' (.num c) && (p.beq' (p₂.normEq0 c))
|
||||
|
||||
@@ -1571,7 +1734,6 @@ theorem gcd_eq_0 [CommRing α] (g n m a b : Int) (h : g = a * n + b * m)
|
||||
rw [← Ring.intCast_add, h₂, zero_add, ← h] at h₁
|
||||
rw [Ring.intCast_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
def eq_gcd_cert (a b : Int) (p₁ p₂ p : Poly) : Bool :=
|
||||
match p₁ with
|
||||
| .add .. => false
|
||||
@@ -1589,7 +1751,6 @@ theorem eq_gcd {α} [CommRing α] (ctx : Context α) (a b : Int) (p₁ p₂ p :
|
||||
rename_i n m g
|
||||
apply gcd_eq_0 g n m a b
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₂.beq' (.num c) |>.and' (p.beq' (p₁.normEq0 c))
|
||||
|
||||
@@ -1598,11 +1759,10 @@ theorem d_normEq0 {α} [CommRing α] (ctx : Context α) (k : Int) (c : Nat) (ini
|
||||
simp [d_normEq0_cert]; intro _ h₁ h₂; subst p p₂; simp [Poly.denote]
|
||||
intro h; rw [p₁.normEq0_eq] <;> assumption
|
||||
|
||||
@[expose] noncomputable def norm_int_cert (e : Expr) (p : Poly) : Bool :=
|
||||
noncomputable def norm_int_cert (e : Expr) (p : Poly) : Bool :=
|
||||
e.toPoly_k.beq' p
|
||||
|
||||
theorem norm_int (ctx : Context Int) (e : Expr) (p : Poly) : norm_int_cert e p → e.denote ctx = p.denote' ctx := by
|
||||
simp [norm_int_cert, Poly.denote'_eq_denote]; intro; subst p; simp [Expr.denote_toPoly]
|
||||
|
||||
end CommRing
|
||||
end Lean.Grind
|
||||
end Lean.Grind.CommRing
|
||||
@@ -169,7 +169,8 @@ theorem zpow_add {a : α} (h : a ≠ 0) (m n : Int) : a ^ (m + n) = a ^ m * a ^
|
||||
| zero => simp [Int.add_neg_one, zpow_sub_one h, zpow_neg_one]
|
||||
| succ n ih => rw [Int.natCast_add_one, Int.neg_add, Int.add_neg_one, ← Int.add_sub_assoc, zpow_sub_one h, zpow_sub_one h, ih, Semiring.mul_assoc]
|
||||
|
||||
instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
-- This is expensive as an instance. Let's see what breaks without it.
|
||||
def noNatZeroDivisors.ofIsCharPZero [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
intro a b h w
|
||||
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
|
||||
simp only [Nat.mod_zero, h, iff_false] at this
|
||||
|
||||
@@ -126,6 +126,52 @@ structure Config where
|
||||
abstractProof := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
/--
|
||||
A minimal configuration, with ematching and splitting disabled, and all solver modules turned off.
|
||||
`grind` will not do anything in this configuration,
|
||||
which can be used a starting point for minimal configurations.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure NoopConfig extends Config where
|
||||
-- Disable splitting
|
||||
splits := 0
|
||||
-- We don't override the various `splitMatch` / `splitIte` settings separately.
|
||||
|
||||
-- Disable e-matching
|
||||
ematch := 0
|
||||
-- We don't override `matchEqs` separately.
|
||||
|
||||
-- Disable extensionality
|
||||
ext := false
|
||||
extAll := false
|
||||
etaStruct := false
|
||||
funext := false
|
||||
|
||||
-- Disable all solver modules
|
||||
ring := false
|
||||
linarith := false
|
||||
cutsat := false
|
||||
ac := false
|
||||
|
||||
/--
|
||||
A `grind` configuration that only uses `cutsat` and splitting.
|
||||
|
||||
Note: `cutsat` benefits from some amount of instantiation, e.g. `Nat.max_def`.
|
||||
We don't currently have a mechanism to enable only a small set of lemmas.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure CutsatConfig extends NoopConfig where
|
||||
cutsat := true
|
||||
-- Allow the default number of splits.
|
||||
splits := ({} : Config).splits
|
||||
|
||||
/--
|
||||
A `grind` configuration that only uses `ring`.
|
||||
-/
|
||||
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
|
||||
structure GrobnerConfig extends NoopConfig where
|
||||
ring := true
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
namespace Lean.Parser.Tactic
|
||||
@@ -420,6 +466,23 @@ syntax (name := grindTrace)
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
(&" on_failure " term)? : tactic
|
||||
|
||||
/--
|
||||
`cutsat` solves linear integer arithmetic goals.
|
||||
|
||||
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `cutsat` solver.
|
||||
Please use `grind` instead if you need additional capabilities.
|
||||
-/
|
||||
syntax (name := cutsat) "cutsat" optConfig : tactic
|
||||
|
||||
/--
|
||||
`grobner` solves goals that can be phrased as polynomial equations (with further polynomial equations as hypotheses)
|
||||
over commutative (semi)rings, using the Grobner basis algorithm.
|
||||
|
||||
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `grobner` solver.
|
||||
Please use `grind` instead if you need additional capabilities.
|
||||
-/
|
||||
syntax (name := grobner) "grobner" optConfig : tactic
|
||||
|
||||
/-!
|
||||
Sets symbol priorities for the E-matching pattern inference procedure used in `grind`
|
||||
-/
|
||||
|
||||
1676
src/Init/Meta.lean
1676
src/Init/Meta.lean
File diff suppressed because it is too large
Load Diff
1679
src/Init/Meta/Defs.lean
Normal file
1679
src/Init/Meta/Defs.lean
Normal file
File diff suppressed because it is too large
Load Diff
@@ -94,7 +94,7 @@ structure Config where
|
||||
-/
|
||||
decide : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
@@ -208,7 +208,7 @@ structure Config where
|
||||
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
|
||||
arith : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
|
||||
@@ -5125,12 +5125,32 @@ inductive ParserDescr where
|
||||
The precedence `prec` and `lhsPrec` are used to determine whether the parser
|
||||
should apply. -/
|
||||
| trailingNode (kind : SyntaxNodeKind) (prec lhsPrec : Nat) (p : ParserDescr)
|
||||
/-- A literal symbol parser: parses `val` as a literal.
|
||||
This parser does not work on identifiers, so `symbol` arguments are declared
|
||||
as "keywords" and cannot be used as identifiers anywhere in the file. -/
|
||||
/--
|
||||
Parses the literal symbol.
|
||||
|
||||
The symbol is automatically included in the set of reserved tokens ("keywords").
|
||||
Keywords cannot be used as identifiers, unless the identifier is otherwise escaped.
|
||||
For example, `"fun"` reserves `fun` as a keyword; to refer an identifier named `fun` one can write `«fun»`.
|
||||
Adding a `&` prefix prevents it from being reserved, for example `&"true"`.
|
||||
|
||||
Whitespace before or after the atom is used as a pretty printing hint.
|
||||
For example, `" + "` parses `+` and pretty prints it with whitespace on both sides.
|
||||
The whitespace has no effect on parsing behavior.
|
||||
-/
|
||||
| symbol (val : String)
|
||||
/-- Like `symbol`, but without reserving `val` as a keyword.
|
||||
If `includeIdent` is true then `ident` will be reinterpreted as `atom` if it matches. -/
|
||||
/--
|
||||
Parses a literal symbol. The `&` prefix prevents it from being included in the set of reserved tokens ("keywords").
|
||||
This means that the symbol can still be recognized as an identifier by other parsers.
|
||||
|
||||
Some syntax categories, such as `tactic`, automatically apply `&` to the first symbol.
|
||||
|
||||
Whitespace before or after the atom is used as a pretty printing hint.
|
||||
For example, `" + "` parses `+` and pretty prints it with whitespace on both sides.
|
||||
The whitespace has no effect on parsing behavior.
|
||||
|
||||
(Not exposed by parser description syntax:
|
||||
If the `includeIdent` argument is true, lets `ident` be reinterpreted as `atom` if it matches.)
|
||||
-/
|
||||
| nonReservedSymbol (val : String) (includeIdent : Bool)
|
||||
/-- Parses using the category parser `catName` with right binding power
|
||||
(i.e. precedence) `rbp`. -/
|
||||
@@ -5150,6 +5170,19 @@ inductive ParserDescr where
|
||||
/-- `sepBy1` is just like `sepBy`, except it takes 1 or more instead of
|
||||
0 or more occurrences of `p`. -/
|
||||
| sepBy1 (p : ParserDescr) (sep : String) (psep : ParserDescr) (allowTrailingSep : Bool := false)
|
||||
/--
|
||||
- `unicode("→", "->")` parses a symbol matching either `→` or `->`. Each symbol is reserved.
|
||||
The second symbol is an ASCII version of the first.
|
||||
The `pp.unicode` option controls which is used when pretty printing.
|
||||
- `unicode("→", "->", preserveForPP)` is the same except for pretty printing behavior.
|
||||
When the `pp.unicode` option is enabled, then the pretty printer uses whichever symbol
|
||||
matches the underlying atom in the syntax.
|
||||
The intent is that `preserveForPP` means that the ASCII variant is preferred.
|
||||
For example, `fun` notation uses `preserveForPP` for its arrow; the delaborator chooses
|
||||
`↦` or `=>` depending on the value of `pp.unicode.fun`, letting users opt-in to formatting with `↦`.
|
||||
Note that `notation` creates a pretty printer preferring the ASCII version.
|
||||
-/
|
||||
| unicodeSymbol (val asciiVal : String) (preserveForPP : Bool)
|
||||
|
||||
instance : Inhabited ParserDescr where
|
||||
default := ParserDescr.symbol ""
|
||||
|
||||
@@ -477,7 +477,7 @@ syntax negConfigItem := " -" noWs ident
|
||||
|
||||
As a special case, `(config := ...)` sets the entire configuration.
|
||||
-/
|
||||
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") (ident <|> &"config")) " := " withoutPosition(term) ")"
|
||||
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") ident " := ") withoutPosition(term) ")"
|
||||
/-- A configuration item for a tactic configuration. -/
|
||||
syntax configItem := posConfigItem <|> negConfigItem <|> valConfigItem
|
||||
|
||||
@@ -2262,6 +2262,18 @@ such as replacing `if c then _ else _` with `if h : c then _ else _` or `xs.map`
|
||||
-/
|
||||
syntax (name := wf_preprocess) "wf_preprocess" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
/--
|
||||
Theorems tagged with the `method_specs_simp` attribute are used by `@[method_specs]` to further
|
||||
rewrite the theorem statement. This is primarily used to rewrite type class methods further to
|
||||
the desired user-visible form, e.g. from `Append.append` to `HAppend.hAppend`, which has the familiar
|
||||
notation associated.
|
||||
|
||||
The `method_specs` theorems are created on demand (using the realizable constant feature). Thus,
|
||||
this simp set should behave the same in all modules. Do not add theorems to it except in the module
|
||||
defining the thing you are rewriting.
|
||||
-/
|
||||
syntax (name := method_specs_simp) "method_specs_simp" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
/-- The possible `norm_cast` kinds: `elim`, `move`, or `squash`. -/
|
||||
syntax normCastLabel := &"elim" <|> &"move" <|> &"squash"
|
||||
|
||||
|
||||
@@ -24,14 +24,17 @@ private def expandIfThenElse
|
||||
pure (⟨holeOrTacticSeq⟩, #[])
|
||||
else if holeOrTacticSeq.isOfKind `Lean.Parser.Term.hole then
|
||||
pure (← mkName, #[])
|
||||
else if tk.isMissing then
|
||||
pure (← `(sorry), #[])
|
||||
else
|
||||
let hole ← withFreshMacroScope mkName
|
||||
let holeId := hole.raw[1]
|
||||
let case ← (open TSyntax.Compat in `(tactic|
|
||||
case $holeId:ident =>%$tk
|
||||
-- annotate `then/else` with state after `case`
|
||||
with_annotate_state $tk skip
|
||||
$holeOrTacticSeq))
|
||||
let holeId : Ident := ⟨hole.raw[1]⟩
|
||||
let tacticSeq : TSyntax `Lean.Parser.Tactic.tacticSeq := ⟨holeOrTacticSeq⟩
|
||||
-- Use `missing` for ref to ensure that the source range is the same as `holeOrTacticSeq`'s.
|
||||
let tacticSeq : TSyntax `Lean.Parser.Tactic.tacticSeq ← MonadRef.withRef .missing `(tacticSeq|
|
||||
with_annotate_state $tk skip
|
||||
($tacticSeq))
|
||||
let case ← withRef tk <| `(tactic| case $holeId:ident =>%$tk $tacticSeq:tacticSeq)
|
||||
pure (hole, #[case])
|
||||
let (posHole, posCase) ← mkCase thenTk pos `(?pos)
|
||||
let (negHole, negCase) ← mkCase elseTk neg `(?neg)
|
||||
|
||||
@@ -220,26 +220,35 @@ end TagAttribute
|
||||
contains the attribute `pAttr` with parameter `p`. -/
|
||||
structure ParametricAttribute (α : Type) where
|
||||
attr : AttributeImpl
|
||||
ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α)
|
||||
ext : PersistentEnvExtension (Name × α) (Name × α) (List Name × NameMap α)
|
||||
preserveOrder : Bool
|
||||
deriving Inhabited
|
||||
|
||||
structure ParametricAttributeImpl (α : Type) extends AttributeImplCore where
|
||||
getParam : Name → Syntax → AttrM α
|
||||
afterSet : Name → α → AttrM Unit := fun _ _ _ => pure ()
|
||||
afterImport : Array (Array (Name × α)) → ImportM Unit := fun _ => pure ()
|
||||
/--
|
||||
If set, entries are not resorted on export and `getParam?` will fall back to a linear instead of
|
||||
binary search insde an imported module's entries.
|
||||
-/
|
||||
preserveOrder : Bool := false
|
||||
|
||||
def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (ParametricAttribute α) := do
|
||||
let ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α) ← registerPersistentEnvExtension {
|
||||
let ext : PersistentEnvExtension (Name × α) (Name × α) (List Name × NameMap α) ← registerPersistentEnvExtension {
|
||||
name := impl.ref
|
||||
mkInitial := pure {}
|
||||
addImportedFn := fun s => impl.afterImport s *> pure {}
|
||||
addEntryFn := fun (s : NameMap α) (p : Name × α) => s.insert p.1 p.2
|
||||
exportEntriesFnEx := fun env m _ =>
|
||||
let r : Array (Name × α) := m.foldl (fun a n p => a.push (n, p)) #[]
|
||||
-- Do not export info for private defs
|
||||
mkInitial := pure ([], {})
|
||||
addImportedFn := fun s => impl.afterImport s *> pure ([], {})
|
||||
addEntryFn := fun (decls, m) (p : Name × α) => (p.1 :: decls, m.insert p.1 p.2)
|
||||
exportEntriesFnEx := fun env (decls, m) _ =>
|
||||
let r := if impl.preserveOrder then
|
||||
decls.toArray.reverse.filterMap (fun n => return (n, ← m.find? n))
|
||||
else
|
||||
m.foldl (fun a n p => a.push (n, p)) #[]
|
||||
-- Do not export info for private defs
|
||||
let r := r.filter (env.contains (skipRealize := false) ·.1)
|
||||
r.qsort (fun a b => Name.quickLt a.1 b.1)
|
||||
statsFn := fun s => "parametric attribute" ++ Format.line ++ "number of local entries: " ++ format s.size
|
||||
statsFn := fun (_, m) => "parametric attribute" ++ Format.line ++ "number of local entries: " ++ format m.size
|
||||
}
|
||||
let attrImpl : AttributeImpl := {
|
||||
impl.toAttributeImplCore with
|
||||
@@ -253,22 +262,26 @@ def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (Parame
|
||||
try impl.afterSet decl val catch _ => setEnv env
|
||||
}
|
||||
registerBuiltinAttribute attrImpl
|
||||
pure { attr := attrImpl, ext := ext }
|
||||
pure { attr := attrImpl, ext, preserveOrder := impl.preserveOrder }
|
||||
|
||||
namespace ParametricAttribute
|
||||
|
||||
def getParam? [Inhabited α] (attr : ParametricAttribute α) (env : Environment) (decl : Name) : Option α :=
|
||||
match env.getModuleIdxFor? decl with
|
||||
| some modIdx =>
|
||||
match (attr.ext.getModuleEntries env modIdx).binSearch (decl, default) (fun a b => Name.quickLt a.1 b.1) with
|
||||
let entry? := if attr.preserveOrder then
|
||||
(attr.ext.getModuleEntries env modIdx).find? (·.1 == decl)
|
||||
else
|
||||
(attr.ext.getModuleEntries env modIdx).binSearch (decl, default) (fun a b => Name.quickLt a.1 b.1)
|
||||
match entry? with
|
||||
| some (_, val) => some val
|
||||
| none => none
|
||||
| none => (attr.ext.getState env).find? decl
|
||||
| none => (attr.ext.getState env).2.find? decl
|
||||
|
||||
def setParam (attr : ParametricAttribute α) (env : Environment) (decl : Name) (param : α) : Except String Environment :=
|
||||
if (env.getModuleIdxFor? decl).isSome then
|
||||
Except.error (s!"Failed to add parametric attribute `[{attr.attr.name}]` to `{decl}`: Declaration is in an imported module")
|
||||
else if ((attr.ext.getState env).find? decl).isSome then
|
||||
else if ((attr.ext.getState env).2.find? decl).isSome then
|
||||
Except.error (s!"Failed to add parametric attribute `[{attr.attr.name}]` to `{decl}`: Attribute has already been set")
|
||||
else
|
||||
Except.ok (attr.ext.addEntry env (decl, param))
|
||||
|
||||
@@ -34,6 +34,7 @@ builtin_initialize
|
||||
add := fun decl stx _ => do
|
||||
Attribute.Builtin.ensureNoArgs stx
|
||||
declareBuiltinDocStringAndRanges decl
|
||||
applicationTime := AttributeApplicationTime.afterCompilation
|
||||
}
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -62,6 +62,7 @@ builtin_initialize exportAttr : ParametricAttribute Name ←
|
||||
return exportName
|
||||
}
|
||||
|
||||
@[export lean_get_export_name_for]
|
||||
def getExportNameFor? (env : Environment) (n : Name) : Option Name :=
|
||||
exportAttr.getParam? env n
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ unsafe def registerInitAttrUnsafe (attrName : Name) (runAfterImport : Bool) (ref
|
||||
ref := ref
|
||||
name := attrName
|
||||
descr := "initialization procedure for global references"
|
||||
-- We want to run `[init]` in declaration order
|
||||
preserveOrder := true
|
||||
getParam := fun declName stx => do
|
||||
let decl ← getConstInfo declName
|
||||
match (← Attribute.Builtin.getIdent? stx) with
|
||||
@@ -64,7 +66,6 @@ unsafe def registerInitAttrUnsafe (attrName : Name) (runAfterImport : Bool) (ref
|
||||
let ctx ← read
|
||||
if runAfterImport && (← isInitializerExecutionEnabled) then
|
||||
for mod in ctx.env.header.moduleNames,
|
||||
modData in ctx.env.header.moduleData,
|
||||
modEntries in entries do
|
||||
-- any native Lean code reachable by the interpreter (i.e. from shared
|
||||
-- libraries with their corresponding module in the Environment) must
|
||||
@@ -83,14 +84,12 @@ unsafe def registerInitAttrUnsafe (attrName : Name) (runAfterImport : Bool) (ref
|
||||
if (← interpretedModInits.get).contains mod then
|
||||
continue
|
||||
interpretedModInits.modify (·.insert mod)
|
||||
for c in modData.constNames do
|
||||
-- make sure to run initializers in declaration order, not extension state order, to respect dependencies
|
||||
if let some (decl, initDecl) := modEntries.binSearch (c, default) (Name.quickLt ·.1 ·.1) then
|
||||
if initDecl.isAnonymous then
|
||||
let initFn ← IO.ofExcept <| ctx.env.evalConst (IO Unit) ctx.opts decl
|
||||
initFn
|
||||
else
|
||||
runInit ctx.env ctx.opts decl initDecl
|
||||
for (decl, initDecl) in modEntries do
|
||||
if initDecl.isAnonymous then
|
||||
let initFn ← IO.ofExcept <| ctx.env.evalConst (IO Unit) ctx.opts decl
|
||||
initFn
|
||||
else
|
||||
runInit ctx.env ctx.opts decl initDecl
|
||||
}
|
||||
|
||||
@[implemented_by registerInitAttrUnsafe]
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Lean.ProjFns
|
||||
public import Lean.Meta.AppBuilder
|
||||
public import Lean.Meta.CtorRecognizer
|
||||
public import Lean.Compiler.BorrowedAnnotation
|
||||
public import Lean.Compiler.CSimpAttr
|
||||
@@ -787,9 +788,14 @@ where
|
||||
visit e
|
||||
|
||||
visitProj (s : Name) (i : Nat) (e : Expr) : M Arg := do
|
||||
match (← visit e) with
|
||||
| .erased | .type .. => return .erased
|
||||
| .fvar fvarId => letValueToArg <| .proj s i fvarId
|
||||
if isRuntimeBuiltinType s then
|
||||
let structInfo := getStructureInfo (← getEnv) s
|
||||
let projExpr ← liftMetaM <| Meta.mkProjection e structInfo.fieldNames[i]!
|
||||
visitApp projExpr
|
||||
else
|
||||
match (← visit e) with
|
||||
| .erased | .type .. => return .erased
|
||||
| .fvar fvarId => letValueToArg <| .proj s i fvarId
|
||||
|
||||
visitLet (e : Expr) (xs : Array Expr) : M Arg := do
|
||||
match e with
|
||||
|
||||
@@ -6,10 +6,10 @@ Authors: Joachim Breitner
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Iterators
|
||||
|
||||
public section
|
||||
public import Init.Prelude
|
||||
import Init.Data.Stream
|
||||
import Init.Data.Range.Polymorphic.Nat
|
||||
import Init.Data.Range.Polymorphic.Iterators
|
||||
|
||||
namespace Array
|
||||
|
||||
@@ -37,7 +37,7 @@ Example:
|
||||
#["a", "red", "x", "r"]
|
||||
```
|
||||
-/
|
||||
def filterPairsM {m} [Monad m] {α} (a : Array α) (f : α → α → m (Bool × Bool)) :
|
||||
public def filterPairsM {m} [Monad m] {α} (a : Array α) (f : α → α → m (Bool × Bool)) :
|
||||
m (Array α) := do
|
||||
let mut removed := Array.replicate a.size false
|
||||
let mut numRemoved := 0
|
||||
@@ -58,4 +58,38 @@ def filterPairsM {m} [Monad m] {α} (a : Array α) (f : α → α → m (Bool ×
|
||||
a' := a'.push a[i]
|
||||
return a'
|
||||
|
||||
/--
|
||||
`maskArray mask xs` keeps those `x` where the corresponding entry in `mask` is `true`
|
||||
-/
|
||||
public def mask {α} (mask : Array Bool) (xs : Array α) : Array α := Id.run do
|
||||
let mut ys := #[]
|
||||
for b in mask, x in xs do
|
||||
if b then ys := ys.push x
|
||||
return ys
|
||||
|
||||
/--
|
||||
Inverse of `Array.mask`:
|
||||
```
|
||||
Array.zipMasked mask (Array.mask (mask.map not) xs) (Array.mask mask xs) == xs
|
||||
```
|
||||
-/
|
||||
public def zipMasked {α} (mask : Array Bool) (xs ys : Array α) : Array α := Id.run do
|
||||
let mut i := 0
|
||||
let mut j := 0
|
||||
let mut zs := #[]
|
||||
for b in mask do
|
||||
if b then
|
||||
if h : j < ys.size then
|
||||
zs := zs.push ys[j]
|
||||
j := j + 1
|
||||
else
|
||||
panic! "zipMaskedArray: not enough elements in ys"
|
||||
else
|
||||
if h : i < xs.size then
|
||||
zs := zs.push xs[i]
|
||||
i := i + 1
|
||||
else
|
||||
panic! "zipMaskedArray: not enough elements in xs"
|
||||
return zs
|
||||
|
||||
end Array
|
||||
|
||||
55
src/Lean/Data/EditDistance.lean
Normal file
55
src/Lean/Data/EditDistance.lean
Normal file
@@ -0,0 +1,55 @@
|
||||
/-
|
||||
Copyright (c) 2024-2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: David Thrane Christiansen
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace Lean.EditDistance
|
||||
|
||||
/--
|
||||
Computes the Levenshtein distance between two strings, up to some cutoff.
|
||||
|
||||
If the return value is `none`, then the distance is certainly greater than the cutoff value, but a
|
||||
returned `some` does not necessarily indicate that the edit distance is less than or equal to the
|
||||
cutoff.
|
||||
-/
|
||||
public def levenshtein (str1 str2 : String) (cutoff : Nat) : Option Nat := Id.run do
|
||||
let len1 := str1.length
|
||||
let len2 := str2.length
|
||||
|
||||
-- The lower bound on the Levenshtein distance is the difference in lengths
|
||||
if max len1 len2 - min len1 len2 > cutoff then return none
|
||||
|
||||
let mut v0 := Vector.replicate (len2 + 1) 0
|
||||
let mut v1 := v0
|
||||
|
||||
for h : i in [0:v0.size] do
|
||||
v0 := v0.set i i
|
||||
let mut iter1 := str1.iter
|
||||
let mut i := 0
|
||||
while h1 : iter1.hasNext do
|
||||
v1 := v1.set 0 (i+1)
|
||||
let mut iter2 := str2.iter
|
||||
let mut j : Fin (len2 + 1) := 0
|
||||
while h2 : iter2.hasNext do
|
||||
let j' : Fin _ := j + 1
|
||||
let deletionCost := v0[j'] + 1
|
||||
let insertionCost := v1[j] + 1
|
||||
let substCost :=
|
||||
if iter1.curr' h1 == iter2.curr' h2 then v0[j]
|
||||
else v0[j] + 1
|
||||
let cost := min (min deletionCost insertionCost) substCost
|
||||
v1 := v1.set j' cost
|
||||
iter2 := iter2.next' h2
|
||||
j := j + 1
|
||||
iter1 := iter1.next' h1
|
||||
i := i + 1
|
||||
-- Terminate early if it's impossible that the result is below the cutoff
|
||||
if v1.all (· > cutoff) then return none
|
||||
v0 := v1
|
||||
some v0[len2]
|
||||
@@ -7,11 +7,17 @@ Authors: David Thrane Christiansen
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Lean.Environment
|
||||
public import Lean.Exception
|
||||
public import Lean.Log
|
||||
public import Lean.DocString.Extension
|
||||
public import Lean.DocString.Links
|
||||
import Lean.Environment
|
||||
import Lean.Exception
|
||||
import Lean.Log
|
||||
import Lean.Elab.DocString
|
||||
import Lean.DocString.Extension
|
||||
import Lean.DocString.Links
|
||||
import Lean.Parser.Types
|
||||
import Lean.DocString.Parser
|
||||
import Lean.ResolveName
|
||||
public import Lean.Elab.Term.TermElabM
|
||||
import Std.Data.HashMap
|
||||
|
||||
public section
|
||||
|
||||
@@ -19,6 +25,8 @@ set_option linter.missingDocs true
|
||||
|
||||
namespace Lean
|
||||
|
||||
open Lean.Elab.Term (TermElabM)
|
||||
|
||||
/--
|
||||
Validates all links to the Lean reference manual in `docstring`.
|
||||
|
||||
@@ -26,7 +34,7 @@ This is intended to be used before saving a docstring that is later subject to r
|
||||
`rewriteManualLinks`.
|
||||
-/
|
||||
def validateDocComment
|
||||
[Monad m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
|
||||
[Monad m] [MonadLiftT IO m] [MonadLog m] [AddMessageContext m] [MonadOptions m]
|
||||
(docstring : TSyntax `Lean.Parser.Command.docComment) :
|
||||
m Unit := do
|
||||
let str := docstring.getDocString
|
||||
@@ -42,27 +50,231 @@ def validateDocComment
|
||||
else
|
||||
logError err
|
||||
|
||||
|
||||
open Lean.Doc in
|
||||
open Parser in
|
||||
/--
|
||||
Adds a docstring to the environment, validating documentation links.
|
||||
Adds a Verso docstring to the specified declaration, which should already be present in the
|
||||
environment.
|
||||
|
||||
`binders` should be the syntax of the parameters to the constant that is being documented, as a null
|
||||
node that contains a sequence of bracketed binders. It is used to allow interactive features such as
|
||||
document highlights and “find references” to work for documented parameters. If no parameter binders
|
||||
are available, pass `Syntax.missing` or an empty null node.
|
||||
|
||||
-/
|
||||
def addDocString
|
||||
[Monad m] [MonadError m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
|
||||
(declName : Name) (docComment : TSyntax `Lean.Parser.Command.docComment) : m Unit := do
|
||||
def versoDocString
|
||||
(declName : Name) (binders : Syntax) (docComment : TSyntax `Lean.Parser.Command.docComment) :
|
||||
TermElabM (Array (Doc.Block ElabInline ElabBlock) × Array (Doc.Part ElabInline ElabBlock Empty)) := do
|
||||
|
||||
let text ← getFileMap
|
||||
-- TODO fallback to string version without nice interactivity
|
||||
let some startPos := docComment.raw[1].getPos? (canonicalOnly := true)
|
||||
| throwErrorAt docComment m!"Documentation comment has no source location, cannot parse"
|
||||
let some endPos := docComment.raw[1].getTailPos? (canonicalOnly := true)
|
||||
| throwErrorAt docComment m!"Documentation comment has no source location, cannot parse"
|
||||
|
||||
-- Skip trailing `-/`
|
||||
let endPos := text.source.prev <| text.source.prev endPos
|
||||
let endPos := if endPos ≤ text.source.endPos then endPos else text.source.endPos
|
||||
have endPos_valid : endPos ≤ text.source.endPos := by
|
||||
unfold endPos
|
||||
split <;> simp [*]
|
||||
|
||||
let env ← getEnv
|
||||
let ictx : InputContext :=
|
||||
.mk text.source (← getFileName) (fileMap := text)
|
||||
(endPos := endPos) (endPos_valid := endPos_valid)
|
||||
let pmctx : ParserModuleContext := {
|
||||
env,
|
||||
options := ← getOptions,
|
||||
currNamespace := (← getCurrNamespace),
|
||||
openDecls := (← getOpenDecls)
|
||||
}
|
||||
let s := mkParserState text.source |>.setPos startPos
|
||||
-- TODO parse one block at a time for error recovery purposes
|
||||
let s := (Doc.Parser.document).run ictx pmctx (getTokenTable env) s
|
||||
|
||||
if !s.allErrors.isEmpty then
|
||||
for (pos, _, err) in s.allErrors do
|
||||
logMessage {
|
||||
fileName := (← getFileName),
|
||||
pos := text.toPosition pos,
|
||||
-- TODO end position
|
||||
data := err.toString
|
||||
}
|
||||
return (#[], #[])
|
||||
else
|
||||
let stx := s.stxStack.back
|
||||
let stx := stx.getArgs
|
||||
Doc.elabBlocks (stx.map (⟨·⟩)) |>.exec declName binders
|
||||
|
||||
open Lean.Doc in
|
||||
open Parser in
|
||||
/--
|
||||
Adds a Verso docstring to the specified declaration, which should already be present in the
|
||||
environment. The docstring is added from a string value, rather than syntax, which means that the
|
||||
interactive features are disabled.
|
||||
-/
|
||||
def versoDocStringFromString
|
||||
(declName : Name) (docComment : String) :
|
||||
TermElabM (Array (Doc.Block ElabInline ElabBlock) × Array (Doc.Part ElabInline ElabBlock Empty)) := do
|
||||
|
||||
let env ← getEnv
|
||||
let ictx : InputContext := .mk docComment (← getFileName)
|
||||
let text := ictx.fileMap
|
||||
let pmctx : ParserModuleContext := {
|
||||
env,
|
||||
options := ← getOptions,
|
||||
currNamespace := (← getCurrNamespace),
|
||||
openDecls := (← getOpenDecls)
|
||||
}
|
||||
let s := mkParserState docComment
|
||||
-- TODO parse one block at a time for error recovery purposes
|
||||
let s := (Doc.Parser.document).run ictx pmctx (getTokenTable env) s
|
||||
|
||||
if !s.allErrors.isEmpty then
|
||||
for (pos, _, err) in s.allErrors do
|
||||
logError err.toString
|
||||
return (#[], #[])
|
||||
else
|
||||
let stx := s.stxStack.back
|
||||
let stx := stx.getArgs
|
||||
let msgs ← Core.getAndEmptyMessageLog
|
||||
let (val, msgs') ←
|
||||
try
|
||||
let range? := (← getRef).getRange?
|
||||
let val ←
|
||||
Elab.withEnableInfoTree false <| withTheReader Core.Context ({· with fileMap := text}) <|
|
||||
(Doc.elabBlocks (stx.map (⟨·⟩))).exec declName (mkNullNode #[]) (suggestionMode := .batch)
|
||||
let msgs' ← Core.getAndEmptyMessageLog
|
||||
pure (val, msgs')
|
||||
finally
|
||||
Core.setMessageLog msgs
|
||||
-- Adjust messages to show them at the call site
|
||||
for msg in msgs'.toArray do
|
||||
logAt (← getRef) msg.data (severity := msg.severity)
|
||||
pure val
|
||||
|
||||
/--
|
||||
Adds a Markdown docstring to the environment, validating documentation links.
|
||||
-/
|
||||
def addMarkdownDocString
|
||||
[Monad m] [MonadLiftT IO m] [MonadOptions m] [MonadEnv m]
|
||||
[MonadError m] [MonadLog m] [AddMessageContext m]
|
||||
(declName : Name) (docComment : TSyntax `Lean.Parser.Command.docComment) :
|
||||
m Unit := do
|
||||
if declName.isAnonymous then
|
||||
-- This case might happen on partial elaboration; ignore instead of triggering any panics below
|
||||
return
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError "invalid doc string, declaration `{.ofConstName declName}` is in an imported module"
|
||||
throwError m!"invalid doc string, declaration `{.ofConstName declName}` is in an imported module"
|
||||
validateDocComment docComment
|
||||
let docString : String ← getDocStringText docComment
|
||||
modifyEnv fun env => docStringExt.insert env declName docString.removeLeadingSpaces
|
||||
|
||||
/--
|
||||
Adds a docstring to the environment, validating documentation links.
|
||||
Adds an elaborated Verso docstring to the environment.
|
||||
-/
|
||||
def addVersoDocStringCore [Monad m] [MonadEnv m] [MonadLiftT BaseIO m] [MonadError m]
|
||||
(declName : Name) (docs : VersoDocString) : m Unit := do
|
||||
let throwImported {α} : m α :=
|
||||
throwError s!"invalid doc string, declaration '{declName}' is in an imported module"
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwImported
|
||||
modifyEnv fun env =>
|
||||
versoDocStringExt.insert env declName docs
|
||||
|
||||
/--
|
||||
Adds a Verso docstring to the environment.
|
||||
|
||||
`binders` should be the syntax of the parameters to the constant that is being documented, as a null
|
||||
node that contains a sequence of bracketed binders. It is used to allow interactive features such as
|
||||
document highlights and “find references” to work for documented parameters. If no parameter binders
|
||||
are available, pass `Syntax.missing` or an empty null node.
|
||||
-/
|
||||
def addVersoDocString
|
||||
(declName : Name) (binders : Syntax) (docComment : TSyntax `Lean.Parser.Command.docComment) :
|
||||
TermElabM Unit := do
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError s!"invalid doc string, declaration '{declName}' is in an imported module"
|
||||
let (blocks, parts) ← versoDocString declName binders docComment
|
||||
addVersoDocStringCore declName ⟨blocks, parts⟩
|
||||
|
||||
/--
|
||||
Adds a Verso docstring to the environment from a string value, which disables the interactive
|
||||
features. This should be used for programs that add documentation when there is no syntax available.
|
||||
-/
|
||||
def addVersoDocStringFromString (declName : Name) (docComment : String) :
|
||||
TermElabM Unit := do
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError s!"invalid doc string, declaration '{declName}' is in an imported module"
|
||||
let (blocks, parts) ← versoDocStringFromString declName docComment
|
||||
addVersoDocStringCore declName ⟨blocks, parts⟩
|
||||
|
||||
|
||||
/--
|
||||
Adds a docstring to the environment. If `isVerso` is `false`, then the docstring is interpreted as
|
||||
Markdown.
|
||||
-/
|
||||
def addDocStringOf
|
||||
(isVerso : Bool) (declName : Name) (binders : Syntax)
|
||||
(docComment : TSyntax `Lean.Parser.Command.docComment) :
|
||||
TermElabM Unit := do
|
||||
if isVerso then
|
||||
addVersoDocString declName binders docComment
|
||||
else
|
||||
addMarkdownDocString declName docComment
|
||||
|
||||
/--
|
||||
Interprets a docstring that has been saved as a Markdown string as Verso, elaborating it. This is
|
||||
used during bootstrapping.
|
||||
-/
|
||||
def makeDocStringVerso (declName : Name) : TermElabM Unit := do
|
||||
let some doc ← findInternalDocString? (← getEnv) declName (includeBuiltin := true)
|
||||
| throwError "No documentation found for `{.ofConstName declName}`"
|
||||
let .inl md := doc
|
||||
| throwError "Documentation for `{.ofConstName declName}` is already in Verso format"
|
||||
removeBuiltinDocString declName
|
||||
removeDocStringCore declName
|
||||
addVersoDocStringFromString declName md
|
||||
|
||||
/--
|
||||
Adds a docstring to the environment.
|
||||
|
||||
If the option `doc.verso` is `true`, the docstring is processed as a Verso docstring. Otherwise, it
|
||||
is considered a Markdown docstring, and documentation links are validated. To explicitly control
|
||||
whether the docstring is in Verso format, use `addDocStringOf` instead.
|
||||
|
||||
For Verso docstrings, `binders` should be the syntax of the parameters to the constant that is being
|
||||
documented, as a null node that contains a sequence of bracketed binders. It is used to allow
|
||||
interactive features such as document highlights and “find references” to work for documented
|
||||
parameters. If no parameter binders are available, pass `Syntax.missing` or an empty null node.
|
||||
`binders` is not used for Markdown docstrings.
|
||||
-/
|
||||
def addDocString
|
||||
(declName : Name) (binders : Syntax) (docComment : TSyntax `Lean.Parser.Command.docComment) :
|
||||
TermElabM Unit := do
|
||||
addDocStringOf (doc.verso.get (← getOptions)) declName binders docComment
|
||||
|
||||
/--
|
||||
Adds a docstring to the environment, if it is provided. If no docstring is provided, nothing
|
||||
happens.
|
||||
|
||||
If the option `doc.verso` is `true`, the docstring is processed as a Verso docstring. Otherwise, it
|
||||
is considered a Markdown docstring, and documentation links are validated. To explicitly control
|
||||
whether the docstring is in Verso format, use `addDocStringOf` instead.
|
||||
|
||||
For Verso docstrings, `binders` should be the syntax of the parameters to the constant that is being
|
||||
documented, as a null node that contains a sequence of bracketed binders. It is used to allow
|
||||
interactive features such as document highlights and “find references” to work for documented
|
||||
parameters. If no parameter binders are available, pass `Syntax.missing` or an empty null node.
|
||||
`binders` is not used for Markdown docstrings.
|
||||
|
||||
-/
|
||||
def addDocString'
|
||||
[Monad m] [MonadError m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
|
||||
(declName : Name) (docString? : Option (TSyntax `Lean.Parser.Command.docComment)) : m Unit :=
|
||||
(declName : Name) (binders : Syntax) (docString? : Option (TSyntax `Lean.Parser.Command.docComment)) :
|
||||
TermElabM Unit :=
|
||||
match docString? with
|
||||
| some docString => addDocString declName docString
|
||||
| some docString => addDocString declName binders docString
|
||||
| none => return ()
|
||||
|
||||
@@ -7,9 +7,12 @@ module
|
||||
|
||||
prelude
|
||||
public import Lean.DeclarationRange
|
||||
public import Lean.Data.Options
|
||||
public import Lean.DocString.Links
|
||||
public import Lean.MonadEnv
|
||||
public import Init.Data.String.Extra
|
||||
public import Lean.DocString.Types
|
||||
import Lean.DocString.Markdown
|
||||
|
||||
public section
|
||||
|
||||
@@ -20,8 +23,81 @@ public section
|
||||
|
||||
namespace Lean
|
||||
|
||||
|
||||
/--
|
||||
Saved data that describes the contents. The `name` should determine both the type of the value and
|
||||
its interpretation; if in doubt, use the name of the elaborator that produces the data.
|
||||
-/
|
||||
structure ElabInline where
|
||||
name : Name
|
||||
val : Dynamic
|
||||
|
||||
instance : Repr ElabInline where
|
||||
reprPrec v _ :=
|
||||
.group <| .nestD <|
|
||||
.group (.nestD ("{ name :=" ++ .line ++ repr v.name)) ++ .line ++
|
||||
.group (.nestD ("val :=" ++ .line ++ "Dynamic.mk " ++ repr v.val.typeName ++ " _ }"))
|
||||
|
||||
private instance : Doc.MarkdownInline ElabInline where
|
||||
-- TODO extensibility
|
||||
toMarkdown go _i content := content.forM go
|
||||
|
||||
|
||||
/--
|
||||
Saved data that describes the contents. The `name` should determine both the type of the value and
|
||||
its interpretation; if in doubt, use the name of the elaborator that produces the data.
|
||||
-/
|
||||
structure ElabBlock where
|
||||
name : Name
|
||||
val : Dynamic
|
||||
|
||||
instance : Repr ElabBlock where
|
||||
reprPrec v _ :=
|
||||
.group <| .nestD <|
|
||||
.group (.nestD ("{ name :=" ++ .line ++ repr v.name)) ++ .line ++
|
||||
.group (.nestD ("val :=" ++ .line ++ "Dynamic.mk " ++ repr v.val.typeName ++ " _ }"))
|
||||
|
||||
|
||||
-- TODO extensible toMarkdown
|
||||
private instance : Doc.MarkdownBlock ElabInline ElabBlock where
|
||||
toMarkdown _goI goB _b content := content.forM goB
|
||||
|
||||
structure VersoDocString where
|
||||
text : Array (Doc.Block ElabInline ElabBlock)
|
||||
subsections : Array (Doc.Part ElabInline ElabBlock Empty)
|
||||
deriving Inhabited
|
||||
|
||||
register_builtin_option doc.verso : Bool := {
|
||||
defValue := false,
|
||||
descr := "whether to use Verso syntax in docstrings"
|
||||
group := "doc"
|
||||
}
|
||||
|
||||
private builtin_initialize builtinDocStrings : IO.Ref (NameMap String) ← IO.mkRef {}
|
||||
builtin_initialize docStringExt : MapDeclarationExtension String ← mkMapDeclarationExtension
|
||||
builtin_initialize docStringExt : MapDeclarationExtension String ←
|
||||
mkMapDeclarationExtension
|
||||
(asyncMode := .async .asyncEnv)
|
||||
(exportEntriesFn := fun _ s level =>
|
||||
if level < .server then
|
||||
{}
|
||||
else
|
||||
s.toArray)
|
||||
private builtin_initialize inheritDocStringExt : MapDeclarationExtension Name ←
|
||||
mkMapDeclarationExtension (exportEntriesFn := fun _ s level =>
|
||||
if level < .server then
|
||||
{}
|
||||
else
|
||||
s.toArray)
|
||||
|
||||
private builtin_initialize builtinVersoDocStrings : IO.Ref (NameMap VersoDocString) ← IO.mkRef {}
|
||||
builtin_initialize versoDocStringExt : MapDeclarationExtension VersoDocString ←
|
||||
mkMapDeclarationExtension
|
||||
(asyncMode := .async .asyncEnv)
|
||||
(exportEntriesFn := fun _ s level =>
|
||||
if level < .server then
|
||||
{}
|
||||
else
|
||||
s.toArray)
|
||||
|
||||
/--
|
||||
Adds a builtin docstring to the compiler.
|
||||
@@ -32,34 +108,91 @@ Links to the Lean manual aren't validated.
|
||||
def addBuiltinDocString (declName : Name) (docString : String) : IO Unit := do
|
||||
builtinDocStrings.modify (·.insert declName docString.removeLeadingSpaces)
|
||||
|
||||
def addDocStringCore [Monad m] [MonadError m] [MonadEnv m] (declName : Name) (docString : String) : m Unit := do
|
||||
/--
|
||||
Removes a builtin docstring from the compiler. This is used when translating between formats.
|
||||
-/
|
||||
def removeBuiltinDocString (declName : Name) : IO Unit := do
|
||||
builtinDocStrings.modify (·.erase declName)
|
||||
|
||||
/--
|
||||
Retrieves all builtin Verso docstrings.
|
||||
-/
|
||||
def getBuiltinVersoDocStrings : IO (NameMap VersoDocString) :=
|
||||
builtinVersoDocStrings.get
|
||||
|
||||
def addDocStringCore [Monad m] [MonadError m] [MonadEnv m] [MonadLiftT BaseIO m] (declName : Name) (docString : String) : m Unit := do
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError "invalid doc string, declaration `{.ofConstName declName}` is in an imported module"
|
||||
throwError m!"invalid doc string, declaration `{.ofConstName declName}` is in an imported module"
|
||||
modifyEnv fun env => docStringExt.insert env declName docString.removeLeadingSpaces
|
||||
|
||||
def addDocStringCore' [Monad m] [MonadError m] [MonadEnv m] (declName : Name) (docString? : Option String) : m Unit :=
|
||||
def removeDocStringCore [Monad m] [MonadError m] [MonadEnv m] [MonadLiftT BaseIO m] (declName : Name) : m Unit := do
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError m!"invalid doc string removal, declaration `{.ofConstName declName}` is in an imported module"
|
||||
modifyEnv fun env => docStringExt.modifyState env (·.erase declName) (asyncMode := .mainOnly)
|
||||
|
||||
def addDocStringCore' [Monad m] [MonadError m] [MonadEnv m] [MonadLiftT BaseIO m] (declName : Name) (docString? : Option String) : m Unit :=
|
||||
match docString? with
|
||||
| some docString => addDocStringCore declName docString
|
||||
| none => return ()
|
||||
|
||||
def addInheritedDocString [Monad m] [MonadError m] [MonadEnv m] (declName target : Name) : m Unit := do
|
||||
unless (← getEnv).getModuleIdxFor? declName |>.isNone do
|
||||
throwError "invalid `[inherit_doc]` attribute, declaration `{.ofConstName declName}` is in an imported module"
|
||||
if inheritDocStringExt.find? (level := .server) (← getEnv) declName |>.isSome then
|
||||
throwError "invalid `[inherit_doc]` attribute, declaration `{.ofConstName declName}` already has an `[inherit_doc]` attribute"
|
||||
if inheritDocStringExt.find? (level := .server) (← getEnv) target == some declName then
|
||||
throwError "invalid `[inherit_doc]` attribute, cycle detected"
|
||||
modifyEnv fun env => inheritDocStringExt.insert env declName target
|
||||
|
||||
/--
|
||||
Finds a docstring without performing any alias resolution or enrichment with extra metadata.
|
||||
For Markdown docstrings, the result is a string; for Verso docstrings, it's a `VersoDocString`.
|
||||
|
||||
Docstrings to be shown to a user should be looked up with `Lean.findDocString?` instead.
|
||||
-/
|
||||
def findSimpleDocString? (env : Environment) (declName : Name) (includeBuiltin := true) : IO (Option String) :=
|
||||
if let some docStr := docStringExt.find? env declName then
|
||||
return some docStr
|
||||
else if includeBuiltin then
|
||||
return (← builtinDocStrings.get).find? declName
|
||||
else
|
||||
return none
|
||||
partial def findInternalDocString? (env : Environment) (declName : Name) (includeBuiltin := true) : IO (Option (String ⊕ VersoDocString)) := do
|
||||
if let some target := inheritDocStringExt.find? (level := .server) env declName then
|
||||
return (← findInternalDocString? env target includeBuiltin)
|
||||
match docStringExt.find? (level := .server) env declName with
|
||||
| some md => return some (.inl md)
|
||||
| none => pure ()
|
||||
match versoDocStringExt.find? (level := .server) env declName with
|
||||
| some v => return some (.inr v)
|
||||
| none => pure ()
|
||||
if includeBuiltin then
|
||||
if let some docStr := (← builtinDocStrings.get).find? declName then
|
||||
return some (.inl docStr)
|
||||
else if let some doc := (← builtinVersoDocStrings.get).find? declName then
|
||||
return some (.inr doc)
|
||||
return none
|
||||
|
||||
/--
|
||||
Finds a docstring without performing any alias resolution or enrichment with extra metadata. The
|
||||
result is rendered as Markdown.
|
||||
|
||||
Docstrings to be shown to a user should be looked up with `Lean.findDocString?` instead.
|
||||
-/
|
||||
def findSimpleDocString? (env : Environment) (declName : Name) (includeBuiltin := true) : IO (Option String) := do
|
||||
match (← findInternalDocString? env declName (includeBuiltin := includeBuiltin)) with
|
||||
| some (.inl str) => return some str
|
||||
| some (.inr verso) => return some (toMarkdown verso)
|
||||
| none => return none
|
||||
|
||||
where
|
||||
toMarkdown : VersoDocString → String
|
||||
| .mk bs ps => Doc.MarkdownM.run' do
|
||||
for b in bs do
|
||||
Doc.ToMarkdown.toMarkdown b
|
||||
for p in ps do
|
||||
Doc.ToMarkdown.toMarkdown p
|
||||
|
||||
|
||||
structure ModuleDoc where
|
||||
doc : String
|
||||
declarationRange : DeclarationRange
|
||||
|
||||
private builtin_initialize moduleDocExt : SimplePersistentEnvExtension ModuleDoc (PersistentArray ModuleDoc) ← registerSimplePersistentEnvExtension {
|
||||
private builtin_initialize moduleDocExt :
|
||||
SimplePersistentEnvExtension ModuleDoc (PersistentArray ModuleDoc) ← registerSimplePersistentEnvExtension {
|
||||
addImportedFn := fun _ => {}
|
||||
addEntryFn := fun s e => s.push e
|
||||
exportEntriesFnEx? := some fun _ _ es level =>
|
||||
|
||||
@@ -55,6 +55,38 @@ private def domainMap : Std.HashMap String String :=
|
||||
("errorExplanation", errorExplanationManualDomain)
|
||||
]
|
||||
|
||||
/-- The valid domain abbreviations in the manual. -/
|
||||
def manualDomains : List String := domainMap.keys
|
||||
|
||||
/--
|
||||
Constructs a link to the manual.
|
||||
-/
|
||||
def manualLink (kind name : String) : Except String String :=
|
||||
if let some domain := domainMap.get? kind then
|
||||
return manualRoot ++ s!"find/?domain={domain}&name={name}"
|
||||
else
|
||||
let acceptableKinds := ", ".intercalate <| domainMap.toList.map fun (k, _) => s!"`{k}`"
|
||||
throw s!"Unknown documentation type `{kind}`. Expected one of the following: {acceptableKinds}"
|
||||
|
||||
private def rw (path : String) : Except String String := do
|
||||
match path.splitOn "/" with
|
||||
| [] | [""] =>
|
||||
throw "Missing documentation type"
|
||||
| kind :: args =>
|
||||
if let some domain := domainMap.get? kind then
|
||||
if let [s] := args then
|
||||
if s.isEmpty then
|
||||
throw s!"Empty {kind} ID"
|
||||
return s!"find/?domain={domain}&name={s}"
|
||||
else
|
||||
throw s!"Expected one item after `{kind}`, but got {args}"
|
||||
else
|
||||
let acceptableKinds := ", ".intercalate <| domainMap.toList.map fun (k, _) => s!"`{k}`"
|
||||
throw s!"Unknown documentation type `{kind}`. Expected one of the following: {acceptableKinds}"
|
||||
|
||||
|
||||
|
||||
|
||||
/--
|
||||
Rewrites links from the internal Lean manual syntax to the correct URL. This rewriting is an
|
||||
overapproximation: any parentheses containing the internal syntax of a Lean manual URL is rewritten.
|
||||
@@ -122,23 +154,6 @@ where
|
||||
lookingAt (goal : String) (iter : String.Iterator) : Bool :=
|
||||
iter.s.substrEq iter.i goal 0 goal.endPos.byteIdx
|
||||
|
||||
rw (path : String) : Except String String := do
|
||||
match path.splitOn "/" with
|
||||
| [] | [""] =>
|
||||
throw "Missing documentation type"
|
||||
| kind :: args =>
|
||||
if let some domain := domainMap.get? kind then
|
||||
if let [s] := args then
|
||||
if s.isEmpty then
|
||||
throw s!"Empty {kind} ID"
|
||||
return s!"find/?domain={domain}&name={s}"
|
||||
else
|
||||
throw s!"Expected one item after `{kind}`, but got {args}"
|
||||
else
|
||||
let acceptableKinds := ", ".intercalate <| domainMap.toList.map fun (k, _) => s!"`{k}`"
|
||||
throw s!"Unknown documentation type `{kind}`. Expected one of the following: {acceptableKinds}"
|
||||
|
||||
|
||||
/--
|
||||
Rewrites Lean reference manual links in `docstring` to point at the reference manual.
|
||||
|
||||
|
||||
295
src/Lean/DocString/Markdown.lean
Normal file
295
src/Lean/DocString/Markdown.lean
Normal file
@@ -0,0 +1,295 @@
|
||||
/-
|
||||
Copyright (c) 2023-2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: David Thrane Christiansen
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
|
||||
import Init.Data.Repr
|
||||
import Init.Data.Ord
|
||||
public import Lean.DocString.Types
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace Lean.Doc
|
||||
|
||||
namespace MarkdownM
|
||||
|
||||
/--
|
||||
The surrounding context of Markdown that's being generated, in order to prevent nestings that
|
||||
Markdown doesn't allow.
|
||||
-/
|
||||
public structure Context where
|
||||
/-- The current code is inside emphasis. -/
|
||||
inEmph : Bool := false
|
||||
/-- The current code is inside strong emphasis. -/
|
||||
inBold : Bool := false
|
||||
/-- The current code is inside a link. -/
|
||||
inLink : Bool := false
|
||||
/-- The prefix that should be added to each line (typically for indentation). -/
|
||||
linePrefix : String := ""
|
||||
|
||||
/-- The state of a Markdown generation task. -/
|
||||
public structure State where
|
||||
/-- The blocks prior to the one being generated. -/
|
||||
priorBlocks : String := ""
|
||||
/-- The block being generated. -/
|
||||
currentBlock : String := ""
|
||||
/-- Footnotes -/
|
||||
footnotes : Array (String × String) := #[]
|
||||
|
||||
private def combineBlocks (prior current : String) :=
|
||||
if prior.isEmpty then current
|
||||
else if current.isEmpty then prior
|
||||
else if prior.endsWith "\n\n" then prior ++ current
|
||||
else if prior.endsWith "\n" then prior ++ "\n" ++ current
|
||||
else prior ++ "\n\n" ++ current
|
||||
|
||||
private def State.endBlock (state : State) : State :=
|
||||
{ state with
|
||||
priorBlocks :=
|
||||
combineBlocks state.priorBlocks state.currentBlock ++
|
||||
(if state.footnotes.isEmpty then ""
|
||||
else state.footnotes.foldl (init := "\n\n") fun s (n, txt) => s ++ s!"[^{n}]:{txt}\n\n"),
|
||||
currentBlock := "",
|
||||
footnotes := #[]
|
||||
}
|
||||
|
||||
private def State.render (state : State) : String :=
|
||||
state.endBlock.priorBlocks
|
||||
|
||||
private def State.push (state : State) (txt : String) : State :=
|
||||
{ state with currentBlock := state.currentBlock ++ txt }
|
||||
|
||||
end MarkdownM
|
||||
|
||||
open MarkdownM in
|
||||
/--
|
||||
The monad for generating Markdown output.
|
||||
-/
|
||||
public abbrev MarkdownM := ReaderT Context (StateM State)
|
||||
|
||||
/--
|
||||
Generates Markdown, rendering the result from the final state.
|
||||
-/
|
||||
public def MarkdownM.run (act : MarkdownM α) (context : Context := {}) (state : State := {}) : (α × String) :=
|
||||
let (val, state) := act context state
|
||||
(val, state.render)
|
||||
|
||||
/--
|
||||
Generates Markdown, rendering the result from the final state, without producing a value.
|
||||
-/
|
||||
public def MarkdownM.run' (act : MarkdownM Unit) (context : Context := {}) (state : State := {}) : String :=
|
||||
act.run context state |>.2
|
||||
|
||||
private def MarkdownM.push (txt : String) : MarkdownM Unit := modify (·.push txt)
|
||||
|
||||
private def MarkdownM.endBlock : MarkdownM Unit := modify (·.endBlock)
|
||||
|
||||
private def MarkdownM.indent: MarkdownM α → MarkdownM α :=
|
||||
withReader fun st => { st with linePrefix := st.linePrefix ++ " " }
|
||||
|
||||
/--
|
||||
A means of transforming values to Markdown representations.
|
||||
-/
|
||||
public class ToMarkdown (α : Type u) where
|
||||
/--
|
||||
A function that transforms an `α` into a Markdown representation.
|
||||
-/
|
||||
toMarkdown : α → MarkdownM Unit
|
||||
|
||||
/--
|
||||
A way to transform inline elements extended with `i` into Markdown.
|
||||
-/
|
||||
public class MarkdownInline (i : Type u) where
|
||||
/--
|
||||
A function that transforms an `i` and its contents into Markdown, given a way to transform the
|
||||
contents.
|
||||
-/
|
||||
toMarkdown : (Inline i → MarkdownM Unit) → i → Array (Inline i) → MarkdownM Unit
|
||||
|
||||
public instance : MarkdownInline Empty where
|
||||
toMarkdown := nofun
|
||||
|
||||
/--
|
||||
A way to transform block elements extended with `b` that contain inline elements extended with `i`
|
||||
into Markdown.
|
||||
-/
|
||||
public class MarkdownBlock (i : Type u) (b : Type v) where
|
||||
/--
|
||||
A function that transforms a `b` and its contents into Markdown, given a way to transform the
|
||||
contents.
|
||||
-/
|
||||
toMarkdown :
|
||||
(Inline i → MarkdownM Unit) → (Block i b → MarkdownM Unit) →
|
||||
b → Array (Block i b) → MarkdownM Unit
|
||||
|
||||
public instance : MarkdownBlock i Empty where
|
||||
toMarkdown := nofun
|
||||
|
||||
private def escape (s : String) : String := Id.run do
|
||||
let mut s' := ""
|
||||
let mut iter := s.iter
|
||||
while h : iter.hasNext do
|
||||
let c := iter.curr' h
|
||||
iter := iter.next' h
|
||||
if isSpecial c then
|
||||
s' := s'.push '\\'
|
||||
s' := s'.push c
|
||||
return s'
|
||||
where
|
||||
isSpecial c := "*_`-+.!<>[]{}()#".any (· == c)
|
||||
|
||||
private def quoteCode (str : String) : String := Id.run do
|
||||
let mut longest := 0
|
||||
let mut current := 0
|
||||
let mut iter := str.iter
|
||||
while h : iter.hasNext do
|
||||
let c := iter.curr' h
|
||||
iter := iter.next' h
|
||||
if c == '`' then
|
||||
current := current + 1
|
||||
else
|
||||
longest := max longest current
|
||||
current := 0
|
||||
let backticks := "".pushn '`' (max longest current + 1)
|
||||
let str := if str.startsWith "`" || str.endsWith "`" then " " ++ str ++ " " else str
|
||||
backticks ++ str ++ backticks
|
||||
|
||||
open MarkdownM in
|
||||
private partial def inlineMarkdown [MarkdownInline i] : Inline i → MarkdownM Unit
|
||||
| .text s =>
|
||||
push (escape s)
|
||||
| .linebreak s => do
|
||||
push <| s.replace "\n" ("\n" ++ (← read).linePrefix )
|
||||
| .emph xs => do
|
||||
unless (← read).inEmph do
|
||||
push "*"
|
||||
withReader (fun ρ => { ρ with inEmph := true }) do
|
||||
for i in xs do inlineMarkdown i
|
||||
unless (← read).inEmph do
|
||||
push "*"
|
||||
| .bold xs => do
|
||||
unless (← read).inBold do
|
||||
push "**"
|
||||
withReader (fun ρ => { ρ with inEmph := true }) do
|
||||
for i in xs do inlineMarkdown i
|
||||
unless (← read).inBold do
|
||||
push "**"
|
||||
| .concat xs =>
|
||||
for i in xs do inlineMarkdown i
|
||||
| .link content url => do
|
||||
if (← read).inLink then
|
||||
for i in content do inlineMarkdown i
|
||||
else
|
||||
push "["
|
||||
for i in content do inlineMarkdown i
|
||||
push "]("
|
||||
push url
|
||||
push ")"
|
||||
| .image alt url =>
|
||||
push s!""
|
||||
| .footnote name content => do
|
||||
push s!"[ˆ^{name}]"
|
||||
let footnoteContent := (content.forM inlineMarkdown) {} {} |>.2.render
|
||||
modify fun st => { st with footnotes := st.footnotes.push (name, footnoteContent) }
|
||||
| .code str =>
|
||||
push (quoteCode str)
|
||||
| .math .display m => push s!"$${m}$$"
|
||||
| .math .inline m => push s!"${m}$"
|
||||
| .other container content => do
|
||||
MarkdownInline.toMarkdown inlineMarkdown container content
|
||||
|
||||
public instance [MarkdownInline i] : ToMarkdown (Inline i) where
|
||||
toMarkdown inline := private inlineMarkdown inline
|
||||
|
||||
private def quoteCodeBlock (indent : Nat) (str : String) : String := Id.run do
|
||||
let mut longest := 2
|
||||
let mut current := 0
|
||||
let mut iter := str.iter
|
||||
let mut out := ""
|
||||
while h : iter.hasNext do
|
||||
let c := iter.curr' h
|
||||
iter := iter.next' h
|
||||
if c == '`' then
|
||||
current := current + 1
|
||||
else
|
||||
longest := max longest current
|
||||
current := 0
|
||||
out := out.push c
|
||||
if c == '\n' then
|
||||
out := out.pushn ' ' indent
|
||||
let backticks := "" |>.pushn ' ' indent |>.pushn '`' (max longest current + 1)
|
||||
backticks ++ "\n" ++ out ++ "\n" ++ backticks ++ "\n"
|
||||
|
||||
open MarkdownM in
|
||||
private partial def blockMarkdown [MarkdownInline i] [MarkdownBlock i b] : Block i b → MarkdownM Unit
|
||||
| .para xs => do
|
||||
for i in xs do
|
||||
ToMarkdown.toMarkdown i
|
||||
endBlock
|
||||
| .concat bs =>
|
||||
for b in bs do
|
||||
blockMarkdown b
|
||||
| .blockquote bs => do
|
||||
withReader (fun ρ => { ρ with linePrefix := ρ.linePrefix ++ "> " })
|
||||
for b in bs do
|
||||
blockMarkdown b
|
||||
endBlock
|
||||
| .ul items => do
|
||||
for item in items do
|
||||
push <| (← read).linePrefix ++ "* "
|
||||
withReader (fun ρ => { ρ with linePrefix := ρ.linePrefix ++ " " }) do
|
||||
for b in item.contents do
|
||||
blockMarkdown b
|
||||
endBlock
|
||||
| .ol start items => do
|
||||
let mut n := max 1 start.toNat
|
||||
for item in items do
|
||||
push <| (← read).linePrefix ++ s!"{n}. "
|
||||
withReader (fun ρ => { ρ with linePrefix := ρ.linePrefix ++ " " }) do
|
||||
for b in item.contents do
|
||||
blockMarkdown b
|
||||
n := n + 1
|
||||
endBlock
|
||||
| .dl items => do
|
||||
for item in items do
|
||||
push <| (← read).linePrefix ++ "* "
|
||||
withReader (fun ρ => { ρ with linePrefix := ρ.linePrefix ++ " " }) do
|
||||
inlineMarkdown (.bold item.term)
|
||||
inlineMarkdown (.text ": " : Inline i)
|
||||
push "\n"
|
||||
push (← read).linePrefix
|
||||
blockMarkdown (.concat item.desc)
|
||||
endBlock
|
||||
| .code str => do
|
||||
unless (← get).currentBlock.isEmpty || (← get).currentBlock.endsWith "\n" do
|
||||
push "\n"
|
||||
push <| quoteCodeBlock (← read).linePrefix.length str
|
||||
endBlock
|
||||
| .other container content =>
|
||||
MarkdownBlock.toMarkdown (i := i) (b := b) inlineMarkdown blockMarkdown container content
|
||||
|
||||
|
||||
public instance [MarkdownInline i] [MarkdownBlock i b] : ToMarkdown (Block i b) where
|
||||
toMarkdown block := private blockMarkdown block
|
||||
|
||||
open MarkdownM in
|
||||
open ToMarkdown in
|
||||
private partial def partMarkdown [MarkdownInline i] [MarkdownBlock i b] (level : Nat) (part : Part i b p) : MarkdownM Unit := do
|
||||
push ("".pushn '#' (level + 1))
|
||||
push " "
|
||||
for i in part.title do
|
||||
toMarkdown i
|
||||
endBlock
|
||||
for b in part.content do
|
||||
toMarkdown b
|
||||
endBlock
|
||||
for p in part.subParts do
|
||||
partMarkdown (level + 1) p
|
||||
|
||||
public instance [MarkdownInline i] [MarkdownBlock i b] : ToMarkdown (Part i b p) where
|
||||
toMarkdown part := private partMarkdown 0 part
|
||||
1169
src/Lean/DocString/Parser.lean
Normal file
1169
src/Lean/DocString/Parser.lean
Normal file
File diff suppressed because it is too large
Load Diff
172
src/Lean/DocString/Syntax.lean
Normal file
172
src/Lean/DocString/Syntax.lean
Normal file
@@ -0,0 +1,172 @@
|
||||
/-
|
||||
Copyright (c) 2023-2025 Lean FRO LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: David Thrane Christiansen
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
|
||||
import Init.Prelude
|
||||
import Init.Notation
|
||||
public import Lean.Parser.Types
|
||||
import Lean.Syntax
|
||||
import Lean.Parser.Extra
|
||||
public import Lean.Parser.Term
|
||||
meta import Lean.Parser.Term
|
||||
|
||||
|
||||
/-!
|
||||
|
||||
This module contains an internal syntax that's used to represent documents.
|
||||
|
||||
Ordinarily, a syntax declaration is used to extend the Lean parser. The parser produces `Syntax`,
|
||||
which is flexible enough to represent essentially anything. However, each syntax declaration will
|
||||
produce parsed syntax trees with a predictable form, and these syntax trees can be matched using
|
||||
quasiquotation patterns. In other words, syntax declarations really do all of the following:
|
||||
|
||||
* They extend Lean's parser
|
||||
* They establish expectations for valid subsets of `Syntax`
|
||||
* They provide a way to pattern-match against the valid `Syntax` that they induce
|
||||
|
||||
The syntax declarations in this module are used somewhat differently. They're not generally intended
|
||||
for direct use with the Lean parser, because the concrete syntax of Verso documents falls outside
|
||||
what can be implemented with Lean's parsing framework. Thus, Verso has a separate parser, written
|
||||
using the lower-level parts of Lean's parser. These syntax declarations are, however, a
|
||||
specification for the syntax trees produced by said parser. The Verso parser is in the module
|
||||
`Lean.DocString.Parser`. Specifying the Verso document syntax as is done here also allows
|
||||
quasiquotation patterns that match against the output of the Verso parser.
|
||||
|
||||
Importantly, Lean quasiquotation patterns do not match the string contents of atoms. This means that
|
||||
the Verso parser may produce a node of kind `` `Lean.Doc.Syntax.li `` in which the first atom is
|
||||
`"1."` rather than `"*'` when parsing an ordered list.
|
||||
|
||||
Parsed Verso documents are transformed into Lean syntax that represents Verso document ASTs (see
|
||||
module `Lean.DocString.Types`). This process potentially invokes user-written metaprograms - while
|
||||
Verso's concrete syntax is not extensible, roles, directives and code blocks all contain explicit
|
||||
hooks for extensibility. This translation step is defined in the module `Lean.DocString.Elab`.
|
||||
|
||||
-/
|
||||
|
||||
open Lean.Parser (rawIdent)
|
||||
|
||||
namespace Lean.Doc.Syntax
|
||||
|
||||
public section
|
||||
|
||||
/-- Argument values -/
|
||||
declare_syntax_cat arg_val
|
||||
scoped syntax (name:=arg_str) str : arg_val
|
||||
scoped syntax (name:=arg_ident) ident : arg_val
|
||||
scoped syntax (name:=arg_num) num : arg_val
|
||||
|
||||
/-- Arguments -/
|
||||
declare_syntax_cat doc_arg
|
||||
/-- Anonymous positional arguments -/
|
||||
scoped syntax (name:=anon) arg_val : doc_arg
|
||||
/-- Named arguments -/
|
||||
scoped syntax (name:=named) "(" ident " := " arg_val ")": doc_arg
|
||||
/-- Named arguments, without parentheses. -/
|
||||
scoped syntax (name:=named_no_paren) ident " := " arg_val : doc_arg
|
||||
/-- Boolean flags, turned on -/
|
||||
scoped syntax (name:=flag_on) "+" ident : doc_arg
|
||||
/-- Boolean flags, turned off -/
|
||||
scoped syntax (name:=flag_off) "-" ident : doc_arg
|
||||
|
||||
/-- Link targets, which may be URLs or named references -/
|
||||
declare_syntax_cat link_target
|
||||
/-- A reference to a URL -/
|
||||
scoped syntax (name:=url) "(" str ")" : link_target
|
||||
/-- A named reference -/
|
||||
scoped syntax (name:=ref) "[" str "]" : link_target
|
||||
|
||||
/--
|
||||
Verso inline objects. These are part of the ordinary text flow of a paragraph.
|
||||
|
||||
This syntax uses the following conventions:
|
||||
* Sequences of inline items are in square brackets
|
||||
* Literal data, like strings or numbers, are in parentheses
|
||||
* Verso metaprogram names and arguments are in curly braces
|
||||
-/
|
||||
declare_syntax_cat inline
|
||||
scoped syntax (name:=text) str : inline
|
||||
/-- Emphasis (often rendered as italics) -/
|
||||
scoped syntax (name:=emph) "_[" inline* "]" : inline
|
||||
/-- Bold emphasis -/
|
||||
scoped syntax (name:=bold) "*[" inline* "]" : inline
|
||||
/-- Link -/
|
||||
scoped syntax (name:=link) "link[" inline* "]" link_target : inline
|
||||
/-- Image -/
|
||||
scoped syntax (name:=image) "image(" str ")" link_target : inline
|
||||
/-- A footnote use -/
|
||||
scoped syntax (name:=footnote) "footnote(" str ")" : inline
|
||||
/-- Line break -/
|
||||
scoped syntax (name:=linebreak) "line!" str : inline
|
||||
/-- Literal code. If the first and last characters are space, and it contains at least one non-space
|
||||
character, then the resulting string has a single space stripped from each end.-/
|
||||
scoped syntax (name:=code) "code(" str ")" : inline
|
||||
/-- A _role_: an extension to the Verso document language in an inline position -/
|
||||
scoped syntax (name:=role) "role{" ident doc_arg* "}" "[" inline* "]" : inline
|
||||
/-- Inline mathematical notation (equivalent to LaTeX's `$` notation) -/
|
||||
scoped syntax (name:=inline_math) "\\math" code : inline
|
||||
/-- Display-mode mathematical notation -/
|
||||
scoped syntax (name:=display_math) "\\displaymath" code : inline
|
||||
|
||||
/--
|
||||
Block-level elements, such as paragraphs, headers, and lists.
|
||||
|
||||
Conventions:
|
||||
* When there's concrete syntax that can be written as Lean atoms, do so (code blocks are ` ``` `,
|
||||
directives `:::`)
|
||||
* When Verso's syntax requires a newline, use `|` because `"\n"` is not a valid Lean token
|
||||
* Directive bodies are in `{` and `}` to avoid quotation parsing issues with `:::` ... `:::`
|
||||
* If there's no concrete syntax per se, such as for paragraphs or lists, use a name with brackets
|
||||
and braces
|
||||
* Use parentheses around required literals, such as the starting number of an ordered list
|
||||
* Use square brackets around sequences of literals
|
||||
* Use curly braces around blocks or lists items (because names and arguments a la roles are always
|
||||
newline-separated for directives and code)
|
||||
-/
|
||||
declare_syntax_cat block
|
||||
|
||||
/-- Items from both ordered and unordered lists -/
|
||||
declare_syntax_cat list_item
|
||||
/-- List item -/
|
||||
syntax (name:=li) "*" block* : list_item
|
||||
|
||||
/-- A description of an item -/
|
||||
declare_syntax_cat desc_item
|
||||
/-- A description of an item -/
|
||||
scoped syntax (name:=desc) ":" inline* "=>" block* : desc_item
|
||||
|
||||
scoped syntax (name:=para) "para[" inline+ "]" : block
|
||||
/-- Unordered List -/
|
||||
scoped syntax (name:=ul) "ul{" list_item* "}" : block
|
||||
/-- Definition list -/
|
||||
scoped syntax (name:=dl) "dl{" desc_item* "}" : block
|
||||
/-- Ordered list -/
|
||||
scoped syntax (name:=ol) "ol(" num ")" "{" list_item* "}" : block
|
||||
/-- Literal code -/
|
||||
scoped syntax (name:=codeblock) "```" (ident doc_arg*)? "|" str "```" : block
|
||||
/-- Quotation -/
|
||||
scoped syntax (name:=blockquote) ">" block* : block
|
||||
/-- A link reference definition -/
|
||||
scoped syntax (name:=link_ref) "[" str "]:" str : block
|
||||
/-- A footnote definition -/
|
||||
scoped syntax (name:=footnote_ref) "[^" str "]:" inline* : block
|
||||
/-- Custom directive -/
|
||||
scoped syntax (name:=directive) ":::" rawIdent doc_arg* "{" block:max* "}" : block
|
||||
/-- A header -/
|
||||
scoped syntax (name:=header) "header(" num ")" "{" inline+ "}" : block
|
||||
open Lean.Parser.Term in
|
||||
|
||||
open Lean.Parser Term in
|
||||
meta def metadataContents : Parser :=
|
||||
structInstFields (sepByIndent structInstField ", " (allowTrailingSep := true))
|
||||
|
||||
/-- Metadata for this section, defined by the current genre -/
|
||||
scoped syntax (name:=metadata_block) "%%%" metadataContents "%%%" : block
|
||||
|
||||
/-- A block-level command -/
|
||||
scoped syntax (name:=command) "command{" rawIdent doc_arg* "}" : block
|
||||
181
src/Lean/DocString/Types.lean
Normal file
181
src/Lean/DocString/Types.lean
Normal file
@@ -0,0 +1,181 @@
|
||||
/-
|
||||
Copyright (c) 2023-2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: David Thrane Christiansen
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.Ord
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace Lean.Doc
|
||||
|
||||
public section
|
||||
|
||||
/--
|
||||
How to render mathematical content.
|
||||
-/
|
||||
inductive MathMode where
|
||||
/-- The math content is part of the text flow. -/
|
||||
| inline
|
||||
/-- The math content is set apart from the text flow, with more space. -/
|
||||
| display
|
||||
deriving Repr, BEq, Hashable, Ord
|
||||
|
||||
/--
|
||||
Inline content that is part of the text flow.
|
||||
-/
|
||||
inductive Inline (i : Type u) : Type u where
|
||||
/--
|
||||
Textual content.
|
||||
-/
|
||||
| text (string : String)
|
||||
/--
|
||||
Emphasis, typically rendered using italic text.
|
||||
-/
|
||||
| emph (content : Array (Inline i))
|
||||
/--
|
||||
Strong emphasis, typically rendered using bold text.
|
||||
-/
|
||||
| bold (content : Array (Inline i))
|
||||
/--
|
||||
Inline literal code, typically rendered in a monospace font.
|
||||
-/
|
||||
| code (string : String)
|
||||
/--
|
||||
Embedded TeX math, to be rendered by an engine such as TeX or KaTeX. The `mode` determines whether
|
||||
it is rendered in inline mode or display mode; even display-mode math is an inline element for
|
||||
purposes of document structure.
|
||||
-/
|
||||
| math (mode : MathMode) (string : String)
|
||||
/--
|
||||
A user's line break. These are typically ignored when rendering, but don't need to be.
|
||||
-/
|
||||
| linebreak (string : String)
|
||||
/--
|
||||
A link to some URL.
|
||||
-/
|
||||
| link (content : Array (Inline i)) (url : String)
|
||||
/--
|
||||
A footnote. In Verso's concrete syntax, their contents are specified elsewhere, but elaboration
|
||||
places the contents at the use site.
|
||||
-/
|
||||
| footnote (name : String) (content : Array (Inline i))
|
||||
/--
|
||||
An image. `alt` should be displayed if the image can't be shown.
|
||||
-/
|
||||
| image (alt : String) (url : String)
|
||||
/--
|
||||
A sequence of inline elements.
|
||||
-/
|
||||
| concat (content : Array (Inline i))
|
||||
/--
|
||||
A genre-specific inline element. `container` specifies what kind of element it is, and `content`
|
||||
specifies the contained elements.
|
||||
-/
|
||||
| other (container : i) (content : Array (Inline i))
|
||||
deriving BEq, Ord, Repr, Inhabited
|
||||
|
||||
/-- Rewrites using a proof that two inline element types are equal. -/
|
||||
def Inline.cast (inlines_eq : i = i') (x : Inline i) : Inline i' :=
|
||||
inlines_eq ▸ x
|
||||
|
||||
instance : Append (Inline i) where
|
||||
append
|
||||
| .concat #[], x => x
|
||||
| x, .concat #[] => x
|
||||
| .concat xs, .concat ys => .concat (xs ++ ys)
|
||||
| .concat xs, x => .concat (xs.push x)
|
||||
| x, .concat xs => .concat (#[x] ++ xs)
|
||||
| x, y => .concat #[x, y]
|
||||
|
||||
/-- No inline content. -/
|
||||
def Inline.empty : Inline i := .concat #[]
|
||||
|
||||
/-- An item in either an ordered or unordered list. -/
|
||||
structure ListItem (α : Type u) where
|
||||
/-- The contents of the list item. -/
|
||||
contents : Array α
|
||||
deriving Repr, BEq, Ord, Inhabited
|
||||
|
||||
/-- An item in a description list. -/
|
||||
structure DescItem (α : Type u) (β : Type v) where
|
||||
/-- The term being described. -/
|
||||
term : Array α
|
||||
/-- The description itself. -/
|
||||
desc : Array β
|
||||
deriving Repr, BEq, Ord, Inhabited
|
||||
|
||||
/--
|
||||
Block-level content in a document.
|
||||
-/
|
||||
inductive Block (i : Type u) (b : Type v) : Type (max u v) where
|
||||
/--
|
||||
A paragraph.
|
||||
-/
|
||||
| para (contents : Array (Inline i))
|
||||
/--
|
||||
A code block.
|
||||
-/
|
||||
| code (content : String)
|
||||
/--
|
||||
An unordered list.
|
||||
-/
|
||||
| ul (items : Array (ListItem (Block i b)))
|
||||
/--
|
||||
An ordered list.
|
||||
-/
|
||||
| ol (start : Int) (items : Array (ListItem (Block i b)))
|
||||
/--
|
||||
A description list that associates explanatory text with shorter items.
|
||||
-/
|
||||
| dl (items : Array (DescItem (Inline i) (Block i b)))
|
||||
/--
|
||||
A quotation.
|
||||
-/
|
||||
| blockquote (items : Array (Block i b))
|
||||
/--
|
||||
Multiple blocks, merged.
|
||||
-/
|
||||
| concat (content : Array (Block i b))
|
||||
/--
|
||||
A genre-specific block. `container` specifies what kind of block it is, while `content` specifies
|
||||
the content within the block.
|
||||
-/
|
||||
| other (container : b) (content : Array (Block i b))
|
||||
deriving BEq, Ord, Repr, Inhabited
|
||||
|
||||
/-- An empty block with no content. -/
|
||||
def Block.empty : Block i b := .concat #[]
|
||||
|
||||
/-- Rewrites using proofs that two inline element types and two block types are equal. -/
|
||||
def Block.cast (inlines_eq : i = i') (blocks_eq : b = b') (x : Block i b) : Block i' b' :=
|
||||
inlines_eq ▸ blocks_eq ▸ x
|
||||
|
||||
/--
|
||||
A logical division of a document.
|
||||
-/
|
||||
structure Part (i : Type u) (b : Type v) (p : Type w) : Type (max u v w) where
|
||||
/-- The part's title -/
|
||||
title : Array (Inline i)
|
||||
/--
|
||||
A string approximation of the part's title, for use in contexts where formatted text is invalid.
|
||||
-/
|
||||
titleString : String
|
||||
/-- Genre-specific metadata -/
|
||||
metadata : Option p
|
||||
/-- The part's textual content -/
|
||||
content : Array (Block i b)
|
||||
/-- Sub-parts (e.g. subsections of a section, sections of a chapter) -/
|
||||
subParts : Array (Part i b p)
|
||||
deriving BEq, Ord, Repr, Inhabited
|
||||
|
||||
/-- Rewrites using proofs that inline element types, block types, and metadata types are equal. -/
|
||||
def Part.cast (inlines_eq : i = i') (blocks_eq : b = b') (metadata_eq : p = p')
|
||||
(x : Part i b p) : Part i' b' p' :=
|
||||
inlines_eq ▸ blocks_eq ▸ metadata_eq ▸ x
|
||||
@@ -60,5 +60,7 @@ public import Lean.Elab.Time
|
||||
public import Lean.Elab.RecommendedSpelling
|
||||
public import Lean.Elab.InfoTrees
|
||||
public import Lean.Elab.ErrorExplanation
|
||||
public import Lean.Elab.DocString
|
||||
public import Lean.Elab.DocString.Builtin
|
||||
|
||||
public section
|
||||
|
||||
@@ -169,9 +169,11 @@ structure State where
|
||||
-- fun x => f x 5
|
||||
```
|
||||
`etaArgs` stores the fresh free variables for implementing the eta-expansion.
|
||||
Each pair records the name to use for the binding and the fvar for the argument.
|
||||
|
||||
When `..` is used, eta-expansion is disabled, and missing arguments are treated as `_`.
|
||||
-/
|
||||
etaArgs : Array Expr := #[]
|
||||
etaArgs : Array (Name × Expr) := #[]
|
||||
/-- Metavariables that we need to set the error context using the application being built. -/
|
||||
toSetErrorCtx : Array MVarId := #[]
|
||||
/-- Metavariables for the instance implicit arguments that have already been processed. -/
|
||||
@@ -420,7 +422,8 @@ private def finalize : M Expr := do
|
||||
for mvarId in s.toSetErrorCtx do
|
||||
registerMVarErrorImplicitArgInfo mvarId ref e
|
||||
if !s.etaArgs.isEmpty then
|
||||
e ← mkLambdaFVars s.etaArgs e
|
||||
e ← mkLambdaFVars (s.etaArgs.map (·.2)) e
|
||||
e := e.updateBinderNames (s.etaArgs.map (some <| ·.1)).toList
|
||||
/-
|
||||
Remark: we should not use `s.fType` as `eType` even when
|
||||
`s.etaArgs.isEmpty`. Reason: it may have been unfolded.
|
||||
@@ -562,8 +565,9 @@ mutual
|
||||
private partial def addEtaArg (argName : Name) : M Expr := do
|
||||
let n ← getBindingName
|
||||
let type ← getArgExpectedType
|
||||
withLocalDeclD n type fun x => do
|
||||
modify fun s => { s with etaArgs := s.etaArgs.push x }
|
||||
-- Use a fresh name to ensure that the remaining arguments can't capture this parameter's name.
|
||||
withLocalDeclD (← Core.mkFreshUserName n) type fun x => do
|
||||
modify fun s => { s with etaArgs := s.etaArgs.push (n, x) }
|
||||
addNewArg argName x
|
||||
main
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ public import Lean.Elab.PreDefinition.TerminationHint
|
||||
public import Lean.Elab.Match
|
||||
public import Lean.Compiler.MetaAttr
|
||||
meta import Lean.Parser.Term
|
||||
meta import Lean.Parser.Tactic
|
||||
import Lean.Linter.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -267,6 +267,15 @@ private partial def elabChoiceAux (cmds : Array Syntax) (i : Nat) : CommandElabM
|
||||
@[builtin_command_elab «init_quot»] def elabInitQuot : CommandElab := fun _ => do
|
||||
liftCoreM <| addDecl Declaration.quotDecl
|
||||
|
||||
@[builtin_command_elab «docs_to_verso»] def elabDocsToVerso : CommandElab := fun stx => do
|
||||
let xs := stx[1].getArgs
|
||||
for x in xs do
|
||||
if x.getKind == identKind then -- skip commas
|
||||
let declName ← liftCoreM <| realizeGlobalConstNoOverload x
|
||||
runTermElabM <| fun _ => withRef x <| makeDocStringVerso declName
|
||||
-- Add the info afterwards so the hover shows the updated docstring
|
||||
addConstInfo x declName
|
||||
|
||||
@[builtin_command_elab «export»] def elabExport : CommandElab := fun stx => do
|
||||
let `(export $ns ($ids*)) := stx | throwUnsupportedSyntax
|
||||
let nss ← resolveNamespace ns
|
||||
@@ -505,7 +514,7 @@ open Lean.Parser.Command.InternalSyntax in
|
||||
-- this is only relevant for declarations added without a declaration range
|
||||
-- in particular `Quot.mk` et al which are added by `init_quot`
|
||||
addDeclarationRangesFromSyntax declName stx id
|
||||
addDocString declName doc
|
||||
runTermElabM fun _ => addDocString declName (mkNullNode #[]) doc
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
@[builtin_command_elab Lean.Parser.Command.include] def elabInclude : CommandElab
|
||||
|
||||
@@ -70,15 +70,22 @@ open Meta
|
||||
if (← getFVarLocalDecl xs[i]).binderInfo.isExplicit then
|
||||
n := n + 1
|
||||
return n
|
||||
let args := args.getElems
|
||||
let mut args := args.getElems
|
||||
if args.size < numExplicitFields then
|
||||
let fieldsStr := if numExplicitFields == 1 then "fields" else "field"
|
||||
let providedStr :=
|
||||
if args.size == 0 then "none were"
|
||||
else if args.size == 1 then "only 1 was"
|
||||
else s!"only {args.size} were"
|
||||
throwError "Insufficient number of fields for `⟨...⟩` constructor: Constructor \
|
||||
let errMsg := m!"Insufficient number of fields for `⟨...⟩` constructor: Constructor \
|
||||
`{ctor}` has {numExplicitFields} explicit {fieldsStr}, but {providedStr} provided"
|
||||
if (← read).errToSorry then
|
||||
logError errMsg
|
||||
else
|
||||
throwError errMsg
|
||||
for _ in args.size...numExplicitFields do
|
||||
let s ← mkLabeledSorry (← mkFreshTypeMVar) (synthetic := true) (unique := false)
|
||||
args := args.push <| ← exprToSyntax s
|
||||
let newStx ← if args.size == numExplicitFields then
|
||||
`($(mkCIdentFrom stx ctor (canonical := true)) $(args)*)
|
||||
else if numExplicitFields == 0 then
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.Range.Polymorphic.Stream
|
||||
public import Lean.Meta.Diagnostics
|
||||
public import Lean.Elab.Binders
|
||||
public import Lean.Elab.Command.Scope
|
||||
public import Lean.Elab.SyntheticMVars
|
||||
public import Lean.Elab.SetOption
|
||||
public import Lean.Language.Basic
|
||||
@@ -19,75 +20,6 @@ public section
|
||||
|
||||
namespace Lean.Elab.Command
|
||||
|
||||
/--
|
||||
A `Scope` records the part of the `CommandElabM` state that respects scoping,
|
||||
such as the data for `universe`, `open`, and `variable` declarations, the current namespace,
|
||||
and currently enabled options.
|
||||
The `CommandElabM` state contains a stack of scopes, and only the top `Scope`
|
||||
on the stack is read from or modified. There is always at least one `Scope` on the stack,
|
||||
even outside any `section` or `namespace`, and each new pushed `Scope`
|
||||
starts as a modified copy of the previous top scope.
|
||||
-/
|
||||
structure Scope where
|
||||
/--
|
||||
The component of the `namespace` or `section` that this scope is associated to.
|
||||
For example, `section a.b.c` and `namespace a.b.c` each create three scopes with headers
|
||||
named `a`, `b`, and `c`.
|
||||
This is used for checking the `end` command. The "base scope" has `""` as its header.
|
||||
-/
|
||||
header : String
|
||||
/--
|
||||
The current state of all set options at this point in the scope. Note that this is the
|
||||
full current set of options and does *not* simply contain the options set
|
||||
while this scope has been active.
|
||||
-/
|
||||
opts : Options := {}
|
||||
/-- The current namespace. The top-level namespace is represented by `Name.anonymous`. -/
|
||||
currNamespace : Name := Name.anonymous
|
||||
/-- All currently `open`ed namespaces and names. -/
|
||||
openDecls : List OpenDecl := []
|
||||
/-- The current list of names for universe level variables to use for new declarations. This is managed by the `universe` command. -/
|
||||
levelNames : List Name := []
|
||||
/--
|
||||
The current list of binders to use for new declarations.
|
||||
This is managed by the `variable` command.
|
||||
Each binder is represented in `Syntax` form, and it is re-elaborated
|
||||
within each command that uses this information.
|
||||
|
||||
This is also used by commands, such as `#check`, to create an initial local context,
|
||||
even if they do not work with binders per se.
|
||||
-/
|
||||
varDecls : Array (TSyntax ``Parser.Term.bracketedBinder) := #[]
|
||||
/--
|
||||
Globally unique internal identifiers for the `varDecls`.
|
||||
There is one identifier per variable introduced by the binders
|
||||
(recall that a binder such as `(a b c : Ty)` can produce more than one variable),
|
||||
and each identifier is the user-provided variable name with a macro scope.
|
||||
This is used by `TermElabM` in `Lean.Elab.Term.Context` to help with processing macros
|
||||
that capture these variables.
|
||||
-/
|
||||
varUIds : Array Name := #[]
|
||||
/-- `include`d section variable names (from `varUIds`) -/
|
||||
includedVars : List Name := []
|
||||
/-- `omit`ted section variable names (from `varUIds`) -/
|
||||
omittedVars : List Name := []
|
||||
/--
|
||||
If true (default: false), all declarations that fail to compile
|
||||
automatically receive the `noncomputable` modifier.
|
||||
A scope with this flag set is created by `noncomputable section`.
|
||||
|
||||
Recall that a new scope inherits all values from its parent scope,
|
||||
so all sections and namespaces nested within a `noncomputable` section also have this flag set.
|
||||
-/
|
||||
isNoncomputable : Bool := false
|
||||
isPublic : Bool := false
|
||||
/--
|
||||
Attributes that should be applied to all matching declaration in the section. Inherited from
|
||||
parent scopes.
|
||||
-/
|
||||
attrs : List (TSyntax ``Parser.Term.attrInstance) := []
|
||||
deriving Inhabited
|
||||
|
||||
structure State where
|
||||
env : Environment
|
||||
messages : MessageLog := {}
|
||||
|
||||
83
src/Lean/Elab/Command/Scope.lean
Normal file
83
src/Lean/Elab/Command/Scope.lean
Normal file
@@ -0,0 +1,83 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Gabriel Ebner
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Lean.Data.Options
|
||||
public import Lean.Parser.Term
|
||||
|
||||
public section
|
||||
|
||||
namespace Lean.Elab.Command
|
||||
/--
|
||||
A `Scope` records the part of the `CommandElabM` state that respects scoping,
|
||||
such as the data for `universe`, `open`, and `variable` declarations, the current namespace,
|
||||
and currently enabled options.
|
||||
The `CommandElabM` state contains a stack of scopes, and only the top `Scope`
|
||||
on the stack is read from or modified. There is always at least one `Scope` on the stack,
|
||||
even outside any `section` or `namespace`, and each new pushed `Scope`
|
||||
starts as a modified copy of the previous top scope.
|
||||
-/
|
||||
structure Scope where
|
||||
/--
|
||||
The component of the `namespace` or `section` that this scope is associated to.
|
||||
For example, `section a.b.c` and `namespace a.b.c` each create three scopes with headers
|
||||
named `a`, `b`, and `c`.
|
||||
This is used for checking the `end` command. The "base scope" has `""` as its header.
|
||||
-/
|
||||
header : String
|
||||
/--
|
||||
The current state of all set options at this point in the scope. Note that this is the
|
||||
full current set of options and does *not* simply contain the options set
|
||||
while this scope has been active.
|
||||
-/
|
||||
opts : Options := {}
|
||||
/-- The current namespace. The top-level namespace is represented by `Name.anonymous`. -/
|
||||
currNamespace : Name := Name.anonymous
|
||||
/-- All currently `open`ed namespaces and names. -/
|
||||
openDecls : List OpenDecl := []
|
||||
/-- The current list of names for universe level variables to use for new declarations. This is managed by the `universe` command. -/
|
||||
levelNames : List Name := []
|
||||
/--
|
||||
The current list of binders to use for new declarations.
|
||||
This is managed by the `variable` command.
|
||||
Each binder is represented in `Syntax` form, and it is re-elaborated
|
||||
within each command that uses this information.
|
||||
|
||||
This is also used by commands, such as `#check`, to create an initial local context,
|
||||
even if they do not work with binders per se.
|
||||
-/
|
||||
varDecls : Array (TSyntax ``Parser.Term.bracketedBinder) := #[]
|
||||
/--
|
||||
Globally unique internal identifiers for the `varDecls`.
|
||||
There is one identifier per variable introduced by the binders
|
||||
(recall that a binder such as `(a b c : Ty)` can produce more than one variable),
|
||||
and each identifier is the user-provided variable name with a macro scope.
|
||||
This is used by `TermElabM` in `Lean.Elab.Term.Context` to help with processing macros
|
||||
that capture these variables.
|
||||
-/
|
||||
varUIds : Array Name := #[]
|
||||
/-- `include`d section variable names (from `varUIds`) -/
|
||||
includedVars : List Name := []
|
||||
/-- `omit`ted section variable names (from `varUIds`) -/
|
||||
omittedVars : List Name := []
|
||||
/--
|
||||
If true (default: false), all declarations that fail to compile
|
||||
automatically receive the `noncomputable` modifier.
|
||||
A scope with this flag set is created by `noncomputable section`.
|
||||
|
||||
Recall that a new scope inherits all values from its parent scope,
|
||||
so all sections and namespaces nested within a `noncomputable` section also have this flag set.
|
||||
-/
|
||||
isNoncomputable : Bool := false
|
||||
/-- True if a `public section` is in scope. -/
|
||||
isPublic : Bool := false
|
||||
/--
|
||||
Attributes that should be applied to all matching declaration in the section. Inherited from
|
||||
parent scopes.
|
||||
-/
|
||||
attrs : List (TSyntax ``Parser.Term.attrInstance) := []
|
||||
deriving Inhabited
|
||||
@@ -85,7 +85,10 @@ inductive ComputeKind where
|
||||
structure Modifiers where
|
||||
/-- Input syntax, used for adjusting declaration range (unless missing) -/
|
||||
stx : TSyntax ``Parser.Command.declModifiers := ⟨.missing⟩
|
||||
docString? : Option (TSyntax ``Parser.Command.docComment) := none
|
||||
/--
|
||||
The docstring, if present, and whether it's Verso.
|
||||
-/
|
||||
docString? : Option (TSyntax ``Parser.Command.docComment × Bool) := none
|
||||
visibility : Visibility := Visibility.regular
|
||||
isProtected : Bool := false
|
||||
computeKind : ComputeKind := .regular
|
||||
@@ -187,7 +190,7 @@ def elabModifiers (stx : TSyntax ``Parser.Command.declModifiers) : m Modifiers :
|
||||
RecKind.partial
|
||||
else
|
||||
RecKind.nonrec
|
||||
let docString? := docCommentStx.getOptional?.map TSyntax.mk
|
||||
let docString? := docCommentStx.getOptional?.map (TSyntax.mk ·, doc.verso.get (← getOptions))
|
||||
let visibility ← match visibilityStx.getOptional? with
|
||||
| none => pure .regular
|
||||
| some v =>
|
||||
@@ -276,6 +279,10 @@ structure ExpandDeclIdResult where
|
||||
declName : Name
|
||||
/-- Universe parameter names provided using the `universe` command and `.{...}` notation. -/
|
||||
levelNames : List Name
|
||||
/-- The docstring, and whether it's Verso -/
|
||||
docString? : Option (TSyntax ``Parser.Command.docComment × Bool)
|
||||
|
||||
open Lean.Elab.Term (TermElabM)
|
||||
|
||||
/--
|
||||
Given a declaration identifier (e.g., `ident (".{" ident,+ "}")?`) that may contain explicit universe parameters
|
||||
@@ -287,7 +294,7 @@ The result also contains the universe parameters provided using `universe` comma
|
||||
|
||||
This commands also stores the doc string stored in `modifiers`.
|
||||
-/
|
||||
def expandDeclId (currNamespace : Name) (currLevelNames : List Name) (declId : Syntax) (modifiers : Modifiers) : m ExpandDeclIdResult := do
|
||||
def expandDeclId (currNamespace : Name) (currLevelNames : List Name) (declId : Syntax) (modifiers : Modifiers) : TermElabM ExpandDeclIdResult := do
|
||||
-- ident >> optional (".{" >> sepBy1 ident ", " >> "}")
|
||||
let (shortName, optUnivDeclStx) := expandDeclIdCore declId
|
||||
let levelNames ← if optUnivDeclStx.isNone then
|
||||
@@ -303,8 +310,8 @@ def expandDeclId (currNamespace : Name) (currLevelNames : List Name) (declId : S
|
||||
pure (id :: levelNames))
|
||||
currLevelNames
|
||||
let (declName, shortName) ← withRef declId <| mkDeclName currNamespace modifiers shortName
|
||||
addDocString' declName modifiers.docString?
|
||||
return { shortName := shortName, declName := declName, levelNames := levelNames }
|
||||
let docString? := modifiers.docString?
|
||||
return { shortName, declName, levelNames, docString? }
|
||||
|
||||
end Methods
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ def elabAxiom (modifiers : Modifiers) (stx : Syntax) : CommandElabM Unit := do
|
||||
let (binders, typeStx) := expandDeclSig stx[2]
|
||||
runTermElabM fun vars => do
|
||||
let scopeLevelNames ← Term.getLevelNames
|
||||
let ⟨shortName, declName, allUserLevelNames⟩ ← Term.expandDeclId (← getCurrNamespace) scopeLevelNames declId modifiers
|
||||
let ⟨shortName, declName, allUserLevelNames, docString?⟩ ← Term.expandDeclId (← getCurrNamespace) scopeLevelNames declId modifiers
|
||||
addDeclarationRangesForBuiltin declName modifiers.stx stx
|
||||
Term.withAutoBoundImplicit do
|
||||
Term.withAutoBoundImplicitForbiddenPred (fun n => shortName == n) do
|
||||
@@ -136,12 +136,15 @@ def elabAxiom (modifiers : Modifiers) (stx : Syntax) : CommandElabM Unit := do
|
||||
trace[Elab.axiom] "{declName} : {type}"
|
||||
Term.ensureNoUnassignedMVars decl
|
||||
addDecl decl
|
||||
withSaveInfoContext do -- save new env
|
||||
Term.addTermInfo' declId (← mkConstWithLevelParams declName) (isBinder := true)
|
||||
|
||||
Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.afterTypeChecking
|
||||
if isExtern (← getEnv) declName then
|
||||
compileDecl decl
|
||||
if let some (doc, isVerso) := docString? then
|
||||
addDocStringOf isVerso declName binders doc
|
||||
Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.afterCompilation
|
||||
withSaveInfoContext do -- save new env with docstring and decl
|
||||
Term.addTermInfo' declId (← mkConstWithLevelParams declName) (isBinder := true)
|
||||
open Lean.Parser.Command.InternalSyntax in
|
||||
/--
|
||||
Macro that expands a declaration with a complex name into an explicit `namespace` block.
|
||||
@@ -334,9 +337,9 @@ def elabMutual : CommandElab := fun stx => do
|
||||
| stx@`($declModifiers:declModifiers $kw:initializeKeyword $[$id? : $type? ←]? $doSeq) => do
|
||||
let attrId := mkIdentFrom stx <| if kw.raw[0].isToken "initialize" then `init else `builtin_init
|
||||
if let (some id, some type) := (id?, type?) then
|
||||
let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(vis?)? $[unsafe%$unsafe?]?) := stx[0]
|
||||
let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(vis?)? $[meta%$meta?]? $[unsafe%$unsafe?]?) := stx[0]
|
||||
| throwErrorAt declModifiers "invalid initialization command, unexpected modifiers"
|
||||
let defStx ← `($[$doc?:docComment]? @[$attrId:ident initFn, $(attrs?.getD ∅),*] $(vis?)? opaque $id : $type)
|
||||
let defStx ← `($[$doc?:docComment]? @[$attrId:ident initFn, $(attrs?.getD ∅),*] $(vis?)? $[meta%$meta?]? opaque $id : $type)
|
||||
let mut fullId := (← getCurrNamespace) ++ id.getId
|
||||
if vis?.any (·.raw.isOfKind ``Parser.Command.private) then
|
||||
fullId := mkPrivateName (← getEnv) fullId
|
||||
@@ -346,17 +349,17 @@ def elabMutual : CommandElab := fun stx => do
|
||||
addDeclarationRangesForBuiltin fullId ⟨defStx.raw[0]⟩ defStx.raw[1]
|
||||
let vis := Parser.Command.visibility.ofBool (!isPrivateName fullId)
|
||||
elabCommand (← `(
|
||||
$vis:visibility $[unsafe%$unsafe?]? def initFn : IO $type := with_decl_name% $(mkIdent fullId) do $doSeq
|
||||
$vis:visibility $[meta%$meta?]? $[unsafe%$unsafe?]? def initFn : IO $type := with_decl_name% $(mkIdent fullId) do $doSeq
|
||||
$defStx:command))
|
||||
else
|
||||
let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(_)? $[unsafe%$unsafe?]?) := declModifiers
|
||||
let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(_)? $[meta%$meta?]? $[unsafe%$unsafe?]?) := declModifiers
|
||||
| throwErrorAt declModifiers "invalid initialization command, unexpected modifiers"
|
||||
let attrs := (attrs?.map (·.getElems)).getD #[]
|
||||
let attrs := attrs.push (← `(Lean.Parser.Term.attrInstance| $attrId:ident))
|
||||
-- `[builtin_init]` can be private as it is used for local codegen only but `[init]` must be
|
||||
-- available for the interpreter.
|
||||
let vis := Parser.Command.visibility.ofBool (attrId.getId == `init)
|
||||
elabCommand (← `($[$doc?:docComment]? @[$[$attrs],*] $vis:visibility $[unsafe%$unsafe?]? def initFn : IO Unit := do $doSeq))
|
||||
elabCommand (← `($[$doc?:docComment]? @[$[$attrs],*] $vis:visibility $[meta%$meta?]? $[unsafe%$unsafe?]? def initFn : IO Unit := do $doSeq))
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
builtin_initialize
|
||||
|
||||
@@ -118,6 +118,8 @@ structure DefView where
|
||||
binders : Syntax
|
||||
type? : Option Syntax
|
||||
value : Syntax
|
||||
/-- The docstring, if present, and whether it's Verso -/
|
||||
docString? : Option (TSyntax ``Parser.Command.docComment × Bool)
|
||||
/--
|
||||
Snapshot for incremental processing of this definition.
|
||||
|
||||
@@ -145,20 +147,22 @@ def mkDefViewOfAbbrev (modifiers : Modifiers) (stx : Syntax) : DefView :=
|
||||
let modifiers := modifiers.addAttr { name := `inline }
|
||||
let modifiers := modifiers.addAttr { name := `reducible }
|
||||
{ ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.abbrev, modifiers,
|
||||
declId := stx[1], binders, type? := type, value := stx[3] }
|
||||
declId := stx[1], binders, type? := type, value := stx[3], docString? := modifiers.docString? }
|
||||
|
||||
def mkDefViewOfDef (modifiers : Modifiers) (stx : Syntax) : DefView :=
|
||||
-- leading_parser "def " >> declId >> optDeclSig >> declVal >> optDefDeriving
|
||||
let (binders, type) := expandOptDeclSig stx[2]
|
||||
let deriving? := if stx[4].isNone then none else some stx[4][1].getSepArgs
|
||||
{ ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.def, modifiers,
|
||||
declId := stx[1], binders, type? := type, value := stx[3], deriving? }
|
||||
declId := stx[1], binders, type? := type, value := stx[3], deriving?,
|
||||
docString? := modifiers.docString? }
|
||||
|
||||
def mkDefViewOfTheorem (modifiers : Modifiers) (stx : Syntax) : DefView :=
|
||||
-- leading_parser "theorem " >> declId >> declSig >> declVal
|
||||
let (binders, type) := expandDeclSig stx[2]
|
||||
{ ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.theorem, modifiers,
|
||||
declId := stx[1], binders, type? := some type, value := stx[3] }
|
||||
declId := stx[1], binders, type? := some type, value := stx[3],
|
||||
docString? := modifiers.docString? }
|
||||
|
||||
def mkDefViewOfInstance (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
|
||||
-- leading_parser Term.attrKind >> "instance " >> optNamedPrio >> optional declId >> declSig >> declVal
|
||||
@@ -179,7 +183,8 @@ def mkDefViewOfInstance (modifiers : Modifiers) (stx : Syntax) : CommandElabM De
|
||||
pure <| mkNode ``Parser.Command.declId #[mkIdentFrom stx[1] id (canonical := true), mkNullNode]
|
||||
return {
|
||||
ref := stx, headerRef := mkNullNode stx.getArgs[*...5], kind := DefKind.instance, modifiers := modifiers,
|
||||
declId := declId, binders := binders, type? := type, value := stx[5]
|
||||
declId := declId, binders := binders, type? := type, value := stx[5],
|
||||
docString? := modifiers.docString?
|
||||
}
|
||||
|
||||
def mkDefViewOfOpaque (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
|
||||
@@ -192,7 +197,8 @@ def mkDefViewOfOpaque (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefV
|
||||
`(Parser.Command.declValSimple| := $val)
|
||||
return {
|
||||
ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.opaque, modifiers := modifiers,
|
||||
declId := stx[1], binders := binders, type? := some type, value := val
|
||||
declId := stx[1], binders := binders, type? := some type, value := val,
|
||||
docString? := modifiers.docString?
|
||||
}
|
||||
|
||||
def mkDefViewOfExample (modifiers : Modifiers) (stx : Syntax) : DefView :=
|
||||
@@ -201,7 +207,8 @@ def mkDefViewOfExample (modifiers : Modifiers) (stx : Syntax) : DefView :=
|
||||
let id := mkIdentFrom stx[0] `_example (canonical := true)
|
||||
let declId := mkNode ``Parser.Command.declId #[id, mkNullNode]
|
||||
{ ref := stx, headerRef := mkNullNode stx.getArgs[*...2], kind := DefKind.example, modifiers := modifiers,
|
||||
declId := declId, binders := binders, type? := type, value := stx[2] }
|
||||
declId := declId, binders := binders, type? := type, value := stx[2],
|
||||
docString? := modifiers.docString? }
|
||||
|
||||
def isDefLike (stx : Syntax) : Bool :=
|
||||
let declKind := stx.getKind
|
||||
|
||||
@@ -6,11 +6,12 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Lean.Meta.Transform
|
||||
public import Lean.Elab.Deriving.Basic
|
||||
public import Lean.Elab.Deriving.Util
|
||||
|
||||
public section
|
||||
public import Lean.Data.Options
|
||||
import Lean.Meta.Transform
|
||||
import Lean.Elab.Deriving.Basic
|
||||
import Lean.Elab.Deriving.Util
|
||||
import Lean.Meta.Eqns
|
||||
import Lean.Meta.SameCtorUtils
|
||||
|
||||
namespace Lean.Elab.Deriving.BEq
|
||||
open Lean.Parser.Term
|
||||
@@ -44,17 +45,20 @@ where
|
||||
-- add `_` pattern for indices
|
||||
for _ in *...indVal.numIndices do
|
||||
patterns := patterns.push (← `(_))
|
||||
let mut ctorArgs1 := #[]
|
||||
let mut ctorArgs2 := #[]
|
||||
let mut ctorArgs1 : Array Term := #[]
|
||||
let mut ctorArgs2 : Array Term := #[]
|
||||
let mut rhs ← `(true)
|
||||
let mut rhs_empty := true
|
||||
for i in *...ctorInfo.numFields do
|
||||
let pos := indVal.numParams + ctorInfo.numFields - i - 1
|
||||
let x := xs[pos]!
|
||||
if type.containsFVar x.fvarId! then
|
||||
if occursOrInType (← getLCtx) x type then
|
||||
-- If resulting type depends on this field, we don't need to compare
|
||||
ctorArgs1 := ctorArgs1.push (← `(_))
|
||||
ctorArgs2 := ctorArgs2.push (← `(_))
|
||||
-- but use inaccessible patterns fail during pattern match compilation if their
|
||||
-- equality does not actually follow from the equality between their types
|
||||
let a := mkIdent (← mkFreshUserName `a)
|
||||
ctorArgs1 := ctorArgs1.push a
|
||||
ctorArgs2 := ctorArgs2.push (← `(term|.( $a:ident )))
|
||||
else
|
||||
let a := mkIdent (← mkFreshUserName `a)
|
||||
let b := mkIdent (← mkFreshUserName `b)
|
||||
@@ -118,18 +122,16 @@ def mkMutualBlock (ctx : Context) : TermElabM Syntax := do
|
||||
$auxDefs:command*
|
||||
end)
|
||||
|
||||
private def mkBEqInstanceCmds (declName : Name) : TermElabM (Array Syntax) := do
|
||||
let ctx ← mkContext ``BEq "beq" declName
|
||||
def mkBEqInstanceCmds (ctx : Context) (declName : Name) : TermElabM (Array Syntax) := do
|
||||
let cmds := #[← mkMutualBlock ctx] ++ (← mkInstanceCmds ctx `BEq #[declName])
|
||||
trace[Elab.Deriving.beq] "\n{cmds}"
|
||||
return cmds
|
||||
|
||||
private def mkBEqEnumFun (ctx : Context) (name : Name) : TermElabM Syntax := do
|
||||
def mkBEqEnumFun (ctx : Context) (name : Name) : TermElabM Syntax := do
|
||||
let auxFunName := ctx.auxFunNames[0]!
|
||||
`(def $(mkIdent auxFunName):ident (x y : $(mkCIdent name)) : Bool := x.ctorIdx == y.ctorIdx)
|
||||
|
||||
private def mkBEqEnumCmd (name : Name): TermElabM (Array Syntax) := do
|
||||
let ctx ← mkContext ``BEq "beq" name
|
||||
def mkBEqEnumCmd (ctx : Context) (name : Name): TermElabM (Array Syntax) := do
|
||||
let cmds := #[← mkBEqEnumFun ctx name] ++ (← mkInstanceCmds ctx `BEq #[name])
|
||||
trace[Elab.Deriving.beq] "\n{cmds}"
|
||||
return cmds
|
||||
@@ -138,12 +140,15 @@ open Command
|
||||
|
||||
def mkBEqInstance (declName : Name) : CommandElabM Unit := do
|
||||
withoutExposeFromCtors declName do
|
||||
let ctx ← liftTermElabM <| mkContext ``BEq "beq" declName
|
||||
let cmds ← liftTermElabM <|
|
||||
if (← isEnumType declName) then
|
||||
mkBEqEnumCmd declName
|
||||
mkBEqEnumCmd ctx declName
|
||||
else
|
||||
mkBEqInstanceCmds declName
|
||||
mkBEqInstanceCmds ctx declName
|
||||
cmds.forM elabCommand
|
||||
unless ctx.usePartial do
|
||||
elabCommand (← `(attribute [method_specs] $(mkIdent ctx.instName):ident))
|
||||
|
||||
def mkBEqInstanceHandler (declNames : Array Name) : CommandElabM Bool := do
|
||||
if (← declNames.allM isInductive) then
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user