mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-17 18:34:06 +00:00
Compare commits
409 Commits
array_modi
...
float32_pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba71869c2b | ||
|
|
520d4b698f | ||
|
|
c7b8c5c6a6 | ||
|
|
3f791933f1 | ||
|
|
63791f0177 | ||
|
|
6abb8aad43 | ||
|
|
4dd182c554 | ||
|
|
762c5758f5 | ||
|
|
6447fda253 | ||
|
|
279f36b4cc | ||
|
|
d2853ecbc4 | ||
|
|
6e60d13084 | ||
|
|
019f8e175f | ||
|
|
c366a291ca | ||
|
|
1400b95ffb | ||
|
|
00c7b85261 | ||
|
|
f6e88e5a05 | ||
|
|
88573c802d | ||
|
|
faf07e58db | ||
|
|
c5181569f9 | ||
|
|
77211029da | ||
|
|
da9a0c4190 | ||
|
|
b9bf94313a | ||
|
|
2a891a3889 | ||
|
|
00718c3959 | ||
|
|
473274f145 | ||
|
|
7b98fbece4 | ||
|
|
24b412ebe3 | ||
|
|
cb600ed9b4 | ||
|
|
57d83c835e | ||
|
|
ce27d49e31 | ||
|
|
8a7889d602 | ||
|
|
69340297be | ||
|
|
222abdd43d | ||
|
|
490be9282e | ||
|
|
cda6d5c67a | ||
|
|
904404303b | ||
|
|
f6bc6b2eb1 | ||
|
|
d9d54c1f99 | ||
|
|
b2336fd980 | ||
|
|
f156f22d7c | ||
|
|
3c348d4526 | ||
|
|
0b8f50f78d | ||
|
|
0d89f0194b | ||
|
|
e157fcbcd1 | ||
|
|
95dbac26cf | ||
|
|
be63c8280e | ||
|
|
6fcf35e930 | ||
|
|
b3e0c9c3fa | ||
|
|
3c5e612dc5 | ||
|
|
29e84fa7ea | ||
|
|
6bf8ff32f0 | ||
|
|
62b8238782 | ||
|
|
0a2a8e8aa4 | ||
|
|
23236ef520 | ||
|
|
b2f70dad52 | ||
|
|
819cb879e1 | ||
|
|
3ee2842e77 | ||
|
|
7b8504cf06 | ||
|
|
ca96922b4b | ||
|
|
a1c3a36433 | ||
|
|
734ea3071d | ||
|
|
f3f00451c8 | ||
|
|
27df5e968a | ||
|
|
3752241edd | ||
|
|
39bffb6fda | ||
|
|
86f303774a | ||
|
|
d97af36867 | ||
|
|
27cc0c8039 | ||
|
|
c9ee66fb1f | ||
|
|
5c7e027b03 | ||
|
|
4969ec9cdb | ||
|
|
827062f807 | ||
|
|
6d495586a1 | ||
|
|
10d1d2cc25 | ||
|
|
2325f5c7b9 | ||
|
|
88e3a2b1ab | ||
|
|
b378fe98a7 | ||
|
|
5f1ff42a15 | ||
|
|
30d01f7a9a | ||
|
|
81b85d8e2f | ||
|
|
5982a6d230 | ||
|
|
ac1197ff59 | ||
|
|
609346f5e0 | ||
|
|
04f80a1f9f | ||
|
|
7e9dd5668b | ||
|
|
79f050b816 | ||
|
|
af4a3f2251 | ||
|
|
7692343720 | ||
|
|
597ef8cfee | ||
|
|
321e148f51 | ||
|
|
ce692436f4 | ||
|
|
23bec25fce | ||
|
|
3d511a582a | ||
|
|
51015bf5c0 | ||
|
|
3ece36de9d | ||
|
|
54c48363ca | ||
|
|
0a22f8fa6f | ||
|
|
f70b7e5722 | ||
|
|
9a17919ef1 | ||
|
|
606aeddf06 | ||
|
|
0eca3bd55d | ||
|
|
43dfc2a25f | ||
|
|
935fcfb6ec | ||
|
|
20acc72a29 | ||
|
|
c3948cba24 | ||
|
|
4e885be96d | ||
|
|
42e98bd3c9 | ||
|
|
884a9ea2ff | ||
|
|
2f5c7d0465 | ||
|
|
a5ffef7e13 | ||
|
|
442c3d5097 | ||
|
|
bf13b24692 | ||
|
|
51d1cc61d7 | ||
|
|
107a2e8b2e | ||
|
|
c4b0b94c91 | ||
|
|
ba3f2b3ecf | ||
|
|
4a69643858 | ||
|
|
b6a0d63612 | ||
|
|
5145030ff4 | ||
|
|
d3cb812fb6 | ||
|
|
e066c17a65 | ||
|
|
38cff08888 | ||
|
|
3388fc8d06 | ||
|
|
5adcd520fa | ||
|
|
1126407d9b | ||
|
|
a19ff61e15 | ||
|
|
6202461a21 | ||
|
|
ea221f3283 | ||
|
|
7c50d597c3 | ||
|
|
99031695bd | ||
|
|
b7248d5295 | ||
|
|
7f2e7e56d2 | ||
|
|
1fe66737ad | ||
|
|
765eb02279 | ||
|
|
a101377054 | ||
|
|
aca9929d84 | ||
|
|
19a701e5c9 | ||
|
|
fc4305ab15 | ||
|
|
9cf83706e7 | ||
|
|
459c6e2a46 | ||
|
|
72e952eadc | ||
|
|
56a80dec1b | ||
|
|
b894464191 | ||
|
|
b30903d1fc | ||
|
|
7fbe8e3b36 | ||
|
|
2fbc46641d | ||
|
|
17419aca7f | ||
|
|
f85c66789d | ||
|
|
c8b4f6b511 | ||
|
|
3c7555168d | ||
|
|
5eef3d27fb | ||
|
|
75d1504af2 | ||
|
|
a00cf6330f | ||
|
|
1f32477385 | ||
|
|
91c14c7ee9 | ||
|
|
69530afdf9 | ||
|
|
b7667c1604 | ||
|
|
d6f898001b | ||
|
|
a38566693b | ||
|
|
4bef3588b5 | ||
|
|
64538cf6e8 | ||
|
|
aadf3f1d2c | ||
|
|
95bf45ff8b | ||
|
|
2a02c121cf | ||
|
|
4600bb16fc | ||
|
|
7ccdfc30ff | ||
|
|
7f0bdefb6e | ||
|
|
799b2b6628 | ||
|
|
b8d6e44c4f | ||
|
|
5a99cb326c | ||
|
|
e10fac93a6 | ||
|
|
62ae320e1c | ||
|
|
98b1edfc1f | ||
|
|
ab162b3f52 | ||
|
|
b8a13ab755 | ||
|
|
405593ea28 | ||
|
|
24f305c0e3 | ||
|
|
5d553d6369 | ||
|
|
a449e3fdd6 | ||
|
|
764386734c | ||
|
|
7f1d7a595b | ||
|
|
f13e5ca852 | ||
|
|
ecbaeff24b | ||
|
|
691acde696 | ||
|
|
b1e0c1b594 | ||
|
|
93b4ec0351 | ||
|
|
f06fc30c0b | ||
|
|
64b35a8c19 | ||
|
|
688ee4c887 | ||
|
|
9a3dd615e0 | ||
|
|
7e6363dc05 | ||
|
|
a074bd9a2b | ||
|
|
498d41633b | ||
|
|
e0d7c3ac79 | ||
|
|
6a5b122b40 | ||
|
|
bf9ddf2c74 | ||
|
|
3f47871e73 | ||
|
|
85f25967ea | ||
|
|
8e1ddbc5aa | ||
|
|
e6e39f502f | ||
|
|
debb82bc20 | ||
|
|
9a85433477 | ||
|
|
4616c0ac3e | ||
|
|
e55b681774 | ||
|
|
63132105ba | ||
|
|
350b36411c | ||
|
|
1c30c76e72 | ||
|
|
d5adadc00e | ||
|
|
f08805e5c4 | ||
|
|
256b49bda9 | ||
|
|
28cf146d00 | ||
|
|
970261b1e1 | ||
|
|
6b811f8c92 | ||
|
|
f721f94045 | ||
|
|
86524d5c23 | ||
|
|
f18d9e04bc | ||
|
|
fa33423c84 | ||
|
|
1315266dd3 | ||
|
|
b1e52f1475 | ||
|
|
985600f448 | ||
|
|
ace6248e20 | ||
|
|
9f42368e1a | ||
|
|
a401368384 | ||
|
|
5e01e628b2 | ||
|
|
3a408e0e54 | ||
|
|
675d2d5a11 | ||
|
|
281c07ca97 | ||
|
|
004430b568 | ||
|
|
61f7dcb36b | ||
|
|
5c611f7814 | ||
|
|
722cb73019 | ||
|
|
258d3725e7 | ||
|
|
456e6d2b79 | ||
|
|
48e3d76173 | ||
|
|
78fe92507c | ||
|
|
811d8fb3c0 | ||
|
|
f55a9a71cb | ||
|
|
d12df6c2ad | ||
|
|
d1a99d8d45 | ||
|
|
c10e4c2256 | ||
|
|
e3420c08f1 | ||
|
|
4f7aa8c3c8 | ||
|
|
dac73c15c8 | ||
|
|
cb40ddad69 | ||
|
|
fc0529b020 | ||
|
|
837a67bedb | ||
|
|
85f2213d5a | ||
|
|
9b167e2051 | ||
|
|
1870c003d0 | ||
|
|
680177049f | ||
|
|
1b806c5535 | ||
|
|
9b18262567 | ||
|
|
d76d631856 | ||
|
|
17e6f3b3c2 | ||
|
|
5f7a40ae48 | ||
|
|
70435dfb5f | ||
|
|
59ee47ad44 | ||
|
|
ebc02fc6e8 | ||
|
|
05caf1bda9 | ||
|
|
b1dee4a42e | ||
|
|
a54226196d | ||
|
|
196b1e9250 | ||
|
|
345ecd20c9 | ||
|
|
7f0fe20315 | ||
|
|
1e98fd7f2d | ||
|
|
76d32cbd2a | ||
|
|
15139b6ef6 | ||
|
|
14c3d4b1a6 | ||
|
|
910b20fb2c | ||
|
|
4df71ed24f | ||
|
|
406da78fc6 | ||
|
|
5d2bd1e2e4 | ||
|
|
c31daece6c | ||
|
|
c157ddda11 | ||
|
|
c77b6a2c64 | ||
|
|
c6e4947f4a | ||
|
|
01814185a6 | ||
|
|
47d0060934 | ||
|
|
b1c2d851e5 | ||
|
|
970dc6f7aa | ||
|
|
8e2f92607f | ||
|
|
ee1fa6eeb7 | ||
|
|
9d2a017704 | ||
|
|
574b86c247 | ||
|
|
75602f7c29 | ||
|
|
0fd90c1283 | ||
|
|
128b049904 | ||
|
|
0e3f26e6df | ||
|
|
1148e6e142 | ||
|
|
02baaa42ff | ||
|
|
e573676db1 | ||
|
|
4dab6a108c | ||
|
|
a4d521cf96 | ||
|
|
99070bf304 | ||
|
|
93dd6f2b36 | ||
|
|
c61ced3f15 | ||
|
|
c779f3a039 | ||
|
|
fc17468f78 | ||
|
|
8b7e3b8942 | ||
|
|
9129990833 | ||
|
|
1659f3bfe2 | ||
|
|
87d3f1f2c8 | ||
|
|
b75cc35db2 | ||
|
|
3952689fb1 | ||
|
|
cd24e9dad4 | ||
|
|
0de925eafc | ||
|
|
79428827b8 | ||
|
|
3c15ab3c09 | ||
|
|
3f33cd6fcd | ||
|
|
1f8d7561fa | ||
|
|
16e5e09ffd | ||
|
|
5549e0509f | ||
|
|
c7f5fd9a83 | ||
|
|
a4057d373e | ||
|
|
fd08c92060 | ||
|
|
be6507fe5b | ||
|
|
c723ae7f97 | ||
|
|
0973ba3e42 | ||
|
|
a75a03c077 | ||
|
|
6922832327 | ||
|
|
f1707117f0 | ||
|
|
3b80d1eb1f | ||
|
|
7730ddd1a0 | ||
|
|
e4a2c3d8f0 | ||
|
|
c2391c45b9 | ||
|
|
465ed8af46 | ||
|
|
008537abbd | ||
|
|
f8242fa965 | ||
|
|
844e7ae7eb | ||
|
|
218601009b | ||
|
|
4af93813f2 | ||
|
|
34be25620f | ||
|
|
a826de8a3d | ||
|
|
0fcee100e7 | ||
|
|
03c6e99ef7 | ||
|
|
0c8d28e9ba | ||
|
|
66d68484af | ||
|
|
5c70e5d845 | ||
|
|
d4b1be094d | ||
|
|
c3cbc92a0c | ||
|
|
0d12618539 | ||
|
|
ac80e261bd | ||
|
|
38c39482f4 | ||
|
|
09802e83cd | ||
|
|
b5bbc57059 | ||
|
|
4714f84fb9 | ||
|
|
5e7d02e4ea | ||
|
|
5357fd2369 | ||
|
|
3450c2a8ac | ||
|
|
95d3b4b58f | ||
|
|
cdbe29b46d | ||
|
|
0d471513c5 | ||
|
|
d23a231908 | ||
|
|
6514385bb9 | ||
|
|
4ee44ceb1d | ||
|
|
1437033e69 | ||
|
|
b308f2bb55 | ||
|
|
9eded87462 | ||
|
|
19bebfc22f | ||
|
|
c57d054b87 | ||
|
|
2f1dc878e4 | ||
|
|
f558402ab8 | ||
|
|
62521f4f2d | ||
|
|
9847923f9b | ||
|
|
709ea6cdf8 | ||
|
|
8c7f7484f9 | ||
|
|
c50f04ace0 | ||
|
|
8b5443eb22 | ||
|
|
08c36e4306 | ||
|
|
8f0328b777 | ||
|
|
38490a4ac7 | ||
|
|
13036655e9 | ||
|
|
4068cf00ee | ||
|
|
abe6d5bca7 | ||
|
|
f292184642 | ||
|
|
a310488b7f | ||
|
|
57a95c8b5f | ||
|
|
266ae428dc | ||
|
|
4c0d12b3f1 | ||
|
|
748f0d6c15 | ||
|
|
07ea626560 | ||
|
|
193b6f2bec | ||
|
|
19ce2040a2 | ||
|
|
059674d967 | ||
|
|
7150a0d538 | ||
|
|
0725cd39a2 | ||
|
|
e07272a53a | ||
|
|
9157c1f279 | ||
|
|
09e1a05ee9 | ||
|
|
8822b0fca7 | ||
|
|
249530f3c1 | ||
|
|
174a5f345a | ||
|
|
45b1b367ca | ||
|
|
c1143d9432 | ||
|
|
66dbad911e | ||
|
|
fad57cf5a2 | ||
|
|
83129b7e3a | ||
|
|
fa711253d6 | ||
|
|
eddbdd77b8 | ||
|
|
f0c190239a | ||
|
|
bab6aff173 | ||
|
|
5bea46deb0 | ||
|
|
462e52d0c0 | ||
|
|
d0abe1d382 | ||
|
|
f752ce2db9 | ||
|
|
07c09ee579 | ||
|
|
919f64b2e6 | ||
|
|
71122696a1 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -39,7 +39,7 @@ Please put an X between the brackets as you perform the following steps:
|
||||
|
||||
### Versions
|
||||
|
||||
[Output of `#eval Lean.versionString`]
|
||||
[Output of `#version` or `#eval Lean.versionString`]
|
||||
[OS version, if not using live.lean-lang.org.]
|
||||
|
||||
### Additional Information
|
||||
|
||||
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,6 +5,10 @@
|
||||
* Include the link to your `RFC` or `bug` issue in the description.
|
||||
* If the issue does not already have approval from a developer, submit the PR as draft.
|
||||
* The PR title/description will become the commit message. Keep it up-to-date as the PR evolves.
|
||||
* For `feat/fix` PRs, the first paragraph starting with "This PR" must be present and will become a
|
||||
changelog entry unless the PR is labeled with `no-changelog`. If the PR does not have this label,
|
||||
it must instead be categorized with one of the `changelog-*` labels (which will be done by a
|
||||
reviewer for external PRs).
|
||||
* A toolchain of the form `leanprover/lean4-pr-releases:pr-release-NNNN` for Linux and M-series Macs will be generated upon build. To generate binaries for Windows and Intel-based Macs as well, write a comment containing `release-ci` on its own line.
|
||||
* If you rebase your PR onto `nightly-with-mathlib` then CI will test Mathlib against your PR.
|
||||
* You can manage the `awaiting-review`, `awaiting-author`, and `WIP` labels yourself, by writing a comment containing one of these labels on its own line.
|
||||
@@ -12,4 +16,6 @@
|
||||
|
||||
---
|
||||
|
||||
Closes #0000 (`RFC` or `bug` issue number fixed by this PR, if any)
|
||||
This PR <short changelog summary for feat/fix, see above>.
|
||||
|
||||
Closes <`RFC` or `bug` issue number fixed by this PR, if any>
|
||||
|
||||
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
commit-message:
|
||||
prefix: "chore: CI"
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -17,6 +17,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v1
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
pyflakes: false # we do not use python scripts
|
||||
|
||||
3
.github/workflows/check-prelude.yml
vendored
3
.github/workflows/check-prelude.yml
vendored
@@ -14,6 +14,7 @@ jobs:
|
||||
sparse-checkout: |
|
||||
src/Lean
|
||||
src/Std
|
||||
src/lake/Lake
|
||||
- name: Check Prelude
|
||||
run: |
|
||||
failed_files=""
|
||||
@@ -21,7 +22,7 @@ jobs:
|
||||
if ! grep -q "^prelude$" "$file"; then
|
||||
failed_files="$failed_files$file\n"
|
||||
fi
|
||||
done < <(find src/Lean src/Std -name '*.lean' -print0)
|
||||
done < <(find src/Lean src/Std src/lake/Lake -name '*.lean' -print0)
|
||||
if [ -n "$failed_files" ]; then
|
||||
echo -e "The following files should use 'prelude':\n$failed_files"
|
||||
exit 1
|
||||
|
||||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -217,7 +217,7 @@ jobs:
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
"shell": "msys2 {0}",
|
||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
|
||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
|
||||
// for reasons unknown, interactivetests are flaky on Windows
|
||||
"CTEST_OPTIONS": "--repeat until-pass:2",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
||||
@@ -227,7 +227,7 @@ jobs:
|
||||
{
|
||||
"name": "Linux aarch64",
|
||||
"os": "nscloud-ubuntu-22.04-arm64-4x8",
|
||||
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
|
||||
@@ -318,7 +318,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: 3.1.44
|
||||
actions-cache-folder: emsdk
|
||||
@@ -492,7 +492,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -536,7 +536,7 @@ jobs:
|
||||
echo -e "\n*Full commit log*\n" >> diff.md
|
||||
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
|
||||
- name: Release Nightly
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
24
.github/workflows/labels-from-comments.yml
vendored
24
.github/workflows/labels-from-comments.yml
vendored
@@ -1,7 +1,8 @@
|
||||
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, `WIP`,
|
||||
# or `release-ci` labels by commenting on the PR or issue.
|
||||
# `release-ci`, or a `changelog-XXX` label by commenting on the PR or issue.
|
||||
# If any labels from the set {`awaiting-review`, `awaiting-author`, `WIP`} are added, other labels
|
||||
# from that set are removed automatically at the same time.
|
||||
# Similarly, if any `changelog-XXX` label is added, other `changelog-YYY` labels are removed.
|
||||
|
||||
name: Label PR based on Comment
|
||||
|
||||
@@ -11,7 +12,7 @@ on:
|
||||
|
||||
jobs:
|
||||
update-label:
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci'))
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci') || contains(github.event.comment.body, 'changelog-'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -20,13 +21,14 @@ jobs:
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const commentLines = context.payload.comment.body.split('\r\n');
|
||||
|
||||
const awaitingReview = commentLines.includes('awaiting-review');
|
||||
const awaitingAuthor = commentLines.includes('awaiting-author');
|
||||
const wip = commentLines.includes('WIP');
|
||||
const releaseCI = commentLines.includes('release-ci');
|
||||
const changelogMatch = commentLines.find(line => line.startsWith('changelog-'));
|
||||
|
||||
if (awaitingReview || awaitingAuthor || wip) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-review' }).catch(() => {});
|
||||
@@ -47,3 +49,19 @@ jobs:
|
||||
if (releaseCI) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['release-ci'] });
|
||||
}
|
||||
|
||||
if (changelogMatch) {
|
||||
const changelogLabel = changelogMatch.trim();
|
||||
const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({ owner, repo, issue_number });
|
||||
const changelogLabels = existingLabels.filter(label => label.name.startsWith('changelog-'));
|
||||
|
||||
// Remove all other changelog labels
|
||||
for (const label of changelogLabels) {
|
||||
if (label.name !== changelogLabel) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label.name }).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new changelog label
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [changelogLabel] });
|
||||
}
|
||||
|
||||
12
.github/workflows/nix-ci.yml
vendored
12
.github/workflows/nix-ci.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build
|
||||
- name: Test
|
||||
run: |
|
||||
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/source/src/build/ ./push-test; false)
|
||||
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/build/source/src/build ./push-test; false)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
with:
|
||||
@@ -110,14 +110,6 @@ jobs:
|
||||
# https://github.com/netlify/cli/issues/1809
|
||||
cp -r --dereference ./result ./dist
|
||||
if: matrix.name == 'Nix Linux'
|
||||
- name: Check manual for broken links
|
||||
id: lychee
|
||||
uses: lycheeverse/lychee-action@v1.9.0
|
||||
with:
|
||||
fail: false # report errors but do not block CI on temporary failures
|
||||
# gmplib.org consistently times out from GH actions
|
||||
# the GitHub token is to avoid rate limiting
|
||||
args: --base './dist' --no-progress --github-token ${{ secrets.GITHUB_TOKEN }} --exclude 'gmplib.org' './dist/**/*.html'
|
||||
- name: Rebuild Nix Store Cache
|
||||
run: |
|
||||
rm -rf nix-store-cache || true
|
||||
@@ -129,7 +121,7 @@ jobs:
|
||||
python3 -c 'import base64; print("alias="+base64.urlsafe_b64encode(bytes.fromhex("${{github.sha}}")).decode("utf-8").rstrip("="))' >> "$GITHUB_OUTPUT"
|
||||
echo "message=`git log -1 --pretty=format:"%s"`" >> "$GITHUB_OUTPUT"
|
||||
- name: Publish manual to Netlify
|
||||
uses: nwtgck/actions-netlify@v2.0
|
||||
uses: nwtgck/actions-netlify@v3.0
|
||||
id: publish-manual
|
||||
with:
|
||||
publish-dir: ./dist
|
||||
|
||||
25
.github/workflows/pr-body.yml
vendored
Normal file
25
.github/workflows/pr-body.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Check PR body for changelog convention
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited, labeled, converted_to_draft, ready_for_review]
|
||||
|
||||
jobs:
|
||||
check-pr-body:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR body
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { title, body, labels, draft } = context.payload.pull_request;
|
||||
if (!draft && /^(feat|fix):/.test(title) && !labels.some(label => label.name == "changelog-no")) {
|
||||
if (!labels.some(label => label.name.startsWith("changelog-"))) {
|
||||
core.setFailed('feat/fix PR must have a `changelog-*` label');
|
||||
}
|
||||
if (!/^This PR [^<]/.test(body)) {
|
||||
core.setFailed('feat/fix PR must have changelog summary starting with "This PR ..." as first line.');
|
||||
}
|
||||
}
|
||||
10
.github/workflows/pr-release.yml
vendored
10
.github/workflows/pr-release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v2 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v7 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Report release status
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
|
||||
- name: 'Setup jq'
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: dcarbone/install-jq-action@v1.0.1
|
||||
uses: dcarbone/install-jq-action@v3.0.1
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
|
||||
- name: Report mathlib base
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const description =
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 30
|
||||
|
||||
607
RELEASES.md
607
RELEASES.md
@@ -8,6 +8,613 @@ This file contains work-in-progress notes for the upcoming release, as well as p
|
||||
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
|
||||
of each version.
|
||||
|
||||
v4.16.0
|
||||
----------
|
||||
|
||||
Development in progress.
|
||||
|
||||
v4.15.0
|
||||
----------
|
||||
|
||||
Release candidate, release notes will be copied from the branch `releases/v4.15.0` once completed.
|
||||
|
||||
v4.14.0
|
||||
----------
|
||||
|
||||
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.13.0...v4.14.0
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* `structure` and `inductive` commands
|
||||
* [#5517](https://github.com/leanprover/lean4/pull/5517) improves universe level inference for the resulting type of an `inductive` or `structure.` Recall that a `Prop`-valued inductive type is a syntactic subsingleton if it has at most one constructor and all the arguments to the constructor are in `Prop`. Such types have large elimination, so they could be defined in `Type` or `Prop` without any trouble. The way inference has changed is that if a type is a syntactic subsingleton with exactly one constructor, and the constructor has at least one parameter/field, then the `inductive`/`structure` command will prefer creating a `Prop` instead of a `Type`. The upshot is that the `: Prop` in `structure S : Prop` is often no longer needed. (With @arthur-adjedj).
|
||||
* [#5842](https://github.com/leanprover/lean4/pull/5842) and [#5783](https://github.com/leanprover/lean4/pull/5783) implement a feature where the `structure` command can now define recursive inductive types:
|
||||
```lean
|
||||
structure Tree where
|
||||
n : Nat
|
||||
children : Fin n → Tree
|
||||
|
||||
def Tree.size : Tree → Nat
|
||||
| {n, children} => Id.run do
|
||||
let mut s := 0
|
||||
for h : i in [0 : n] do
|
||||
s := s + (children ⟨i, h.2⟩).size
|
||||
pure s
|
||||
```
|
||||
* [#5814](https://github.com/leanprover/lean4/pull/5814) fixes a bug where Mathlib's `Type*` elaborator could lead to incorrect universe parameters with the `inductive` command.
|
||||
* [#3152](https://github.com/leanprover/lean4/pull/3152) and [#5844](https://github.com/leanprover/lean4/pull/5844) fix bugs in default value processing for structure instance notation (with @arthur-adjedj).
|
||||
* [#5399](https://github.com/leanprover/lean4/pull/5399) promotes instance synthesis order calculation failure from a soft error to a hard error.
|
||||
* [#5542](https://github.com/leanprover/lean4/pull/5542) deprecates `:=` variants of `inductive` and `structure` (see breaking changes).
|
||||
|
||||
* **Application elaboration improvements**
|
||||
* [#5671](https://github.com/leanprover/lean4/pull/5671) makes `@[elab_as_elim]` require at least one discriminant, since otherwise there is no advantage to this alternative elaborator.
|
||||
* [#5528](https://github.com/leanprover/lean4/pull/5528) enables field notation in explicit mode. The syntax `@x.f` elaborates as `@S.f` with `x` supplied to the appropriate parameter.
|
||||
* [#5692](https://github.com/leanprover/lean4/pull/5692) modifies the dot notation resolution algorithm so that it can apply `CoeFun` instances. For example, Mathlib has `Multiset.card : Multiset α →+ Nat`, and now with `m : Multiset α`, the notation `m.card` resolves to `⇑Multiset.card m`.
|
||||
* [#5658](https://github.com/leanprover/lean4/pull/5658) fixes a bug where 'don't know how to synthesize implicit argument' errors might have the incorrect local context when the eta arguments feature is activated.
|
||||
* [#5933](https://github.com/leanprover/lean4/pull/5933) fixes a bug where `..` ellipses in patterns made use of optparams and autoparams.
|
||||
* [#5770](https://github.com/leanprover/lean4/pull/5770) makes dot notation for structures resolve using *all* ancestors. Adds a *resolution order* for generalized field notation. This is the order of namespaces visited during resolution when trying to resolve names. The algorithm to compute a resolution order is the commonly used C3 linearization (used for example by Python), which when successful ensures that immediate parents' namespaces are considered before more distant ancestors' namespaces. By default we use a relaxed version of the algorithm that tolerates inconsistencies, but using `set_option structure.strictResolutionOrder true` makes inconsistent parent orderings into warnings.
|
||||
|
||||
* **Recursion and induction principles**
|
||||
* [#5619](https://github.com/leanprover/lean4/pull/5619) fixes functional induction principle generation to avoid over-eta-expanding in the preprocessing step.
|
||||
* [#5766](https://github.com/leanprover/lean4/pull/5766) fixes structural nested recursion so that it is not confused when a nested type appears first.
|
||||
* [#5803](https://github.com/leanprover/lean4/pull/5803) fixes a bug in functional induction principle generation when there are `let` bindings.
|
||||
* [#5904](https://github.com/leanprover/lean4/pull/5904) improves functional induction principle generation to unfold aux definitions more carefully.
|
||||
* [#5850](https://github.com/leanprover/lean4/pull/5850) refactors code for `Predefinition.Structural`.
|
||||
|
||||
* **Error messages**
|
||||
* [#5276](https://github.com/leanprover/lean4/pull/5276) fixes a bug in "type mismatch" errors that would structurally assign metavariables during the algorithm to expose differences.
|
||||
* [#5919](https://github.com/leanprover/lean4/pull/5919) makes "type mismatch" errors add type ascriptions to expose differences for numeric literals.
|
||||
* [#5922](https://github.com/leanprover/lean4/pull/5922) makes "type mismatch" errors expose differences in the bodies of functions and pi types.
|
||||
* [#5888](https://github.com/leanprover/lean4/pull/5888) improves the error message for invalid induction alternative names in `match` expressions (@josojo).
|
||||
* [#5719](https://github.com/leanprover/lean4/pull/5719) improves `calc` error messages.
|
||||
|
||||
* [#5627](https://github.com/leanprover/lean4/pull/5627) and [#5663](https://github.com/leanprover/lean4/pull/5663) improve the **`#eval` command** and introduce some new features.
|
||||
* Now results can be pretty printed if there is a `ToExpr` instance, which means **hoverable output**. If `ToExpr` fails, it then tries looking for a `Repr` or `ToString` instance like before. Setting `set_option eval.pp false` disables making use of `ToExpr` instances.
|
||||
* There is now **auto-derivation** of `Repr` instances, enabled with the `pp.derive.repr` option (default to **true**). For example:
|
||||
```lean
|
||||
inductive Baz
|
||||
| a | b
|
||||
|
||||
#eval Baz.a
|
||||
-- Baz.a
|
||||
```
|
||||
It simply does `deriving instance Repr for Baz` when there's no way to represent `Baz`.
|
||||
* The option `eval.type` controls whether or not to include the type in the output. For now the default is false.
|
||||
* Now expressions such as `#eval do return 2`, where monad is unknown, work. It tries unifying the monad with `CommandElabM`, `TermElabM`, or `IO`.
|
||||
* The classes `Lean.Eval` and `Lean.MetaEval` have been removed. These each used to be responsible for adapting monads and printing results. Now the `MonadEval` class is responsible for adapting monads for evaluation (it is similar to `MonadLift`, but instances are allowed to use default data when initializing state), and representing results is handled through a separate process.
|
||||
* Error messages about failed instance synthesis are now more precise. Once it detects that a `MonadEval` class applies, then the error message will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
|
||||
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log messages.
|
||||
* Fixes a bug where `let rec` could not be used in `#eval`.
|
||||
|
||||
* `partial` definitions
|
||||
* [#5780](https://github.com/leanprover/lean4/pull/5780) improves the error message when `partial` fails to prove a type is inhabited. Add delta deriving.
|
||||
* [#5821](https://github.com/leanprover/lean4/pull/5821) gives `partial` inhabitation the ability to create local `Inhabited` instances from parameters.
|
||||
|
||||
* **New tactic configuration syntax.** The configuration syntax for all core tactics has been given an upgrade. Rather than `simp (config := { contextual := true, maxSteps := 22})`, one can now write `simp +contextual (maxSteps := 22)`. Tactic authors can migrate by switching from `(config)?` to `optConfig` in tactic syntaxes and potentially deleting `mkOptionalNode` in elaborators. [#5883](https://github.com/leanprover/lean4/pull/5883), [#5898](https://github.com/leanprover/lean4/pull/5898), [#5928](https://github.com/leanprover/lean4/pull/5928), and [#5932](https://github.com/leanprover/lean4/pull/5932). (Tactic authors, see breaking changes.)
|
||||
|
||||
* `simp` tactic
|
||||
* [#5632](https://github.com/leanprover/lean4/pull/5632) fixes the simpproc for `Fin` literals to reduce more consistently.
|
||||
* [#5648](https://github.com/leanprover/lean4/pull/5648) fixes a bug in `simpa ... using t` where metavariables in `t` were not properly accounted for, and also improves the type mismatch error.
|
||||
* [#5838](https://github.com/leanprover/lean4/pull/5838) fixes the docstring of `simp!` to actually talk about `simp!`.
|
||||
* [#5870](https://github.com/leanprover/lean4/pull/5870) adds support for `attribute [simp ←]` (note the reverse direction). This adds the reverse of a theorem as a global simp theorem.
|
||||
|
||||
* `decide` tactic
|
||||
* [#5665](https://github.com/leanprover/lean4/pull/5665) adds `decide!` tactic for using kernel reduction (warning: this is renamed to `decide +kernel` in a future release).
|
||||
|
||||
* `bv_decide` tactic
|
||||
* [#5714](https://github.com/leanprover/lean4/pull/5714) adds inequality regression tests (@alexkeizer).
|
||||
* [#5608](https://github.com/leanprover/lean4/pull/5608) adds `bv_toNat` tag for `toNat_ofInt` (@bollu).
|
||||
* [#5618](https://github.com/leanprover/lean4/pull/5618) adds support for `at` in `ac_nf` and uses it in `bv_normalize` (@tobiasgrosser).
|
||||
* [#5628](https://github.com/leanprover/lean4/pull/5628) adds udiv support.
|
||||
* [#5635](https://github.com/leanprover/lean4/pull/5635) adds auxiliary bitblasters for negation and subtraction.
|
||||
* [#5637](https://github.com/leanprover/lean4/pull/5637) adds more `getLsbD` bitblaster theory.
|
||||
* [#5652](https://github.com/leanprover/lean4/pull/5652) adds umod support.
|
||||
* [#5653](https://github.com/leanprover/lean4/pull/5653) adds performance benchmark for modulo.
|
||||
* [#5655](https://github.com/leanprover/lean4/pull/5655) reduces error on `bv_check` to warning.
|
||||
* [#5670](https://github.com/leanprover/lean4/pull/5670) adds `~~~(-x)` support.
|
||||
* [#5673](https://github.com/leanprover/lean4/pull/5673) disables `ac_nf` by default.
|
||||
* [#5675](https://github.com/leanprover/lean4/pull/5675) fixes context tracking in `bv_decide` counter example.
|
||||
* [#5676](https://github.com/leanprover/lean4/pull/5676) adds an error when the LRAT proof is invalid.
|
||||
* [#5781](https://github.com/leanprover/lean4/pull/5781) introduces uninterpreted symbols everywhere.
|
||||
* [#5823](https://github.com/leanprover/lean4/pull/5823) adds `BitVec.sdiv` support.
|
||||
* [#5852](https://github.com/leanprover/lean4/pull/5852) adds `BitVec.ofBool` support.
|
||||
* [#5855](https://github.com/leanprover/lean4/pull/5855) adds `if` support.
|
||||
* [#5869](https://github.com/leanprover/lean4/pull/5869) adds support for all the SMTLIB BitVec divison/remainder operations.
|
||||
* [#5886](https://github.com/leanprover/lean4/pull/5886) adds embedded constraint substitution.
|
||||
* [#5918](https://github.com/leanprover/lean4/pull/5918) fixes loose mvars bug in `bv_normalize`.
|
||||
* Documentation:
|
||||
* [#5636](https://github.com/leanprover/lean4/pull/5636) adds remarks about multiplication.
|
||||
|
||||
* `conv` mode
|
||||
* [#5861](https://github.com/leanprover/lean4/pull/5861) improves the `congr` conv tactic to handle "over-applied" functions.
|
||||
* [#5894](https://github.com/leanprover/lean4/pull/5894) improves the `arg` conv tactic so that it can access more arguments and so that it can handle "over-applied" functions (it generates a specialized congruence lemma for the specific argument in question). Makes `arg 1` and `arg 2` apply to pi types in more situations. Adds negative indexing, for example `arg -2` is equivalent to the `lhs` tactic. Makes the `enter [...]` tactic show intermediate states like `rw`.
|
||||
|
||||
* **Other tactics**
|
||||
* [#4846](https://github.com/leanprover/lean4/pull/4846) fixes a bug where `generalize ... at *` would apply to implementation details (@ymherklotz).
|
||||
* [#5730](https://github.com/leanprover/lean4/pull/5730) upstreams the `classical` tactic combinator.
|
||||
* [#5815](https://github.com/leanprover/lean4/pull/5815) improves the error message when trying to unfold a local hypothesis that is not a local definition.
|
||||
* [#5862](https://github.com/leanprover/lean4/pull/5862) and [#5863](https://github.com/leanprover/lean4/pull/5863) change how `apply` and `simp` elaborate, making them not disable error recovery. This improves hovers and completions when the term has elaboration errors.
|
||||
|
||||
* `deriving` clauses
|
||||
* [#5899](https://github.com/leanprover/lean4/pull/5899) adds declaration ranges for delta-derived instances.
|
||||
* [#5265](https://github.com/leanprover/lean4/pull/5265) removes unused syntax in `deriving` clauses for providing arguments to deriving handlers (see breaking changes).
|
||||
|
||||
* [#5065](https://github.com/leanprover/lean4/pull/5065) upstreams and updates `#where`, a command that reports the current scope information.
|
||||
|
||||
* **Linters**
|
||||
* [#5338](https://github.com/leanprover/lean4/pull/5338) makes the unused variables linter ignore variables defined in tactics by default now, avoiding performance bottlenecks.
|
||||
* [#5644](https://github.com/leanprover/lean4/pull/5644) ensures that linters in general do not run on `#guard_msgs` itself.
|
||||
|
||||
* **Metaprogramming interface**
|
||||
* [#5720](https://github.com/leanprover/lean4/pull/5720) adds `pushGoal`/`pushGoals` and `popGoal` for manipulating the goal state. These are an alternative to `replaceMainGoal` and `getMainGoal`, and with them you don't need to worry about making sure nothing clears assigned metavariables from the goal list between assigning the main goal and using `replaceMainGoal`. Modifies `closeMainGoalUsing`, which is like a `TacticM` version of `liftMetaTactic`. Now the callback is run in a context where the main goal is removed from the goal list, and the callback is free to modify the goal list. Furthermore, the `checkUnassigned` argument has been replaced with `checkNewUnassigned`, which checks whether the value assigned to the goal has any *new* metavariables, relative to the start of execution of the callback. Modifies `withCollectingNewGoalsFrom` to take the `parentTag` argument explicitly rather than indirectly via `getMainTag`. Modifies `elabTermWithHoles` to optionally take `parentTag?`.
|
||||
* [#5563](https://github.com/leanprover/lean4/pull/5563) fixes `getFunInfo` and `inferType` to use `withAtLeastTransparency` rather than `withTransparency`.
|
||||
* [#5679](https://github.com/leanprover/lean4/pull/5679) fixes `RecursorVal.getInduct` to return the name of major argument’s type. This makes "structure eta" work for nested inductives.
|
||||
* [#5681](https://github.com/leanprover/lean4/pull/5681) removes unused `mkRecursorInfoForKernelRec`.
|
||||
* [#5686](https://github.com/leanprover/lean4/pull/5686) makes discrimination trees index the domains of foralls, for better performance of the simplify and type class search.
|
||||
* [#5760](https://github.com/leanprover/lean4/pull/5760) adds `Lean.Expr.name?` recognizer for `Name` expressions.
|
||||
* [#5800](https://github.com/leanprover/lean4/pull/5800) modifies `liftCommandElabM` to preserve more state, fixing an issue where using it would drop messages.
|
||||
* [#5857](https://github.com/leanprover/lean4/pull/5857) makes it possible to use dot notation in `m!` strings, for example `m!"{.ofConstName n}"`.
|
||||
* [#5841](https://github.com/leanprover/lean4/pull/5841) and [#5853](https://github.com/leanprover/lean4/pull/5853) record the complete list of `structure` parents in the `StructureInfo` environment extension.
|
||||
|
||||
* **Other fixes or improvements**
|
||||
* [#5566](https://github.com/leanprover/lean4/pull/5566) fixes a bug introduced in [#4781](https://github.com/leanprover/lean4/pull/4781) where heartbeat exceptions were no longer being handled properly. Now such exceptions are tagged with `runtime.maxHeartbeats` (@eric-wieser).
|
||||
* [#5708](https://github.com/leanprover/lean4/pull/5708) modifies the proof objects produced by the proof-by-reflection tactics `ac_nf0` and `simp_arith` so that the kernel is less prone to reducing expensive atoms.
|
||||
* [#5768](https://github.com/leanprover/lean4/pull/5768) adds a `#version` command that prints Lean's version information.
|
||||
* [#5822](https://github.com/leanprover/lean4/pull/5822) fixes elaborator algorithms to match kernel algorithms for primitive projections (`Expr.proj`).
|
||||
* [#5811](https://github.com/leanprover/lean4/pull/5811) improves the docstring for the `rwa` tactic.
|
||||
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
|
||||
* [#5224](https://github.com/leanprover/lean4/pull/5224) fixes `WorkspaceClientCapabilities` to make `applyEdit` optional, in accordance with the LSP specification (@pzread).
|
||||
* [#5340](https://github.com/leanprover/lean4/pull/5340) fixes a server deadlock when shutting down the language server and a desync between client and language server after a file worker crash.
|
||||
* [#5560](https://github.com/leanprover/lean4/pull/5560) makes `initialize` and `builtin_initialize` participate in the call hierarchy and other requests.
|
||||
* [#5650](https://github.com/leanprover/lean4/pull/5650) makes references in attributes participate in the call hierarchy and other requests.
|
||||
* [#5666](https://github.com/leanprover/lean4/pull/5666) add auto-completion in tactic blocks without having to type the first character of the tactic, and adds tactic completion docs to tactic auto-completion items.
|
||||
* [#5677](https://github.com/leanprover/lean4/pull/5677) fixes several cases where goal states were not displayed in certain text cursor positions.
|
||||
* [#5707](https://github.com/leanprover/lean4/pull/5707) indicates deprecations in auto-completion items.
|
||||
* [#5736](https://github.com/leanprover/lean4/pull/5736), [#5752](https://github.com/leanprover/lean4/pull/5752), [#5763](https://github.com/leanprover/lean4/pull/5763), [#5802](https://github.com/leanprover/lean4/pull/5802), and [#5805](https://github.com/leanprover/lean4/pull/5805) fix various performance issues in the language server.
|
||||
* [#5801](https://github.com/leanprover/lean4/pull/5801) distinguishes theorem auto-completions from non-theorem auto-completions.
|
||||
|
||||
### Pretty printing
|
||||
|
||||
* [#5640](https://github.com/leanprover/lean4/pull/5640) fixes a bug where goal states in messages might print newlines as spaces.
|
||||
* [#5643](https://github.com/leanprover/lean4/pull/5643) adds option `pp.mvars.delayed` (default false), which when false causes delayed assignment metavariables to pretty print with what they are assigned to. Now `fun x : Nat => ?a` pretty prints as `fun x : Nat => ?a` rather than `fun x ↦ ?m.7 x`.
|
||||
* [#5711](https://github.com/leanprover/lean4/pull/5711) adds options `pp.mvars.anonymous` and `pp.mvars.levels`, which when false respectively cause expression metavariables and level metavariables to pretty print as `?_`.
|
||||
* [#5710](https://github.com/leanprover/lean4/pull/5710) adjusts the `⋯` elaboration warning to mention `pp.maxSteps`.
|
||||
|
||||
* [#5759](https://github.com/leanprover/lean4/pull/5759) fixes the app unexpander for `sorryAx`.
|
||||
* [#5827](https://github.com/leanprover/lean4/pull/5827) improves accuracy of binder names in the signature pretty printer (like in output of `#check`). Also fixes the issue where consecutive hygienic names pretty print without a space separating them, so we now have `(x✝ y✝ : Nat)` rather than `(x✝y✝ : Nat)`.
|
||||
* [#5830](https://github.com/leanprover/lean4/pull/5830) makes sure all the core delaborators respond to `pp.explicit` when appropriate.
|
||||
* [#5639](https://github.com/leanprover/lean4/pull/5639) makes sure name literals use escaping when pretty printing.
|
||||
* [#5854](https://github.com/leanprover/lean4/pull/5854) adds delaborators for `<|>`, `<*>`, `>>`, `<*`, and `*>`.
|
||||
|
||||
### Library
|
||||
|
||||
* `Array`
|
||||
* [#5687](https://github.com/leanprover/lean4/pull/5687) deprecates `Array.data`.
|
||||
* [#5705](https://github.com/leanprover/lean4/pull/5705) uses a better default value for `Array.swapAt!`.
|
||||
* [#5748](https://github.com/leanprover/lean4/pull/5748) moves `Array.mapIdx` lemmas to a new file.
|
||||
* [#5749](https://github.com/leanprover/lean4/pull/5749) simplifies signature of `Array.mapIdx`.
|
||||
* [#5758](https://github.com/leanprover/lean4/pull/5758) upstreams `Array.reduceOption`.
|
||||
* [#5786](https://github.com/leanprover/lean4/pull/5786) adds simp lemmas for `Array.isEqv` and `BEq`.
|
||||
* [#5796](https://github.com/leanprover/lean4/pull/5796) renames `Array.shrink` to `Array.take`, and relates it to `List.take`.
|
||||
* [#5798](https://github.com/leanprover/lean4/pull/5798) upstreams `List.modify`, adds lemmas, relates to `Array.modify`.
|
||||
* [#5799](https://github.com/leanprover/lean4/pull/5799) relates `Array.forIn` and `List.forIn`.
|
||||
* [#5833](https://github.com/leanprover/lean4/pull/5833) adds `Array.forIn'`, and relates to `List`.
|
||||
* [#5848](https://github.com/leanprover/lean4/pull/5848) fixes deprecations in `Init.Data.Array.Basic` to not recommend the deprecated constant.
|
||||
* [#5895](https://github.com/leanprover/lean4/pull/5895) adds `LawfulBEq (Array α) ↔ LawfulBEq α`.
|
||||
* [#5896](https://github.com/leanprover/lean4/pull/5896) moves `@[simp]` from `back_eq_back?` to `back_push`.
|
||||
* [#5897](https://github.com/leanprover/lean4/pull/5897) renames `Array.back` to `back!`.
|
||||
|
||||
* `List`
|
||||
* [#5605](https://github.com/leanprover/lean4/pull/5605) removes `List.redLength`.
|
||||
* [#5696](https://github.com/leanprover/lean4/pull/5696) upstreams `List.mapIdx` and adds lemmas.
|
||||
* [#5697](https://github.com/leanprover/lean4/pull/5697) upstreams `List.foldxM_map`.
|
||||
* [#5701](https://github.com/leanprover/lean4/pull/5701) renames `List.join` to `List.flatten`.
|
||||
* [#5703](https://github.com/leanprover/lean4/pull/5703) upstreams `List.sum`.
|
||||
* [#5706](https://github.com/leanprover/lean4/pull/5706) marks `prefix_append_right_inj` as a simp lemma.
|
||||
* [#5716](https://github.com/leanprover/lean4/pull/5716) fixes `List.drop_drop` addition order.
|
||||
* [#5731](https://github.com/leanprover/lean4/pull/5731) renames `List.bind` and `Array.concatMap` to `flatMap`.
|
||||
* [#5732](https://github.com/leanprover/lean4/pull/5732) renames `List.pure` to `List.singleton`.
|
||||
* [#5742](https://github.com/leanprover/lean4/pull/5742) upstreams `ne_of_mem_of_not_mem`.
|
||||
* [#5743](https://github.com/leanprover/lean4/pull/5743) upstreams `ne_of_apply_ne`.
|
||||
* [#5816](https://github.com/leanprover/lean4/pull/5816) adds more `List.modify` lemmas.
|
||||
* [#5879](https://github.com/leanprover/lean4/pull/5879) renames `List.groupBy` to `splitBy`.
|
||||
* [#5913](https://github.com/leanprover/lean4/pull/5913) relates `for` loops over `List` with `foldlM`.
|
||||
|
||||
* `Nat`
|
||||
* [#5694](https://github.com/leanprover/lean4/pull/5694) removes `instBEqNat`, which is redundant with `instBEqOfDecidableEq` but not defeq.
|
||||
* [#5746](https://github.com/leanprover/lean4/pull/5746) deprecates `Nat.sum`.
|
||||
* [#5785](https://github.com/leanprover/lean4/pull/5785) adds `Nat.forall_lt_succ` and variants.
|
||||
|
||||
* Fixed width integers
|
||||
* [#5323](https://github.com/leanprover/lean4/pull/5323) redefine unsigned fixed width integers in terms of `BitVec`.
|
||||
* [#5735](https://github.com/leanprover/lean4/pull/5735) adds `UIntX.[val_ofNat, toBitVec_ofNat]`.
|
||||
* [#5790](https://github.com/leanprover/lean4/pull/5790) defines `Int8`.
|
||||
* [#5901](https://github.com/leanprover/lean4/pull/5901) removes native code for `UInt8.modn`.
|
||||
|
||||
* `BitVec`
|
||||
* [#5604](https://github.com/leanprover/lean4/pull/5604) completes `BitVec.[getMsbD|getLsbD|msb]` for shifts (@luisacicolini).
|
||||
* [#5609](https://github.com/leanprover/lean4/pull/5609) adds lemmas for division when denominator is zero (@bollu).
|
||||
* [#5620](https://github.com/leanprover/lean4/pull/5620) documents Bitblasting (@bollu)
|
||||
* [#5623](https://github.com/leanprover/lean4/pull/5623) moves `BitVec.udiv/umod/sdiv/smod` after `add/sub/mul/lt` (@tobiasgrosser).
|
||||
* [#5645](https://github.com/leanprover/lean4/pull/5645) defines `udiv` normal form to be `/`, resp. `umod` and `%` (@bollu).
|
||||
* [#5646](https://github.com/leanprover/lean4/pull/5646) adds lemmas about arithmetic inequalities (@bollu).
|
||||
* [#5680](https://github.com/leanprover/lean4/pull/5680) expands relationship with `toFin` (@tobiasgrosser).
|
||||
* [#5691](https://github.com/leanprover/lean4/pull/5691) adds `BitVec.(getMSbD, msb)_(add, sub)` and `BitVec.getLsbD_sub` (@luisacicolini).
|
||||
* [#5712](https://github.com/leanprover/lean4/pull/5712) adds `BitVec.[udiv|umod]_[zero|one|self]` (@tobiasgrosser).
|
||||
* [#5718](https://github.com/leanprover/lean4/pull/5718) adds `BitVec.sdiv_[zero|one|self]` (@tobiasgrosser).
|
||||
* [#5721](https://github.com/leanprover/lean4/pull/5721) adds `BitVec.(msb, getMsbD, getLsbD)_(neg, abs)` (@luisacicolini).
|
||||
* [#5772](https://github.com/leanprover/lean4/pull/5772) adds `BitVec.toInt_sub`, simplifies `BitVec.toInt_neg` (@tobiasgrosser).
|
||||
* [#5778](https://github.com/leanprover/lean4/pull/5778) prove that `intMin` the smallest signed bitvector (@alexkeizer).
|
||||
* [#5851](https://github.com/leanprover/lean4/pull/5851) adds `(msb, getMsbD)_twoPow` (@luisacicolini).
|
||||
* [#5858](https://github.com/leanprover/lean4/pull/5858) adds `BitVec.[zero_ushiftRight|zero_sshiftRight|zero_mul]` and cleans up BVDecide (@tobiasgrosser).
|
||||
* [#5865](https://github.com/leanprover/lean4/pull/5865) adds `BitVec.(msb, getMsbD)_concat` (@luisacicolini).
|
||||
* [#5881](https://github.com/leanprover/lean4/pull/5881) adds `Hashable (BitVec n)`
|
||||
|
||||
* `String`/`Char`
|
||||
* [#5728](https://github.com/leanprover/lean4/pull/5728) upstreams `String.dropPrefix?`.
|
||||
* [#5745](https://github.com/leanprover/lean4/pull/5745) changes `String.dropPrefix?` signature.
|
||||
* [#5747](https://github.com/leanprover/lean4/pull/5747) adds `Hashable Char` instance
|
||||
|
||||
* `HashMap`
|
||||
* [#5880](https://github.com/leanprover/lean4/pull/5880) adds interim implementation of `HashMap.modify`/`alter`
|
||||
|
||||
* **Other**
|
||||
* [#5704](https://github.com/leanprover/lean4/pull/5704) removes `@[simp]` from `Option.isSome_eq_isSome`.
|
||||
* [#5739](https://github.com/leanprover/lean4/pull/5739) upstreams material on `Prod`.
|
||||
* [#5740](https://github.com/leanprover/lean4/pull/5740) moves `Antisymm` to `Std.Antisymm`.
|
||||
* [#5741](https://github.com/leanprover/lean4/pull/5741) upstreams basic material on `Sum`.
|
||||
* [#5756](https://github.com/leanprover/lean4/pull/5756) adds `Nat.log2_two_pow` (@spinylobster).
|
||||
* [#5892](https://github.com/leanprover/lean4/pull/5892) removes duplicated `ForIn` instances.
|
||||
* [#5900](https://github.com/leanprover/lean4/pull/5900) removes `@[simp]` from `Sum.forall` and `Sum.exists`.
|
||||
* [#5812](https://github.com/leanprover/lean4/pull/5812) removes redundant `Decidable` assumptions (@FR-vdash-bot).
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
|
||||
* [#5685](https://github.com/leanprover/lean4/pull/5685) fixes help message flags, removes the `-f` flag and adds the `-g` flag (@James-Oswald).
|
||||
* [#5930](https://github.com/leanprover/lean4/pull/5930) adds `--short-version` (`-V`) option to display short version (@juhp).
|
||||
* [#5144](https://github.com/leanprover/lean4/pull/5144) switches all 64-bit platforms over to consistently using GMP for bignum arithmetic.
|
||||
* [#5753](https://github.com/leanprover/lean4/pull/5753) raises the minimum supported Windows version to Windows 10 1903 (released May 2019).
|
||||
|
||||
### Lake
|
||||
|
||||
* [#5715](https://github.com/leanprover/lean4/pull/5715) changes `lake new math` to use `autoImplicit false` (@eric-wieser).
|
||||
* [#5688](https://github.com/leanprover/lean4/pull/5688) makes `Lake` not create core aliases in the `Lake` namespace.
|
||||
* [#5924](https://github.com/leanprover/lean4/pull/5924) adds a `text` option for `buildFile*` utilities.
|
||||
* [#5789](https://github.com/leanprover/lean4/pull/5789) makes `lake init` not `git init` when inside git work tree (@haoxins).
|
||||
* [#5684](https://github.com/leanprover/lean4/pull/5684) has Lake update a package's `lean-toolchain` file on `lake update` if it finds the package's direct dependencies use a newer compatible toolchain. To skip this step, use the `--keep-toolchain` CLI option. (See breaking changes.)
|
||||
* [#6218](https://github.com/leanprover/lean4/pull/6218) makes Lake no longer automatically fetch GitHub cloud releases if the package build directory is already present (mirroring the behavior of the Reservoir cache). This prevents the cache from clobbering existing prebuilt artifacts. Users can still manually fetch the cache and clobber the build directory by running `lake build <pkg>:release`.
|
||||
* [#6231](https://github.com/leanprover/lean4/pull/6231) improves the errors Lake produces when it fails to fetch a dependency from Reservoir. If the package is not indexed, it will produce a suggestion about how to require it from GitHub.
|
||||
|
||||
### Documentation
|
||||
|
||||
* [#5617](https://github.com/leanprover/lean4/pull/5617) fixes MSYS2 build instructions.
|
||||
* [#5725](https://github.com/leanprover/lean4/pull/5725) points out that `OfScientific` is called with raw literals (@eric-wieser).
|
||||
* [#5794](https://github.com/leanprover/lean4/pull/5794) adds a stub for application ellipsis notation (@eric-wieser).
|
||||
|
||||
### Breaking changes
|
||||
|
||||
* The syntax for providing arguments to deriving handlers has been removed, which was not used by any major Lean projects in the ecosystem. As a result, the `applyDerivingHandlers` now takes one fewer argument, `registerDerivingHandlerWithArgs` is now simply `registerDerivingHandler`, `DerivingHandler` no longer includes the unused parameter, and `DerivingHandlerNoArgs` has been deprecated. To migrate code, delete the unused `none` argument and use `registerDerivingHandler` and `DerivingHandler`. ([#5265](https://github.com/leanprover/lean4/pull/5265))
|
||||
* The minimum supported Windows version has been raised to Windows 10 1903, released May 2019. ([#5753](https://github.com/leanprover/lean4/pull/5753))
|
||||
* The `--lean` CLI option for `lake` was removed. Use the `LEAN` environment variable instead. ([#5684](https://github.com/leanprover/lean4/pull/5684))
|
||||
* The `inductive ... :=`, `structure ... :=`, and `class ... :=` syntaxes have been deprecated in favor of the `... where` variants. The old syntax produces a warning, controlled by the `linter.deprecated` option. ([#5542](https://github.com/leanprover/lean4/pull/5542))
|
||||
* The generated tactic configuration elaborators now land in `TacticM` to make use of the current recovery state. Commands that wish to elaborate configurations should now use `declare_command_config_elab` instead of `declare_config_elab` to get an elaborator landing in `CommandElabM`. Syntaxes should migrate to `optConfig` instead of `(config)?`, but the elaborators are reverse compatible. ([#5883](https://github.com/leanprover/lean4/pull/5883))
|
||||
|
||||
|
||||
v4.13.0
|
||||
----------
|
||||
|
||||
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.12.0...v4.13.0
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* `structure` command
|
||||
* [#5511](https://github.com/leanprover/lean4/pull/5511) allows structure parents to be type synonyms.
|
||||
* [#5531](https://github.com/leanprover/lean4/pull/5531) allows default values for structure fields to be noncomputable.
|
||||
|
||||
* `rfl` and `apply_rfl` tactics
|
||||
* [#3714](https://github.com/leanprover/lean4/pull/3714), [#3718](https://github.com/leanprover/lean4/pull/3718) improve the `rfl` tactic and give better error messages.
|
||||
* [#3772](https://github.com/leanprover/lean4/pull/3772) makes `rfl` no longer use kernel defeq for ground terms.
|
||||
* [#5329](https://github.com/leanprover/lean4/pull/5329) tags `Iff.refl` with `@[refl]` (@Parcly-Taxel)
|
||||
* [#5359](https://github.com/leanprover/lean4/pull/5359) ensures that the `rfl` tactic tries `Iff.rfl` (@Parcly-Taxel)
|
||||
|
||||
* `unfold` tactic
|
||||
* [#4834](https://github.com/leanprover/lean4/pull/4834) let `unfold` do zeta-delta reduction of local definitions, incorporating functionality of the Mathlib `unfold_let` tactic.
|
||||
|
||||
* `omega` tactic
|
||||
* [#5382](https://github.com/leanprover/lean4/pull/5382) fixes spurious error in [#5315](https://github.com/leanprover/lean4/issues/5315)
|
||||
* [#5523](https://github.com/leanprover/lean4/pull/5523) supports `Int.toNat`
|
||||
|
||||
* `simp` tactic
|
||||
* [#5479](https://github.com/leanprover/lean4/pull/5479) lets `simp` apply rules with higher-order patterns.
|
||||
|
||||
* `induction` tactic
|
||||
* [#5494](https://github.com/leanprover/lean4/pull/5494) fixes `induction`’s "pre-tactic" block to always be indented, avoiding unintended uses of it.
|
||||
|
||||
* `ac_nf` tactic
|
||||
* [#5524](https://github.com/leanprover/lean4/pull/5524) adds `ac_nf`, a counterpart to `ac_rfl`, for normalizing expressions with respect to associativity and commutativity. Tests it with `BitVec` expressions.
|
||||
|
||||
* `bv_decide`
|
||||
* [#5211](https://github.com/leanprover/lean4/pull/5211) makes `extractLsb'` the primitive `bv_decide` understands, rather than `extractLsb` (@alexkeizer)
|
||||
* [#5365](https://github.com/leanprover/lean4/pull/5365) adds `bv_decide` diagnoses.
|
||||
* [#5375](https://github.com/leanprover/lean4/pull/5375) adds `bv_decide` normalization rules for `ofBool (a.getLsbD i)` and `ofBool a[i]` (@alexkeizer)
|
||||
* [#5423](https://github.com/leanprover/lean4/pull/5423) enhances the rewriting rules of `bv_decide`
|
||||
* [#5433](https://github.com/leanprover/lean4/pull/5433) presents the `bv_decide` counterexample at the API
|
||||
* [#5484](https://github.com/leanprover/lean4/pull/5484) handles `BitVec.ofNat` with `Nat` fvars in `bv_decide`
|
||||
* [#5506](https://github.com/leanprover/lean4/pull/5506), [#5507](https://github.com/leanprover/lean4/pull/5507) add `bv_normalize` rules.
|
||||
* [#5568](https://github.com/leanprover/lean4/pull/5568) generalize the `bv_normalize` pipeline to support more general preprocessing passes
|
||||
* [#5573](https://github.com/leanprover/lean4/pull/5573) gets `bv_normalize` up-to-date with the current `BitVec` rewrites
|
||||
* Cleanups: [#5408](https://github.com/leanprover/lean4/pull/5408), [#5493](https://github.com/leanprover/lean4/pull/5493), [#5578](https://github.com/leanprover/lean4/pull/5578)
|
||||
|
||||
|
||||
* Elaboration improvements
|
||||
* [#5266](https://github.com/leanprover/lean4/pull/5266) preserve order of overapplied arguments in `elab_as_elim` procedure.
|
||||
* [#5510](https://github.com/leanprover/lean4/pull/5510) generalizes `elab_as_elim` to allow arbitrary motive applications.
|
||||
* [#5283](https://github.com/leanprover/lean4/pull/5283), [#5512](https://github.com/leanprover/lean4/pull/5512) refine how named arguments suppress explicit arguments. Breaking change: some previously omitted explicit arguments may need explicit `_` arguments now.
|
||||
* [#5376](https://github.com/leanprover/lean4/pull/5376) modifies projection instance binder info for instances, making parameters that are instance implicit in the type be implicit.
|
||||
* [#5402](https://github.com/leanprover/lean4/pull/5402) localizes universe metavariable errors to `let` bindings and `fun` binders if possible. Makes "cannot synthesize metavariable" errors take precedence over unsolved universe level errors.
|
||||
* [#5419](https://github.com/leanprover/lean4/pull/5419) must not reduce `ite` in the discriminant of `match`-expression when reducibility setting is `.reducible`
|
||||
* [#5474](https://github.com/leanprover/lean4/pull/5474) have autoparams report parameter/field on failure
|
||||
* [#5530](https://github.com/leanprover/lean4/pull/5530) makes automatic instance names about types with hygienic names be hygienic.
|
||||
|
||||
* Deriving handlers
|
||||
* [#5432](https://github.com/leanprover/lean4/pull/5432) makes `Repr` deriving instance handle explicit type parameters
|
||||
|
||||
* Functional induction
|
||||
* [#5364](https://github.com/leanprover/lean4/pull/5364) adds more equalities in context, more careful cleanup.
|
||||
|
||||
* Linters
|
||||
* [#5335](https://github.com/leanprover/lean4/pull/5335) fixes the unused variables linter complaining about match/tactic combinations
|
||||
* [#5337](https://github.com/leanprover/lean4/pull/5337) fixes the unused variables linter complaining about some wildcard patterns
|
||||
|
||||
* Other fixes
|
||||
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
|
||||
|
||||
* Metaprogramming
|
||||
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
|
||||
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
|
||||
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
|
||||
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.
|
||||
* [#5587](https://github.com/leanprover/lean4/pull/5587) allows `MVarId.assertHypotheses` to set `BinderInfo` and `LocalDeclKind`.
|
||||
* [#5588](https://github.com/leanprover/lean4/pull/5588) adds `MVarId.tryClearMany'`, a variant of `MVarId.tryClearMany`.
|
||||
|
||||
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
|
||||
* [#5205](https://github.com/leanprover/lean4/pull/5205) decreases the latency of auto-completion in tactic blocks.
|
||||
* [#5237](https://github.com/leanprover/lean4/pull/5237) fixes symbol occurrence highlighting in VS Code not highlighting occurrences when moving the text cursor into the identifier from the right.
|
||||
* [#5257](https://github.com/leanprover/lean4/pull/5257) fixes several instances of incorrect auto-completions being reported.
|
||||
* [#5299](https://github.com/leanprover/lean4/pull/5299) allows auto-completion to report completions for global identifiers when the elaborator fails to provide context-specific auto-completions.
|
||||
* [#5312](https://github.com/leanprover/lean4/pull/5312) fixes the server breaking when changing whitespace after the module header.
|
||||
* [#5322](https://github.com/leanprover/lean4/pull/5322) fixes several instances of auto-completion reporting non-existent namespaces.
|
||||
* [#5428](https://github.com/leanprover/lean4/pull/5428) makes sure to always report some recent file range as progress when waiting for elaboration.
|
||||
|
||||
|
||||
### Pretty printing
|
||||
|
||||
* [#4979](https://github.com/leanprover/lean4/pull/4979) make pretty printer escape identifiers that are tokens.
|
||||
* [#5389](https://github.com/leanprover/lean4/pull/5389) makes formatter use the current token table.
|
||||
* [#5513](https://github.com/leanprover/lean4/pull/5513) use breakable instead of unbreakable whitespace when formatting tokens.
|
||||
|
||||
|
||||
### Library
|
||||
|
||||
* [#5222](https://github.com/leanprover/lean4/pull/5222) reduces allocations in `Json.compress`.
|
||||
* [#5231](https://github.com/leanprover/lean4/pull/5231) upstreams `Zero` and `NeZero`
|
||||
* [#5292](https://github.com/leanprover/lean4/pull/5292) refactors `Lean.Elab.Deriving.FromToJson` (@arthur-adjedj)
|
||||
* [#5415](https://github.com/leanprover/lean4/pull/5415) implements `Repr Empty` (@TomasPuverle)
|
||||
* [#5421](https://github.com/leanprover/lean4/pull/5421) implements `To/FromJSON Empty` (@TomasPuverle)
|
||||
|
||||
* Logic
|
||||
* [#5263](https://github.com/leanprover/lean4/pull/5263) allows simplifying `dite_not`/`decide_not` with only `Decidable (¬p)`.
|
||||
* [#5268](https://github.com/leanprover/lean4/pull/5268) fixes binders on `ite_eq_left_iff`
|
||||
* [#5284](https://github.com/leanprover/lean4/pull/5284) turns off `Inhabited (Sum α β)` instances
|
||||
* [#5355](https://github.com/leanprover/lean4/pull/5355) adds simp lemmas for `LawfulBEq`
|
||||
* [#5374](https://github.com/leanprover/lean4/pull/5374) add `Nonempty` instances for products, allowing more `partial` functions to elaborate successfully
|
||||
* [#5447](https://github.com/leanprover/lean4/pull/5447) updates Pi instance names
|
||||
* [#5454](https://github.com/leanprover/lean4/pull/5454) makes some instance arguments implicit
|
||||
* [#5456](https://github.com/leanprover/lean4/pull/5456) adds `heq_comm`
|
||||
* [#5529](https://github.com/leanprover/lean4/pull/5529) moves `@[simp]` from `exists_prop'` to `exists_prop`
|
||||
|
||||
* `Bool`
|
||||
* [#5228](https://github.com/leanprover/lean4/pull/5228) fills gaps in Bool lemmas
|
||||
* [#5332](https://github.com/leanprover/lean4/pull/5332) adds notation `^^` for Bool.xor
|
||||
* [#5351](https://github.com/leanprover/lean4/pull/5351) removes `_root_.and` (and or/not/xor) and instead exports/uses `Bool.and` (etc.).
|
||||
|
||||
* `BitVec`
|
||||
* [#5240](https://github.com/leanprover/lean4/pull/5240) removes BitVec simps with complicated RHS
|
||||
* [#5247](https://github.com/leanprover/lean4/pull/5247) `BitVec.getElem_zeroExtend`
|
||||
* [#5248](https://github.com/leanprover/lean4/pull/5248) simp lemmas for BitVec, improving confluence
|
||||
* [#5249](https://github.com/leanprover/lean4/pull/5249) removes `@[simp]` from some BitVec lemmas
|
||||
* [#5252](https://github.com/leanprover/lean4/pull/5252) changes `BitVec.intMin/Max` from abbrev to def
|
||||
* [#5278](https://github.com/leanprover/lean4/pull/5278) adds `BitVec.getElem_truncate` (@tobiasgrosser)
|
||||
* [#5281](https://github.com/leanprover/lean4/pull/5281) adds udiv/umod bitblasting for `bv_decide` (@bollu)
|
||||
* [#5297](https://github.com/leanprover/lean4/pull/5297) `BitVec` unsigned order theoretic results
|
||||
* [#5313](https://github.com/leanprover/lean4/pull/5313) adds more basic BitVec ordering theory for UInt
|
||||
* [#5314](https://github.com/leanprover/lean4/pull/5314) adds `toNat_sub_of_le` (@bollu)
|
||||
* [#5357](https://github.com/leanprover/lean4/pull/5357) adds `BitVec.truncate` lemmas
|
||||
* [#5358](https://github.com/leanprover/lean4/pull/5358) introduces `BitVec.setWidth` to unify zeroExtend and truncate (@tobiasgrosser)
|
||||
* [#5361](https://github.com/leanprover/lean4/pull/5361) some BitVec GetElem lemmas
|
||||
* [#5385](https://github.com/leanprover/lean4/pull/5385) adds `BitVec.ofBool_[and|or|xor]_ofBool` theorems (@tobiasgrosser)
|
||||
* [#5404](https://github.com/leanprover/lean4/pull/5404) more of `BitVec.getElem_*` (@tobiasgrosser)
|
||||
* [#5410](https://github.com/leanprover/lean4/pull/5410) BitVec analogues of `Nat.{mul_two, two_mul, mul_succ, succ_mul}` (@bollu)
|
||||
* [#5411](https://github.com/leanprover/lean4/pull/5411) `BitVec.toNat_{add,sub,mul_of_lt}` for BitVector non-overflow reasoning (@bollu)
|
||||
* [#5413](https://github.com/leanprover/lean4/pull/5413) adds `_self`, `_zero`, and `_allOnes` for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5416](https://github.com/leanprover/lean4/pull/5416) adds LawCommIdentity + IdempotentOp for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5418](https://github.com/leanprover/lean4/pull/5418) decidable quantifers for BitVec
|
||||
* [#5450](https://github.com/leanprover/lean4/pull/5450) adds `BitVec.toInt_[intMin|neg|neg_of_ne_intMin]` (@tobiasgrosser)
|
||||
* [#5459](https://github.com/leanprover/lean4/pull/5459) missing BitVec lemmas
|
||||
* [#5469](https://github.com/leanprover/lean4/pull/5469) adds `BitVec.[not_not, allOnes_shiftLeft_or_shiftLeft, allOnes_shiftLeft_and_shiftLeft]` (@luisacicolini)
|
||||
* [#5478](https://github.com/leanprover/lean4/pull/5478) adds `BitVec.(shiftLeft_add_distrib, shiftLeft_ushiftRight)` (@luisacicolini)
|
||||
* [#5487](https://github.com/leanprover/lean4/pull/5487) adds `sdiv_eq`, `smod_eq` to allow `sdiv`/`smod` bitblasting (@bollu)
|
||||
* [#5491](https://github.com/leanprover/lean4/pull/5491) adds `BitVec.toNat_[abs|sdiv|smod]` (@tobiasgrosser)
|
||||
* [#5492](https://github.com/leanprover/lean4/pull/5492) `BitVec.(not_sshiftRight, not_sshiftRight_not, getMsb_not, msb_not)` (@luisacicolini)
|
||||
* [#5499](https://github.com/leanprover/lean4/pull/5499) `BitVec.Lemmas` - drop non-terminal simps (@tobiasgrosser)
|
||||
* [#5505](https://github.com/leanprover/lean4/pull/5505) unsimps `BitVec.divRec_succ'`
|
||||
* [#5508](https://github.com/leanprover/lean4/pull/5508) adds `BitVec.getElem_[add|add_add_bool|mul|rotateLeft|rotateRight…` (@tobiasgrosser)
|
||||
* [#5554](https://github.com/leanprover/lean4/pull/5554) adds `Bitvec.[add, sub, mul]_eq_xor` and `width_one_cases` (@luisacicolini)
|
||||
|
||||
* `List`
|
||||
* [#5242](https://github.com/leanprover/lean4/pull/5242) improve naming for `List.mergeSort` lemmas
|
||||
* [#5302](https://github.com/leanprover/lean4/pull/5302) provide `mergeSort` comparator autoParam
|
||||
* [#5373](https://github.com/leanprover/lean4/pull/5373) fix name of `List.length_mergeSort`
|
||||
* [#5377](https://github.com/leanprover/lean4/pull/5377) upstream `map_mergeSort`
|
||||
* [#5378](https://github.com/leanprover/lean4/pull/5378) modify signature of lemmas about `mergeSort`
|
||||
* [#5245](https://github.com/leanprover/lean4/pull/5245) avoid importing `List.Basic` without List.Impl
|
||||
* [#5260](https://github.com/leanprover/lean4/pull/5260) review of List API
|
||||
* [#5264](https://github.com/leanprover/lean4/pull/5264) review of List API
|
||||
* [#5269](https://github.com/leanprover/lean4/pull/5269) remove HashMap's duplicated Pairwise and Sublist
|
||||
* [#5271](https://github.com/leanprover/lean4/pull/5271) remove @[simp] from `List.head_mem` and similar
|
||||
* [#5273](https://github.com/leanprover/lean4/pull/5273) lemmas about `List.attach`
|
||||
* [#5275](https://github.com/leanprover/lean4/pull/5275) reverse direction of `List.tail_map`
|
||||
* [#5277](https://github.com/leanprover/lean4/pull/5277) more `List.attach` lemmas
|
||||
* [#5285](https://github.com/leanprover/lean4/pull/5285) `List.count` lemmas
|
||||
* [#5287](https://github.com/leanprover/lean4/pull/5287) use boolean predicates in `List.filter`
|
||||
* [#5289](https://github.com/leanprover/lean4/pull/5289) `List.mem_ite_nil_left` and analogues
|
||||
* [#5293](https://github.com/leanprover/lean4/pull/5293) cleanup of `List.findIdx` / `List.take` lemmas
|
||||
* [#5294](https://github.com/leanprover/lean4/pull/5294) switch primes on `List.getElem_take`
|
||||
* [#5300](https://github.com/leanprover/lean4/pull/5300) more `List.findIdx` theorems
|
||||
* [#5310](https://github.com/leanprover/lean4/pull/5310) fix `List.all/any` lemmas
|
||||
* [#5311](https://github.com/leanprover/lean4/pull/5311) fix `List.countP` lemmas
|
||||
* [#5316](https://github.com/leanprover/lean4/pull/5316) `List.tail` lemma
|
||||
* [#5331](https://github.com/leanprover/lean4/pull/5331) fix implicitness of `List.getElem_mem`
|
||||
* [#5350](https://github.com/leanprover/lean4/pull/5350) `List.replicate` lemmas
|
||||
* [#5352](https://github.com/leanprover/lean4/pull/5352) `List.attachWith` lemmas
|
||||
* [#5353](https://github.com/leanprover/lean4/pull/5353) `List.head_mem_head?`
|
||||
* [#5360](https://github.com/leanprover/lean4/pull/5360) lemmas about `List.tail`
|
||||
* [#5391](https://github.com/leanprover/lean4/pull/5391) review of `List.erase` / `List.find` lemmas
|
||||
* [#5392](https://github.com/leanprover/lean4/pull/5392) `List.fold` / `attach` lemmas
|
||||
* [#5393](https://github.com/leanprover/lean4/pull/5393) `List.fold` relators
|
||||
* [#5394](https://github.com/leanprover/lean4/pull/5394) lemmas about `List.maximum?`
|
||||
* [#5403](https://github.com/leanprover/lean4/pull/5403) theorems about `List.toArray`
|
||||
* [#5405](https://github.com/leanprover/lean4/pull/5405) reverse direction of `List.set_map`
|
||||
* [#5448](https://github.com/leanprover/lean4/pull/5448) add lemmas about `List.IsPrefix` (@Command-Master)
|
||||
* [#5460](https://github.com/leanprover/lean4/pull/5460) missing `List.set_replicate_self`
|
||||
* [#5518](https://github.com/leanprover/lean4/pull/5518) rename `List.maximum?` to `max?`
|
||||
* [#5519](https://github.com/leanprover/lean4/pull/5519) upstream `List.fold` lemmas
|
||||
* [#5520](https://github.com/leanprover/lean4/pull/5520) restore `@[simp]` on `List.getElem_mem` etc.
|
||||
* [#5521](https://github.com/leanprover/lean4/pull/5521) List simp fixes
|
||||
* [#5550](https://github.com/leanprover/lean4/pull/5550) `List.unattach` and simp lemmas
|
||||
* [#5594](https://github.com/leanprover/lean4/pull/5594) induction-friendly `List.min?_cons`
|
||||
|
||||
* `Array`
|
||||
* [#5246](https://github.com/leanprover/lean4/pull/5246) cleanup imports of Array.Lemmas
|
||||
* [#5255](https://github.com/leanprover/lean4/pull/5255) split Init.Data.Array.Lemmas for better bootstrapping
|
||||
* [#5288](https://github.com/leanprover/lean4/pull/5288) rename `Array.data` to `Array.toList`
|
||||
* [#5303](https://github.com/leanprover/lean4/pull/5303) cleanup of `List.getElem_append` variants
|
||||
* [#5304](https://github.com/leanprover/lean4/pull/5304) `Array.not_mem_empty`
|
||||
* [#5400](https://github.com/leanprover/lean4/pull/5400) reorganization in Array/Basic
|
||||
* [#5420](https://github.com/leanprover/lean4/pull/5420) make `Array` functions either semireducible or use structural recursion
|
||||
* [#5422](https://github.com/leanprover/lean4/pull/5422) refactor `DecidableEq (Array α)`
|
||||
* [#5452](https://github.com/leanprover/lean4/pull/5452) refactor of Array
|
||||
* [#5458](https://github.com/leanprover/lean4/pull/5458) cleanup of Array docstrings after refactor
|
||||
* [#5461](https://github.com/leanprover/lean4/pull/5461) restore `@[simp]` on `Array.swapAt!_def`
|
||||
* [#5465](https://github.com/leanprover/lean4/pull/5465) improve Array GetElem lemmas
|
||||
* [#5466](https://github.com/leanprover/lean4/pull/5466) `Array.foldX` lemmas
|
||||
* [#5472](https://github.com/leanprover/lean4/pull/5472) @[simp] lemmas about `List.toArray`
|
||||
* [#5485](https://github.com/leanprover/lean4/pull/5485) reverse simp direction for `toArray_concat`
|
||||
* [#5514](https://github.com/leanprover/lean4/pull/5514) `Array.eraseReps`
|
||||
* [#5515](https://github.com/leanprover/lean4/pull/5515) upstream `Array.qsortOrd`
|
||||
* [#5516](https://github.com/leanprover/lean4/pull/5516) upstream `Subarray.empty`
|
||||
* [#5526](https://github.com/leanprover/lean4/pull/5526) fix name of `Array.length_toList`
|
||||
* [#5527](https://github.com/leanprover/lean4/pull/5527) reduce use of deprecated lemmas in Array
|
||||
* [#5534](https://github.com/leanprover/lean4/pull/5534) cleanup of Array GetElem lemmas
|
||||
* [#5536](https://github.com/leanprover/lean4/pull/5536) fix `Array.modify` lemmas
|
||||
* [#5551](https://github.com/leanprover/lean4/pull/5551) upstream `Array.flatten` lemmas
|
||||
* [#5552](https://github.com/leanprover/lean4/pull/5552) switch obvious cases of array "bang"`[]!` indexing to rely on hypothesis (@TomasPuverle)
|
||||
* [#5577](https://github.com/leanprover/lean4/pull/5577) add missing simp to `Array.size_feraseIdx`
|
||||
* [#5586](https://github.com/leanprover/lean4/pull/5586) `Array/Option.unattach`
|
||||
|
||||
* `Option`
|
||||
* [#5272](https://github.com/leanprover/lean4/pull/5272) remove @[simp] from `Option.pmap/pbind` and add simp lemmas
|
||||
* [#5307](https://github.com/leanprover/lean4/pull/5307) restoring Option simp confluence
|
||||
* [#5354](https://github.com/leanprover/lean4/pull/5354) remove @[simp] from `Option.bind_map`
|
||||
* [#5532](https://github.com/leanprover/lean4/pull/5532) `Option.attach`
|
||||
* [#5539](https://github.com/leanprover/lean4/pull/5539) fix explicitness of `Option.mem_toList`
|
||||
|
||||
* `Nat`
|
||||
* [#5241](https://github.com/leanprover/lean4/pull/5241) add @[simp] to `Nat.add_eq_zero_iff`
|
||||
* [#5261](https://github.com/leanprover/lean4/pull/5261) Nat bitwise lemmas
|
||||
* [#5262](https://github.com/leanprover/lean4/pull/5262) `Nat.testBit_add_one` should not be a global simp lemma
|
||||
* [#5267](https://github.com/leanprover/lean4/pull/5267) protect some Nat bitwise theorems
|
||||
* [#5305](https://github.com/leanprover/lean4/pull/5305) rename Nat bitwise lemmas
|
||||
* [#5306](https://github.com/leanprover/lean4/pull/5306) add `Nat.self_sub_mod` lemma
|
||||
* [#5503](https://github.com/leanprover/lean4/pull/5503) restore @[simp] to upstreamed `Nat.lt_off_iff`
|
||||
|
||||
* `Int`
|
||||
* [#5301](https://github.com/leanprover/lean4/pull/5301) rename `Int.div/mod` to `Int.tdiv/tmod`
|
||||
* [#5320](https://github.com/leanprover/lean4/pull/5320) add `ediv_nonneg_of_nonpos_of_nonpos` to DivModLemmas (@sakehl)
|
||||
|
||||
* `Fin`
|
||||
* [#5250](https://github.com/leanprover/lean4/pull/5250) missing lemma about `Fin.ofNat'`
|
||||
* [#5356](https://github.com/leanprover/lean4/pull/5356) `Fin.ofNat'` uses `NeZero`
|
||||
* [#5379](https://github.com/leanprover/lean4/pull/5379) remove some @[simp]s from Fin lemmas
|
||||
* [#5380](https://github.com/leanprover/lean4/pull/5380) missing Fin @[simp] lemmas
|
||||
|
||||
* `HashMap`
|
||||
* [#5244](https://github.com/leanprover/lean4/pull/5244) (`DHashMap`|`HashMap`|`HashSet`).(`getKey?`|`getKey`|`getKey!`|`getKeyD`)
|
||||
* [#5362](https://github.com/leanprover/lean4/pull/5362) remove the last use of `Lean.(HashSet|HashMap)`
|
||||
* [#5369](https://github.com/leanprover/lean4/pull/5369) `HashSet.ofArray`
|
||||
* [#5370](https://github.com/leanprover/lean4/pull/5370) `HashSet.partition`
|
||||
* [#5581](https://github.com/leanprover/lean4/pull/5581) `Singleton`/`Insert`/`Union` instances for `HashMap`/`Set`
|
||||
* [#5582](https://github.com/leanprover/lean4/pull/5582) `HashSet.all`/`any`
|
||||
* [#5590](https://github.com/leanprover/lean4/pull/5590) adding `Insert`/`Singleton`/`Union` instances for `HashMap`/`Set.Raw`
|
||||
* [#5591](https://github.com/leanprover/lean4/pull/5591) `HashSet.Raw.all/any`
|
||||
|
||||
* `Monads`
|
||||
* [#5463](https://github.com/leanprover/lean4/pull/5463) upstream some monad lemmas
|
||||
* [#5464](https://github.com/leanprover/lean4/pull/5464) adjust simp attributes on monad lemmas
|
||||
* [#5522](https://github.com/leanprover/lean4/pull/5522) more monadic simp lemmas
|
||||
|
||||
* Simp lemma cleanup
|
||||
* [#5251](https://github.com/leanprover/lean4/pull/5251) remove redundant simp annotations
|
||||
* [#5253](https://github.com/leanprover/lean4/pull/5253) remove Int simp lemmas that can't fire
|
||||
* [#5254](https://github.com/leanprover/lean4/pull/5254) variables appearing on both sides of an iff should be implicit
|
||||
* [#5381](https://github.com/leanprover/lean4/pull/5381) cleaning up redundant simp lemmas
|
||||
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
|
||||
* [#4685](https://github.com/leanprover/lean4/pull/4685) fixes a typo in the C `run_new_frontend` signature
|
||||
* [#4729](https://github.com/leanprover/lean4/pull/4729) has IR checker suggest using `noncomputable`
|
||||
* [#5143](https://github.com/leanprover/lean4/pull/5143) adds a shared library for Lake
|
||||
* [#5437](https://github.com/leanprover/lean4/pull/5437) removes (syntactically) duplicate imports (@euprunin)
|
||||
* [#5462](https://github.com/leanprover/lean4/pull/5462) updates `src/lake/lakefile.toml` to the adjusted Lake build process
|
||||
* [#5541](https://github.com/leanprover/lean4/pull/5541) removes new shared libs before build to better support Windows
|
||||
* [#5558](https://github.com/leanprover/lean4/pull/5558) make `lean.h` compile with MSVC (@kant2002)
|
||||
* [#5564](https://github.com/leanprover/lean4/pull/5564) removes non-conforming size-0 arrays (@eric-wieser)
|
||||
|
||||
|
||||
### Lake
|
||||
* Reservoir build cache. Lake will now attempt to fetch a pre-built copy of the package from Reservoir before building it. This is only enabled for packages in the leanprover or leanprover-community organizations on versions indexed by Reservoir. Users can force Lake to build packages from the source by passing --no-cache on the CLI or by setting the LAKE_NO_CACHE environment variable to true. [#5486](https://github.com/leanprover/lean4/pull/5486), [#5572](https://github.com/leanprover/lean4/pull/5572), [#5583](https://github.com/leanprover/lean4/pull/5583), [#5600](https://github.com/leanprover/lean4/pull/5600), [#5641](https://github.com/leanprover/lean4/pull/5641), [#5642](https://github.com/leanprover/lean4/pull/5642).
|
||||
* [#5504](https://github.com/leanprover/lean4/pull/5504) lake new and lake init now produce TOML configurations by default.
|
||||
* [#5878](https://github.com/leanprover/lean4/pull/5878) fixes a serious issue where Lake would delete path dependencies when attempting to cleanup a dependency required with an incorrect name.
|
||||
|
||||
* **Breaking changes**
|
||||
* [#5641](https://github.com/leanprover/lean4/pull/5641) A Lake build of target within a package will no longer build a package's dependencies package-level extra target dependencies. At the technical level, a package's extraDep facet no longer transitively builds its dependencies’ extraDep facets (which include their extraDepTargets).
|
||||
|
||||
### Documentation fixes
|
||||
|
||||
* [#3918](https://github.com/leanprover/lean4/pull/3918) `@[builtin_doc]` attribute (@digama0)
|
||||
* [#4305](https://github.com/leanprover/lean4/pull/4305) explains the borrow syntax (@eric-wieser)
|
||||
* [#5349](https://github.com/leanprover/lean4/pull/5349) adds documentation for `groupBy.loop` (@vihdzp)
|
||||
* [#5473](https://github.com/leanprover/lean4/pull/5473) fixes typo in `BitVec.mul` docstring (@llllvvuu)
|
||||
* [#5476](https://github.com/leanprover/lean4/pull/5476) fixes typos in `Lean.MetavarContext`
|
||||
* [#5481](https://github.com/leanprover/lean4/pull/5481) removes mention of `Lean.withSeconds` (@alexkeizer)
|
||||
* [#5497](https://github.com/leanprover/lean4/pull/5497) updates documentation and tests for `toUIntX` functions (@TomasPuverle)
|
||||
* [#5087](https://github.com/leanprover/lean4/pull/5087) mentions that `inferType` does not ensure type correctness
|
||||
* Many fixes to spelling across the doc-strings, (@euprunin): [#5425](https://github.com/leanprover/lean4/pull/5425) [#5426](https://github.com/leanprover/lean4/pull/5426) [#5427](https://github.com/leanprover/lean4/pull/5427) [#5430](https://github.com/leanprover/lean4/pull/5430) [#5431](https://github.com/leanprover/lean4/pull/5431) [#5434](https://github.com/leanprover/lean4/pull/5434) [#5435](https://github.com/leanprover/lean4/pull/5435) [#5436](https://github.com/leanprover/lean4/pull/5436) [#5438](https://github.com/leanprover/lean4/pull/5438) [#5439](https://github.com/leanprover/lean4/pull/5439) [#5440](https://github.com/leanprover/lean4/pull/5440) [#5599](https://github.com/leanprover/lean4/pull/5599)
|
||||
|
||||
### Changes to CI
|
||||
|
||||
* [#5343](https://github.com/leanprover/lean4/pull/5343) allows addition of `release-ci` label via comment (@thorimur)
|
||||
* [#5344](https://github.com/leanprover/lean4/pull/5344) sets check level correctly during workflow (@thorimur)
|
||||
* [#5444](https://github.com/leanprover/lean4/pull/5444) Mathlib's `lean-pr-testing-NNNN` branches should use Batteries' `lean-pr-testing-NNNN` branches
|
||||
* [#5489](https://github.com/leanprover/lean4/pull/5489) commit `lake-manifest.json` when updating `lean-pr-testing` branches
|
||||
* [#5490](https://github.com/leanprover/lean4/pull/5490) use separate secrets for commenting and branching in `pr-release.yml`
|
||||
|
||||
v4.12.0
|
||||
----------
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[0829/202002.254:ERROR:crashpad_client_win.cc(868)] not connected
|
||||
@@ -103,10 +103,21 @@ your PR using rebase merge, bypassing the merge queue.
|
||||
As written above, changes in meta code in the current stage usually will only
|
||||
affect later stages. This is an issue in two specific cases.
|
||||
|
||||
* For the special case of *quotations*, it is desirable to have changes in builtin parsers affect them immediately: when the changes in the parser become active in the next stage, builtin macros implemented via quotations should generate syntax trees compatible with the new parser, and quotation patterns in builtin macros and elaborators should be able to match syntax created by the new parser and macros.
|
||||
Since quotations capture the syntax tree structure during execution of the current stage and turn it into code for the next stage, we need to run the current stage's builtin parsers in quotations via the interpreter for this to work.
|
||||
Caveats:
|
||||
* We activate this behavior by default when building stage 1 by setting `-Dinternal.parseQuotWithCurrentStage=true`.
|
||||
We force-disable it inside `macro/macro_rules/elab/elab_rules` via `suppressInsideQuot` as they are guaranteed not to run in the next stage and may need to be run in the current one, so the stage 0 parser is the correct one to use for them.
|
||||
It may be necessary to extend this disabling to functions that contain quotations and are (exclusively) used by one of the mentioned commands. A function using quotations should never be used by both builtin and non-builtin macros/elaborators. Example: https://github.com/leanprover/lean4/blob/f70b7e5722da6101572869d87832494e2f8534b7/src/Lean/Elab/Tactic/Config.lean#L118-L122
|
||||
* The parser needs to be reachable via an `import` statement, otherwise the version of the previous stage will silently be used.
|
||||
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading tokens is taken from the previous stage.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422R13
|
||||
|
||||
* For *non-builtin* meta code such as `notation`s or `macro`s in
|
||||
`Notation.lean`, we expect changes to affect the current file and all later
|
||||
files of the same stage immediately, just like outside the stdlib. To ensure
|
||||
this, we need to build the stage using `-Dinterpreter.prefer_native=false` -
|
||||
this, we build stage 1 using `-Dinterpreter.prefer_native=false` -
|
||||
otherwise, when executing a macro, the interpreter would notice that there is
|
||||
already a native symbol available for this function and run it instead of the
|
||||
new IR, but the symbol is from the previous stage!
|
||||
@@ -124,26 +135,11 @@ affect later stages. This is an issue in two specific cases.
|
||||
further stages (e.g. after an `update-stage0`) will then need to be compiled
|
||||
with the flag set to `false` again since they will expect the new signature.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
|
||||
When enabling `prefer_native`, we usually want to *disable* `parseQuotWithCurrentStage` as it would otherwise make quotations use the interpreter after all.
|
||||
However, there is a specific case where we want to set both options to `true`: when we make changes to a non-builtin parser like `simp` that has a builtin elaborator, we cannot have the new parser be active outside of quotations in stage 1 as the builtin elaborator from stage 0 would not understand them; on the other hand, we need quotations in e.g. the builtin `simp` elaborator to produce the new syntax in the next stage.
|
||||
As this issue usually affects only tactics, enabling `debug.byAsSorry` instead of `prefer_native` can be a simpler solution.
|
||||
|
||||
* For the special case of *quotations*, it is desirable to have changes in
|
||||
built-in parsers affect them immediately: when the changes in the parser
|
||||
become active in the next stage, macros implemented via quotations should
|
||||
generate syntax trees compatible with the new parser, and quotation patterns
|
||||
in macro and elaborators should be able to match syntax created by the new
|
||||
parser and macros. Since quotations capture the syntax tree structure during
|
||||
execution of the current stage and turn it into code for the next stage, we
|
||||
need to run the current stage's built-in parsers in quotation via the
|
||||
interpreter for this to work. Caveats:
|
||||
* Since interpreting full parsers is not nearly as cheap and we rarely change
|
||||
built-in syntax, this needs to be opted in using `-Dinternal.parseQuotWithCurrentStage=true`.
|
||||
* The parser needs to be reachable via an `import` statement, otherwise the
|
||||
version of the previous stage will silently be used.
|
||||
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading
|
||||
tokens is taken from the previous stage.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422
|
||||
(from before the flag defaulted to `false`).
|
||||
For a `prefer_native` example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
|
||||
|
||||
To modify either of these flags both for building and editing the stdlib, adjust
|
||||
the code in `stage0/src/stdlib_flags.h`. The flags will automatically be reset
|
||||
|
||||
@@ -12,17 +12,17 @@ Remark: this example is based on an example found in the Idris manual.
|
||||
Vectors
|
||||
--------
|
||||
|
||||
A `Vector` is a list of size `n` whose elements belong to a type `α`.
|
||||
A `Vec` is a list of size `n` whose elements belong to a type `α`.
|
||||
-/
|
||||
|
||||
inductive Vector (α : Type u) : Nat → Type u
|
||||
| nil : Vector α 0
|
||||
| cons : α → Vector α n → Vector α (n+1)
|
||||
inductive Vec (α : Type u) : Nat → Type u
|
||||
| nil : Vec α 0
|
||||
| cons : α → Vec α n → Vec α (n+1)
|
||||
|
||||
/-!
|
||||
We can overload the `List.cons` notation `::` and use it to create `Vector`s.
|
||||
We can overload the `List.cons` notation `::` and use it to create `Vec`s.
|
||||
-/
|
||||
infix:67 " :: " => Vector.cons
|
||||
infix:67 " :: " => Vec.cons
|
||||
|
||||
/-!
|
||||
Now, we define the types of our simple functional language.
|
||||
@@ -50,11 +50,11 @@ the builtin instance for `Add Int` as the solution.
|
||||
/-!
|
||||
Expressions are indexed by the types of the local variables, and the type of the expression itself.
|
||||
-/
|
||||
inductive HasType : Fin n → Vector Ty n → Ty → Type where
|
||||
inductive HasType : Fin n → Vec Ty n → Ty → Type where
|
||||
| stop : HasType 0 (ty :: ctx) ty
|
||||
| pop : HasType k ctx ty → HasType k.succ (u :: ctx) ty
|
||||
|
||||
inductive Expr : Vector Ty n → Ty → Type where
|
||||
inductive Expr : Vec Ty n → Ty → Type where
|
||||
| var : HasType i ctx ty → Expr ctx ty
|
||||
| val : Int → Expr ctx Ty.int
|
||||
| lam : Expr (a :: ctx) ty → Expr ctx (Ty.fn a ty)
|
||||
@@ -102,8 +102,8 @@ indexed over the types in scope. Since an environment is just another form of li
|
||||
to the vector of local variable types, we overload again the notation `::` so that we can use the usual list syntax.
|
||||
Given a proof that a variable is defined in the context, we can then produce a value from the environment.
|
||||
-/
|
||||
inductive Env : Vector Ty n → Type where
|
||||
| nil : Env Vector.nil
|
||||
inductive Env : Vec Ty n → Type where
|
||||
| nil : Env Vec.nil
|
||||
| cons : Ty.interp a → Env ctx → Env (a :: ctx)
|
||||
|
||||
infix:67 " :: " => Env.cons
|
||||
|
||||
@@ -82,9 +82,7 @@ theorem Expr.typeCheck_correct (h₁ : HasType e ty) (h₂ : e.typeCheck ≠ .un
|
||||
/-!
|
||||
Now, we prove that if `Expr.typeCheck e` returns `Maybe.unknown`, then forall `ty`, `HasType e ty` does not hold.
|
||||
The notation `e.typeCheck` is sugar for `Expr.typeCheck e`. Lean can infer this because we explicitly said that `e` has type `Expr`.
|
||||
The proof is by induction on `e` and case analysis. The tactic `rename_i` is used to rename "inaccessible" variables.
|
||||
We say a variable is inaccessible if it is introduced by a tactic (e.g., `cases`) or has been shadowed by another variable introduced
|
||||
by the user. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
|
||||
The proof is by induction on `e` and case analysis. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
|
||||
the cases corresponding to the constructors `Expr.nat` and `Expr.bool`.
|
||||
-/
|
||||
theorem Expr.typeCheck_complete {e : Expr} : e.typeCheck = .unknown → ¬ HasType e ty := by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
source ../../tests/common.sh
|
||||
|
||||
exec_check lean -Dlinter.all=false "$f"
|
||||
exec_check_raw lean -Dlinter.all=false "$f"
|
||||
|
||||
@@ -128,16 +128,16 @@ Numeric literals can be specified in various bases.
|
||||
|
||||
```
|
||||
numeral : numeral10 | numeral2 | numeral8 | numeral16
|
||||
numeral10 : [0-9]+
|
||||
numeral2 : "0" [bB] [0-1]+
|
||||
numeral8 : "0" [oO] [0-7]+
|
||||
numeral16 : "0" [xX] hex_char+
|
||||
numeral10 : [0-9]+ ("_"+ [0-9]+)*
|
||||
numeral2 : "0" [bB] ("_"* [0-1]+)+
|
||||
numeral8 : "0" [oO] ("_"* [0-7]+)+
|
||||
numeral16 : "0" [xX] ("_"* hex_char+)+
|
||||
```
|
||||
|
||||
Floating point literals are also possible with optional exponent:
|
||||
|
||||
```
|
||||
float : [0-9]+ "." [0-9]+ [[eE[+-][0-9]+]
|
||||
float : numeral10 "." numeral10? [eE[+-]numeral10]
|
||||
```
|
||||
|
||||
For example:
|
||||
@@ -147,6 +147,7 @@ constant w : Int := 55
|
||||
constant x : Nat := 26085
|
||||
constant y : Nat := 0x65E5
|
||||
constant z : Float := 2.548123e-05
|
||||
constant b : Bool := 0b_11_01_10_00
|
||||
```
|
||||
|
||||
Note: that negative numbers are created by applying the "-" negation prefix operator to the number, for example:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](doc/dev/index.md).
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Quickstart](doc/quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -15,6 +15,13 @@ Mode](https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-devi
|
||||
which will allow Lean to create symlinks that e.g. enable go-to-definition in
|
||||
the stdlib.
|
||||
|
||||
## Installing the Windows SDK
|
||||
|
||||
Install the Windows SDK from [Microsoft](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/).
|
||||
The oldest supported version is 10.0.18362.0. If you installed the Windows SDK to the default location,
|
||||
then there should be a directory with the version number at `C:\Program Files (x86)\Windows Kits\10\Include`.
|
||||
If there are multiple directories, only the highest version number matters.
|
||||
|
||||
## Installing dependencies
|
||||
|
||||
[The official webpage of MSYS2][msys2] provides one-click installers.
|
||||
|
||||
@@ -138,8 +138,8 @@ definition:
|
||||
|
||||
-/
|
||||
instance : Applicative List where
|
||||
pure := List.pure
|
||||
seq f x := List.bind f fun y => Functor.map y (x ())
|
||||
pure := List.singleton
|
||||
seq f x := List.flatMap f fun y => Functor.map y (x ())
|
||||
/-!
|
||||
|
||||
Notice you can now sequence a _list_ of functions and a _list_ of items.
|
||||
|
||||
@@ -128,8 +128,8 @@ Applying the identity function through an applicative structure should not chang
|
||||
values or structure. For example:
|
||||
-/
|
||||
instance : Applicative List where
|
||||
pure := List.pure
|
||||
seq f x := List.bind f fun y => Functor.map y (x ())
|
||||
pure := List.singleton
|
||||
seq f x := List.flatMap f fun y => Functor.map y (x ())
|
||||
|
||||
#eval pure id <*> [1, 2, 3] -- [1, 2, 3]
|
||||
/-!
|
||||
@@ -235,8 +235,8 @@ structure or its values.
|
||||
Left identity is `x >>= pure = x` and is demonstrated by the following examples on a monadic `List`:
|
||||
-/
|
||||
instance : Monad List where
|
||||
pure := List.pure
|
||||
bind := List.bind
|
||||
pure := List.singleton
|
||||
bind := List.flatMap
|
||||
|
||||
def a := ["apple", "orange"]
|
||||
|
||||
|
||||
@@ -192,8 +192,8 @@ implementation of `pure` and `bind`.
|
||||
|
||||
-/
|
||||
instance : Monad List where
|
||||
pure := List.pure
|
||||
bind := List.bind
|
||||
pure := List.singleton
|
||||
bind := List.flatMap
|
||||
/-!
|
||||
|
||||
Like you saw with the applicative `seq` operator, the `bind` operator applies the given function
|
||||
|
||||
@@ -139,7 +139,7 @@ You might be wondering, how does the context actually move through the `ReaderM`
|
||||
add an input argument to a function by modifying its return type? There is a special command in
|
||||
Lean that will show you the reduced types:
|
||||
-/
|
||||
#reduce ReaderM Environment String -- Environment → String
|
||||
#reduce (types := true) ReaderM Environment String -- Environment → String
|
||||
/-!
|
||||
And you can see here that this type is actually a function! It's a function that takes an
|
||||
`Environment` as input and returns a `String`.
|
||||
@@ -196,4 +196,4 @@ entirely.
|
||||
|
||||
Now it's time to move on to [StateM Monad](states.lean.md) which is like a `ReaderM` that is
|
||||
also updatable.
|
||||
-/
|
||||
-/
|
||||
|
||||
@@ -7,7 +7,7 @@ Platforms built & tested by our CI, available as binary releases via elan (see b
|
||||
* x86-64 Linux with glibc 2.27+
|
||||
* x86-64 macOS 10.15+
|
||||
* aarch64 (Apple Silicon) macOS 10.15+
|
||||
* x86-64 Windows 10+
|
||||
* x86-64 Windows 11 (any version), Windows 10 (version 1903 or higher), Windows Server 2022
|
||||
|
||||
### Tier 2
|
||||
|
||||
|
||||
@@ -38,7 +38,11 @@
|
||||
# more convenient `ctest` output
|
||||
CTEST_OUTPUT_ON_FAILURE = 1;
|
||||
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
GMP = pkgsDist.gmp.override { withStatic = true; };
|
||||
GMP = (pkgsDist.gmp.override { withStatic = true; }).overrideAttrs (attrs:
|
||||
pkgs.lib.optionalAttrs (pkgs.stdenv.system == "aarch64-linux") {
|
||||
# would need additional linking setup on Linux aarch64, we don't use it anywhere else either
|
||||
hardeningDisable = [ "stackprotector" ];
|
||||
});
|
||||
LIBUV = pkgsDist.libuv.overrideAttrs (attrs: {
|
||||
configureFlags = ["--enable-static"];
|
||||
hardeningDisable = [ "stackprotector" ];
|
||||
|
||||
@@ -170,7 +170,7 @@ lib.warn "The Nix-based build is deprecated" rec {
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi' -j$NIX_BUILD_CORES
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
|
||||
12
script/mathlib-bench
Executable file
12
script/mathlib-bench
Executable file
@@ -0,0 +1,12 @@
|
||||
#! /bin/env bash
|
||||
# Open a Mathlib4 PR for benchmarking a given Lean 4 PR
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
[ $# -eq 1 ] || (echo "usage: $0 <lean4 PR #>"; exit 1)
|
||||
|
||||
LEAN_PR=$1
|
||||
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
|
||||
PR_NUMBER=$(echo "$PR_RESPONSE" | jq '.number')
|
||||
echo "opened https://github.com/leanprover-community/mathlib4/pull/$PR_NUMBER"
|
||||
gh api repos/leanprover-community/mathlib4/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null
|
||||
@@ -64,7 +64,7 @@ fi
|
||||
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
|
||||
# but do not change sysroot so users can still link against system libs
|
||||
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
|
||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -lpthread -ldl -lrt -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
||||
# when not using the above flags, link GMP dynamically/as usual
|
||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -luv -lpthread -ldl -lrt -Wl,--no-as-needed'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
|
||||
@@ -31,14 +31,20 @@ cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
|
||||
# runtime
|
||||
(cd llvm; cp --parents lib/clang/*/lib/*/libclang_rt.builtins* ../stage1)
|
||||
# further dependencies
|
||||
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase,psapi,iphlpapi,userenv,ws2_32,dbghelp,ole32}.* /clang64/lib/libgmp.a /clang64/lib/libuv.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
|
||||
# Note: even though we're linking against libraries like `libbcrypt.a` which appear to be static libraries from the file name,
|
||||
# we're not actually linking statically against the code.
|
||||
# Rather, `libbcrypt.a` is an import library (see https://en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries) that just
|
||||
# tells the compiler how to dynamically link against `bcrypt.dll` (which is located in the System32 folder).
|
||||
# This distinction is relevant specifically for `libicu.a`/`icu.dll` because there we want updates to the time zone database to
|
||||
# be delivered to users via Windows Update without having to recompile Lean or Lean programs.
|
||||
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase,psapi,iphlpapi,userenv,ws2_32,dbghelp,ole32,icu}.* /clang64/lib/libgmp.a /clang64/lib/libuv.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
|
||||
echo -n " -DLEAN_STANDALONE=ON"
|
||||
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER=$PWD/llvm/bin/clang++.exe -DCMAKE_CXX_COMPILER_WORKS=1 -DLEAN_CXX_STDLIB='-lc++ -lc++abi'"
|
||||
echo -n " -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_CXX_COMPILER=clang++"
|
||||
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter /clang64/include/'"
|
||||
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang.exe"
|
||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -static-libgcc -Wl,-Bstatic -lgmp $(pkg-config --static --libs libuv) -lunwind -Wl,-Bdynamic -fuse-ld=lld'"
|
||||
# when not using the above flags, link GMP dynamically/as usual
|
||||
# when not using the above flags, link GMP dynamically/as usual. Always link ICU dynamically.
|
||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp $(pkg-config --libs libuv) -lucrtbase'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"
|
||||
|
||||
@@ -10,13 +10,15 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 12)
|
||||
set(LEAN_VERSION_MINOR 16)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
set(LEAN_VERSION_STRING "${LEAN_VERSION_MAJOR}.${LEAN_VERSION_MINOR}.${LEAN_VERSION_PATCH}")
|
||||
if (LEAN_SPECIAL_VERSION_DESC)
|
||||
string(APPEND LEAN_VERSION_STRING "-${LEAN_SPECIAL_VERSION_DESC}")
|
||||
elseif (NOT LEAN_VERSION_IS_RELEASE)
|
||||
string(APPEND LEAN_VERSION_STRING "-pre")
|
||||
endif()
|
||||
|
||||
set(LEAN_PLATFORM_TARGET "" CACHE STRING "LLVM triple of the target platform")
|
||||
@@ -49,6 +51,8 @@ option(LLVM "LLVM" OFF)
|
||||
option(USE_GITHASH "GIT_HASH" ON)
|
||||
# When ON we install LICENSE files to CMAKE_INSTALL_PREFIX
|
||||
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
|
||||
# When ON we install a copy of cadical
|
||||
option(INSTALL_CADICAL "Install a copy of cadical" ON)
|
||||
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
|
||||
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
|
||||
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
|
||||
@@ -118,7 +122,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
# From https://emscripten.org/docs/compiling/WebAssembly.html#backends:
|
||||
# > The simple and safe thing is to pass all -s flags at both compile and link time.
|
||||
set(EMSCRIPTEN_SETTINGS "-s ALLOW_MEMORY_GROWTH=1 -fwasm-exceptions -pthread -flto")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -pthread")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -pthread")
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_EMSCRIPTEN ${EMSCRIPTEN_SETTINGS}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${EMSCRIPTEN_SETTINGS}")
|
||||
endif()
|
||||
@@ -153,7 +157,11 @@ if ((${MULTI_THREAD} MATCHES "ON") AND (${CMAKE_SYSTEM_NAME} MATCHES "Darwin"))
|
||||
endif ()
|
||||
|
||||
# We want explicit stack probes in huge Lean stack frames for robust stack overflow detection
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fstack-clash-protection")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fstack-clash-protection")
|
||||
|
||||
# This makes signed integer overflow guaranteed to match 2's complement.
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fwrapv")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fwrapv")
|
||||
|
||||
if(NOT MULTI_THREAD)
|
||||
message(STATUS "Disabled multi-thread support, it will not be safe to run multiple threads in parallel")
|
||||
@@ -297,6 +305,23 @@ if(NOT LEAN_STANDALONE)
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Windows SDK (for ICU)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
# Pass 'tools' to skip MSVC version check (as MSVC/Visual Studio is not necessarily installed)
|
||||
find_package(WindowsSDK REQUIRED COMPONENTS tools)
|
||||
|
||||
# This will give a semicolon-separated list of include directories
|
||||
get_windowssdk_include_dirs(${WINDOWSSDK_LATEST_DIR} WINDOWSSDK_INCLUDE_DIRS)
|
||||
|
||||
# To successfully build against Windows SDK headers, the Windows SDK headers must have lower
|
||||
# priority than other system headers, so use `-idirafter`. Unfortunately, CMake does not
|
||||
# support this using `include_directories`.
|
||||
string(REPLACE ";" "\" -idirafter \"" WINDOWSSDK_INCLUDE_DIRS "${WINDOWSSDK_INCLUDE_DIRS}")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -idirafter \"${WINDOWSSDK_INCLUDE_DIRS}\"")
|
||||
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -licu")
|
||||
endif()
|
||||
|
||||
# ccache
|
||||
if(CCACHE AND NOT CMAKE_CXX_COMPILER_LAUNCHER AND NOT CMAKE_C_COMPILER_LAUNCHER)
|
||||
find_program(CCACHE_PATH ccache)
|
||||
@@ -426,7 +451,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
|
||||
endif()
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
|
||||
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
|
||||
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
|
||||
@@ -439,7 +464,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fPIC")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
string(APPEND LAKESHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libLake_shared.dll.a -Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLake.a.export -Wl,--no-whole-archive")
|
||||
endif()
|
||||
@@ -454,7 +479,7 @@ if(NOT(${CMAKE_SYSTEM_NAME} MATCHES "Windows") AND NOT(${CMAKE_SYSTEM_NAME} MATC
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -rdynamic")
|
||||
# hide all other symbols
|
||||
string(APPEND CMAKE_CXX_FLAGS " -fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
string(APPEND LEANC_EXTRA_FLAGS " -fvisibility=hidden")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " -fvisibility=hidden")
|
||||
endif()
|
||||
|
||||
# On Windows, add bcrypt for random number generation
|
||||
@@ -480,7 +505,7 @@ endif()
|
||||
# Git HASH
|
||||
if(USE_GITHASH)
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1 ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||
if(${GIT_SHA1} MATCHES "GITDIR-NOTFOUND")
|
||||
message(STATUS "Failed to read git_sha1")
|
||||
set(GIT_SHA1 "")
|
||||
@@ -519,9 +544,10 @@ include_directories(${CMAKE_BINARY_DIR}/include) # config.h etc., "public" head
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
|
||||
string(APPEND LEANC_OPTS " ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}")
|
||||
|
||||
# Do embed flag for finding system libraries in dev builds
|
||||
# Do embed flag for finding system headers and libraries in dev builds
|
||||
if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
|
||||
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
string(APPEND LEANC_EXTRA_CC_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(initialize)
|
||||
@@ -593,7 +619,7 @@ else()
|
||||
OUTPUT_NAME leancpp)
|
||||
endif()
|
||||
|
||||
if((${STAGE} GREATER 0) AND CADICAL)
|
||||
if((${STAGE} GREATER 0) AND CADICAL AND INSTALL_CADICAL)
|
||||
add_custom_target(copy-cadical
|
||||
COMMAND cmake -E copy_if_different "${CADICAL}" "${CMAKE_BINARY_DIR}/bin/cadical${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
add_dependencies(leancpp copy-cadical)
|
||||
@@ -715,7 +741,7 @@ file(COPY ${LEAN_SOURCE_DIR}/bin/leanmake DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
|
||||
|
||||
if (${STAGE} GREATER 0 AND CADICAL)
|
||||
if (${STAGE} GREATER 0 AND CADICAL AND INSTALL_CADICAL)
|
||||
install(PROGRAMS "${CADICAL}" DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -36,3 +36,4 @@ import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
|
||||
@@ -8,6 +8,42 @@ import Init.Core
|
||||
|
||||
universe u v w
|
||||
|
||||
/--
|
||||
A `ForIn'` instance, which handles `for h : x in c do`,
|
||||
can also handle `for x in x do` by ignoring `h`, and so provides a `ForIn` instance.
|
||||
|
||||
Note that this instance will cause a potentially non-defeq duplication if both `ForIn` and `ForIn'`
|
||||
instances are provided for the same type.
|
||||
-/
|
||||
-- We set the priority to 500 so it is below the default,
|
||||
-- but still above the low priority instance from `Stream`.
|
||||
instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α where
|
||||
forIn x b f := forIn' x b fun a _ => f a
|
||||
|
||||
@[simp] theorem forIn'_eq_forIn [d : Membership α ρ] [ForIn' m ρ α d] {β} [Monad m] (x : ρ) (b : β)
|
||||
(f : (a : α) → a ∈ x → β → m (ForInStep β)) (g : (a : α) → β → m (ForInStep β))
|
||||
(h : ∀ a m b, f a m b = g a b) :
|
||||
forIn' x b f = forIn x b g := by
|
||||
simp [instForInOfForIn']
|
||||
congr
|
||||
apply funext
|
||||
intro a
|
||||
apply funext
|
||||
intro m
|
||||
apply funext
|
||||
intro b
|
||||
simp [h]
|
||||
rfl
|
||||
|
||||
/-- Extract the value from a `ForInStep`, ignoring whether it is `done` or `yield`. -/
|
||||
def ForInStep.value (x : ForInStep α) : α :=
|
||||
match x with
|
||||
| ForInStep.done b => b
|
||||
| ForInStep.yield b => b
|
||||
|
||||
@[simp] theorem ForInStep.value_done (b : β) : (ForInStep.done b).value = b := rfl
|
||||
@[simp] theorem ForInStep.value_yield (b : β) : (ForInStep.yield b).value = b := rfl
|
||||
|
||||
@[reducible]
|
||||
def Functor.mapRev {f : Type u → Type v} [Functor f] {α β : Type u} : f α → (α → β) → f β :=
|
||||
fun a f => f <$> a
|
||||
|
||||
@@ -7,6 +7,7 @@ prelude
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Control.Except
|
||||
import Init.Control.StateRef
|
||||
import Init.Ext
|
||||
|
||||
open Function
|
||||
|
||||
@@ -14,7 +15,7 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@@ -105,7 +106,7 @@ instance : LawfulFunctor (Except ε) := inferInstance
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@@ -167,7 +168,7 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
|
||||
|
||||
namespace StateT
|
||||
|
||||
theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
@[ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
|
||||
@@ -6,8 +6,7 @@ Authors: Leonardo de Moura, Sebastian Ullrich
|
||||
The State monad transformer using IO references.
|
||||
-/
|
||||
prelude
|
||||
import Init.System.IO
|
||||
import Init.Control.State
|
||||
import Init.System.ST
|
||||
|
||||
def StateRefT' (ω : Type) (σ : Type) (m : Type → Type) (α : Type) : Type := ReaderT (ST.Ref ω σ) m α
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Notation for operators defined at Prelude.lean
|
||||
-/
|
||||
prelude
|
||||
import Init.Tactics
|
||||
import Init.Meta
|
||||
|
||||
namespace Lean.Parser.Tactic.Conv
|
||||
|
||||
@@ -46,12 +47,20 @@ scoped syntax (name := withAnnotateState)
|
||||
/-- `skip` does nothing. -/
|
||||
syntax (name := skip) "skip" : conv
|
||||
|
||||
/-- Traverses into the left subterm of a binary operator.
|
||||
(In general, for an `n`-ary operator, it traverses into the second to last argument.) -/
|
||||
/--
|
||||
Traverses into the left subterm of a binary operator.
|
||||
|
||||
In general, for an `n`-ary operator, it traverses into the second to last argument.
|
||||
It is a synonym for `arg -2`.
|
||||
-/
|
||||
syntax (name := lhs) "lhs" : conv
|
||||
|
||||
/-- Traverses into the right subterm of a binary operator.
|
||||
(In general, for an `n`-ary operator, it traverses into the last argument.) -/
|
||||
/--
|
||||
Traverses into the right subterm of a binary operator.
|
||||
|
||||
In general, for an `n`-ary operator, it traverses into the last argument.
|
||||
It is a synonym for `arg -1`.
|
||||
-/
|
||||
syntax (name := rhs) "rhs" : conv
|
||||
|
||||
/-- Traverses into the function of a (unary) function application.
|
||||
@@ -74,13 +83,17 @@ subgoals for all the function arguments. For example, if the target is `f x y` t
|
||||
`congr` produces two subgoals, one for `x` and one for `y`. -/
|
||||
syntax (name := congr) "congr" : conv
|
||||
|
||||
syntax argArg := "@"? "-"? num
|
||||
|
||||
/--
|
||||
* `arg i` traverses into the `i`'th argument of the target. For example if the
|
||||
target is `f a b c d` then `arg 1` traverses to `a` and `arg 3` traverses to `c`.
|
||||
The index may be negative; `arg -1` traverses into the last argument,
|
||||
`arg -2` into the second-to-last argument, and so on.
|
||||
* `arg @i` is the same as `arg i` but it counts all arguments instead of just the
|
||||
explicit arguments.
|
||||
* `arg 0` traverses into the function. If the target is `f a b c d`, `arg 0` traverses into `f`. -/
|
||||
syntax (name := arg) "arg " "@"? num : conv
|
||||
syntax (name := arg) "arg " argArg : conv
|
||||
|
||||
/-- `ext x` traverses into a binder (a `fun x => e` or `∀ x, e` expression)
|
||||
to target `e`, introducing name `x` in the process. -/
|
||||
@@ -130,11 +143,11 @@ For example, if we are searching for `f _` in `f (f a) = f b`:
|
||||
syntax (name := pattern) "pattern " (occs)? term : conv
|
||||
|
||||
/-- `rw [thm]` rewrites the target using `thm`. See the `rw` tactic for more information. -/
|
||||
syntax (name := rewrite) "rewrite" (config)? rwRuleSeq : conv
|
||||
syntax (name := rewrite) "rewrite" optConfig rwRuleSeq : conv
|
||||
|
||||
/-- `simp [thm]` performs simplification using `thm` and marked `@[simp]` lemmas.
|
||||
See the `simp` tactic for more information. -/
|
||||
syntax (name := simp) "simp" (config)? (discharger)? (&" only")?
|
||||
syntax (name := simp) "simp" optConfig (discharger)? (&" only")?
|
||||
(" [" withoutPosition((simpStar <|> simpErase <|> simpLemma),*) "]")? : conv
|
||||
|
||||
/--
|
||||
@@ -151,7 +164,7 @@ example (a : Nat): (0 + 0) = a - a := by
|
||||
rw [← Nat.sub_self a]
|
||||
```
|
||||
-/
|
||||
syntax (name := dsimp) "dsimp" (config)? (discharger)? (&" only")?
|
||||
syntax (name := dsimp) "dsimp" optConfig (discharger)? (&" only")?
|
||||
(" [" withoutPosition((simpErase <|> simpLemma),*) "]")? : conv
|
||||
|
||||
/-- `simp_match` simplifies match expressions. For example,
|
||||
@@ -247,12 +260,12 @@ macro (name := failIfSuccess) tk:"fail_if_success " s:convSeq : conv =>
|
||||
|
||||
/-- `rw [rules]` applies the given list of rewrite rules to the target.
|
||||
See the `rw` tactic for more information. -/
|
||||
macro "rw" c:(config)? s:rwRuleSeq : conv => `(conv| rewrite $[$c]? $s)
|
||||
macro "rw" c:optConfig s:rwRuleSeq : conv => `(conv| rewrite $c:optConfig $s)
|
||||
|
||||
/-- `erw [rules]` is a shorthand for `rw (config := { transparency := .default }) [rules]`.
|
||||
/-- `erw [rules]` is a shorthand for `rw (transparency := .default) [rules]`.
|
||||
This does rewriting up to unfolding of regular definitions (by comparison to regular `rw`
|
||||
which only unfolds `@[reducible]` definitions). -/
|
||||
macro "erw" s:rwRuleSeq : conv => `(conv| rw (config := { transparency := .default }) $s)
|
||||
macro "erw" c:optConfig s:rwRuleSeq : conv => `(conv| rw $[$(getConfigItems c)]* (transparency := .default) $s:rwRuleSeq)
|
||||
|
||||
/-- `args` traverses into all arguments. Synonym for `congr`. -/
|
||||
macro "args" : conv => `(conv| congr)
|
||||
@@ -263,7 +276,7 @@ macro "right" : conv => `(conv| rhs)
|
||||
/-- `intro` traverses into binders. Synonym for `ext`. -/
|
||||
macro "intro" xs:(ppSpace colGt ident)* : conv => `(conv| ext $xs*)
|
||||
|
||||
syntax enterArg := ident <|> ("@"? num)
|
||||
syntax enterArg := ident <|> argArg
|
||||
|
||||
/-- `enter [arg, ...]` is a compact way to describe a path to a subterm.
|
||||
It is a shorthand for other conv tactics as follows:
|
||||
@@ -272,12 +285,7 @@ It is a shorthand for other conv tactics as follows:
|
||||
* `enter [x]` (where `x` is an identifier) is equivalent to `ext x`.
|
||||
For example, given the target `f (g a (fun x => x b))`, `enter [1, 2, x, 1]`
|
||||
will traverse to the subterm `b`. -/
|
||||
syntax "enter" " [" withoutPosition(enterArg,+) "]" : conv
|
||||
macro_rules
|
||||
| `(conv| enter [$i:num]) => `(conv| arg $i)
|
||||
| `(conv| enter [@$i]) => `(conv| arg @$i)
|
||||
| `(conv| enter [$id:ident]) => `(conv| ext $id)
|
||||
| `(conv| enter [$arg, $args,*]) => `(conv| (enter [$arg]; enter [$args,*]))
|
||||
syntax (name := enter) "enter" " [" withoutPosition(enterArg,+) "]" : conv
|
||||
|
||||
/-- The `apply thm` conv tactic is the same as `apply thm` the tactic.
|
||||
There are no restrictions on `thm`, but strange results may occur if `thm`
|
||||
|
||||
@@ -324,7 +324,6 @@ class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)
|
||||
|
||||
export ForIn' (forIn')
|
||||
|
||||
|
||||
/--
|
||||
Auxiliary type used to compile `do` notation. It is used when compiling a do block
|
||||
nested inside a combinator like `tryCatch`. It encodes the possible ways the
|
||||
@@ -862,16 +861,21 @@ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
|
||||
|
||||
/-! # Decidable -/
|
||||
|
||||
theorem decide_true_eq_true (h : Decidable True) : @decide True h = true :=
|
||||
@[simp] theorem decide_true (h : Decidable True) : @decide True h = true :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
| isFalse h => False.elim <| h ⟨⟩
|
||||
|
||||
theorem decide_false_eq_false (h : Decidable False) : @decide False h = false :=
|
||||
@[simp] theorem decide_false (h : Decidable False) : @decide False h = false :=
|
||||
match h with
|
||||
| isFalse _ => rfl
|
||||
| isTrue h => False.elim h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_true (since := "2024-11-05")] abbrev decide_true_eq_true := decide_true
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_false (since := "2024-11-05")] abbrev decide_false_eq_false := decide_false
|
||||
|
||||
/-- Similar to `decide`, but uses an explicit instance -/
|
||||
@[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool :=
|
||||
decide (h := d)
|
||||
@@ -1918,12 +1922,12 @@ represents an element of `Squash α` the same as `α` itself
|
||||
`Squash.lift` will extract a value in any subsingleton `β` from a function on `α`,
|
||||
while `Nonempty.rec` can only do the same when `β` is a proposition.
|
||||
-/
|
||||
def Squash (α : Type u) := Quot (fun (_ _ : α) => True)
|
||||
def Squash (α : Sort u) := Quot (fun (_ _ : α) => True)
|
||||
|
||||
/-- The canonical quotient map into `Squash α`. -/
|
||||
def Squash.mk {α : Type u} (x : α) : Squash α := Quot.mk _ x
|
||||
def Squash.mk {α : Sort u} (x : α) : Squash α := Quot.mk _ x
|
||||
|
||||
theorem Squash.ind {α : Type u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q :=
|
||||
theorem Squash.ind {α : Sort u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q :=
|
||||
Quot.ind h
|
||||
|
||||
/-- If `β` is a subsingleton, then a function `α → β` lifts to `Squash α → β`. -/
|
||||
|
||||
@@ -19,7 +19,9 @@ import Init.Data.ByteArray
|
||||
import Init.Data.FloatArray
|
||||
import Init.Data.Fin
|
||||
import Init.Data.UInt
|
||||
import Init.Data.SInt
|
||||
import Init.Data.Float
|
||||
import Init.Data.Float32
|
||||
import Init.Data.Option
|
||||
import Init.Data.Ord
|
||||
import Init.Data.Random
|
||||
@@ -41,3 +43,5 @@ import Init.Data.PLift
|
||||
import Init.Data.Zero
|
||||
import Init.Data.NeZero
|
||||
import Init.Data.Function
|
||||
import Init.Data.RArray
|
||||
import Init.Data.Vector
|
||||
|
||||
@@ -17,3 +17,8 @@ import Init.Data.Array.TakeDrop
|
||||
import Init.Data.Array.Bootstrap
|
||||
import Init.Data.Array.GetLit
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Array.Set
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.Array.FinRange
|
||||
import Init.Data.Array.Perm
|
||||
import Init.Data.Array.Find
|
||||
|
||||
@@ -10,6 +10,17 @@ import Init.Data.List.Attach
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
`O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`.
|
||||
|
||||
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
|
||||
-/
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) (l : Array α) (H : ∀ a ∈ l, P a) : Array β :=
|
||||
(l.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`Array {x // P x}` is the same as the input `Array α`.
|
||||
@@ -35,6 +46,10 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
l.toArray.attach = (l.attachWith (· ∈ l.toArray) (by simp)).toArray := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem _root_.List.pmap_toArray {l : List α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l.toArray, P a} :
|
||||
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toList_attachWith {l : Array α} {P : α → Prop} {H : ∀ x ∈ l, P x} :
|
||||
(l.attachWith P H).toList = l.toList.attachWith P (by simpa [mem_toList] using H) := by
|
||||
simp [attachWith]
|
||||
@@ -43,6 +58,387 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
l.attach.toList = l.toList.attachWith (· ∈ l) (by simp [mem_toList]) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toList_pmap {l : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l, P a} :
|
||||
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
|
||||
simp [pmap]
|
||||
|
||||
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||
@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : Array α) (H : ∀ a ∈ l, P a) :
|
||||
Array β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h'
|
||||
|
||||
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
|
||||
funext α β p f L h'
|
||||
cases L
|
||||
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith]
|
||||
apply List.pmap_congr_left
|
||||
intro a m h₁ h₂
|
||||
congr
|
||||
|
||||
@[simp] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
|
||||
@[simp] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (l : Array α) (h : ∀ b ∈ l.push a, P b) :
|
||||
pmap f (l.push a) h =
|
||||
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
|
||||
@[simp] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #[], P x) : (#[] : Array α).attachWith P H = #[] := rfl
|
||||
|
||||
@[simp] theorem _root_.List.attachWith_mem_toArray {l : List α} :
|
||||
l.attachWith (fun x => x ∈ l.toArray) (fun x h => by simpa using h) =
|
||||
l.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
simp only [List.attachWith, List.attach, List.map_pmap]
|
||||
apply List.pmap_congr_left
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (l : Array α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) l H = map f l := by
|
||||
cases l; simp
|
||||
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (l : Array α) {H₁ H₂}
|
||||
(h : ∀ a ∈ l, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
|
||||
cases l
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (l H) :
|
||||
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
|
||||
cases l
|
||||
simp [List.map_pmap]
|
||||
|
||||
theorem pmap_map {p : β → Prop} (g : ∀ b, p b → γ) (f : α → β) (l H) :
|
||||
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
|
||||
cases l
|
||||
simp [List.pmap_map]
|
||||
|
||||
theorem attach_congr {l₁ l₂ : Array α} (h : l₁ = l₂) :
|
||||
l₁.attach = l₂.attach.map (fun x => ⟨x.1, h ▸ x.2⟩) := by
|
||||
subst h
|
||||
simp
|
||||
|
||||
theorem attachWith_congr {l₁ l₂ : Array α} (w : l₁ = l₂) {P : α → Prop} {H : ∀ x ∈ l₁, P x} :
|
||||
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w ▸ h) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_push {a : α} {l : Array α} :
|
||||
(l.push a).attach =
|
||||
(l.attach.map (fun ⟨x, h⟩ => ⟨x, mem_push_of_mem a h⟩)).push ⟨a, by simp⟩ := by
|
||||
cases l
|
||||
rw [attach_congr (List.push_toArray _ _)]
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_push {a : α} {l : Array α} {P : α → Prop} {H : ∀ x ∈ l.push a, P x} :
|
||||
(l.push a).attachWith P H =
|
||||
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push ⟨a, H a (by simp)⟩ := by
|
||||
cases l
|
||||
simp [attachWith_congr (List.push_toArray _ _)]
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
cases l
|
||||
simp [List.pmap_eq_map_attach]
|
||||
|
||||
theorem attach_map_coe (l : Array α) (f : α → β) :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
cases l
|
||||
simp [List.attach_map_coe]
|
||||
|
||||
theorem attach_map_val (l : Array α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
@[simp]
|
||||
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_coe {p : α → Prop} (f : α → β) (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem mem_attach (l : Array α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
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]
|
||||
|
||||
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⟩
|
||||
|
||||
@[simp]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).size = l.size := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem size_attach {L : Array α} : L.attach.size = L.size := by
|
||||
cases L; simp
|
||||
|
||||
@[simp]
|
||||
theorem size_attachWith {p : α → Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_empty_iff {p : α → Prop} {f : ∀ a, p a → β} {l H} : pmap f l H = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem pmap_ne_empty_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ #[] ↔ xs ≠ #[] := by
|
||||
cases xs; simp
|
||||
|
||||
theorem pmap_eq_self {l : Array α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
cases l; simp [List.pmap_eq_self]
|
||||
|
||||
@[simp]
|
||||
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem attach_ne_empty_iff {l : Array α} : l.attach ≠ #[] ↔ l ≠ #[] := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_eq_empty_iff {l : Array α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_ne_empty_iff {l : Array α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H ≠ #[] ↔ l ≠ #[] := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||
(hn : n < (pmap f l h).size) :
|
||||
(pmap f l h)[n] =
|
||||
f (l[n]'(@size_pmap _ _ p f l h ▸ hn))
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f l h ▸ hn))) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : Array α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap _ _ h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
theorem foldl_pmap (l : Array α) {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]
|
||||
|
||||
theorem foldr_pmap (l : Array α) {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
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldl_subtype` below.
|
||||
-/
|
||||
theorem foldl_attach (l : Array α) (f : β → α → β) (b : β) :
|
||||
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
|
||||
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldr_subtype` below.
|
||||
-/
|
||||
theorem foldr_attach (l : Array α) (f : α → β → β) (b : β) :
|
||||
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
|
||||
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
theorem attach_map {l : Array α} (f : α → β) :
|
||||
(l.map f).attach = l.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem attachWith_map {l : Array α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ l.map f → P b} :
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases l
|
||||
ext
|
||||
· simp
|
||||
· simp only [List.map_toArray, List.attachWith_toArray, List.getElem_toArray,
|
||||
List.getElem_attachWith, List.getElem_map, Function.comp_apply]
|
||||
erw [List.getElem_attachWith] -- Why is `erw` needed here?
|
||||
|
||||
theorem map_attachWith {l : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f =
|
||||
l.pmap (fun a (h : a ∈ l ∧ P a) => f ⟨a, H _ h.1⟩) (fun a h => ⟨h, H a h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
|
||||
theorem map_attach {l : Array α} (f : { x // x ∈ l } → β) :
|
||||
l.attach.map f = l.pmap (fun a h => f ⟨a, h⟩) (fun _ => id) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem attach_filterMap {l : Array α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
cases l
|
||||
rw [attach_congr (List.filterMap_toArray f _)]
|
||||
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
|
||||
|
||||
theorem attach_filter {l : Array α} (p : α → Bool) :
|
||||
(l.filter p).attach = l.attach.filterMap
|
||||
fun x => if w : p x.1 then some ⟨x.1, mem_filter.mpr ⟨x.2, w⟩⟩ else none := by
|
||||
cases l
|
||||
rw [attach_congr (List.filter_toArray p _)]
|
||||
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
pmap (α := { x // x ∈ l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
|
||||
(fun a _ => H₁ a a.2) := by
|
||||
cases l
|
||||
simp [List.pmap_pmap, List.pmap_map]
|
||||
|
||||
@[simp] theorem pmap_append {p : ι → Prop} (f : ∀ a : ι, p a → α) (l₁ l₂ : Array ι)
|
||||
(h : ∀ a ∈ l₁ ++ l₂, p a) :
|
||||
(l₁ ++ l₂).pmap f h =
|
||||
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
|
||||
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ : Array α)
|
||||
(h₁ : ∀ a ∈ l₁, p a) (h₂ : ∀ a ∈ l₂, p a) :
|
||||
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
|
||||
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
|
||||
pmap_append f l₁ l₂ _
|
||||
|
||||
@[simp] theorem attach_append (xs ys : Array α) :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
cases xs
|
||||
cases ys
|
||||
rw [attach_congr (List.append_toArray _ _)]
|
||||
simp [List.attach_append, Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
induction xs <;> simp_all
|
||||
|
||||
theorem reverse_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_reverse (xs : Array α) :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr (List.reverse_toArray _)]
|
||||
simp
|
||||
|
||||
theorem reverse_attach (xs : Array α) :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).back? = xs.attach.back?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back?_eq_some h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem back?_attach {xs : Array α} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back?_eq_some h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`Array.unattach` is the (one-sided) inverse of `Array.attach`. It is a synonym for `Array.map Subtype.val`.
|
||||
@@ -83,7 +479,7 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
|
||||
|
||||
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
|
||||
cases l
|
||||
simp
|
||||
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
|
||||
|
||||
@[simp] theorem unattach_attachWith {p : α → Prop} {l : Array α}
|
||||
{H : ∀ a ∈ l, p a} :
|
||||
@@ -91,6 +487,15 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : Array { x // p x }} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem getElem_unattach
|
||||
{p : α → Prop} {l : Array { x // p x }} (i : Nat) (h : i < l.unattach.size) :
|
||||
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
|
||||
simp [unattach]
|
||||
|
||||
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -11,7 +11,9 @@ import Init.Data.UInt.BasicAux
|
||||
import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.GetElem
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.List.ToArrayImpl
|
||||
import Init.Data.Array.Set
|
||||
|
||||
universe u v w
|
||||
|
||||
/-! ### Array literal syntax -/
|
||||
@@ -25,11 +27,12 @@ variable {α : Type u}
|
||||
|
||||
namespace Array
|
||||
|
||||
@[deprecated size (since := "2024-10-13")] abbrev data := @toList
|
||||
@[deprecated toList (since := "2024-10-13")] abbrev data := @toList
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp] theorem size_set (a : Array α) (i : Fin a.size) (v : α) : (set a i v).size = a.size :=
|
||||
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
||||
(set a i v h).size = a.size :=
|
||||
List.length_set ..
|
||||
|
||||
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
|
||||
@@ -82,6 +85,27 @@ theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
|
||||
|
||||
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
|
||||
|
||||
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
|
||||
|
||||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||
structure Mem (as : Array α) (a : α) : Prop where
|
||||
val : a ∈ as.toList
|
||||
|
||||
instance : Membership α (Array α) where
|
||||
mem := Mem
|
||||
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
@@ -125,7 +149,7 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
`fset` may be slightly slower than `uset`. -/
|
||||
@[extern "lean_array_uset"]
|
||||
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
|
||||
a.set ⟨i.toNat, h⟩ v
|
||||
a.set i.toNat v h
|
||||
|
||||
@[extern "lean_array_pop"]
|
||||
def pop (a : Array α) : Array α where
|
||||
@@ -147,14 +171,15 @@ This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_fswap"]
|
||||
def swap (a : Array α) (i j : @& Fin a.size) : Array α :=
|
||||
let v₁ := a.get i
|
||||
let v₂ := a.get j
|
||||
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
|
||||
let v₁ := a[i]
|
||||
let v₂ := a[j]
|
||||
let a' := a.set i v₂
|
||||
a'.set (size_set a i v₂ ▸ j) v₁
|
||||
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
|
||||
|
||||
@[simp] theorem size_swap (a : Array α) (i j : Fin a.size) : (a.swap i j).size = a.size := by
|
||||
show ((a.set i (a.get j)).set (size_set a i _ ▸ j) (a.get i)).size = a.size
|
||||
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
|
||||
show ((a.set i a[j]).set j a[i]
|
||||
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
|
||||
rw [size_set, size_set]
|
||||
|
||||
/--
|
||||
@@ -164,12 +189,14 @@ This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_swap"]
|
||||
def swap! (a : Array α) (i j : @& Nat) : Array α :=
|
||||
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
|
||||
if h₁ : i < a.size then
|
||||
if h₂ : j < a.size then swap a ⟨i, h₁⟩ ⟨j, h₂⟩
|
||||
if h₂ : j < a.size then swap a i j
|
||||
else a
|
||||
else a
|
||||
|
||||
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
|
||||
|
||||
/-! ### GetElem instance for `USize`, backed by `uget` -/
|
||||
|
||||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
@@ -214,60 +241,63 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (mkEmpty n) where
|
||||
|
||||
/-- The array `#[0, 1, ..., n - 1]`. -/
|
||||
def range (n : Nat) : Array Nat :=
|
||||
n.fold (flip Array.push) (mkEmpty n)
|
||||
ofFn fun (i : Fin n) => i
|
||||
|
||||
def singleton (v : α) : Array α :=
|
||||
mkArray 1 v
|
||||
|
||||
def back [Inhabited α] (a : Array α) : α :=
|
||||
a.get! (a.size - 1)
|
||||
def back! [Inhabited α] (a : Array α) : α :=
|
||||
a[a.size - 1]!
|
||||
|
||||
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
|
||||
|
||||
def get? (a : Array α) (i : Nat) : Option α :=
|
||||
if h : i < a.size then some a[i] else none
|
||||
|
||||
def back? (a : Array α) : Option α :=
|
||||
a.get? (a.size - 1)
|
||||
a[a.size - 1]?
|
||||
|
||||
@[inline] def swapAt (a : Array α) (i : Fin a.size) (v : α) : α × Array α :=
|
||||
let e := a.get i
|
||||
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
|
||||
let e := a[i]
|
||||
let a := a.set i v
|
||||
(e, a)
|
||||
|
||||
@[inline]
|
||||
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
if h : i < a.size then
|
||||
swapAt a ⟨i, h⟩ v
|
||||
swapAt a i v
|
||||
else
|
||||
have : Inhabited (α × Array α) := ⟨(v, a)⟩
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
|
||||
def shrink (a : Array α) (n : Nat) : Array α :=
|
||||
/-- `take a n` returns the first `n` elements of `a`. -/
|
||||
def take (a : Array α) (n : Nat) : Array α :=
|
||||
let rec loop
|
||||
| 0, a => a
|
||||
| n+1, a => loop n a.pop
|
||||
loop (a.size - n) a
|
||||
|
||||
@[deprecated take (since := "2024-10-22")] abbrev shrink := @take
|
||||
|
||||
@[inline]
|
||||
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||||
if h : i < a.size then
|
||||
let idx : Fin a.size := ⟨i, h⟩
|
||||
let v := a.get idx
|
||||
let v := a[i]
|
||||
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
|
||||
-- Note: we assume that arrays have a uniform representation irrespective
|
||||
-- of the element type, and that it is valid to store `box(0)` in any array.
|
||||
let a' := a.set idx (unsafeCast ())
|
||||
let a' := a.set i (unsafeCast ())
|
||||
let v ← f v
|
||||
pure <| a'.set (size_set a .. ▸ idx) v
|
||||
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
|
||||
else
|
||||
pure a
|
||||
|
||||
@[implemented_by modifyMUnsafe]
|
||||
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||||
if h : i < a.size then
|
||||
let idx := ⟨i, h⟩
|
||||
let v := a.get idx
|
||||
let v := a[i]
|
||||
let v ← f v
|
||||
pure <| a.set idx v
|
||||
pure <| a.set i v
|
||||
else
|
||||
pure a
|
||||
|
||||
@@ -283,21 +313,21 @@ def modifyOp (self : Array α) (idx : Nat) (f : α → α) : Array α :=
|
||||
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
|
||||
|
||||
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
|
||||
@[inline] unsafe def forInUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : m β :=
|
||||
@[inline] unsafe def forIn'Unsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let sz := as.usize
|
||||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||||
if i < sz then
|
||||
let a := as.uget i lcProof
|
||||
match (← f a b) with
|
||||
match (← f a lcProof b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop (i+1) b
|
||||
else
|
||||
pure b
|
||||
loop 0 b
|
||||
|
||||
/-- Reference implementation for `forIn` -/
|
||||
@[implemented_by Array.forInUnsafe]
|
||||
protected def forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : m β :=
|
||||
/-- Reference implementation for `forIn'` -/
|
||||
@[implemented_by Array.forIn'Unsafe]
|
||||
protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
|
||||
match i, h with
|
||||
| 0, _ => pure b
|
||||
@@ -305,15 +335,17 @@ protected def forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m
|
||||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||||
match (← f as[as.size - 1 - i] b) with
|
||||
match (← f as[as.size - 1 - i] (getElem_mem this) b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
|
||||
instance : ForIn m (Array α) α where
|
||||
forIn := Array.forIn
|
||||
instance : ForIn' m (Array α) α inferInstance where
|
||||
forIn' := Array.forIn'
|
||||
|
||||
/-- See comment at `forInUnsafe` -/
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
|
||||
/-- See comment at `forIn'Unsafe` -/
|
||||
@[inline]
|
||||
unsafe def foldlMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Array α) (start := 0) (stop := as.size) : m β :=
|
||||
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
|
||||
@@ -348,7 +380,7 @@ def foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β
|
||||
else
|
||||
fold as.size (Nat.le_refl _)
|
||||
|
||||
/-- See comment at `forInUnsafe` -/
|
||||
/-- See comment at `forIn'Unsafe` -/
|
||||
@[inline]
|
||||
unsafe def foldrMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → β → m β) (init : β) (as : Array α) (start := as.size) (stop := 0) : m β :=
|
||||
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
|
||||
@@ -387,7 +419,7 @@ def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
else
|
||||
pure init
|
||||
|
||||
/-- See comment at `forInUnsafe` -/
|
||||
/-- See comment at `forIn'Unsafe` -/
|
||||
@[inline]
|
||||
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
||||
let sz := as.usize
|
||||
@@ -418,6 +450,8 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
map 0 (mkEmpty as.size)
|
||||
|
||||
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
|
||||
|
||||
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
|
||||
@[inline]
|
||||
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
@@ -430,30 +464,34 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
rw [← inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
|
||||
apply Nat.le_add_right
|
||||
have : i + (j + 1) = as.size := by rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
|
||||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get ⟨j, j_lt⟩)))
|
||||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get j j_lt)))
|
||||
map as.size 0 rfl (mkEmpty as.size)
|
||||
|
||||
@[inline]
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : Nat → α → m β) : m (Array β) :=
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β) :=
|
||||
as.mapFinIdxM fun i a => f i a
|
||||
|
||||
@[inline]
|
||||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : α → m (Option β)) : m (Option β) := do
|
||||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) := do
|
||||
for a in as do
|
||||
match (← f a) with
|
||||
| some b => return b
|
||||
| _ => pure ⟨⟩
|
||||
return none
|
||||
|
||||
/--
|
||||
Note that the universe level is contrained to `Type` here,
|
||||
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
|
||||
-/
|
||||
@[inline]
|
||||
def findM? {α : Type} {m : Type → Type} [Monad m] (as : Array α) (p : α → m Bool) : m (Option α) := do
|
||||
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
||||
for a in as do
|
||||
if (← p a) then
|
||||
return a
|
||||
return none
|
||||
|
||||
@[inline]
|
||||
def findIdxM? [Monad m] (as : Array α) (p : α → m Bool) : m (Option Nat) := do
|
||||
def findIdxM? [Monad m] (p : α → m Bool) (as : Array α) : m (Option Nat) := do
|
||||
let mut i := 0
|
||||
for a in as do
|
||||
if (← p a) then
|
||||
@@ -505,7 +543,7 @@ def allM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as :
|
||||
return !(← as.anyM (start := start) (stop := stop) fun v => return !(← p v))
|
||||
|
||||
@[inline]
|
||||
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : α → m (Option β)) : m (Option β) :=
|
||||
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) :=
|
||||
let rec @[specialize] find : (i : Nat) → i ≤ as.size → m (Option β)
|
||||
| 0, _ => pure none
|
||||
| i+1, h => do
|
||||
@@ -519,7 +557,7 @@ def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
find as.size (Nat.le_refl _)
|
||||
|
||||
@[inline]
|
||||
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (as : Array α) (p : α → m Bool) : m (Option α) :=
|
||||
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) :=
|
||||
as.findSomeRevM? fun a => return if (← p a) then some a else none
|
||||
|
||||
@[inline]
|
||||
@@ -548,7 +586,7 @@ def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size →
|
||||
Id.run <| as.mapFinIdxM f
|
||||
|
||||
@[inline]
|
||||
def mapIdx {α : Type u} {β : Type v} (as : Array α) (f : Nat → α → β) : Array β :=
|
||||
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapIdxM f
|
||||
|
||||
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
|
||||
@@ -556,29 +594,33 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
||||
arr.mapIdx fun i a => (a, i)
|
||||
|
||||
@[inline]
|
||||
def find? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
|
||||
Id.run <| as.findM? p
|
||||
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run do
|
||||
for a in as do
|
||||
if p a then
|
||||
return a
|
||||
return none
|
||||
|
||||
@[inline]
|
||||
def findSome? {α : Type u} {β : Type v} (as : Array α) (f : α → Option β) : Option β :=
|
||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeM? f
|
||||
|
||||
@[inline]
|
||||
def findSome! {α : Type u} {β : Type v} [Inhabited β] (a : Array α) (f : α → Option β) : β :=
|
||||
match findSome? a f with
|
||||
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α → Option β) (a : Array α) : β :=
|
||||
match a.findSome? f with
|
||||
| some b => b
|
||||
| none => panic! "failed to find element"
|
||||
|
||||
@[inline]
|
||||
def findSomeRev? {α : Type u} {β : Type v} (as : Array α) (f : α → Option β) : Option β :=
|
||||
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeRevM? f
|
||||
|
||||
@[inline]
|
||||
def findRev? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
|
||||
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findRevM? p
|
||||
|
||||
@[inline]
|
||||
def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
|
||||
def findIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option Nat :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (j : Nat) :=
|
||||
if h : j < as.size then
|
||||
@@ -587,14 +629,20 @@ def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||||
a.findIdx? fun a => a == v
|
||||
@[inline]
|
||||
def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (j : Nat) :=
|
||||
if h : j < as.size then
|
||||
if p as[j] then some ⟨j, h⟩ else loop (j + 1)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
|
||||
if h : i < a.size then
|
||||
let idx : Fin a.size := ⟨i, h⟩;
|
||||
if a.get idx == v then some idx
|
||||
if a[i] == v then some ⟨i, h⟩
|
||||
else indexOfAux a v (i+1)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
@@ -602,6 +650,10 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
|
||||
indexOfAux a v 0
|
||||
|
||||
@[deprecated indexOf? (since := "2024-11-20")]
|
||||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||||
a.findIdx? fun a => a == v
|
||||
|
||||
@[inline]
|
||||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.anyM p start stop
|
||||
@@ -642,7 +694,7 @@ instance : HAppend (Array α) (List α) (Array α) := ⟨Array.appendList⟩
|
||||
def flatMapM [Monad m] (f : α → m (Array β)) (as : Array α) : m (Array β) :=
|
||||
as.foldlM (init := empty) fun bs a => do return bs ++ (← f a)
|
||||
|
||||
@[deprecated concatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
|
||||
@[deprecated flatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
|
||||
|
||||
@[inline]
|
||||
def flatMap (f : α → Array β) (as : Array α) : Array β :=
|
||||
@@ -710,7 +762,7 @@ where
|
||||
loop (as : Array α) (i : Nat) (j : Fin as.size) :=
|
||||
if h : i < j then
|
||||
have := termination h
|
||||
let as := as.swap ⟨i, Nat.lt_trans h j.2⟩ j
|
||||
let as := as.swap i j (Nat.lt_trans h j.2)
|
||||
have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
|
||||
loop as (i+1) ⟨j-1, this⟩
|
||||
else
|
||||
@@ -719,7 +771,7 @@ where
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def popWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
if h : as.size > 0 then
|
||||
if p (as.get ⟨as.size - 1, Nat.sub_lt h (by decide)⟩) then
|
||||
if p (as[as.size - 1]'(Nat.sub_lt h (by decide))) then
|
||||
popWhile p as.pop
|
||||
else
|
||||
as
|
||||
@@ -731,7 +783,7 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
go (i : Nat) (r : Array α) : Array α :=
|
||||
if h : i < as.size then
|
||||
let a := as.get ⟨i, h⟩
|
||||
let a := as[i]
|
||||
if p a then
|
||||
go (i+1) (r.push a)
|
||||
else
|
||||
@@ -741,49 +793,63 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
go 0 #[]
|
||||
|
||||
/-- Remove the element at a given index from an array without bounds checks, using a `Fin` index.
|
||||
/--
|
||||
Remove the element at a given index from an array without a runtime bounds checks,
|
||||
using a `Nat` index and a tactic-provided bound.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
|
||||
if h : i.val + 1 < a.size then
|
||||
let a' := a.swap ⟨i.val + 1, h⟩ i
|
||||
let i' : Fin a'.size := ⟨i.val + 1, by simp [a', h]⟩
|
||||
a'.feraseIdx i'
|
||||
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
|
||||
if h' : i + 1 < a.size then
|
||||
let a' := a.swap (i + 1) i
|
||||
a'.eraseIdx (i + 1) (by simp [a', h'])
|
||||
else
|
||||
a.pop
|
||||
termination_by a.size - i.val
|
||||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ i.isLt
|
||||
termination_by a.size - i
|
||||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
|
||||
-- This is required in `Lean.Data.PersistentHashMap`.
|
||||
@[simp] theorem size_feraseIdx (a : Array α) (i : Fin a.size) : (a.feraseIdx i).size = a.size - 1 := by
|
||||
induction a, i using Array.feraseIdx.induct with
|
||||
| @case1 a i h a' _ ih =>
|
||||
unfold feraseIdx
|
||||
simp [h, a', ih]
|
||||
| case2 a i h =>
|
||||
unfold feraseIdx
|
||||
simp [h]
|
||||
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
|
||||
induction a, i, h using Array.eraseIdx.induct with
|
||||
| @case1 a i h h' a' ih =>
|
||||
unfold eraseIdx
|
||||
simp [h', a', ih]
|
||||
| case2 a i h h' =>
|
||||
unfold eraseIdx
|
||||
simp [h']
|
||||
|
||||
/-- Remove the element at a given index from an array, or do nothing if the index is out of bounds.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
def eraseIdx (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.feraseIdx ⟨i, h⟩ else a
|
||||
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.eraseIdx i h else a
|
||||
|
||||
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`. -/
|
||||
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
|
||||
|
||||
def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
match as.indexOf? a with
|
||||
| none => as
|
||||
| some i => as.feraseIdx i
|
||||
| some i => as.eraseIdx i
|
||||
|
||||
/-- Erase the first element that satisfies the predicate `p`. -/
|
||||
def eraseP (as : Array α) (p : α → Bool) : Array α :=
|
||||
match as.findIdx? p with
|
||||
| none => as
|
||||
| some i => as.eraseIdxIfInBounds i
|
||||
|
||||
/-- Insert element `a` at position `i`. -/
|
||||
@[inline] def insertAt (as : Array α) (i : Fin (as.size + 1)) (a : α) : Array α :=
|
||||
@[inline] def insertIdx (as : Array α) (i : Nat) (a : α) (_ : i ≤ as.size := by get_elem_tactic) : Array α :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (as : Array α) (j : Fin as.size) :=
|
||||
if i.1 < j then
|
||||
let j' := ⟨j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2⟩
|
||||
if i < j then
|
||||
let j' : Fin as.size := ⟨j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2⟩
|
||||
let as := as.swap j' j
|
||||
loop as ⟨j', by rw [size_swap]; exact j'.2⟩
|
||||
else
|
||||
@@ -793,12 +859,23 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
let as := as.push a
|
||||
loop as ⟨j, size_push .. ▸ j.lt_succ_self⟩
|
||||
|
||||
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
|
||||
|
||||
/-- Insert element `a` at position `i`. Panics if `i` is not `i ≤ as.size`. -/
|
||||
def insertAt! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertAt as ⟨i, Nat.lt_succ_of_le h⟩ a
|
||||
insertIdx as i a
|
||||
else panic! "invalid index"
|
||||
|
||||
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
|
||||
|
||||
/-- Insert element `a` at position `i`, or do nothing if `as.size < i`. -/
|
||||
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertIdx as i a
|
||||
else
|
||||
as
|
||||
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool :=
|
||||
if h : i < as.size then
|
||||
@@ -822,12 +899,12 @@ def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
|
||||
false
|
||||
|
||||
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def zipWithAux (f : α → β → γ) (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) : Array γ :=
|
||||
def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ :=
|
||||
if h : i < as.size then
|
||||
let a := as[i]
|
||||
if h : i < bs.size then
|
||||
let b := bs[i]
|
||||
zipWithAux f as bs (i+1) <| cs.push <| f a b
|
||||
zipWithAux as bs f (i+1) <| cs.push <| f a b
|
||||
else
|
||||
cs
|
||||
else
|
||||
@@ -835,14 +912,27 @@ def zipWithAux (f : α → β → γ) (as : Array α) (bs : Array β) (i : Nat)
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : Array γ :=
|
||||
zipWithAux f as bs 0 #[]
|
||||
zipWithAux as bs f 0 #[]
|
||||
|
||||
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
|
||||
zipWith as bs Prod.mk
|
||||
|
||||
def zipWithAll (as : Array α) (bs : Array β) (f : Option α → Option β → γ) : Array γ :=
|
||||
go as bs 0 #[]
|
||||
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
|
||||
if i < max as.size bs.size then
|
||||
let a := as[i]?
|
||||
let b := bs[i]?
|
||||
go as bs (i+1) (cs.push (f a b))
|
||||
else
|
||||
cs
|
||||
termination_by max as.size bs.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
def unzip (as : Array (α × β)) : Array α × Array β :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
|
||||
|
||||
@[deprecated partition (since := "2024-11-06")]
|
||||
def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) a =>
|
||||
if p a then (as.push a, bs) else (as, bs.push a)
|
||||
|
||||
@@ -60,7 +60,7 @@ where
|
||||
if ptrEq a b then
|
||||
go (i+1) as
|
||||
else
|
||||
go (i+1) (as.set ⟨i, h⟩ b)
|
||||
go (i+1) (as.set i b h)
|
||||
else
|
||||
return as
|
||||
|
||||
|
||||
@@ -5,59 +5,64 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Omega
|
||||
universe u v
|
||||
|
||||
-- TODO: CLEANUP
|
||||
|
||||
namespace Array
|
||||
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
|
||||
-- TODO: remove `partial` using well-founded recursion
|
||||
|
||||
@[specialize] partial def binSearchAux {α : Type u} {β : Type v} [Inhabited β] (lt : α → α → Bool) (found : Option α → β) (as : Array α) (k : α) : Nat → Nat → β
|
||||
| lo, hi =>
|
||||
if lo <= hi then
|
||||
let _ := Inhabited.mk k
|
||||
let m := (lo + hi)/2
|
||||
let a := as.get! m
|
||||
if lt a k then binSearchAux lt found as k (m+1) hi
|
||||
else if lt k a then
|
||||
if m == 0 then found none
|
||||
else binSearchAux lt found as k lo (m-1)
|
||||
else found (some a)
|
||||
else found none
|
||||
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α → α → Bool) (found : Option α → β) (as : Array α) (k : α) :
|
||||
(lo : Fin (as.size + 1)) → (hi : Fin as.size) → (lo.1 ≤ hi.1) → β
|
||||
| lo, hi, h =>
|
||||
let m := (lo.1 + hi.1)/2
|
||||
let a := as[m]
|
||||
if lt a k then
|
||||
if h' : m + 1 ≤ hi.1 then
|
||||
binSearchAux lt found as k ⟨m+1, by omega⟩ hi h'
|
||||
else found none
|
||||
else if lt k a then
|
||||
if h' : m = 0 ∨ m - 1 < lo.1 then found none
|
||||
else binSearchAux lt found as k lo ⟨m-1, by omega⟩ (by simp; omega)
|
||||
else found (some a)
|
||||
termination_by lo hi => hi.1 - lo.1
|
||||
|
||||
@[inline] def binSearch {α : Type} (as : Array α) (k : α) (lt : α → α → Bool) (lo := 0) (hi := as.size - 1) : Option α :=
|
||||
if lo < as.size then
|
||||
if h : lo < as.size then
|
||||
let hi := if hi < as.size then hi else as.size - 1
|
||||
binSearchAux lt id as k lo hi
|
||||
if w : lo ≤ hi then
|
||||
binSearchAux lt id as k ⟨lo, by omega⟩ ⟨hi, by simp [hi]; split <;> omega⟩ (by simp [hi]; omega)
|
||||
else
|
||||
none
|
||||
else
|
||||
none
|
||||
|
||||
@[inline] def binSearchContains {α : Type} (as : Array α) (k : α) (lt : α → α → Bool) (lo := 0) (hi := as.size - 1) : Bool :=
|
||||
if lo < as.size then
|
||||
if h : lo < as.size then
|
||||
let hi := if hi < as.size then hi else as.size - 1
|
||||
binSearchAux lt Option.isSome as k lo hi
|
||||
if w : lo ≤ hi then
|
||||
binSearchAux lt Option.isSome as k ⟨lo, by omega⟩ ⟨hi, by simp [hi]; split <;> omega⟩ (by simp [hi]; omega)
|
||||
else
|
||||
false
|
||||
else
|
||||
false
|
||||
|
||||
@[specialize] private partial def binInsertAux {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
@[specialize] private def binInsertAux {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
(lt : α → α → Bool)
|
||||
(merge : α → m α)
|
||||
(add : Unit → m α)
|
||||
(as : Array α)
|
||||
(k : α) : Nat → Nat → m (Array α)
|
||||
| lo, hi =>
|
||||
let _ := Inhabited.mk k
|
||||
-- as[lo] < k < as[hi]
|
||||
let mid := (lo + hi)/2
|
||||
let midVal := as.get! mid
|
||||
if lt midVal k then
|
||||
if mid == lo then do let v ← add (); pure <| as.insertAt! (lo+1) v
|
||||
else binInsertAux lt merge add as k mid hi
|
||||
else if lt k midVal then
|
||||
binInsertAux lt merge add as k lo mid
|
||||
(k : α) : (lo : Fin as.size) → (hi : Fin as.size) → (lo.1 ≤ hi.1) → (lt as[lo] k) → m (Array α)
|
||||
| lo, hi, h, w =>
|
||||
let mid := (lo.1 + hi.1)/2
|
||||
let midVal := as[mid]
|
||||
if w₁ : lt midVal k then
|
||||
if h' : mid = lo then do let v ← add (); pure <| as.insertIdx (lo+1) v
|
||||
else binInsertAux lt merge add as k ⟨mid, by omega⟩ hi (by simp; omega) w₁
|
||||
else if w₂ : lt k midVal then
|
||||
have : mid ≠ lo := fun z => by simp [midVal, z] at w₁; simp_all
|
||||
binInsertAux lt merge add as k lo ⟨mid, by omega⟩ (by simp; omega) w
|
||||
else do
|
||||
as.modifyM mid <| fun v => merge v
|
||||
termination_by lo hi => hi.1 - lo.1
|
||||
|
||||
@[specialize] def binInsertM {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
(lt : α → α → Bool)
|
||||
@@ -65,13 +70,12 @@ namespace Array
|
||||
(add : Unit → m α)
|
||||
(as : Array α)
|
||||
(k : α) : m (Array α) :=
|
||||
let _ := Inhabited.mk k
|
||||
if as.isEmpty then do let v ← add (); pure <| as.push v
|
||||
else if lt k (as.get! 0) then do let v ← add (); pure <| as.insertAt! 0 v
|
||||
else if !lt (as.get! 0) k then as.modifyM 0 <| merge
|
||||
else if lt as.back k then do let v ← add (); pure <| as.push v
|
||||
else if !lt k as.back then as.modifyM (as.size - 1) <| merge
|
||||
else binInsertAux lt merge add as k 0 (as.size - 1)
|
||||
if h : as.size = 0 then do let v ← add (); pure <| as.push v
|
||||
else if lt k as[0] then do let v ← add (); pure <| as.insertIdx 0 v
|
||||
else if h' : !lt as[0] k then as.modifyM 0 <| merge
|
||||
else if lt as[as.size - 1] k then do let v ← add (); pure <| as.push v
|
||||
else if !lt k as[as.size - 1] then as.modifyM (as.size - 1) <| merge
|
||||
else binInsertAux lt merge add as k ⟨0, by omega⟩ ⟨as.size - 1, by omega⟩ (by simp) (by simpa using h')
|
||||
|
||||
@[inline] def binInsert {α : Type u} (lt : α → α → Bool) (as : Array α) (k : α) : Array α :=
|
||||
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k
|
||||
|
||||
@@ -15,26 +15,26 @@ This file contains some theorems about `Array` and `List` needed for `Init.Data.
|
||||
|
||||
namespace Array
|
||||
|
||||
theorem foldlM_eq_foldlM_toList.aux [Monad m]
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
||||
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
|
||||
unfold foldlM.loop
|
||||
split; split
|
||||
· cases Nat.not_le_of_gt ‹_› (Nat.zero_add _ ▸ H)
|
||||
· rename_i i; rw [Nat.succ_add] at H
|
||||
simp [foldlM_eq_foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (config := {occs := .pos [2]}) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||
simp [foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (occs := [2]) [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
@[simp] theorem foldlM_toList [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
arr.foldlM f init = arr.toList.foldlM f init := by
|
||||
simp [foldlM, foldlM_eq_foldlM_toList.aux]
|
||||
arr.toList.foldlM f init = arr.foldlM f init := by
|
||||
simp [foldlM, foldlM_toList.aux]
|
||||
|
||||
theorem foldl_eq_foldl_toList (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.toList.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_eq_foldlM_toList ..
|
||||
@[simp] theorem foldl_toList (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.toList.foldl f init = arr.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_toList ..
|
||||
|
||||
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
|
||||
(f : α → β → m β) (arr : Array α) (init : β) (i h) :
|
||||
@@ -51,23 +51,23 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
|
||||
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
|
||||
simp [foldrM, h, ← foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
|
||||
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
@[simp] theorem foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.toList.foldrM f init := by
|
||||
arr.toList.foldrM f init = arr.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
|
||||
|
||||
theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.toList.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_eq_foldrM_toList ..
|
||||
@[simp] theorem foldr_toList (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.toList.foldr f init = arr.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_toList ..
|
||||
|
||||
@[simp] theorem push_toList (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
|
||||
simp [toListAppend, foldr_eq_foldr_toList]
|
||||
simp [toListAppend, ← foldr_toList]
|
||||
|
||||
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
|
||||
simp [toListImpl, foldr_eq_foldr_toList]
|
||||
simp [toListImpl, ← foldr_toList]
|
||||
|
||||
@[simp] theorem pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
|
||||
|
||||
@@ -76,9 +76,20 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
|
||||
@[simp] theorem toList_append (arr arr' : Array α) :
|
||||
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
|
||||
rw [← append_eq_append]; unfold Array.append
|
||||
rw [foldl_eq_foldl_toList]
|
||||
rw [← foldl_toList]
|
||||
induction arr'.toList generalizing arr <;> simp [*]
|
||||
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
@[simp] theorem appendList_eq_append
|
||||
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
|
||||
|
||||
@@ -87,20 +98,44 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing arr <;> simp [*]
|
||||
|
||||
@[deprecated foldlM_eq_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldlM_eq_foldlM_data := @foldlM_eq_foldlM_toList
|
||||
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.toList.foldrM f init := by
|
||||
simp
|
||||
|
||||
@[deprecated foldl_eq_foldl_toList (since := "2024-09-09")]
|
||||
abbrev foldl_eq_foldl_data := @foldl_eq_foldl_toList
|
||||
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
arr.foldlM f init = arr.toList.foldlM f init:= by
|
||||
simp
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldr_toList`." (since := "2024-11-13")]
|
||||
theorem foldr_eq_foldr_toList
|
||||
(f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.toList.foldr f init := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldl_toList`." (since := "2024-11-13")]
|
||||
theorem foldl_eq_foldl_toList
|
||||
(f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.toList.foldl f init:= by
|
||||
simp
|
||||
|
||||
@[deprecated foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldlM_eq_foldlM_data := @foldlM_toList
|
||||
|
||||
@[deprecated foldl_toList (since := "2024-09-09")]
|
||||
abbrev foldl_eq_foldl_data := @foldl_toList
|
||||
|
||||
@[deprecated foldrM_eq_reverse_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_reverse_foldlM_data := @foldrM_eq_reverse_foldlM_toList
|
||||
|
||||
@[deprecated foldrM_eq_foldrM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_foldrM_data := @foldrM_eq_foldrM_toList
|
||||
@[deprecated foldrM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_foldrM_data := @foldrM_toList
|
||||
|
||||
@[deprecated foldr_eq_foldr_toList (since := "2024-09-09")]
|
||||
abbrev foldr_eq_foldr_data := @foldr_eq_foldr_toList
|
||||
@[deprecated foldr_toList (since := "2024-09-09")]
|
||||
abbrev foldr_eq_foldr_data := @foldr_toList
|
||||
|
||||
@[deprecated push_toList (since := "2024-09-09")]
|
||||
abbrev push_data := @push_toList
|
||||
|
||||
@@ -6,16 +6,15 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.BEq
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.ByCases
|
||||
|
||||
namespace Array
|
||||
|
||||
theorem rel_of_isEqvAux
|
||||
(r : α → α → Bool) (a b : Array α) (hsz : a.size = b.size) (i : Nat) (hi : i ≤ a.size)
|
||||
{r : α → α → Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i ≤ a.size)
|
||||
(heqv : Array.isEqvAux a b hsz r i hi)
|
||||
(j : Nat) (hj : j < i) : r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz ▸ hi))) := by
|
||||
{j : Nat} (hj : j < i) : r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz ▸ hi))) := by
|
||||
induction i with
|
||||
| zero => contradiction
|
||||
| succ i ih =>
|
||||
@@ -28,7 +27,7 @@ theorem rel_of_isEqvAux
|
||||
subst hj'
|
||||
exact heqv.left
|
||||
|
||||
theorem isEqvAux_of_rel (r : α → α → Bool) (a b : Array α) (hsz : a.size = b.size) (i : Nat) (hi : i ≤ a.size)
|
||||
theorem isEqvAux_of_rel {r : α → α → Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i ≤ a.size)
|
||||
(w : ∀ j, (hj : j < i) → r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz ▸ hi)))) : Array.isEqvAux a b hsz r i hi := by
|
||||
induction i with
|
||||
| zero => simp [Array.isEqvAux]
|
||||
@@ -36,18 +35,18 @@ theorem isEqvAux_of_rel (r : α → α → Bool) (a b : Array α) (hsz : a.size
|
||||
simp only [isEqvAux, Bool.and_eq_true]
|
||||
exact ⟨w i (Nat.lt_add_one i), ih _ fun j hj => w j (Nat.lt_add_right 1 hj)⟩
|
||||
|
||||
theorem rel_of_isEqv (r : α → α → Bool) (a b : Array α) :
|
||||
theorem rel_of_isEqv {r : α → α → Bool} {a b : Array α} :
|
||||
Array.isEqv a b r → ∃ h : a.size = b.size, ∀ (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h ▸ h')) := by
|
||||
simp only [isEqv]
|
||||
split <;> rename_i h
|
||||
· exact fun h' => ⟨h, rel_of_isEqvAux r a b h a.size (Nat.le_refl ..) h'⟩
|
||||
· exact fun h' => ⟨h, fun i => rel_of_isEqvAux h (Nat.le_refl ..) h'⟩
|
||||
· intro; contradiction
|
||||
|
||||
theorem isEqv_iff_rel (a b : Array α) (r) :
|
||||
Array.isEqv a b r ↔ ∃ h : a.size = b.size, ∀ (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h ▸ h')) :=
|
||||
⟨rel_of_isEqv r a b, fun ⟨h, w⟩ => by
|
||||
⟨rel_of_isEqv, fun ⟨h, w⟩ => by
|
||||
simp only [isEqv, ← h, ↓reduceDIte]
|
||||
exact isEqvAux_of_rel r a b h a.size (by simp [h]) w⟩
|
||||
exact isEqvAux_of_rel h (by simp [h]) w⟩
|
||||
|
||||
theorem isEqv_eq_decide (a b : Array α) (r) :
|
||||
Array.isEqv a b r =
|
||||
@@ -67,7 +66,7 @@ theorem isEqv_eq_decide (a b : Array α) (r) :
|
||||
simp [isEqv_eq_decide, List.isEqv_eq_decide]
|
||||
|
||||
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) (h : Array.isEqv a b (fun x y => x = y)) : a = b := by
|
||||
have ⟨h, h'⟩ := rel_of_isEqv (fun x y => x = y) a b h
|
||||
have ⟨h, h'⟩ := rel_of_isEqv h
|
||||
exact ext _ _ h (fun i lt _ => by simpa using h' i lt)
|
||||
|
||||
theorem isEqvAux_self (r : α → α → Bool) (hr : ∀ a, r a a) (a : Array α) (i : Nat) (h : i ≤ a.size) :
|
||||
|
||||
14
src/Init/Data/Array/FinRange.lean
Normal file
14
src/Init/Data/Array/FinRange.lean
Normal file
@@ -0,0 +1,14 @@
|
||||
/-
|
||||
Copyright (c) 2024 François G. Dorais. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
namespace Array
|
||||
|
||||
/-- `finRange n` is the array of all elements of `Fin n` in order. -/
|
||||
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
|
||||
|
||||
end Array
|
||||
281
src/Init/Data/Array/Find.lean
Normal file
281
src/Init/Data/Array/Find.lean
Normal file
@@ -0,0 +1,281 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Find
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.findSome?`, `Array.find?`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp] theorem findSomeRev?_push_of_isSome (l : Array α) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
|
||||
cases l; simp_all
|
||||
|
||||
@[simp] theorem findSomeRev?_push_of_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
|
||||
cases l; simp_all
|
||||
|
||||
theorem exists_of_findSome?_eq_some {f : α → Option β} {l : Array α} (w : l.findSome? f = some b) :
|
||||
∃ a, a ∈ l ∧ f a = b := by
|
||||
cases l; simp_all [List.exists_of_findSome?_eq_some]
|
||||
|
||||
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none ↔ ∀ x ∈ l, p x = none := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem findSome?_isSome_iff {f : α → Option β} {l : Array α} :
|
||||
(l.findSome? f).isSome ↔ ∃ x, x ∈ l ∧ (f x).isSome := by
|
||||
cases l; simp
|
||||
|
||||
theorem findSome?_eq_some_iff {f : α → Option β} {l : Array α} {b : β} :
|
||||
l.findSome? f = some b ↔ ∃ (l₁ : Array α) (a : α) (l₂ : Array α), l = l₁.push a ++ l₂ ∧ f a = some b ∧ ∀ x ∈ l₁, f x = none := by
|
||||
cases l
|
||||
simp only [List.findSome?_toArray, List.findSome?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, a, l₂, rfl, h₁, h₂⟩
|
||||
exact ⟨l₁.toArray, a, l₂.toArray, by simp_all⟩
|
||||
· rintro ⟨l₁, a, l₂, h₀, h₁, h₂⟩
|
||||
exact ⟨l₁.toList, a, l₂.toList, by simpa using congrArg toList h₀, h₁, by simpa⟩
|
||||
|
||||
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem getElem?_zero_filterMap (f : α → Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
|
||||
cases l; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filterMap (f : α → Option β) (l : Array α) (h) :
|
||||
(l.filterMap f)[0] = (l.findSome? f).get (by cases l; simpa [List.length_filterMap_eq_countP] using h) := by
|
||||
cases l; simp [← List.head_eq_getElem, ← getElem?_zero_filterMap]
|
||||
|
||||
@[simp] theorem back?_filterMap (f : α → Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem back!_filterMap [Inhabited β] (f : α → Option β) (l : Array α) :
|
||||
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem map_findSome? (f : α → Option β) (g : β → γ) (l : Array α) :
|
||||
(l.findSome? f).map g = l.findSome? (Option.map g ∘ f) := by
|
||||
cases l; simp
|
||||
|
||||
theorem findSome?_map (f : β → γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p ∘ f) := by
|
||||
cases l; simp [List.findSome?_map]
|
||||
|
||||
theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
|
||||
cases l₁; cases l₂; simp [List.findSome?_append]
|
||||
|
||||
theorem getElem?_zero_flatten (L : Array (Array α)) :
|
||||
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
|
||||
cases L using array_array_induction
|
||||
simp [← List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
|
||||
(L.findSome? fun l => l[0]?).isSome := by
|
||||
cases L using array_array_induction
|
||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
||||
List.findSome?_isSome_iff, isSome_getElem?]
|
||||
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
|
||||
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
exact ⟨xs, m, by simpa using h⟩
|
||||
|
||||
theorem getElem_zero_flatten {L : Array (Array α)} (h) :
|
||||
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
|
||||
have t := getElem?_zero_flatten L
|
||||
simp [getElem?_eq_getElem, h] at t
|
||||
simp [← t]
|
||||
|
||||
theorem back?_flatten {L : Array (Array α)} :
|
||||
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
|
||||
cases L using array_array_induction
|
||||
simp [List.getLast?_flatten, ← List.map_reverse, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@[simp] theorem findSome?_mkArray_of_pos (h : 0 < n) : findSome? f (mkArray n a) = f a := by
|
||||
simp [findSome?_mkArray, Nat.ne_of_gt h]
|
||||
|
||||
-- Argument is unused, but used to decide whether `simp` should unfold.
|
||||
@[simp] theorem findSome?_mkArray_of_isSome (_ : (f a).isSome) :
|
||||
findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
simp [findSome?_mkArray]
|
||||
|
||||
@[simp] theorem findSome?_mkArray_of_isNone (h : (f a).isNone) :
|
||||
findSome? f (mkArray n a) = none := by
|
||||
rw [Option.isNone_iff_eq_none] at h
|
||||
simp [findSome?_mkArray, h]
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp] theorem find?_singleton (a : α) (p : α → Bool) :
|
||||
#[a].find? p = if p a then some a else none := by
|
||||
simp [singleton_eq_toArray_singleton]
|
||||
|
||||
@[simp] theorem findRev?_push_of_pos (l : Array α) (h : p a) :
|
||||
findRev? p (l.push a) = some a := by
|
||||
cases l; simp [h]
|
||||
|
||||
@[simp] theorem findRev?_cons_of_neg (l : Array α) (h : ¬p a) :
|
||||
findRev? p (l.push a) = findRev? p l := by
|
||||
cases l; simp [h]
|
||||
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
cases l; simp
|
||||
|
||||
theorem find?_eq_some_iff_append {xs : Array α} :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ (as bs : Array α), xs = as.push b ++ bs ∧ ∀ a ∈ as, !p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.find?_toArray, List.find?_eq_some_iff_append, Bool.not_eq_eq_eq_not,
|
||||
Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ⟨⟨x, rfl⟩, h⟩⟩
|
||||
exact ⟨as.toArray, ⟨x.toArray, by simp⟩ , by simpa using h⟩
|
||||
· rintro ⟨as, ⟨⟨x, h'⟩, h⟩⟩
|
||||
exact ⟨as.toList, ⟨x.toList, by simpa using congrArg Array.toList h'⟩,
|
||||
by simpa using h⟩
|
||||
|
||||
@[simp]
|
||||
theorem find?_push_eq_some {xs : Array α} :
|
||||
(xs.push a).find? p = some b ↔ xs.find? p = some b ∨ (xs.find? p = none ∧ (p a ∧ a = b)) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_some {xs : Array α} (h : find? p xs = some a) : p a := by
|
||||
cases xs
|
||||
simp at h
|
||||
exact List.find?_some h
|
||||
|
||||
theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ xs := by
|
||||
cases xs
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
@[simp] 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
|
||||
|
||||
@[simp] theorem getElem?_zero_filter (p : α → Bool) (l : Array α) :
|
||||
(l.filter p)[0]? = l.find? p := by
|
||||
cases l; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filter (p : α → Bool) (l : Array α) (h) :
|
||||
(l.filter p)[0] =
|
||||
(l.find? p).get (by cases l; simpa [← List.countP_eq_length_filter] using h) := by
|
||||
cases l
|
||||
simp [List.getElem_zero_eq_head]
|
||||
|
||||
@[simp] theorem back?_filter (p : α → Bool) (l : Array α) : (l.filter p).back? = l.findRev? p := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem back!_filter [Inhabited α] (p : α → Bool) (l : Array α) :
|
||||
(l.filter p).back! = (l.findRev? p).get! := by
|
||||
cases l; simp [Option.get!_eq_getD]
|
||||
|
||||
@[simp] theorem find?_filterMap (xs : Array α) (f : α → Option β) (p : β → Bool) :
|
||||
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_map (f : β → α) (xs : Array β) :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_append {l₁ l₂ : Array α} :
|
||||
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α → Bool) :
|
||||
xs.flatten.find? p = xs.findSome? (·.find? p) := by
|
||||
cases xs using array_array_induction
|
||||
simp [List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem find?_flatten_eq_none {xs : Array (Array α)} {p : α → Bool} :
|
||||
xs.flatten.find? p = none ↔ ∀ ys ∈ xs, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
|
||||
Moreover, no earlier array in `xs` has an element satisfying `p`.
|
||||
-/
|
||||
theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α → Bool} {a : α} :
|
||||
xs.flatten.find? p = some a ↔
|
||||
p a ∧ ∃ (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
|
||||
xs = as.push (ys.push a ++ zs) ++ bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
cases xs using array_array_induction
|
||||
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ys, ⟨⟨zs, bs, rfl⟩, h₁, h₂⟩⟩
|
||||
exact ⟨as.toArray.map List.toArray, ys.toArray,
|
||||
⟨zs.toArray, bs.toArray.map List.toArray, by simp⟩, by simpa using h₁, by simpa using h₂⟩
|
||||
· rintro ⟨as, ys, ⟨⟨zs, bs, h⟩, h₁, h₂⟩⟩
|
||||
replace h := congrArg (·.map Array.toList) (congrArg Array.toList h)
|
||||
simp [Function.comp_def] at h
|
||||
exact ⟨as.toList.map Array.toList, ys.toList,
|
||||
⟨zs.toList, bs.toList.map Array.toList, by simpa using h⟩,
|
||||
by simpa using h₁, by simpa using h₂⟩
|
||||
|
||||
@[simp] theorem find?_flatMap (xs : Array α) (f : α → Array β) (p : β → Bool) :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
simp [List.find?_flatMap, Array.flatMap_toArray]
|
||||
|
||||
theorem find?_flatMap_eq_none {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
simp
|
||||
|
||||
theorem find?_mkArray :
|
||||
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_length_pos (h : 0 < n) :
|
||||
find? p (mkArray n a) = if p a then some a else none := by
|
||||
simp [find?_mkArray, Nat.ne_of_gt h]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_pos (h : p a) :
|
||||
find? p (mkArray n a) = if n = 0 then none else some a := by
|
||||
simp [find?_mkArray, h]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_neg (h : ¬ p a) : find? p (mkArray n a) = none := by
|
||||
simp [find?_mkArray, h]
|
||||
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
|
||||
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α → Bool) (h) :
|
||||
((mkArray n a).find? p).get h = a := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
|
||||
theorem find?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (p : β → Bool) :
|
||||
(xs.pmap f H).find? p = (xs.attach.find? (fun ⟨a, m⟩ => p (f a (H a m)))).map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
simp only [pmap_eq_map_attach, find?_map]
|
||||
rfl
|
||||
|
||||
end Array
|
||||
@@ -41,6 +41,6 @@ where
|
||||
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) ▸ h₂) :=
|
||||
rfl
|
||||
go (i : Nat) (hi : i ≤ as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.get_drop_eq_drop, *]
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
|
||||
@[inline] def Array.insertionSort (a : Array α) (lt : α → α → Bool) : Array α :=
|
||||
@[inline] def Array.insertionSort (a : Array α) (lt : α → α → Bool := by exact (· < ·)) : Array α :=
|
||||
traverse a 0 a.size
|
||||
where
|
||||
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
|
||||
@@ -23,6 +23,6 @@ where
|
||||
| j'+1 =>
|
||||
have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
|
||||
if lt a[j] a[j'] then
|
||||
swapLoop (a.swap ⟨j, h⟩ ⟨j', h'⟩) j' (by rw [size_swap]; assumption; done)
|
||||
swapLoop (a.swap j j') j' (by rw [size_swap]; assumption; done)
|
||||
else
|
||||
a
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,33 +60,53 @@ theorem mapFinIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
||||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem toList_mapFinIdx (a : Array α) (f : Fin a.size → α → β) :
|
||||
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a => f ⟨i, by simp⟩ a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
theorem mapIdx_induction (as : Array α) (f : Nat → α → β)
|
||||
theorem mapIdx_induction (f : Nat → α → β) (as : Array α)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
motive as.size ∧ ∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
mapFinIdx_induction as (fun i a => f i a) motive h0 p hs
|
||||
|
||||
theorem mapIdx_spec (as : Array α) (f : Nat → α → β)
|
||||
theorem mapIdx_spec (f : Nat → α → β) (as : Array α)
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx (a : Array α) (f : Nat → α → β) : (a.mapIdx f).size = a.size :=
|
||||
@[simp] theorem size_mapIdx (f : Nat → α → β) (as : Array α) : (as.mapIdx f).size = as.size :=
|
||||
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem getElem_mapIdx (a : Array α) (f : Nat → α → β) (i : Nat)
|
||||
(h : i < (mapIdx a f).size) :
|
||||
(a.mapIdx f)[i] = f i (a[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i (by simp_all)
|
||||
@[simp] theorem getElem_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat)
|
||||
(h : i < (as.mapIdx f).size) :
|
||||
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i as[i]) fun _ => rfl).2 i (by simp_all)
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (a : Array α) (f : Nat → α → β) (i : Nat) :
|
||||
(a.mapIdx f)[i]? =
|
||||
a[i]?.map (f i) := by
|
||||
@[simp] theorem getElem?_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat) :
|
||||
(as.mapIdx f)[i]? =
|
||||
as[i]?.map (f i) := by
|
||||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
|
||||
@[simp] theorem toList_mapIdx (f : Nat → α → β) (as : Array α) :
|
||||
(as.mapIdx f).toList = as.toList.mapIdx (fun i a => f i a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp] theorem mapFinIdx_toArray (l : List α) (f : Fin l.length → α → β) :
|
||||
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_toArray (f : Nat → α → β) (l : List α) :
|
||||
l.toArray.mapIdx f = (l.mapIdx f).toArray := by
|
||||
ext <;> simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -10,25 +10,16 @@ import Init.Data.List.BasicAux
|
||||
|
||||
namespace Array
|
||||
|
||||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||
structure Mem (as : Array α) (a : α) : Prop where
|
||||
val : a ∈ as.toList
|
||||
|
||||
instance : Membership α (Array α) where
|
||||
mem := Mem
|
||||
|
||||
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
|
||||
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf (as.get i h) < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
||||
simpa using Nat.lt_trans (List.sizeOf_get _ ⟨i, h⟩) (by simp_arith)
|
||||
|
||||
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
|
||||
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _
|
||||
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _ h
|
||||
|
||||
/-- This tactic, added to the `decreasing_trivial` toolbox, proves that
|
||||
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions
|
||||
|
||||
159
src/Init/Data/Array/Monadic.lean
Normal file
159
src/Init/Data/Array/Monadic.lean
Normal file
@@ -0,0 +1,159 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.List.Monadic
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.forIn'` and `Array.forIn`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ## Monadic operations -/
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α → m β) (l : Array α) :
|
||||
mapM f l = l.foldlM (fun acc a => return (acc.push (← f a))) #[] := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.mapM_toArray, bind_pure_comp, size_toArray, List.foldlM_toArray']
|
||||
rw [List.mapM_eq_reverse_foldlM_cons]
|
||||
simp only [bind_pure_comp, Functor.map_map]
|
||||
suffices ∀ (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
|
||||
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
|
||||
exact this []
|
||||
intro k
|
||||
induction l generalizing k with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp [ih, List.foldlM_cons]
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : Array β₁) (init : α) :
|
||||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||||
cases l
|
||||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : Array β₁)
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
cases l
|
||||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_map]
|
||||
|
||||
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : Array α) (init : γ) :
|
||||
(l.filterMap f).foldlM g init =
|
||||
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
|
||||
cases l
|
||||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_filterMap]
|
||||
rfl
|
||||
|
||||
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : Array α) (init : γ) :
|
||||
(l.filterMap f).foldrM g init =
|
||||
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
|
||||
cases l
|
||||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_filterMap]
|
||||
rfl
|
||||
|
||||
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : Array α) (init : β) :
|
||||
(l.filter p).foldlM g init =
|
||||
l.foldlM (fun x y => if p y then g x y else pure x) init := by
|
||||
cases l
|
||||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_filter]
|
||||
|
||||
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : Array α) (init : β) :
|
||||
(l.filter p).foldrM g init =
|
||||
l.foldrM (fun x y => if p x then g x y else pure y) init := by
|
||||
cases l
|
||||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_filter]
|
||||
|
||||
/-! ### forIn' -/
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
|
||||
forIn' l init f = ForInStep.value <$>
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => match b with
|
||||
| .yield b => f a m b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
cases l
|
||||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp only [List.forIn'_toArray, List.forIn'_eq_foldlM, List.attachWith_mem_toArray, size_toArray,
|
||||
List.length_map, List.length_attach, List.foldlM_toArray', List.foldlM_map]
|
||||
congr
|
||||
|
||||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||||
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
|
||||
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => g a m b <$> f a m b) init := by
|
||||
cases l
|
||||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' l init (fun a m b => pure (.yield (f a m b))) =
|
||||
pure (f := m) (l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init) := by
|
||||
cases l
|
||||
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(f : α → β → m (ForInStep β)) (init : β) (l : Array α) :
|
||||
forIn l init f = ForInStep.value <$>
|
||||
l.foldlM (fun b a => match b with
|
||||
| .yield b => f a b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
cases l
|
||||
simp only [List.forIn_toArray, List.forIn_eq_foldlM, size_toArray, List.foldlM_toArray']
|
||||
congr
|
||||
|
||||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||||
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
|
||||
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
l.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
cases l
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : α → β → β) (init : β) :
|
||||
forIn l init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (l.foldl (fun b a => f a b) init) := by
|
||||
cases l
|
||||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
(l : Array α) (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init := by
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
end Array
|
||||
65
src/Init/Data/Array/Perm.lean
Normal file
65
src/Init/Data/Array/Perm.lean
Normal file
@@ -0,0 +1,65 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Nat.Perm
|
||||
import Init.Data.Array.Lemmas
|
||||
|
||||
namespace Array
|
||||
|
||||
open List
|
||||
|
||||
/--
|
||||
`Perm as bs` asserts that `as` and `bs` are permutations of each other.
|
||||
|
||||
This is a wrapper around `List.Perm`, and for now has much less API.
|
||||
For more complicated verification, use `perm_iff_toList_perm` and the `List` API.
|
||||
-/
|
||||
def Perm (as bs : Array α) : Prop :=
|
||||
as.toList ~ bs.toList
|
||||
|
||||
@[inherit_doc] scoped infixl:50 " ~ " => Perm
|
||||
|
||||
theorem perm_iff_toList_perm {as bs : Array α} : as ~ bs ↔ as.toList ~ bs.toList := Iff.rfl
|
||||
|
||||
@[simp] theorem perm_toArray (as bs : List α) : as.toArray ~ bs.toArray ↔ as ~ bs := by
|
||||
simp [perm_iff_toList_perm]
|
||||
|
||||
@[simp, refl] protected theorem Perm.refl (l : Array α) : l ~ l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
protected theorem Perm.rfl {l : List α} : l ~ l := .refl _
|
||||
|
||||
theorem Perm.of_eq {l₁ l₂ : Array α} (h : l₁ = l₂) : l₁ ~ l₂ := h ▸ .rfl
|
||||
|
||||
protected theorem Perm.symm {l₁ l₂ : Array α} (h : l₁ ~ l₂) : l₂ ~ l₁ := by
|
||||
cases l₁; cases l₂
|
||||
simp only [perm_toArray] at h
|
||||
simpa using h.symm
|
||||
|
||||
protected theorem Perm.trans {l₁ l₂ l₃ : Array α} (h₁ : l₁ ~ l₂) (h₂ : l₂ ~ l₃) : l₁ ~ l₃ := by
|
||||
cases l₁; cases l₂; cases l₃
|
||||
simp only [perm_toArray] at h₁ h₂
|
||||
simpa using h₁.trans h₂
|
||||
|
||||
instance : Trans (Perm (α := α)) (Perm (α := α)) (Perm (α := α)) where
|
||||
trans h₁ h₂ := Perm.trans h₁ h₂
|
||||
|
||||
theorem perm_comm {l₁ l₂ : Array α} : l₁ ~ l₂ ↔ l₂ ~ l₁ := ⟨Perm.symm, Perm.symm⟩
|
||||
|
||||
theorem Perm.push (x y : α) {l₁ l₂ : Array α} (p : l₁ ~ l₂) :
|
||||
(l₁.push x).push y ~ (l₂.push y).push x := by
|
||||
cases l₁; cases l₂
|
||||
simp only [perm_toArray] at p
|
||||
simp only [push_toArray, List.append_assoc, singleton_append, perm_toArray]
|
||||
exact p.append (Perm.swap' _ _ Perm.nil)
|
||||
|
||||
theorem swap_perm {as : Array α} {i j : Nat} (h₁ : i < as.size) (h₂ : j < as.size) :
|
||||
as.swap i j ~ as := by
|
||||
simp only [swap, perm_iff_toList_perm, toList_set]
|
||||
apply set_set_perm
|
||||
|
||||
end Array
|
||||
@@ -4,46 +4,46 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Vector.Basic
|
||||
import Init.Data.Ord
|
||||
|
||||
namespace Array
|
||||
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
|
||||
|
||||
def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat × Array α :=
|
||||
if h : as.size = 0 then (0, as) else have : Inhabited α := ⟨as[0]'(by revert h; cases as.size <;> simp)⟩ -- TODO: remove
|
||||
private def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {n : Nat // lo ≤ n} × Vector α n :=
|
||||
let mid := (lo + hi) / 2
|
||||
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
|
||||
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
|
||||
let as := if lt (as.get! mid) (as.get! hi) then as.swap! mid hi else as
|
||||
let pivot := as.get! hi
|
||||
let rec loop (as : Array α) (i j : Nat) :=
|
||||
let as := if lt as[mid] as[lo] then as.swap lo mid else as
|
||||
let as := if lt as[hi] as[lo] then as.swap lo hi else as
|
||||
let as := if lt as[mid] as[hi] then as.swap mid hi else as
|
||||
let pivot := as[hi]
|
||||
let rec loop (as : Vector α n) (i j : Nat)
|
||||
(ilo : lo ≤ i := by omega) (jh : j < n := by omega) (w : i ≤ j := by omega) :=
|
||||
if h : j < hi then
|
||||
if lt (as.get! j) pivot then
|
||||
let as := as.swap! i j
|
||||
loop as (i+1) (j+1)
|
||||
if lt as[j] pivot then
|
||||
loop (as.swap i j) (i+1) (j+1)
|
||||
else
|
||||
loop as i (j+1)
|
||||
else
|
||||
let as := as.swap! i hi
|
||||
(i, as)
|
||||
termination_by hi - j
|
||||
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
|
||||
(⟨i, ilo⟩, as.swap i hi)
|
||||
loop as lo lo
|
||||
|
||||
@[inline] partial def qsort (as : Array α) (lt : α → α → Bool) (low := 0) (high := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort (as : Array α) (low high : Nat) :=
|
||||
if low < high then
|
||||
let p := qpartition as lt low high;
|
||||
-- TODO: fix `partial` support in the equation compiler, it breaks if we use `let (mid, as) := partition as lt low high`
|
||||
let mid := p.1
|
||||
let as := p.2
|
||||
if mid >= high then as
|
||||
@[inline] def qsort (as : Array α) (lt : α → α → Bool := by exact (· < ·))
|
||||
(low := 0) (high := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) :=
|
||||
if h₁ : lo < hi then
|
||||
let ⟨⟨mid, hmid⟩, as⟩ := qpartition as lt lo hi
|
||||
if h₂ : mid ≥ hi then
|
||||
as
|
||||
else
|
||||
let as := sort as low mid
|
||||
sort as (mid+1) high
|
||||
sort (sort as lo mid) (mid+1) hi
|
||||
else as
|
||||
sort as low high
|
||||
if h : as.size = 0 then
|
||||
as
|
||||
else
|
||||
let low := min low (as.size - 1)
|
||||
let high := min high (as.size - 1)
|
||||
sort ⟨as, rfl⟩ low high |>.toArray
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
|
||||
41
src/Init/Data/Array/Set.lean
Normal file
41
src/Init/Data/Array/Set.lean
Normal file
@@ -0,0 +1,41 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Tactics
|
||||
|
||||
|
||||
/--
|
||||
Set an element in an array, using a proof that the index is in bounds.
|
||||
(This proof can usually be omitted, and will be synthesized automatically.)
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_fset"]
|
||||
def Array.set (a : Array α) (i : @& Nat) (v : α) (h : i < a.size := by get_elem_tactic) :
|
||||
Array α where
|
||||
toList := a.toList.set i v
|
||||
|
||||
/--
|
||||
Set an element in an array, or do nothing if the index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[inline] def Array.setIfInBounds (a : Array α) (i : Nat) (v : α) : Array α :=
|
||||
dite (LT.lt i a.size) (fun h => a.set i v h) (fun _ => a)
|
||||
|
||||
@[deprecated Array.setIfInBounds (since := "2024-11-24")] abbrev Array.setD := @Array.setIfInBounds
|
||||
|
||||
/--
|
||||
Set an element in an array, or panic if the index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_set"]
|
||||
def Array.set! (a : Array α) (i : @& Nat) (v : α) : Array α :=
|
||||
Array.setIfInBounds a i v
|
||||
@@ -15,15 +15,6 @@ structure Subarray (α : Type u) where
|
||||
start_le_stop : start ≤ stop
|
||||
stop_le_array_size : stop ≤ array.size
|
||||
|
||||
@[deprecated Subarray.array (since := "2024-04-13")]
|
||||
abbrev Subarray.as (s : Subarray α) : Array α := s.array
|
||||
|
||||
@[deprecated Subarray.start_le_stop (since := "2024-04-13")]
|
||||
theorem Subarray.h₁ (s : Subarray α) : s.start ≤ s.stop := s.start_le_stop
|
||||
|
||||
@[deprecated Subarray.stop_le_array_size (since := "2024-04-13")]
|
||||
theorem Subarray.h₂ (s : Subarray α) : s.stop ≤ s.array.size := s.stop_le_array_size
|
||||
|
||||
namespace Subarray
|
||||
|
||||
def size (s : Subarray α) : Nat :=
|
||||
@@ -48,7 +39,7 @@ instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
||||
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
||||
if h : i < s.size then s[i] else v₀
|
||||
|
||||
abbrev get! [Inhabited α] (s : Subarray α) (i : Nat) : α :=
|
||||
getD s i default
|
||||
|
||||
@@ -23,16 +23,13 @@ def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α)
|
||||
let ⟨i', isLt⟩ := i
|
||||
have := s.start_le_stop
|
||||
have := s.stop_le_array_size
|
||||
have : i' ≤ s.stop - s.start := Nat.lt_succ.mp isLt
|
||||
have : s.start + i' ≤ s.stop := by omega
|
||||
have : s.start + i' ≤ s.array.size := by omega
|
||||
have : s.start + i' ≤ s.stop := by
|
||||
simp only [size] at isLt
|
||||
omega
|
||||
let pre := {s with
|
||||
stop := s.start + i',
|
||||
start_le_stop := by omega,
|
||||
stop_le_array_size := by assumption
|
||||
stop_le_array_size := by omega
|
||||
}
|
||||
let post := {s with
|
||||
start := s.start + i'
|
||||
@@ -48,9 +45,7 @@ def drop (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
array := arr.array
|
||||
start := min (arr.start + i) arr.stop
|
||||
stop := arr.stop
|
||||
start_le_stop := by
|
||||
rw [Nat.min_def]
|
||||
split <;> simp only [Nat.le_refl, *]
|
||||
start_le_stop := by omega
|
||||
stop_le_array_size := arr.stop_le_array_size
|
||||
|
||||
/--
|
||||
@@ -63,9 +58,7 @@ def take (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
stop := min (arr.start + i) arr.stop
|
||||
start_le_stop := by
|
||||
have := arr.start_le_stop
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
omega
|
||||
stop_le_array_size := by
|
||||
have := arr.stop_le_array_size
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
omega
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Array
|
||||
theorem exists_of_uset (self : Array α) (i d h) :
|
||||
∃ l₁ l₂, self.toList = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||
(self.uset i d h).toList = l₁ ++ d :: l₂ := by
|
||||
simpa only [ugetElem_eq_getElem, getElem_eq_getElem_toList, uset, toList_set] using
|
||||
simpa only [ugetElem_eq_getElem, ← getElem_toList, uset, toList_set] using
|
||||
List.exists_of_set _
|
||||
|
||||
end Array
|
||||
|
||||
@@ -29,9 +29,6 @@ section Nat
|
||||
|
||||
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||
|
||||
@[deprecated isLt (since := "2024-03-12")]
|
||||
theorem toNat_lt (x : BitVec n) : x.toNat < 2^n := x.isLt
|
||||
|
||||
/-- Theorem for normalizing the bit vector literal representation. -/
|
||||
-- TODO: This needs more usage data to assess which direction the simp should go.
|
||||
@[simp, bv_toNat] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
|
||||
@@ -354,17 +351,17 @@ end relations
|
||||
section cast
|
||||
|
||||
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
|
||||
@[inline] def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq ▸ x.isLt)
|
||||
@[inline] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq ▸ x.isLt)
|
||||
|
||||
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
||||
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
|
||||
(BitVec.ofNat n x).cast h = BitVec.ofNat m x := by
|
||||
subst h; rfl
|
||||
|
||||
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
|
||||
cast h₂ (cast h₁ x) = cast (h₁ ▸ h₂) x :=
|
||||
(x.cast h₁).cast h₂ = x.cast (h₁ ▸ h₂) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : cast h x = x := rfl
|
||||
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
|
||||
|
||||
/--
|
||||
Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to yield a
|
||||
@@ -634,6 +631,16 @@ def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
|
||||
|
||||
end bitwise
|
||||
|
||||
/-- Compute a hash of a bitvector, combining 64-bit words using `mixHash`. -/
|
||||
def hash (bv : BitVec n) : UInt64 :=
|
||||
if n ≤ 64 then
|
||||
bv.toFin.val.toUInt64
|
||||
else
|
||||
mixHash (bv.toFin.val.toUInt64) (hash ((bv >>> 64).setWidth (n - 64)))
|
||||
|
||||
instance : Hashable (BitVec n) where
|
||||
hash := hash
|
||||
|
||||
section normalization_eqs
|
||||
/-! We add simp-lemmas that rewrite bitvector operations into the equivalent notation -/
|
||||
@[simp] theorem append_eq (x : BitVec w) (y : BitVec v) : BitVec.append x y = x ++ y := rfl
|
||||
|
||||
@@ -76,7 +76,7 @@ to prove the correctness of the circuit that is built by `bv_decide`.
|
||||
def blastMul (aig : AIG BVBit) (input : AIG.BinaryRefVec aig w) : AIG.RefVecEntry BVBit w
|
||||
theorem denote_blastMul (aig : AIG BVBit) (lhs rhs : BitVec w) (assign : Assignment) :
|
||||
...
|
||||
⟦(blastMul aig input).aig, (blastMul aig input).vec.get idx hidx, assign.toAIGAssignment⟧
|
||||
⟦(blastMul aig input).aig, (blastMul aig input).vec[idx], assign.toAIGAssignment⟧
|
||||
=
|
||||
(lhs * rhs).getLsbD idx
|
||||
```
|
||||
@@ -174,6 +174,30 @@ theorem carry_succ (i : Nat) (x y : BitVec w) (c : Bool) :
|
||||
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
|
||||
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
|
||||
|
||||
theorem carry_succ_one (i : Nat) (x : BitVec w) (h : 0 < w) :
|
||||
carry (i+1) x (1#w) false = decide (∀ j ≤ i, x.getLsbD j = true) := by
|
||||
induction i with
|
||||
| zero => simp [carry_succ, h]
|
||||
| succ i ih =>
|
||||
rw [carry_succ, ih]
|
||||
simp only [getLsbD_one, add_one_ne_zero, decide_false, Bool.and_false, atLeastTwo_false_mid]
|
||||
cases hx : x.getLsbD (i+1)
|
||||
case false =>
|
||||
have : ∃ j ≤ i + 1, x.getLsbD j = false :=
|
||||
⟨i+1, by omega, hx⟩
|
||||
simpa
|
||||
case true =>
|
||||
suffices
|
||||
(∀ (j : Nat), j ≤ i → x.getLsbD j = true)
|
||||
↔ (∀ (j : Nat), j ≤ i + 1 → x.getLsbD j = true) by
|
||||
simpa
|
||||
constructor
|
||||
· intro h j hj
|
||||
rcases Nat.le_or_eq_of_le_succ hj with (hj' | rfl)
|
||||
· apply h; assumption
|
||||
· exact hx
|
||||
· intro h j hj; apply h; omega
|
||||
|
||||
/--
|
||||
If `x &&& y = 0`, then the carry bit `(x + y + 0)` is always `false` for any index `i`.
|
||||
Intuitively, this is because a carry is only produced when at least two of `x`, `y`, and the
|
||||
@@ -225,7 +249,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
|
||||
[ Nat.testBit_mod_two_pow,
|
||||
Nat.testBit_mul_two_pow_add_eq,
|
||||
i_lt,
|
||||
decide_True,
|
||||
decide_true,
|
||||
Bool.true_and,
|
||||
Nat.add_assoc,
|
||||
Nat.add_left_comm (_%_) (_ * _) _,
|
||||
@@ -322,6 +346,10 @@ theorem getMsbD_sub {i : Nat} {i_lt : i < w} {x y : BitVec w} :
|
||||
· rfl
|
||||
· omega
|
||||
|
||||
theorem getElem_sub {i : Nat} {x y : BitVec w} (h : i < w) :
|
||||
(x - y)[i] = (x[i] ^^ ((~~~y + 1#w)[i] ^^ carry i x (~~~y + 1#w) false)) := by
|
||||
simp [← getLsbD_eq_getElem, getLsbD_sub, h]
|
||||
|
||||
theorem msb_sub {x y: BitVec w} :
|
||||
(x - y).msb
|
||||
= (x.msb ^^ ((~~~y + 1#w).msb ^^ carry (w - 1 - 0) x (~~~y + 1#w) false)) := by
|
||||
@@ -352,6 +380,121 @@ theorem bit_neg_eq_neg (x : BitVec w) : -x = (adc (((iunfoldr (fun (i : Fin w) c
|
||||
simp [← sub_toAdd, BitVec.sub_add_cancel]
|
||||
· simp [bit_not_testBit x _]
|
||||
|
||||
/--
|
||||
Remember that negating a bitvector is equal to incrementing the complement
|
||||
by one, i.e., `-x = ~~~x + 1`. See also `neg_eq_not_add`.
|
||||
|
||||
This computation has two crucial properties:
|
||||
- The least significant bit of `-x` is the same as the least significant bit of `x`, and
|
||||
- The `i+1`-th least significant bit of `-x` is the complement of the `i+1`-th bit of `x`, unless
|
||||
all of the preceding bits are `false`, in which case the bit is equal to the `i+1`-th bit of `x`
|
||||
-/
|
||||
theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
getLsbD (-x) i =
|
||||
(getLsbD x i ^^ decide (i < w) && decide (∃ j < i, getLsbD x j = true)) := by
|
||||
rw [neg_eq_not_add]
|
||||
by_cases hi : i < w
|
||||
· rw [getLsbD_add hi]
|
||||
have : 0 < w := by omega
|
||||
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
_root_.true_and, not_eq_eq_eq_not]
|
||||
cases i with
|
||||
| zero =>
|
||||
have carry_zero : carry 0 ?x ?y false = false := by
|
||||
simp [carry]; omega
|
||||
simp [hi, carry_zero]
|
||||
| succ =>
|
||||
rw [carry_succ_one _ _ (by omega), ← Bool.xor_not, ← decide_not]
|
||||
simp only [add_one_ne_zero, decide_false, getLsbD_not, and_eq_true, decide_eq_true_eq,
|
||||
not_eq_eq_eq_not, Bool.not_true, false_bne, not_exists, _root_.not_and, not_eq_true,
|
||||
bne_right_inj, decide_eq_decide]
|
||||
constructor
|
||||
· rintro h j hj; exact And.right <| h j (by omega)
|
||||
· rintro h j hj; exact ⟨by omega, h j (by omega)⟩
|
||||
· have h_ge : w ≤ i := by omega
|
||||
simp [getLsbD_ge _ _ h_ge, h_ge, hi]
|
||||
|
||||
theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
(-x)[i] = (x[i] ^^ decide (∃ j < i, x.getLsbD j = true)) := by
|
||||
simp [← getLsbD_eq_getElem, getLsbD_neg, h]
|
||||
|
||||
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
getMsbD (-x) i =
|
||||
(getMsbD x i ^^ decide (∃ j < w, i < j ∧ getMsbD x j = true)) := by
|
||||
simp only [getMsbD, getLsbD_neg, Bool.decide_and, Bool.and_eq_true, decide_eq_true_eq]
|
||||
by_cases hi : i < w
|
||||
case neg =>
|
||||
simp [hi]; omega
|
||||
case pos =>
|
||||
have h₁ : w - 1 - i < w := by omega
|
||||
simp only [hi, decide_true, h₁, Bool.true_and, Bool.bne_right_inj, decide_eq_decide]
|
||||
constructor
|
||||
· rintro ⟨j, hj, h⟩
|
||||
refine ⟨w - 1 - j, by omega, by omega, by omega, _root_.cast ?_ h⟩
|
||||
congr; omega
|
||||
· rintro ⟨j, hj₁, hj₂, -, h⟩
|
||||
exact ⟨w - 1 - j, by omega, h⟩
|
||||
|
||||
theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
(-x).msb = ((x != 0#w && x != intMin w) ^^ x.msb) := by
|
||||
simp only [BitVec.msb, getMsbD_neg]
|
||||
by_cases hmin : x = intMin _
|
||||
case pos =>
|
||||
have : (∃ j, j < w ∧ 0 < j ∧ 0 < w ∧ j = 0) ↔ False := by
|
||||
simp; omega
|
||||
simp [hmin, getMsbD_intMin, this]
|
||||
case neg =>
|
||||
by_cases hzero : x = 0#w
|
||||
case pos => simp [hzero]
|
||||
case neg =>
|
||||
have w_pos : 0 < w := by
|
||||
cases w
|
||||
· rw [@of_length_zero x] at hzero
|
||||
contradiction
|
||||
· omega
|
||||
suffices ∃ j, j < w ∧ 0 < j ∧ x.getMsbD j = true
|
||||
by simp [show x != 0#w by simpa, show x != intMin w by simpa, this]
|
||||
false_or_by_contra
|
||||
rename_i getMsbD_x
|
||||
simp only [not_exists, _root_.not_and, not_eq_true] at getMsbD_x
|
||||
/- `getMsbD` says that all bits except the msb are `false` -/
|
||||
cases hmsb : x.msb
|
||||
case true =>
|
||||
apply hmin
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
case succ => exact getMsbD_x _ hi (by omega)
|
||||
case false =>
|
||||
apply hzero
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
simp only [getMsbD_zero]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
case succ => exact getMsbD_x _ hi (by omega)
|
||||
|
||||
/-! ### abs -/
|
||||
|
||||
theorem msb_abs {w : Nat} {x : BitVec w} :
|
||||
x.abs.msb = (decide (x = intMin w) && decide (0 < w)) := by
|
||||
simp only [BitVec.abs, getMsbD_neg, ne_eq, decide_not, Bool.not_bne]
|
||||
by_cases h₀ : 0 < w
|
||||
· by_cases h₁ : x = intMin w
|
||||
· simp [h₁, msb_intMin]
|
||||
· simp only [neg_eq, h₁, decide_false]
|
||||
by_cases h₂ : x.msb
|
||||
· simp [h₂, msb_neg]
|
||||
and_intros
|
||||
· by_cases h₃ : x = 0#w
|
||||
· simp [h₃] at h₂
|
||||
· simp [h₃]
|
||||
· simp [h₁]
|
||||
· simp [h₂]
|
||||
· simp [BitVec.msb, show w = 0 by omega]
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true := by
|
||||
@@ -431,18 +574,18 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
||||
rw [add_eq_or_of_and_eq_zero]
|
||||
· ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
· simp only [getLsbD_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
|
||||
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
||||
by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
· have hik'' : ¬ (k < i) := by omega
|
||||
simp [hik', hik'']
|
||||
· ext k
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and,
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and,
|
||||
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
|
||||
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
|
||||
|
||||
@@ -957,8 +1100,8 @@ def sshiftRightRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :
|
||||
|
||||
@[simp]
|
||||
theorem sshiftRightRec_zero_eq (x : BitVec w₁) (y : BitVec w₂) :
|
||||
sshiftRightRec x y 0 = x.sshiftRight' (y &&& 1#w₂) := by
|
||||
simp only [sshiftRightRec, twoPow_zero]
|
||||
sshiftRightRec x y 0 = x.sshiftRight' (y &&& twoPow w₂ 0) := by
|
||||
simp only [sshiftRightRec]
|
||||
|
||||
@[simp]
|
||||
theorem sshiftRightRec_succ_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :
|
||||
|
||||
@@ -65,7 +65,7 @@ theorem iunfoldr_getLsbD' {f : Fin w → α → α × Bool} (state : Nat → α)
|
||||
intro
|
||||
apply And.intro
|
||||
· intro i
|
||||
have := Fin.size_pos i
|
||||
have := Fin.pos i
|
||||
contradiction
|
||||
· rfl
|
||||
case step =>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -238,8 +238,8 @@ theorem not_bne_not : ∀ (x y : Bool), ((!x) != (!y)) = (x != y) := by simp
|
||||
@[simp] theorem bne_assoc : ∀ (x y z : Bool), ((x != y) != z) = (x != (y != z)) := by decide
|
||||
instance : Std.Associative (· != ·) := ⟨bne_assoc⟩
|
||||
|
||||
@[simp] theorem bne_left_inj : ∀ {x y z : Bool}, (x != y) = (x != z) ↔ y = z := by decide
|
||||
@[simp] theorem bne_right_inj : ∀ {x y z : Bool}, (x != z) = (y != z) ↔ x = y := by decide
|
||||
@[simp] theorem bne_right_inj : ∀ {x y z : Bool}, (x != y) = (x != z) ↔ y = z := by decide
|
||||
@[simp] theorem bne_left_inj : ∀ {x y z : Bool}, (x != z) = (y != z) ↔ x = y := by decide
|
||||
|
||||
theorem eq_not_of_ne : ∀ {x y : Bool}, x ≠ y → x = !y := by decide
|
||||
|
||||
@@ -295,9 +295,9 @@ theorem xor_right_comm : ∀ (x y z : Bool), ((x ^^ y) ^^ z) = ((x ^^ z) ^^ y) :
|
||||
|
||||
theorem xor_assoc : ∀ (x y z : Bool), ((x ^^ y) ^^ z) = (x ^^ (y ^^ z)) := bne_assoc
|
||||
|
||||
theorem xor_left_inj : ∀ {x y z : Bool}, (x ^^ y) = (x ^^ z) ↔ y = z := bne_left_inj
|
||||
theorem xor_right_inj : ∀ {x y z : Bool}, (x ^^ y) = (x ^^ z) ↔ y = z := bne_right_inj
|
||||
|
||||
theorem xor_right_inj : ∀ {x y z : Bool}, (x ^^ z) = (y ^^ z) ↔ x = y := bne_right_inj
|
||||
theorem xor_left_inj : ∀ {x y z : Bool}, (x ^^ z) = (y ^^ z) ↔ x = y := bne_left_inj
|
||||
|
||||
/-! ### le/lt -/
|
||||
|
||||
@@ -384,6 +384,15 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
||||
@[simp] theorem toNat_eq_one {b : Bool} : b.toNat = 1 ↔ b = true := by
|
||||
cases b <;> simp
|
||||
|
||||
/-! ## toInt -/
|
||||
|
||||
/-- convert a `Bool` to an `Int`, `false -> 0`, `true -> 1` -/
|
||||
def toInt (b : Bool) : Int := cond b 1 0
|
||||
|
||||
@[simp] theorem toInt_false : false.toInt = 0 := rfl
|
||||
|
||||
@[simp] theorem toInt_true : true.toInt = 1 := rfl
|
||||
|
||||
/-! ### ite -/
|
||||
|
||||
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
|
||||
|
||||
@@ -42,7 +42,7 @@ def usize (a : @& ByteArray) : USize :=
|
||||
a.size.toUSize
|
||||
|
||||
@[extern "lean_byte_array_uget"]
|
||||
def uget : (a : @& ByteArray) → (i : USize) → i.toNat < a.size → UInt8
|
||||
def uget : (a : @& ByteArray) → (i : USize) → (h : i.toNat < a.size := by get_elem_tactic) → UInt8
|
||||
| ⟨bs⟩, i, h => bs[i]
|
||||
|
||||
@[extern "lean_byte_array_get"]
|
||||
@@ -50,11 +50,11 @@ def get! : (@& ByteArray) → (@& Nat) → UInt8
|
||||
| ⟨bs⟩, i => bs.get! i
|
||||
|
||||
@[extern "lean_byte_array_fget"]
|
||||
def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
|
||||
| ⟨bs⟩, i => bs.get i
|
||||
def get : (a : @& ByteArray) → (i : @& Nat) → (h : i < a.size := by get_elem_tactic) → UInt8
|
||||
| ⟨bs⟩, i, _ => bs[i]
|
||||
|
||||
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
getElem xs i h := xs.get i
|
||||
|
||||
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
@@ -64,11 +64,11 @@ def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
||||
|
||||
@[extern "lean_byte_array_fset"]
|
||||
def set : (a : ByteArray) → (@& Fin a.size) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set i b⟩
|
||||
def set : (a : ByteArray) → (i : @& Nat) → UInt8 → (h : i < a.size := by get_elem_tactic) → ByteArray
|
||||
| ⟨bs⟩, i, b, h => ⟨bs.set i b h⟩
|
||||
|
||||
@[extern "lean_byte_array_uset"]
|
||||
def uset : (a : ByteArray) → (i : USize) → UInt8 → i.toNat < a.size → ByteArray
|
||||
def uset : (a : ByteArray) → (i : USize) → UInt8 → (h : i.toNat < a.size := by get_elem_tactic) → ByteArray
|
||||
| ⟨bs⟩, i, v, h => ⟨bs.uset i v h⟩
|
||||
|
||||
@[extern "lean_byte_array_hash"]
|
||||
@@ -108,8 +108,18 @@ def toList (bs : ByteArray) : List UInt8 :=
|
||||
|
||||
@[inline] def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
||||
let rec @[specialize] loop (i : Nat) :=
|
||||
if i < a.size then
|
||||
if p (a.get! i) then some i else loop (i+1)
|
||||
if h : i < a.size then
|
||||
if p a[i] then some i else loop (i+1)
|
||||
else
|
||||
none
|
||||
termination_by a.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
loop start
|
||||
|
||||
@[inline] def findFinIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option (Fin a.size) :=
|
||||
let rec @[specialize] loop (i : Nat) :=
|
||||
if h : i < a.size then
|
||||
if p a[i] then some ⟨i, h⟩ else loop (i+1)
|
||||
else
|
||||
none
|
||||
termination_by a.size - i
|
||||
@@ -144,7 +154,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
|
||||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||||
match (← f (as.get ⟨as.size - 1 - i, this⟩) b) with
|
||||
match (← f as[as.size - 1 - i] b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
@@ -178,7 +188,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
|
||||
match i with
|
||||
| 0 => pure b
|
||||
| i'+1 =>
|
||||
loop i' (j+1) (← f b (as.get ⟨j, Nat.lt_of_lt_of_le hlt h⟩))
|
||||
loop i' (j+1) (← f b as[j])
|
||||
else
|
||||
pure b
|
||||
loop (stop - start) start init
|
||||
|
||||
@@ -8,6 +8,8 @@ import Init.Data.Queue
|
||||
import Init.System.Promise
|
||||
import Init.System.Mutex
|
||||
|
||||
set_option linter.deprecated false
|
||||
|
||||
namespace IO
|
||||
|
||||
/--
|
||||
@@ -15,6 +17,7 @@ Internal state of an `Channel`.
|
||||
|
||||
We maintain the invariant that at all times either `consumers` or `values` is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.State from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
structure Channel.State (α : Type) where
|
||||
values : Std.Queue α := ∅
|
||||
consumers : Std.Queue (Promise (Option α)) := ∅
|
||||
@@ -27,12 +30,14 @@ FIFO channel with unbounded buffer, where `recv?` returns a `Task`.
|
||||
A channel can be closed. Once it is closed, all `send`s are ignored, and
|
||||
`recv?` returns `none` once the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel (α : Type) : Type := Mutex (Channel.State α)
|
||||
|
||||
instance : Nonempty (Channel α) :=
|
||||
inferInstanceAs (Nonempty (Mutex _))
|
||||
|
||||
/-- Creates a new `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.new from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.new : BaseIO (Channel α) :=
|
||||
Mutex.new {}
|
||||
|
||||
@@ -41,6 +46,7 @@ Sends a message on an `Channel`.
|
||||
|
||||
This function does not block.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.send from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -54,6 +60,7 @@ def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
|
||||
/--
|
||||
Closes an `Channel`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.close from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.close (ch : Channel α) : BaseIO Unit :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -67,6 +74,7 @@ Every message is only received once.
|
||||
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||
ch.atomically do
|
||||
let st ← get
|
||||
@@ -85,6 +93,7 @@ def Channel.recv? (ch : Channel α) : BaseIO (Task (Option α)) :=
|
||||
|
||||
Note that if this function is called twice, each `forAsync` only gets half the messages.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.forAsync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
partial def Channel.forAsync (f : α → BaseIO Unit) (ch : Channel α)
|
||||
(prio : Task.Priority := .default) : BaseIO (Task Unit) := do
|
||||
BaseIO.bindTask (prio := prio) (← ch.recv?) fun
|
||||
@@ -96,11 +105,13 @@ Receives all currently queued messages from the channel.
|
||||
|
||||
Those messages are dequeued and will not be returned by `recv?`.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.recvAllCurrent from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.recvAllCurrent (ch : Channel α) : BaseIO (Array α) :=
|
||||
ch.atomically do
|
||||
modifyGet fun st => (st.values.toArray, { st with values := ∅ })
|
||||
|
||||
/-- Type tag for synchronous (blocking) operations on a `Channel`. -/
|
||||
@[deprecated "Use Std.Channel.Sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync := Channel
|
||||
|
||||
/--
|
||||
@@ -110,6 +121,7 @@ For example, `ch.sync.recv?` blocks until the next message,
|
||||
and `for msg in ch.sync do ...` iterates synchronously over the channel.
|
||||
These functions should only be used in dedicated threads.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.sync from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.sync (ch : Channel α) : Channel.Sync α := ch
|
||||
|
||||
/--
|
||||
@@ -118,9 +130,11 @@ Synchronously receives a message from the channel.
|
||||
Every message is only received once.
|
||||
Returns `none` if the channel is closed and the queue is empty.
|
||||
-/
|
||||
@[deprecated "Use Std.Channel.Sync.recv? from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
def Channel.Sync.recv? (ch : Channel.Sync α) : BaseIO (Option α) := do
|
||||
IO.wait (← Channel.recv? ch)
|
||||
|
||||
@[deprecated "Use Std.Channel.Sync.forIn from Std.Sync.Channel instead" (since := "2024-12-02")]
|
||||
private partial def Channel.Sync.forIn [Monad m] [MonadLiftT BaseIO m]
|
||||
(ch : Channel.Sync α) (f : α → β → m (ForInStep β)) : β → m β := fun b => do
|
||||
match ← ch.recv? with
|
||||
|
||||
@@ -36,12 +36,6 @@ def succ : Fin n → Fin (n + 1)
|
||||
|
||||
variable {n : Nat}
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n + 1` as a `Fin n.succ`.
|
||||
-/
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
|
||||
⟨a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)⟩
|
||||
|
||||
/--
|
||||
Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
@@ -50,9 +44,12 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
-- We intend to deprecate `Fin.ofNat` in favor of `Fin.ofNat'` (and later rename).
|
||||
-- This is waiting on https://github.com/leanprover/lean4/pull/5323
|
||||
-- attribute [deprecated Fin.ofNat' (since := "2024-09-16")] Fin.ofNat
|
||||
/--
|
||||
Returns `a` modulo `n + 1` as a `Fin n.succ`.
|
||||
-/
|
||||
@[deprecated Fin.ofNat' (since := "2024-11-27")]
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
|
||||
⟨a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)⟩
|
||||
|
||||
private theorem mlt {b : Nat} : {a : Nat} → a < n → b % n < n
|
||||
| 0, h => Nat.mod_lt _ h
|
||||
@@ -165,6 +162,7 @@ theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
|
||||
theorem val_lt_of_le (i : Fin b) (h : b ≤ n) : i.val < n :=
|
||||
Nat.lt_of_lt_of_le i.isLt h
|
||||
|
||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||
protected theorem pos (i : Fin n) : 0 < n :=
|
||||
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
|
||||
|
||||
@@ -178,7 +176,7 @@ protected theorem pos (i : Fin n) : 0 < n :=
|
||||
@[inline] def castLE (h : n ≤ m) (i : Fin n) : Fin m := ⟨i, Nat.lt_of_lt_of_le i.2 h⟩
|
||||
|
||||
/-- `cast eq i` embeds `i` into an equal `Fin` type. -/
|
||||
@[inline] def cast (eq : n = m) (i : Fin n) : Fin m := ⟨i, eq ▸ i.2⟩
|
||||
@[inline] protected def cast (eq : n = m) (i : Fin n) : Fin m := ⟨i, eq ▸ i.2⟩
|
||||
|
||||
/-- `castAdd m i` embeds `i : Fin n` in `Fin (n+m)`. See also `Fin.natAdd` and `Fin.addNat`. -/
|
||||
@[inline] def castAdd (m) : Fin n → Fin (n + m) :=
|
||||
|
||||
@@ -5,22 +5,217 @@ Authors: François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Linear
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Data.Fin.Lemmas
|
||||
|
||||
namespace Fin
|
||||
|
||||
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
|
||||
@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where
|
||||
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
|
||||
loop (x : α) (i : Nat) : α :=
|
||||
@[semireducible, specialize] loop (x : α) (i : Nat) : α :=
|
||||
if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x
|
||||
termination_by n - i
|
||||
|
||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop n (Nat.le_refl n) init where
|
||||
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
|
||||
@[specialize] loop : (i : _) → i ≤ n → α → α
|
||||
| 0, _, x => x
|
||||
| i+1, h, x => loop i (Nat.le_of_lt h) (f ⟨i, h⟩ x)
|
||||
termination_by structural i => i
|
||||
|
||||
/--
|
||||
Folds a monadic function over `Fin n` from left to right:
|
||||
```
|
||||
Fin.foldlM n f x₀ = do
|
||||
let x₁ ← f x₀ 0
|
||||
let x₂ ← f x₁ 1
|
||||
...
|
||||
let xₙ ← f xₙ₋₁ (n-1)
|
||||
pure xₙ
|
||||
```
|
||||
-/
|
||||
@[inline] def foldlM [Monad m] (n) (f : α → Fin n → m α) (init : α) : m α := loop init 0 where
|
||||
/--
|
||||
Inner loop for `Fin.foldlM`.
|
||||
```
|
||||
Fin.foldlM.loop n f xᵢ i = do
|
||||
let xᵢ₊₁ ← f xᵢ i
|
||||
...
|
||||
let xₙ ← f xₙ₋₁ (n-1)
|
||||
pure xₙ
|
||||
```
|
||||
-/
|
||||
@[semireducible, specialize] loop (x : α) (i : Nat) : m α := do
|
||||
if h : i < n then f x ⟨i, h⟩ >>= (loop · (i+1)) else pure x
|
||||
termination_by n - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop ⟨n, Nat.le_refl n⟩ init where
|
||||
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
|
||||
loop : {i // i ≤ n} → α → α
|
||||
| ⟨0, _⟩, x => x
|
||||
| ⟨i+1, h⟩, x => loop ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x)
|
||||
/--
|
||||
Folds a monadic function over `Fin n` from right to left:
|
||||
```
|
||||
Fin.foldrM n f xₙ = do
|
||||
let xₙ₋₁ ← f (n-1) xₙ
|
||||
let xₙ₋₂ ← f (n-2) xₙ₋₁
|
||||
...
|
||||
let x₀ ← f 0 x₁
|
||||
pure x₀
|
||||
```
|
||||
-/
|
||||
@[inline] def foldrM [Monad m] (n) (f : Fin n → α → m α) (init : α) : m α :=
|
||||
loop ⟨n, Nat.le_refl n⟩ init where
|
||||
/--
|
||||
Inner loop for `Fin.foldrM`.
|
||||
```
|
||||
Fin.foldrM.loop n f i xᵢ = do
|
||||
let xᵢ₋₁ ← f (i-1) xᵢ
|
||||
...
|
||||
let x₁ ← f 1 x₂
|
||||
let x₀ ← f 0 x₁
|
||||
pure x₀
|
||||
```
|
||||
-/
|
||||
@[semireducible, specialize] loop : {i // i ≤ n} → α → m α
|
||||
| ⟨0, _⟩, x => pure x
|
||||
| ⟨i+1, h⟩, x => f ⟨i, h⟩ x >>= loop ⟨i, Nat.le_of_lt h⟩
|
||||
|
||||
/-! ### foldlM -/
|
||||
|
||||
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
|
||||
rw [foldlM.loop, dif_pos h]
|
||||
|
||||
theorem foldlM_loop_eq [Monad m] (f : α → Fin n → m α) (x) : foldlM.loop n f x n = pure x := by
|
||||
rw [foldlM.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1) :
|
||||
foldlM.loop (n+1) f x i = f x ⟨i, h⟩ >>= (foldlM.loop n (fun x j => f x j.succ) . i) := by
|
||||
if h' : i < n then
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
congr; funext
|
||||
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]
|
||||
congr; funext
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) (x) : foldlM 0 f x = pure x :=
|
||||
foldlM_loop_eq ..
|
||||
|
||||
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) (x) :
|
||||
foldlM (n+1) f x = f x 0 >>= foldlM n (fun x j => f x j.succ) := foldlM_loop ..
|
||||
|
||||
/-! ### foldrM -/
|
||||
|
||||
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop_succ [Monad m] (f : Fin n → α → m α) (x) (h : i < n) :
|
||||
foldrM.loop n f ⟨i+1, h⟩ x = f ⟨i, h⟩ x >>= foldrM.loop n f ⟨i, Nat.le_of_lt h⟩ := by
|
||||
rw [foldrM.loop]
|
||||
|
||||
theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) (h : i+1 ≤ n+1) :
|
||||
foldrM.loop (n+1) f ⟨i+1, h⟩ x =
|
||||
foldrM.loop n (fun j => f j.succ) ⟨i, Nat.le_of_succ_le_succ h⟩ x >>= f 0 := by
|
||||
induction i generalizing x with
|
||||
| zero =>
|
||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
congr; funext
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
|
||||
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) (x) : foldrM 0 f x = pure x :=
|
||||
foldrM_loop_zero ..
|
||||
|
||||
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) :
|
||||
foldrM (n+1) f x = foldrM n (fun i => f i.succ) x >>= f 0 := foldrM_loop ..
|
||||
|
||||
/-! ### foldl -/
|
||||
|
||||
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
|
||||
rw [foldl.loop, dif_pos h]
|
||||
|
||||
theorem foldl_loop_eq (f : α → Fin n → α) (x) : foldl.loop n f x n = x := by
|
||||
rw [foldl.loop, dif_neg (Nat.lt_irrefl _)]
|
||||
|
||||
theorem foldl_loop (f : α → Fin (n+1) → α) (x) (h : i < n+1) :
|
||||
foldl.loop (n+1) f x i = foldl.loop n (fun x j => f x j.succ) (f x ⟨i, h⟩) i := by
|
||||
if h' : i < n then
|
||||
rw [foldl_loop_lt _ _ h]
|
||||
rw [foldl_loop_lt _ _ h', foldl_loop]; rfl
|
||||
else
|
||||
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
|
||||
rw [foldl_loop_lt]
|
||||
rw [foldl_loop_eq, foldl_loop_eq]
|
||||
|
||||
@[simp] theorem foldl_zero (f : α → Fin 0 → α) (x) : foldl 0 f x = x :=
|
||||
foldl_loop_eq ..
|
||||
|
||||
theorem foldl_succ (f : α → Fin (n+1) → α) (x) :
|
||||
foldl (n+1) f x = foldl n (fun x i => f x i.succ) (f x 0) :=
|
||||
foldl_loop ..
|
||||
|
||||
theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) :
|
||||
foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by
|
||||
rw [foldl_succ]
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldl_succ, Fin.last]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc]
|
||||
|
||||
theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
|
||||
foldl n f x = foldlM (m:=Id) n f x := by
|
||||
induction n generalizing x <;> simp [foldl_succ, foldlM_succ, *]
|
||||
|
||||
/-! ### foldr -/
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f ⟨i, h⟩ x) := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
foldr.loop (n+1) f (i+1) h x =
|
||||
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
|
||||
induction i generalizing x with
|
||||
| zero => simp [foldr_loop_succ, foldr_loop_zero]
|
||||
| succ i ih => rw [foldr_loop_succ, ih]; rfl
|
||||
|
||||
@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x :=
|
||||
foldr_loop_zero ..
|
||||
|
||||
theorem foldr_succ (f : Fin (n+1) → α → α) (x) :
|
||||
foldr (n+1) f x = f 0 (foldr n (fun i => f i.succ) x) := foldr_loop ..
|
||||
|
||||
theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) :
|
||||
foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldr_succ, Fin.last]
|
||||
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc]
|
||||
|
||||
theorem foldr_eq_foldrM (f : Fin n → α → α) (x) :
|
||||
foldr n f x = foldrM (m:=Id) n f x := by
|
||||
induction n <;> simp [foldr_succ, foldrM_succ, *]
|
||||
|
||||
theorem foldl_rev (f : Fin n → α → α) (x) :
|
||||
foldl n (fun x i => f i.rev x) x = foldr n f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => rw [foldl_succ, foldr_succ_last, ← ih]; simp [rev_succ]
|
||||
|
||||
theorem foldr_rev (f : α → Fin n → α) (x) :
|
||||
foldr n (fun i x => f x i.rev) x = foldl n f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => rw [foldl_succ_last, foldr_succ, ← ih]; simp [rev_succ]
|
||||
|
||||
end Fin
|
||||
|
||||
@@ -13,17 +13,19 @@ import Init.Omega
|
||||
|
||||
namespace Fin
|
||||
|
||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||
theorem size_pos (i : Fin n) : 0 < n := Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
|
||||
@[deprecated Fin.pos (since := "2024-11-11")]
|
||||
theorem size_pos (i : Fin n) : 0 < n := i.pos
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.size_pos
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@[deprecated pos' (since := "2024-11-11")] abbrev size_pos' := @pos'
|
||||
|
||||
@[simp] theorem is_lt (a : Fin n) : (a : Nat) < n := a.2
|
||||
|
||||
@@ -240,7 +242,7 @@ theorem fin_one_eq_zero (a : Fin 1) : a = 0 := Subsingleton.elim a 0
|
||||
rw [eq_comm]
|
||||
simp
|
||||
|
||||
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem val_add (a b : Fin n) : (a + b).val = (a.val + b.val) % n := rfl
|
||||
|
||||
@@ -368,25 +370,25 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
Fin.castLE mn ∘ Fin.castLE km = Fin.castLE (Nat.le_trans km mn) :=
|
||||
funext (castLE_castLE km mn)
|
||||
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (i.cast h : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : (last n).cast h = last n' :=
|
||||
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : Fin.cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_refl (n : Nat) (h : n = n) : cast h = id := by
|
||||
@[simp] theorem cast_refl (n : Nat) (h : n = n) : Fin.cast h = id := by
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
cast h' (cast h i) = cast (Eq.trans h h') i := rfl
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = cast rfl := rfl
|
||||
@[simp] theorem castAdd_zero : (castAdd 0 : Fin n → Fin (n + 0)) = Fin.cast rfl := rfl
|
||||
|
||||
theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m := by simp
|
||||
|
||||
@@ -404,37 +406,37 @@ theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
|
||||
|
||||
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
|
||||
(i.castAdd m).cast h = (i.cast (Nat.add_right_cancel h)).castAdd m := rfl
|
||||
|
||||
@[simp] theorem cast_castAdd_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||
cast h (castAdd m' i) = castAdd m i := rfl
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
castAdd p (castAdd n i) = cast (Nat.add_assoc ..).symm (castAdd (n + p) i) := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
@[simp] theorem cast_succ_eq {n' : Nat} (i : Fin n) (h : n.succ = n'.succ) :
|
||||
cast h i.succ = (cast (Nat.succ.inj h) i).succ := rfl
|
||||
i.succ.cast h = (i.cast (Nat.succ.inj h)).succ := rfl
|
||||
|
||||
theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
|
||||
(cast h i).succ = cast (by rw [h]) i.succ := rfl
|
||||
(i.cast h).succ = i.succ.cast (by rw [h]) := rfl
|
||||
|
||||
@[simp] theorem coe_castSucc (i : Fin n) : (Fin.castSucc i : Nat) = i := rfl
|
||||
@[simp] theorem coe_castSucc (i : Fin n) : (i.castSucc : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem castSucc_mk (n i : Nat) (h : i < n) : castSucc ⟨i, h⟩ = ⟨i, Nat.lt.step h⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
|
||||
cast h (castSucc i) = castSucc (cast (Nat.succ.inj h) i) := rfl
|
||||
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
|
||||
|
||||
theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
|
||||
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < i.succ :=
|
||||
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
||||
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ := by
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ j.castSucc ↔ i < j.succ := by
|
||||
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
|
||||
|
||||
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
Fin.castSucc i < j ↔ i.succ ≤ j := .rfl
|
||||
i.castSucc < j ↔ i.succ ≤ j := .rfl
|
||||
|
||||
@[simp] theorem succ_last (n : Nat) : (last n).succ = last n.succ := rfl
|
||||
|
||||
@@ -442,48 +444,48 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
i.succ = last (n + 1) ↔ i = last n := by rw [← succ_last, succ_inj]
|
||||
|
||||
@[simp] theorem castSucc_castLT (i : Fin (n + 1)) (h : (i : Nat) < n) :
|
||||
castSucc (castLT i h) = i := rfl
|
||||
(castLT i h).castSucc = i := rfl
|
||||
|
||||
@[simp] theorem castLT_castSucc {n : Nat} (a : Fin n) (h : (a : Nat) < n) :
|
||||
castLT (castSucc a) h = a := rfl
|
||||
castLT a.castSucc h = a := rfl
|
||||
|
||||
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
|
||||
Fin.castSucc a < Fin.castSucc b ↔ a < b := .rfl
|
||||
a.castSucc < b.castSucc ↔ a < b := .rfl
|
||||
|
||||
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [Fin.ext_iff]
|
||||
theorem castSucc_inj {a b : Fin n} : a.castSucc = b.castSucc ↔ a = b := by simp [Fin.ext_iff]
|
||||
|
||||
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
||||
theorem castSucc_lt_last (a : Fin n) : a.castSucc < last n := a.is_lt
|
||||
|
||||
@[simp] theorem castSucc_zero : castSucc (0 : Fin (n + 1)) = 0 := rfl
|
||||
|
||||
@[simp] theorem castSucc_one {n : Nat} : castSucc (1 : Fin (n + 2)) = 1 := rfl
|
||||
|
||||
/-- `castSucc i` is positive when `i` is positive -/
|
||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
|
||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < i.castSucc := by
|
||||
simpa [lt_def] using h
|
||||
|
||||
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : castSucc a = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||
@[simp] theorem castSucc_eq_zero_iff {a : Fin (n + 1)} : a.castSucc = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||
|
||||
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : castSucc a ≠ 0 ↔ a ≠ 0 :=
|
||||
theorem castSucc_ne_zero_iff {a : Fin (n + 1)} : a.castSucc ≠ 0 ↔ a ≠ 0 :=
|
||||
not_congr <| castSucc_eq_zero_iff
|
||||
|
||||
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
||||
castSucc (Fin.succ j) = Fin.succ (castSucc j) := by simp [Fin.ext_iff]
|
||||
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
|
||||
|
||||
@[simp]
|
||||
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
|
||||
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
|
||||
cases n
|
||||
· exact a.elim0
|
||||
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||
|
||||
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
|
||||
theorem lt_succ {a : Fin n} : a.castSucc < a.succ := by
|
||||
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||
|
||||
theorem exists_castSucc_eq {n : Nat} {i : Fin (n + 1)} : (∃ j, castSucc j = i) ↔ i ≠ last n :=
|
||||
⟨fun ⟨j, hj⟩ => hj ▸ Fin.ne_of_lt j.castSucc_lt_last,
|
||||
fun hi => ⟨i.castLT <| Fin.val_lt_last hi, rfl⟩⟩
|
||||
|
||||
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = castSucc i.succ := rfl
|
||||
theorem succ_castSucc {n : Nat} (i : Fin n) : i.castSucc.succ = i.succ.castSucc := rfl
|
||||
|
||||
@[simp] theorem coe_addNat (m : Nat) (i : Fin n) : (addNat i m : Nat) = i + m := rfl
|
||||
|
||||
@@ -500,17 +502,17 @@ theorem le_coe_addNat (m : Nat) (i : Fin n) : m ≤ addNat i m :=
|
||||
addNat ⟨i, hi⟩ n = ⟨i + n, Nat.add_lt_add_right hi n⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_addNat_zero {n n' : Nat} (i : Fin n) (h : n + 0 = n') :
|
||||
cast h (addNat i 0) = cast ((Nat.add_zero _).symm.trans h) i := rfl
|
||||
(addNat i 0).cast h = i.cast ((Nat.add_zero _).symm.trans h) := rfl
|
||||
|
||||
/-- For rewriting in the reverse direction, see `Fin.cast_addNat_left`. -/
|
||||
theorem addNat_cast {n n' m : Nat} (i : Fin n') (h : n' = n) :
|
||||
addNat (cast h i) m = cast (congrArg (. + m) h) (addNat i m) := rfl
|
||||
addNat (i.cast h) m = (addNat i m).cast (congrArg (. + m) h) := rfl
|
||||
|
||||
theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
cast h (addNat i m) = addNat (cast (Nat.add_right_cancel h) i) m := rfl
|
||||
(addNat i m).cast h = addNat (i.cast (Nat.add_right_cancel h)) m := rfl
|
||||
|
||||
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||
cast h (addNat i m') = addNat i m :=
|
||||
(addNat i m').cast h = addNat i m :=
|
||||
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||
|
||||
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
@@ -520,46 +522,46 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
|
||||
theorem le_coe_natAdd (m : Nat) (i : Fin n) : m ≤ natAdd m i := Nat.le_add_right ..
|
||||
|
||||
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = cast (Nat.zero_add n).symm := by ext; simp
|
||||
@[simp] theorem natAdd_zero {n : Nat} : natAdd 0 = Fin.cast (Nat.zero_add n).symm := by ext; simp
|
||||
|
||||
/-- For rewriting in the reverse direction, see `Fin.cast_natAdd_right`. -/
|
||||
theorem natAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||
natAdd m (cast h i) = cast (congrArg _ h) (natAdd m i) := rfl
|
||||
natAdd m (i.cast h) = (natAdd m i).cast (congrArg _ h) := rfl
|
||||
|
||||
theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
|
||||
cast h (natAdd m i) = natAdd m (cast (Nat.add_left_cancel h) i) := rfl
|
||||
(natAdd m i).cast h = natAdd m (i.cast (Nat.add_left_cancel h)) := rfl
|
||||
|
||||
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
|
||||
cast h (natAdd m' i) = natAdd m i :=
|
||||
(natAdd m' i).cast h = natAdd m i :=
|
||||
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||
|
||||
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
|
||||
castAdd p (natAdd m i) = (natAdd m (castAdd p i)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
natAdd m (castAdd p i) = cast (Nat.add_assoc ..) (castAdd p (natAdd m i)) := rfl
|
||||
natAdd m (castAdd p i) = (castAdd p (natAdd m i)).cast (Nat.add_assoc ..) := rfl
|
||||
|
||||
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
|
||||
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
|
||||
natAdd m (natAdd n i) = (natAdd (m + n) i).cast (Nat.add_assoc ..) :=
|
||||
Fin.ext <| (Nat.add_assoc ..).symm
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
||||
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
|
||||
(natAdd 0 i).cast h = i.cast ((Nat.zero_add _).symm.trans h) :=
|
||||
Fin.ext <| Nat.zero_add _
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
||||
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||
(natAdd n i).cast (Nat.add_comm ..) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||
|
||||
@[simp]
|
||||
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
||||
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||
(addNat i m).cast (Nat.add_comm ..) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||
|
||||
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
||||
|
||||
@[simp] theorem addNat_last (n : Nat) :
|
||||
addNat (last n) m = cast (by omega) (last (n + m)) := by
|
||||
addNat (last n) m = (last (n + m)).cast (by omega) := by
|
||||
ext
|
||||
simp
|
||||
|
||||
@@ -640,7 +642,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 ≤ ↑i) : (subNat 1 i h).succ = i := by
|
||||
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 ≤ (i : Nat)) : (subNat 1 i h).succ = i := by
|
||||
ext
|
||||
simp
|
||||
omega
|
||||
@@ -655,7 +657,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
|
||||
|
||||
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
|
||||
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [← cast_addNat]
|
||||
natAdd n (subNat n (i.cast (Nat.add_comm ..)) h) = i := by simp [← cast_addNat]
|
||||
|
||||
/-! ### recursion and induction principles -/
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ opaque floatSpec : FloatSpec := {
|
||||
structure Float where
|
||||
val : floatSpec.float
|
||||
|
||||
instance : Inhabited Float := ⟨{ val := floatSpec.val }⟩
|
||||
instance : Nonempty Float := ⟨{ val := floatSpec.val }⟩
|
||||
|
||||
@[extern "lean_float_add"] opaque Float.add : Float → Float → Float
|
||||
@[extern "lean_float_sub"] opaque Float.sub : Float → Float → Float
|
||||
@@ -47,6 +47,25 @@ def Float.lt : Float → Float → Prop := fun a b =>
|
||||
def Float.le : Float → Float → Prop := fun a b =>
|
||||
floatSpec.le a.val b.val
|
||||
|
||||
/--
|
||||
Raw transmutation from `UInt64`.
|
||||
|
||||
Floats and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
-/
|
||||
@[extern "lean_float_of_bits"] opaque Float.ofBits : UInt64 → Float
|
||||
|
||||
/--
|
||||
Raw transmutation to `UInt64`.
|
||||
|
||||
Floats and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
|
||||
Note that this function is distinct from `Float.toUInt64`, which attempts
|
||||
to preserve the numeric value, and not the bitwise value.
|
||||
-/
|
||||
@[extern "lean_float_to_bits"] opaque Float.toBits : Float → UInt64
|
||||
|
||||
instance : Add Float := ⟨Float.add⟩
|
||||
instance : Sub Float := ⟨Float.sub⟩
|
||||
instance : Mul Float := ⟨Float.mul⟩
|
||||
@@ -117,6 +136,9 @@ instance : ToString Float where
|
||||
|
||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
||||
|
||||
instance : Inhabited Float where
|
||||
default := UInt64.toFloat 0
|
||||
|
||||
instance : Repr Float where
|
||||
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
|
||||
|
||||
|
||||
180
src/Init/Data/Float32.lean
Normal file
180
src/Init/Data/Float32.lean
Normal file
@@ -0,0 +1,180 @@
|
||||
/-
|
||||
Copyright (c) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Core
|
||||
import Init.Data.Int.Basic
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.Data.Float
|
||||
|
||||
/-
|
||||
#exit -- TODO: Remove after update stage0
|
||||
|
||||
-- Just show FloatSpec is inhabited.
|
||||
opaque float32Spec : FloatSpec := {
|
||||
float := Unit,
|
||||
val := (),
|
||||
lt := fun _ _ => True,
|
||||
le := fun _ _ => True,
|
||||
decLt := fun _ _ => inferInstanceAs (Decidable True),
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
/-- Native floating point type, corresponding to the IEEE 754 *binary32* format
|
||||
(`float` in C or `f32` in Rust). -/
|
||||
structure Float32 where
|
||||
val : float32Spec.float
|
||||
|
||||
instance : Nonempty Float32 := ⟨{ val := float32Spec.val }⟩
|
||||
|
||||
@[extern "lean_float32_add"] opaque Float32.add : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_sub"] opaque Float32.sub : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_mul"] opaque Float32.mul : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_div"] opaque Float32.div : Float32 → Float32 → Float32
|
||||
@[extern "lean_float32_negate"] opaque Float32.neg : Float32 → Float32
|
||||
|
||||
set_option bootstrap.genMatcherCode false
|
||||
def Float32.lt : Float32 → Float32 → Prop := fun a b =>
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.lt a b
|
||||
|
||||
def Float32.le : Float32 → Float32 → Prop := fun a b =>
|
||||
float32Spec.le a.val b.val
|
||||
|
||||
/--
|
||||
Raw transmutation from `UInt32`.
|
||||
|
||||
Float32s and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
-/
|
||||
@[extern "lean_float32_of_bits"] opaque Float32.ofBits : UInt32 → Float32
|
||||
|
||||
/--
|
||||
Raw transmutation to `UInt32`.
|
||||
|
||||
Float32s and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
|
||||
Note that this function is distinct from `Float32.toUInt32`, which attempts
|
||||
to preserve the numeric value, and not the bitwise value.
|
||||
-/
|
||||
@[extern "lean_float32_to_bits"] opaque Float32.toBits : Float32 → UInt32
|
||||
|
||||
instance : Add Float32 := ⟨Float32.add⟩
|
||||
instance : Sub Float32 := ⟨Float32.sub⟩
|
||||
instance : Mul Float32 := ⟨Float32.mul⟩
|
||||
instance : Div Float32 := ⟨Float32.div⟩
|
||||
instance : Neg Float32 := ⟨Float32.neg⟩
|
||||
instance : LT Float32 := ⟨Float32.lt⟩
|
||||
instance : LE Float32 := ⟨Float32.le⟩
|
||||
|
||||
/-- Note: this is not reflexive since `NaN != NaN`.-/
|
||||
@[extern "lean_float32_beq"] opaque Float32.beq (a b : Float32) : Bool
|
||||
|
||||
instance : BEq Float32 := ⟨Float32.beq⟩
|
||||
|
||||
@[extern "lean_float32_decLt"] opaque Float32.decLt (a b : Float32) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.decLt a b
|
||||
|
||||
@[extern "lean_float32_decLe"] opaque Float32.decLe (a b : Float32) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| ⟨a⟩, ⟨b⟩ => float32Spec.decLe a b
|
||||
|
||||
instance float32DecLt (a b : Float32) : Decidable (a < b) := Float32.decLt a b
|
||||
instance float32DecLe (a b : Float32) : Decidable (a ≤ b) := Float32.decLe a b
|
||||
|
||||
@[extern "lean_float32_to_string"] opaque Float32.toString : Float32 → String
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt8` (including Inf), returns the maximum value of `UInt8`
|
||||
(i.e. `UInt8.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint8"] opaque Float32.toUInt8 : Float32 → UInt8
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt16` (including Inf), returns the maximum value of `UInt16`
|
||||
(i.e. `UInt16.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint16"] opaque Float32.toUInt16 : Float32 → UInt16
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt32` (including Inf), returns the maximum value of `UInt32`
|
||||
(i.e. `UInt32.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint32"] opaque Float32.toUInt32 : Float32 → UInt32
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `UInt64` (including Inf), returns the maximum value of `UInt64`
|
||||
(i.e. `UInt64.size - 1`).
|
||||
-/
|
||||
@[extern "lean_float32_to_uint64"] opaque Float32.toUInt64 : Float32 → UInt64
|
||||
/-- If the given float is non-negative, truncates the value to the nearest non-negative integer.
|
||||
If negative or NaN, returns `0`.
|
||||
If larger than the maximum value for `USize` (including Inf), returns the maximum value of `USize`
|
||||
(i.e. `USize.size - 1`). This value is platform dependent).
|
||||
-/
|
||||
@[extern "lean_float32_to_usize"] opaque Float32.toUSize : Float32 → USize
|
||||
|
||||
@[extern "lean_float32_isnan"] opaque Float32.isNaN : Float32 → Bool
|
||||
@[extern "lean_float32_isfinite"] opaque Float32.isFinite : Float32 → Bool
|
||||
@[extern "lean_float32_isinf"] opaque Float32.isInf : Float32 → Bool
|
||||
/-- Splits the given float `x` into a significand/exponent pair `(s, i)`
|
||||
such that `x = s * 2^i` where `s ∈ (-1;-0.5] ∪ [0.5; 1)`.
|
||||
Returns an undefined value if `x` is not finite.
|
||||
-/
|
||||
@[extern "lean_float32_frexp"] opaque Float32.frExp : Float32 → Float32 × Int
|
||||
|
||||
instance : ToString Float32 where
|
||||
toString := Float32.toString
|
||||
|
||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat32 (n : UInt64) : Float32
|
||||
|
||||
instance : Inhabited Float32 where
|
||||
default := UInt64.toFloat32 0
|
||||
|
||||
instance : Repr Float32 where
|
||||
reprPrec n prec := if n < UInt64.toFloat32 0 then Repr.addAppParen (toString n) prec else toString n
|
||||
|
||||
instance : ReprAtom Float32 := ⟨⟩
|
||||
|
||||
@[extern "sinf"] opaque Float32.sin : Float32 → Float32
|
||||
@[extern "cosf"] opaque Float32.cos : Float32 → Float32
|
||||
@[extern "tanf"] opaque Float32.tan : Float32 → Float32
|
||||
@[extern "asinf"] opaque Float32.asin : Float32 → Float32
|
||||
@[extern "acosf"] opaque Float32.acos : Float32 → Float32
|
||||
@[extern "atanf"] opaque Float32.atan : Float32 → Float32
|
||||
@[extern "atan2f"] opaque Float32.atan2 : Float32 → Float32 → Float32
|
||||
@[extern "sinhf"] opaque Float32.sinh : Float32 → Float32
|
||||
@[extern "coshf"] opaque Float32.cosh : Float32 → Float32
|
||||
@[extern "tanhf"] opaque Float32.tanh : Float32 → Float32
|
||||
@[extern "asinhf"] opaque Float32.asinh : Float32 → Float32
|
||||
@[extern "acoshf"] opaque Float32.acosh : Float32 → Float32
|
||||
@[extern "atanhf"] opaque Float32.atanh : Float32 → Float32
|
||||
@[extern "expf"] opaque Float32.exp : Float32 → Float32
|
||||
@[extern "exp2f"] opaque Float32.exp2 : Float32 → Float32
|
||||
@[extern "logf"] opaque Float32.log : Float32 → Float32
|
||||
@[extern "log2f"] opaque Float32.log2 : Float32 → Float32
|
||||
@[extern "log10f"] opaque Float32.log10 : Float32 → Float32
|
||||
@[extern "powf"] opaque Float32.pow : Float32 → Float32 → Float32
|
||||
@[extern "sqrtf"] opaque Float32.sqrt : Float32 → Float32
|
||||
@[extern "cbrtf"] opaque Float32.cbrt : Float32 → Float32
|
||||
@[extern "ceilf"] opaque Float32.ceil : Float32 → Float32
|
||||
@[extern "floorf"] opaque Float32.floor : Float32 → Float32
|
||||
@[extern "roundf"] opaque Float32.round : Float32 → Float32
|
||||
@[extern "fabsf"] opaque Float32.abs : Float32 → Float32
|
||||
|
||||
instance : HomogeneousPow Float32 := ⟨Float32.pow⟩
|
||||
|
||||
instance : Min Float32 := minOfLe
|
||||
|
||||
instance : Max Float32 := maxOfLe
|
||||
|
||||
/--
|
||||
Efficiently computes `x * 2^i`.
|
||||
-/
|
||||
@[extern "lean_float32_scaleb"]
|
||||
opaque Float32.scaleB (x : Float32) (i : @& Int) : Float32
|
||||
-/
|
||||
@@ -46,8 +46,8 @@ def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
|
||||
| ⟨ds⟩, i, h => ds[i]
|
||||
|
||||
@[extern "lean_float_array_fget"]
|
||||
def get : (ds : @& FloatArray) → (@& Fin ds.size) → Float
|
||||
| ⟨ds⟩, i => ds.get i
|
||||
def get : (ds : @& FloatArray) → (i : @& Nat) → (h : i < ds.size := by get_elem_tactic) → Float
|
||||
| ⟨ds⟩, i, h => ds.get i h
|
||||
|
||||
@[extern "lean_float_array_get"]
|
||||
def get! : (@& FloatArray) → (@& Nat) → Float
|
||||
@@ -55,23 +55,23 @@ def get! : (@& FloatArray) → (@& Nat) → Float
|
||||
|
||||
def get? (ds : FloatArray) (i : Nat) : Option Float :=
|
||||
if h : i < ds.size then
|
||||
ds.get ⟨i, h⟩
|
||||
some (ds.get i h)
|
||||
else
|
||||
none
|
||||
|
||||
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
getElem xs i h := xs.get i h
|
||||
|
||||
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
@[extern "lean_float_array_uset"]
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → (h : i.toNat < a.size := by get_elem_tactic) → FloatArray
|
||||
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
||||
|
||||
@[extern "lean_float_array_fset"]
|
||||
def set : (ds : FloatArray) → (@& Fin ds.size) → Float → FloatArray
|
||||
| ⟨ds⟩, i, d => ⟨ds.set i d⟩
|
||||
def set : (ds : FloatArray) → (i : @& Nat) → Float → (h : i < ds.size := by get_elem_tactic) → FloatArray
|
||||
| ⟨ds⟩, i, d, h => ⟨ds.set i d h⟩
|
||||
|
||||
@[extern "lean_float_array_set"]
|
||||
def set! : FloatArray → (@& Nat) → Float → FloatArray
|
||||
@@ -83,7 +83,7 @@ def isEmpty (s : FloatArray) : Bool :=
|
||||
partial def toList (ds : FloatArray) : List Float :=
|
||||
let rec loop (i r) :=
|
||||
if h : i < ds.size then
|
||||
loop (i+1) (ds.get ⟨i, h⟩ :: r)
|
||||
loop (i+1) (ds[i] :: r)
|
||||
else
|
||||
r.reverse
|
||||
loop 0 []
|
||||
@@ -115,7 +115,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatA
|
||||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||||
match (← f (as.get ⟨as.size - 1 - i, this⟩) b) with
|
||||
match (← f as[as.size - 1 - i] b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
@@ -149,7 +149,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → Float →
|
||||
match i with
|
||||
| 0 => pure b
|
||||
| i'+1 =>
|
||||
loop i' (j+1) (← f b (as.get ⟨j, Nat.lt_of_lt_of_le hlt h⟩))
|
||||
loop i' (j+1) (← f b (as[j]'(Nat.lt_of_lt_of_le hlt h)))
|
||||
else
|
||||
pure b
|
||||
loop (stop - start) start init
|
||||
|
||||
@@ -48,6 +48,9 @@ instance : Hashable UInt64 where
|
||||
instance : Hashable USize where
|
||||
hash n := n.toUInt64
|
||||
|
||||
instance : Hashable ByteArray where
|
||||
hash as := as.foldl (fun r a => mixHash r (hash a)) 7
|
||||
|
||||
instance : Hashable (Fin n) where
|
||||
hash v := v.val.toUInt64
|
||||
|
||||
|
||||
@@ -34,4 +34,8 @@ theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
@[simp]
|
||||
theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
end Int
|
||||
|
||||
@@ -29,6 +29,8 @@ At that time, we did not rename `div` and `mod` to `tdiv` and `tmod` (along with
|
||||
In September 2024, we decided to do this rename (with deprecations in place),
|
||||
and later we intend to rename `ediv` and `emod` to `div` and `mod`, as nearly all users will only
|
||||
ever need to use these functions and their associated lemmas.
|
||||
|
||||
In December 2024, we removed `tdiv` and `tmod`, but have not yet renamed `ediv` and `emod`.
|
||||
-/
|
||||
|
||||
/-! ### T-rounding division -/
|
||||
@@ -71,8 +73,6 @@ def tdiv : (@& Int) → (@& Int) → Int
|
||||
| -[m +1], ofNat n => -ofNat (succ m / n)
|
||||
| -[m +1], -[n +1] => ofNat (succ m / succ n)
|
||||
|
||||
@[deprecated tdiv (since := "2024-09-11")] abbrev div := tdiv
|
||||
|
||||
/-- Integer modulo. This function uses the
|
||||
[*"T-rounding"*][t-rounding] (**T**runcation-rounding) convention
|
||||
to pair with `Int.tdiv`, meaning that `tmod a b + b * (tdiv a b) = a`
|
||||
@@ -107,8 +107,6 @@ def tmod : (@& Int) → (@& Int) → Int
|
||||
| -[m +1], ofNat n => -ofNat (succ m % n)
|
||||
| -[m +1], -[n +1] => -ofNat (succ m % succ n)
|
||||
|
||||
@[deprecated tmod (since := "2024-09-11")] abbrev mod := tmod
|
||||
|
||||
/-! ### F-rounding division
|
||||
This pair satisfies `fdiv x y = floor (x / y)`.
|
||||
-/
|
||||
@@ -251,8 +249,6 @@ instance : Mod Int where
|
||||
|
||||
theorem ofNat_tdiv (m n : Nat) : ↑(m / n) = tdiv ↑m ↑n := rfl
|
||||
|
||||
@[deprecated ofNat_tdiv (since := "2024-09-11")] abbrev ofNat_div := ofNat_tdiv
|
||||
|
||||
theorem ofNat_fdiv : ∀ m n : Nat, ↑(m / n) = fdiv ↑m ↑n
|
||||
| 0, _ => by simp [fdiv]
|
||||
| succ _, _ => rfl
|
||||
|
||||
@@ -125,7 +125,7 @@ theorem eq_one_of_mul_eq_one_right {a b : Int} (H : 0 ≤ a) (H' : a * b = 1) :
|
||||
eq_one_of_dvd_one H ⟨b, H'.symm⟩
|
||||
|
||||
theorem eq_one_of_mul_eq_one_left {a b : Int} (H : 0 ≤ b) (H' : a * b = 1) : b = 1 :=
|
||||
eq_one_of_mul_eq_one_right H <| by rw [Int.mul_comm, H']
|
||||
eq_one_of_mul_eq_one_right (b := a) H <| by rw [Int.mul_comm, H']
|
||||
|
||||
/-! ### *div zero -/
|
||||
|
||||
@@ -1267,7 +1267,7 @@ theorem bmod_le {x : Int} {m : Nat} (h : 0 < m) : bmod x m ≤ (m - 1) / 2 := by
|
||||
_ = ((m + 1 - 2) + 2)/2 := by simp
|
||||
_ = (m - 1) / 2 + 1 := by
|
||||
rw [add_ediv_of_dvd_right]
|
||||
· simp (config := {decide := true}) only [Int.ediv_self]
|
||||
· simp +decide only [Int.ediv_self]
|
||||
congr 2
|
||||
rw [Int.add_sub_assoc, ← Int.sub_neg]
|
||||
congr
|
||||
@@ -1285,7 +1285,7 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
|
||||
simp only [bmod, ofNat_eq_coe, natAbs_ofNat, natCast_add, ofNat_one,
|
||||
emod_self_add_one (ofNat_nonneg x)]
|
||||
match x with
|
||||
| 0 => rw [if_pos] <;> simp (config := {decide := true})
|
||||
| 0 => rw [if_pos] <;> simp +decide
|
||||
| (x+1) =>
|
||||
rw [if_neg]
|
||||
· simp [← Int.sub_sub]
|
||||
@@ -1315,65 +1315,3 @@ theorem bmod_natAbs_plus_one (x : Int) (w : 1 < x.natAbs) : bmod x (x.natAbs + 1
|
||||
all_goals decide
|
||||
· exact ofNat_nonneg x
|
||||
· exact succ_ofNat_pos (x + 1)
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated Int.zero_tdiv (since := "2024-09-11")] protected abbrev zero_div := @Int.zero_tdiv
|
||||
@[deprecated Int.tdiv_zero (since := "2024-09-11")] protected abbrev div_zero := @Int.tdiv_zero
|
||||
@[deprecated tdiv_eq_ediv (since := "2024-09-11")] abbrev div_eq_ediv := @tdiv_eq_ediv
|
||||
@[deprecated fdiv_eq_tdiv (since := "2024-09-11")] abbrev fdiv_eq_div := @fdiv_eq_tdiv
|
||||
@[deprecated zero_tmod (since := "2024-09-11")] abbrev zero_mod := @zero_tmod
|
||||
@[deprecated tmod_zero (since := "2024-09-11")] abbrev mod_zero := @tmod_zero
|
||||
@[deprecated tmod_add_tdiv (since := "2024-09-11")] abbrev mod_add_div := @tmod_add_tdiv
|
||||
@[deprecated tdiv_add_tmod (since := "2024-09-11")] abbrev div_add_mod := @tdiv_add_tmod
|
||||
@[deprecated tmod_add_tdiv' (since := "2024-09-11")] abbrev mod_add_div' := @tmod_add_tdiv'
|
||||
@[deprecated tdiv_add_tmod' (since := "2024-09-11")] abbrev div_add_mod' := @tdiv_add_tmod'
|
||||
@[deprecated tmod_def (since := "2024-09-11")] abbrev mod_def := @tmod_def
|
||||
@[deprecated tmod_eq_emod (since := "2024-09-11")] abbrev mod_eq_emod := @tmod_eq_emod
|
||||
@[deprecated fmod_eq_tmod (since := "2024-09-11")] abbrev fmod_eq_mod := @fmod_eq_tmod
|
||||
@[deprecated Int.tdiv_one (since := "2024-09-11")] protected abbrev div_one := @Int.tdiv_one
|
||||
@[deprecated Int.tdiv_neg (since := "2024-09-11")] protected abbrev div_neg := @Int.tdiv_neg
|
||||
@[deprecated Int.neg_tdiv (since := "2024-09-11")] protected abbrev neg_div := @Int.neg_tdiv
|
||||
@[deprecated Int.neg_tdiv_neg (since := "2024-09-11")] protected abbrev neg_div_neg := @Int.neg_tdiv_neg
|
||||
@[deprecated Int.tdiv_nonneg (since := "2024-09-11")] protected abbrev div_nonneg := @Int.tdiv_nonneg
|
||||
@[deprecated Int.tdiv_nonpos (since := "2024-09-11")] protected abbrev div_nonpos := @Int.tdiv_nonpos
|
||||
@[deprecated Int.tdiv_eq_zero_of_lt (since := "2024-09-11")] abbrev div_eq_zero_of_lt := @Int.tdiv_eq_zero_of_lt
|
||||
@[deprecated Int.mul_tdiv_cancel (since := "2024-09-11")] protected abbrev mul_div_cancel := @Int.mul_tdiv_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel_left (since := "2024-09-11")] protected abbrev mul_div_cancel_left := @Int.mul_tdiv_cancel_left
|
||||
@[deprecated Int.tdiv_self (since := "2024-09-11")] protected abbrev div_self := @Int.tdiv_self
|
||||
@[deprecated Int.mul_tdiv_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev mul_div_cancel_of_mod_eq_zero := @Int.mul_tdiv_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.tdiv_mul_cancel_of_tmod_eq_zero (since := "2024-09-11")] abbrev div_mul_cancel_of_mod_eq_zero := @Int.tdiv_mul_cancel_of_tmod_eq_zero
|
||||
@[deprecated Int.dvd_of_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_of_mod_eq_zero := @Int.dvd_of_tmod_eq_zero
|
||||
@[deprecated Int.mul_tdiv_assoc (since := "2024-09-11")] protected abbrev mul_div_assoc := @Int.mul_tdiv_assoc
|
||||
@[deprecated Int.mul_tdiv_assoc' (since := "2024-09-11")] protected abbrev mul_div_assoc' := @Int.mul_tdiv_assoc'
|
||||
@[deprecated Int.tdiv_dvd_tdiv (since := "2024-09-11")] abbrev div_dvd_div := @Int.tdiv_dvd_tdiv
|
||||
@[deprecated Int.natAbs_tdiv (since := "2024-09-11")] abbrev natAbs_div := @Int.natAbs_tdiv
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_right := @Int.tdiv_eq_of_eq_mul_right
|
||||
@[deprecated Int.eq_tdiv_of_mul_eq_right (since := "2024-09-11")] protected abbrev eq_div_of_mul_eq_right := @Int.eq_tdiv_of_mul_eq_right
|
||||
@[deprecated Int.ofNat_tmod (since := "2024-09-11")] abbrev ofNat_mod := @Int.ofNat_tmod
|
||||
@[deprecated Int.tmod_one (since := "2024-09-11")] abbrev mod_one := @Int.tmod_one
|
||||
@[deprecated Int.tmod_eq_of_lt (since := "2024-09-11")] abbrev mod_eq_of_lt := @Int.tmod_eq_of_lt
|
||||
@[deprecated Int.tmod_lt_of_pos (since := "2024-09-11")] abbrev mod_lt_of_pos := @Int.tmod_lt_of_pos
|
||||
@[deprecated Int.tmod_nonneg (since := "2024-09-11")] abbrev mod_nonneg := @Int.tmod_nonneg
|
||||
@[deprecated Int.tmod_neg (since := "2024-09-11")] abbrev mod_neg := @Int.tmod_neg
|
||||
@[deprecated Int.mul_tmod_left (since := "2024-09-11")] abbrev mul_mod_left := @Int.mul_tmod_left
|
||||
@[deprecated Int.mul_tmod_right (since := "2024-09-11")] abbrev mul_mod_right := @Int.mul_tmod_right
|
||||
@[deprecated Int.tmod_eq_zero_of_dvd (since := "2024-09-11")] abbrev mod_eq_zero_of_dvd := @Int.tmod_eq_zero_of_dvd
|
||||
@[deprecated Int.dvd_iff_tmod_eq_zero (since := "2024-09-11")] abbrev dvd_iff_mod_eq_zero := @Int.dvd_iff_tmod_eq_zero
|
||||
@[deprecated Int.neg_mul_tmod_right (since := "2024-09-11")] abbrev neg_mul_mod_right := @Int.neg_mul_tmod_right
|
||||
@[deprecated Int.neg_mul_tmod_left (since := "2024-09-11")] abbrev neg_mul_mod_left := @Int.neg_mul_tmod_left
|
||||
@[deprecated Int.tdiv_mul_cancel (since := "2024-09-11")] protected abbrev div_mul_cancel := @Int.tdiv_mul_cancel
|
||||
@[deprecated Int.mul_tdiv_cancel' (since := "2024-09-11")] protected abbrev mul_div_cancel' := @Int.mul_tdiv_cancel'
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_right (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_right := @Int.eq_mul_of_tdiv_eq_right
|
||||
@[deprecated Int.tmod_self (since := "2024-09-11")] abbrev mod_self := @Int.tmod_self
|
||||
@[deprecated Int.neg_tmod_self (since := "2024-09-11")] abbrev neg_mod_self := @Int.neg_tmod_self
|
||||
@[deprecated Int.lt_tdiv_add_one_mul_self (since := "2024-09-11")] abbrev lt_div_add_one_mul_self := @Int.lt_tdiv_add_one_mul_self
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_right (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_right := @Int.tdiv_eq_iff_eq_mul_right
|
||||
@[deprecated Int.tdiv_eq_iff_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_iff_eq_mul_left := @Int.tdiv_eq_iff_eq_mul_left
|
||||
@[deprecated Int.eq_mul_of_tdiv_eq_left (since := "2024-09-11")] protected abbrev eq_mul_of_div_eq_left := @Int.eq_mul_of_tdiv_eq_left
|
||||
@[deprecated Int.tdiv_eq_of_eq_mul_left (since := "2024-09-11")] protected abbrev div_eq_of_eq_mul_left := @Int.tdiv_eq_of_eq_mul_left
|
||||
@[deprecated Int.eq_zero_of_tdiv_eq_zero (since := "2024-09-11")] protected abbrev eq_zero_of_div_eq_zero := @Int.eq_zero_of_tdiv_eq_zero
|
||||
@[deprecated Int.tdiv_left_inj (since := "2024-09-11")] protected abbrev div_left_inj := @Int.tdiv_left_inj
|
||||
@[deprecated Int.tdiv_sign (since := "2024-09-11")] abbrev div_sign := @Int.tdiv_sign
|
||||
@[deprecated Int.sign_eq_tdiv_abs (since := "2024-09-11")] protected abbrev sign_eq_div_abs := @Int.sign_eq_tdiv_abs
|
||||
@[deprecated Int.tdiv_eq_ediv_of_dvd (since := "2024-09-11")] abbrev div_eq_ediv_of_dvd := @Int.tdiv_eq_ediv_of_dvd
|
||||
|
||||
@@ -329,22 +329,22 @@ theorem toNat_sub (m n : Nat) : toNat (m - n) = m - n := by
|
||||
/- ## add/sub injectivity -/
|
||||
|
||||
@[simp]
|
||||
protected theorem add_right_inj {i j : Int} (k : Int) : (i + k = j + k) ↔ i = j := by
|
||||
protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) ↔ i = j := by
|
||||
apply Iff.intro
|
||||
· intro p
|
||||
rw [←Int.add_sub_cancel i k, ←Int.add_sub_cancel j k, p]
|
||||
· exact congrArg (· + k)
|
||||
|
||||
@[simp]
|
||||
protected theorem add_left_inj {i j : Int} (k : Int) : (k + i = k + j) ↔ i = j := by
|
||||
protected theorem add_right_inj {i j : Int} (k : Int) : (k + i = k + j) ↔ i = j := by
|
||||
simp [Int.add_comm k]
|
||||
|
||||
@[simp]
|
||||
protected theorem sub_left_inj {i j : Int} (k : Int) : (k - i = k - j) ↔ i = j := by
|
||||
protected theorem sub_right_inj {i j : Int} (k : Int) : (k - i = k - j) ↔ i = j := by
|
||||
simp [Int.sub_eq_add_neg, Int.neg_inj]
|
||||
|
||||
@[simp]
|
||||
protected theorem sub_right_inj {i j : Int} (k : Int) : (i - k = j - k) ↔ i = j := by
|
||||
protected theorem sub_left_inj {i j : Int} (k : Int) : (i - k = j - k) ↔ i = j := by
|
||||
simp [Int.sub_eq_add_neg]
|
||||
|
||||
/- ## Ring properties -/
|
||||
|
||||
@@ -1007,9 +1007,9 @@ theorem sign_eq_neg_one_iff_neg {a : Int} : sign a = -1 ↔ a < 0 :=
|
||||
match x with
|
||||
| 0 => rfl
|
||||
| .ofNat (_ + 1) =>
|
||||
simp (config := { decide := true }) only [sign, true_iff]
|
||||
simp +decide only [sign, true_iff]
|
||||
exact Int.le_add_one (ofNat_nonneg _)
|
||||
| .negSucc _ => simp (config := { decide := true }) [sign]
|
||||
| .negSucc _ => simp +decide [sign]
|
||||
|
||||
theorem mul_sign : ∀ i : Int, i * sign i = natAbs i
|
||||
| succ _ => Int.mul_one _
|
||||
|
||||
@@ -24,4 +24,7 @@ import Init.Data.List.Zip
|
||||
import Init.Data.List.Perm
|
||||
import Init.Data.List.Sort
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.List.ToArrayImpl
|
||||
import Init.Data.List.MapIdx
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace List
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`. -/
|
||||
@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
| [], _ => []
|
||||
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
|
||||
|
||||
@@ -46,6 +46,11 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
|
||||
exact go L h'
|
||||
|
||||
@[simp] theorem pmap_nil {P : α → Prop} (f : ∀ a, P a → β) : pmap f [] (by simp) = [] := rfl
|
||||
|
||||
@[simp] theorem pmap_cons {P : α → Prop} (f : ∀ a, P a → β) (a : α) (l : List α) (h : ∀ b ∈ a :: l, P b) :
|
||||
pmap f (a :: l) h = f a (forall_mem_cons.1 h).1 :: pmap f l (forall_mem_cons.1 h).2 := rfl
|
||||
|
||||
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||
|
||||
@[simp] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
|
||||
@@ -148,7 +153,7 @@ theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h :
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : length (pmap f l H) = length l := by
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
· rfl
|
||||
· simp only [*, pmap, length]
|
||||
@@ -169,6 +174,13 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ [] ↔ xs ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem pmap_eq_self {l : List α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
rw [pmap_eq_map_attach]
|
||||
conv => lhs; rhs; rw [← attach_map_subtype_val l]
|
||||
rw [map_inj_left]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem attach_eq_nil_iff {l : List α} : l.attach = [] ↔ l = [] :=
|
||||
pmap_eq_nil_iff
|
||||
@@ -192,7 +204,7 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (getElem?_mem H) := by
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons hd tl hl =>
|
||||
@@ -208,7 +220,7 @@ theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
|
||||
· simp_all
|
||||
|
||||
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (get?_mem H) := by
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
|
||||
simp only [get?_eq_getElem?]
|
||||
simp [getElem?_pmap, h]
|
||||
|
||||
@@ -231,18 +243,18 @@ theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
|
||||
(hn : n < (pmap f l h).length) :
|
||||
get (pmap f l h) ⟨n, hn⟩ =
|
||||
f (get l ⟨n, @length_pmap _ _ p f l h ▸ hn⟩)
|
||||
(h _ (get_mem l n (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
(h _ (getElem_mem (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (getElem?_mem a)) :=
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : List α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => getElem?_mem a) :=
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
@@ -326,6 +338,7 @@ This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldl_subtype` below.
|
||||
-/
|
||||
theorem foldl_attach (l : List α) (f : β → α → β) (b : β) :
|
||||
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
|
||||
@@ -341,6 +354,7 @@ This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldr_subtype` below.
|
||||
-/
|
||||
theorem foldr_attach (l : List α) (f : α → β → β) (b : β) :
|
||||
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
|
||||
@@ -445,16 +459,16 @@ theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ :
|
||||
pmap_append f l₁ l₂ _
|
||||
|
||||
@[simp] theorem attach_append (xs ys : List α) :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_right xs h⟩ := by
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, pmap_append]
|
||||
congr 1 <;>
|
||||
exact pmap_congr_left _ fun _ _ _ _ => rfl
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : List α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_of_mem_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_of_mem_right xs h)) := by
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp only [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
@@ -591,6 +605,15 @@ def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) := l.map (
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Function.comp_def]
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : List { x // p x }} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem getElem_unattach
|
||||
{p : α → Prop} {l : List { x // p x }} (i : Nat) (h : i < l.unattach.length) :
|
||||
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
|
||||
simp [unattach]
|
||||
|
||||
/-! ### Recognizing higher order functions on subtypes using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -29,7 +29,7 @@ The operations are organized as follow:
|
||||
* Lexicographic ordering: `lt`, `le`, and instances.
|
||||
* Head and tail operators: `head`, `head?`, `headD?`, `tail`, `tail?`, `tailD`.
|
||||
* Basic operations:
|
||||
`map`, `filter`, `filterMap`, `foldr`, `append`, `flatten`, `pure`, `bind`, `replicate`, and
|
||||
`map`, `filter`, `filterMap`, `foldr`, `append`, `flatten`, `pure`, `flatMap`, `replicate`, and
|
||||
`reverse`.
|
||||
* Additional functions defined in terms of these: `leftpad`, `rightPad`, and `reduceOption`.
|
||||
* Operations using indexes: `mapIdx`.
|
||||
@@ -38,14 +38,14 @@ The operations are organized as follow:
|
||||
* Sublists: `take`, `drop`, `takeWhile`, `dropWhile`, `partition`, `dropLast`,
|
||||
`isPrefixOf`, `isPrefixOf?`, `isSuffixOf`, `isSuffixOf?`, `Subset`, `Sublist`,
|
||||
`rotateLeft` and `rotateRight`.
|
||||
* Manipulating elements: `replace`, `insert`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Manipulating elements: `replace`, `modify`, `insert`, `insertIdx`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Finding elements: `find?`, `findSome?`, `findIdx`, `indexOf`, `findIdx?`, `indexOf?`,
|
||||
`countP`, `count`, and `lookup`.
|
||||
* Logic: `any`, `all`, `or`, and `and`.
|
||||
* Zippers: `zipWith`, `zip`, `zipWithAll`, and `unzip`.
|
||||
* Ranges and enumeration: `range`, `iota`, `enumFrom`, and `enum`.
|
||||
* Minima and maxima: `min?` and `max?`.
|
||||
* Other functions: `intersperse`, `intercalate`, `eraseDups`, `eraseReps`, `span`, `groupBy`,
|
||||
* Other functions: `intersperse`, `intercalate`, `eraseDups`, `eraseReps`, `span`, `splitBy`,
|
||||
`removeAll`
|
||||
(currently these functions are mostly only used in meta code,
|
||||
and do not have API suitable for verification).
|
||||
@@ -231,7 +231,7 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
|
||||
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
|
||||
|
||||
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
|
||||
@[deprecated (since := "2024-06-07")] abbrev ext := @ext_get?
|
||||
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
@@ -551,7 +551,7 @@ theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux a
|
||||
/-! ### flatten -/
|
||||
|
||||
/--
|
||||
`O(|flatten L|)`. `join L` concatenates all the lists in `L` into one list.
|
||||
`O(|flatten L|)`. `flatten L` concatenates all the lists in `L` into one list.
|
||||
* `flatten [[a], [], [b, c], [d, e, f]] = [a, b, c, d, e, f]`
|
||||
-/
|
||||
def flatten : List (List α) → List α
|
||||
@@ -682,7 +682,7 @@ theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
/-- `notElem a l` is `!(elem a l)`. -/
|
||||
@[deprecated (since := "2024-06-15")]
|
||||
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
|
||||
def notElem [BEq α] (a : α) (as : List α) : Bool :=
|
||||
!(as.elem a)
|
||||
|
||||
@@ -726,13 +726,13 @@ theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h :
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)
|
||||
|
||||
theorem mem_append_of_mem_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs := by
|
||||
theorem mem_append_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs := by
|
||||
intro h
|
||||
induction h with
|
||||
| head => apply Mem.head
|
||||
| tail => apply Mem.tail; assumption
|
||||
|
||||
theorem mem_append_of_mem_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs := by
|
||||
theorem mem_append_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs := by
|
||||
intro h
|
||||
induction as with
|
||||
| nil => simp [h]
|
||||
@@ -1113,12 +1113,50 @@ theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
/--
|
||||
Apply a function to the nth tail of `l`. Returns the input without
|
||||
using `f` if the index is larger than the length of the List.
|
||||
```
|
||||
modifyTailIdx f 2 [a, b, c] = [a, b] ++ f [c]
|
||||
```
|
||||
-/
|
||||
@[simp] def modifyTailIdx (f : List α → List α) : Nat → List α → List α
|
||||
| 0, l => f l
|
||||
| _+1, [] => []
|
||||
| n+1, a :: l => a :: modifyTailIdx f n l
|
||||
|
||||
/-- Apply `f` to the head of the list, if it exists. -/
|
||||
@[inline] def modifyHead (f : α → α) : List α → List α
|
||||
| [] => []
|
||||
| a :: l => f a :: l
|
||||
|
||||
@[simp] theorem modifyHead_nil (f : α → α) : [].modifyHead f = [] := by rw [modifyHead]
|
||||
@[simp] theorem modifyHead_cons (a : α) (l : List α) (f : α → α) :
|
||||
(a :: l).modifyHead f = f a :: l := by rw [modifyHead]
|
||||
|
||||
/--
|
||||
Apply `f` to the nth element of the list, if it exists, replacing that element with the result.
|
||||
-/
|
||||
def modify (f : α → α) : Nat → List α → List α :=
|
||||
modifyTailIdx (modifyHead f)
|
||||
|
||||
/-! ### insert -/
|
||||
|
||||
/-- Inserts an element into a list without duplication. -/
|
||||
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
|
||||
if l.elem a then l else a :: l
|
||||
|
||||
/--
|
||||
`insertIdx n a l` inserts `a` into the list `l` after the first `n` elements of `l`
|
||||
```
|
||||
insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
|
||||
```
|
||||
-/
|
||||
def insertIdx (n : Nat) (a : α) : List α → List α :=
|
||||
modifyTailIdx (cons a) n
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/--
|
||||
@@ -1389,10 +1427,10 @@ def zipWithAll (f : Option α → Option β → γ) : List α → List β → Li
|
||||
| a :: as, [] => (a :: as).map fun a => f (some a) none
|
||||
| a :: as, b :: bs => f a b :: zipWithAll f as bs
|
||||
|
||||
@[simp] theorem zipWithAll_nil_right :
|
||||
@[simp] theorem zipWithAll_nil :
|
||||
zipWithAll f as [] = as.map fun a => f (some a) none := by
|
||||
cases as <;> rfl
|
||||
@[simp] theorem zipWithAll_nil_left :
|
||||
@[simp] theorem nil_zipWithAll :
|
||||
zipWithAll f [] bs = bs.map fun b => f none (some b) := rfl
|
||||
@[simp] theorem zipWithAll_cons_cons :
|
||||
zipWithAll f (a :: as) (b :: bs) = f (some a) (some b) :: zipWithAll f as bs := rfl
|
||||
@@ -1610,23 +1648,23 @@ where
|
||||
| true => loop as (a::rs)
|
||||
| false => (rs.reverse, a::as)
|
||||
|
||||
/-! ### groupBy -/
|
||||
/-! ### splitBy -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `groupBy R l` splits `l` into chains of elements
|
||||
`O(|l|)`. `splitBy R l` splits `l` into chains of elements
|
||||
such that adjacent elements are related by `R`.
|
||||
|
||||
* `groupBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
|
||||
* `groupBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
|
||||
* `splitBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
|
||||
* `splitBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
|
||||
-/
|
||||
@[specialize] def groupBy (R : α → α → Bool) : List α → List (List α)
|
||||
@[specialize] def splitBy (R : α → α → Bool) : List α → List (List α)
|
||||
| [] => []
|
||||
| a::as => loop as a [] []
|
||||
where
|
||||
/--
|
||||
The arguments of `groupBy.loop l ag g gs` represent the following:
|
||||
The arguments of `splitBy.loop l ag g gs` represent the following:
|
||||
|
||||
- `l : List α` are the elements which we still need to group.
|
||||
- `l : List α` are the elements which we still need to split.
|
||||
- `ag : α` is the previous element for which a comparison was performed.
|
||||
- `g : List α` is the group currently being assembled, in **reverse order**.
|
||||
- `gs : List (List α)` is all of the groups that have been completed, in **reverse order**.
|
||||
@@ -1637,6 +1675,8 @@ where
|
||||
| false => loop as a [] ((ag::g).reverse::gs)
|
||||
| [], ag, g, gs => ((ag::g).reverse::gs).reverse
|
||||
|
||||
@[deprecated splitBy (since := "2024-10-30"), inherit_doc splitBy] abbrev groupBy := @splitBy
|
||||
|
||||
/-! ### removeAll -/
|
||||
|
||||
/-- `O(|xs|)`. Computes the "set difference" of lists,
|
||||
|
||||
@@ -155,7 +155,8 @@ def mapMono (as : List α) (f : α → α) : List α :=
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
|
||||
theorem getElem_append_left {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
|
||||
(as ++ bs)[i] = as[i] := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
|
||||
@@ -5,6 +5,8 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Control.Lawful
|
||||
import Init.Data.List.Basic
|
||||
|
||||
namespace List
|
||||
@@ -207,6 +209,16 @@ def findM? {m : Type → Type u} [Monad m] {α : Type} (p : α → m Bool) : Lis
|
||||
| true => pure (some a)
|
||||
| false => findM? p as
|
||||
|
||||
@[simp]
|
||||
theorem findM?_id (p : α → Bool) (as : List α) : findM? (m := Id) p as = as.find? p := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, find?]
|
||||
cases p a with
|
||||
| true => rfl
|
||||
| false => rw [ih]; rfl
|
||||
|
||||
@[specialize]
|
||||
def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (Option β)) : List α → m (Option β)
|
||||
| [] => pure none
|
||||
@@ -215,26 +227,27 @@ def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
||||
| some b => pure (some b)
|
||||
| none => findSomeM? f as
|
||||
|
||||
@[inline] protected def forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : List α) (init : β) (f : α → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop
|
||||
| [], b => pure b
|
||||
| a::as, b => do
|
||||
match (← f a b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop as b
|
||||
loop as init
|
||||
@[simp]
|
||||
theorem findSomeM?_id (f : α → Option β) (as : List α) : findSomeM? (m := Id) f as = as.findSome? f := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findSomeM?, findSome?]
|
||||
cases f a with
|
||||
| some b => rfl
|
||||
| none => rw [ih]; rfl
|
||||
|
||||
instance : ForIn m (List α) α where
|
||||
forIn := List.forIn
|
||||
|
||||
@[simp] theorem forIn_eq_forIn [Monad m] : @List.forIn α β m _ = forIn := rfl
|
||||
|
||||
@[simp] theorem forIn_nil [Monad m] (f : α → β → m (ForInStep β)) (b : β) : forIn [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_cons [Monad m] (f : α → β → m (ForInStep β)) (a : α) (as : List α) (b : β)
|
||||
: forIn (a::as) b f = f a b >>= fun | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f :=
|
||||
rfl
|
||||
theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
as.findM? p = as.findSomeM? fun a => return if (← p a) then some a else none := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, findSomeM?]
|
||||
simp [ih]
|
||||
congr
|
||||
apply funext
|
||||
intro b
|
||||
cases b <;> simp
|
||||
|
||||
@[inline] protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : List α) (init : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop : (as' : List α) → (b : β) → Exists (fun bs => bs ++ as' = as) → m β
|
||||
@@ -243,7 +256,7 @@ instance : ForIn m (List α) α where
|
||||
have : a ∈ as := by
|
||||
have ⟨bs, h⟩ := h
|
||||
subst h
|
||||
exact mem_append_of_mem_right _ (Mem.head ..)
|
||||
exact mem_append_right _ (Mem.head ..)
|
||||
match (← f a this b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b =>
|
||||
@@ -254,14 +267,15 @@ instance : ForIn m (List α) α where
|
||||
instance : ForIn' m (List α) α inferInstance where
|
||||
forIn' := List.forIn'
|
||||
|
||||
@[simp] theorem forIn'_eq_forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : List α) (init : β) (f : α → β → m (ForInStep β)) : forIn' as init (fun a _ b => f a b) = forIn as init f := by
|
||||
simp [forIn', forIn, List.forIn, List.forIn']
|
||||
have : ∀ cs h, List.forIn'.loop cs (fun a _ b => f a b) as init h = List.forIn.loop f as init := by
|
||||
intro cs h
|
||||
induction as generalizing cs init with
|
||||
| nil => intros; rfl
|
||||
| cons a as ih => intros; simp [List.forIn.loop, List.forIn'.loop, ih]
|
||||
apply this
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
|
||||
@[simp] theorem forIn'_eq_forIn' [Monad m] : @List.forIn' α β m _ = forIn' := rfl
|
||||
|
||||
@[simp] theorem forIn'_nil [Monad m] (f : (a : α) → a ∈ [] → β → m (ForInStep β)) (b : β) : forIn' [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_nil [Monad m] (f : α → β → m (ForInStep β)) (b : β) : forIn [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
instance : ForM m (List α) α where
|
||||
forM := List.forM
|
||||
|
||||
@@ -153,7 +153,7 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
|
||||
simp only [length_filterMap_eq_countP]
|
||||
congr
|
||||
ext a
|
||||
simp (config := { contextual := true }) [Option.getD_eq_iff, Option.isSome_eq_isSome]
|
||||
simp +contextual [Option.getD_eq_iff, Option.isSome_eq_isSome]
|
||||
|
||||
@[simp] theorem countP_flatten (l : List (List α)) :
|
||||
countP p l.flatten = (l.map (countP p)).sum := by
|
||||
@@ -162,6 +162,10 @@ theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : List α)
|
||||
|
||||
@[deprecated countP_flatten (since := "2024-10-14")] abbrev countP_join := @countP_flatten
|
||||
|
||||
theorem countP_flatMap (p : β → Bool) (l : List α) (f : α → List β) :
|
||||
countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by
|
||||
rw [List.flatMap, countP_flatten, map_map]
|
||||
|
||||
@[simp] theorem countP_reverse (l : List α) : countP p l.reverse = countP p l := by
|
||||
simp [countP_eq_length_filter, filter_reverse]
|
||||
|
||||
@@ -315,7 +319,7 @@ theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = len
|
||||
theorem count_le_count_map [DecidableEq β] (l : List α) (f : α → β) (x : α) :
|
||||
count x l ≤ count (f x) (map f l) := by
|
||||
rw [count, count, countP_map]
|
||||
apply countP_mono_left; simp (config := { contextual := true })
|
||||
apply countP_mono_left; simp +contextual
|
||||
|
||||
theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List α) :
|
||||
count b (filterMap f l) = countP (fun a => f a == some b) l := by
|
||||
@@ -326,6 +330,9 @@ theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : List
|
||||
· simp
|
||||
· simp
|
||||
|
||||
theorem count_flatMap {α} [BEq β] (l : List α) (f : α → List β) (x : β) :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap _ _ _
|
||||
|
||||
theorem count_erase (a b : α) :
|
||||
∀ l : List α, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||
| [] => by simp
|
||||
|
||||
48
src/Init/Data/List/FinRange.lean
Normal file
48
src/Init/Data/List/FinRange.lean
Normal file
@@ -0,0 +1,48 @@
|
||||
/-
|
||||
Copyright (c) 2024 François G. Dorais. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.OfFn
|
||||
|
||||
namespace List
|
||||
|
||||
/-- `finRange n` lists all elements of `Fin n` in order -/
|
||||
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp] theorem length_finRange (n) : (List.finRange n).length = n := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem getElem_finRange (i : Nat) (h : i < (List.finRange n).length) :
|
||||
(finRange n)[i] = Fin.cast (length_finRange n) ⟨i, h⟩ := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem finRange_zero : finRange 0 = [] := by simp [finRange, ofFn]
|
||||
|
||||
theorem finRange_succ (n) : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by
|
||||
apply List.ext_getElem; simp; intro i; cases i <;> simp
|
||||
|
||||
theorem finRange_succ_last (n) :
|
||||
finRange (n+1) = (finRange n).map Fin.castSucc ++ [Fin.last n] := by
|
||||
apply List.ext_getElem
|
||||
· simp
|
||||
· intros
|
||||
simp only [List.finRange, List.getElem_ofFn, getElem_append, length_map, length_ofFn,
|
||||
getElem_map, Fin.castSucc_mk, getElem_singleton]
|
||||
split
|
||||
· rfl
|
||||
· next h => exact Fin.eq_last_of_not_lt h
|
||||
|
||||
theorem finRange_reverse (n) : (finRange n).reverse = (finRange n).map Fin.rev := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
conv => lhs; rw [finRange_succ_last]
|
||||
conv => rhs; rw [finRange_succ]
|
||||
rw [reverse_append, reverse_cons, reverse_nil, nil_append, singleton_append, ← map_reverse,
|
||||
map_cons, ih, map_map, map_map]
|
||||
congr; funext
|
||||
simp [Fin.rev_succ]
|
||||
|
||||
end List
|
||||
@@ -10,7 +10,8 @@ import Init.Data.List.Sublist
|
||||
import Init.Data.List.Range
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, and `List.indexOf`.
|
||||
Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `List.indexOf`,
|
||||
and `List.lookup`.
|
||||
-/
|
||||
|
||||
namespace List
|
||||
@@ -95,22 +96,22 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
|
||||
· simp only [Option.guard_eq_none] at h
|
||||
simp [ih, h]
|
||||
|
||||
@[simp] theorem filterMap_head? (f : α → Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
|
||||
@[simp] theorem head?_filterMap (f : α → Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [filterMap_cons, findSome?_cons]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp] theorem filterMap_head (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
@[simp] theorem head_filterMap (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem filterMap_getLast? (f : α → Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
@[simp] theorem getLast?_filterMap (f : α → Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filterMap_reverse]
|
||||
|
||||
@[simp] theorem filterMap_getLast (f : α → Option β) (l : List α) (h) :
|
||||
@[simp] theorem getLast_filterMap (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).getLast h = (l.reverse.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast_eq_some]
|
||||
|
||||
@@ -179,7 +180,7 @@ theorem IsPrefix.findSome?_eq_some {l₁ l₂ : List α} {f : α → Option β}
|
||||
List.findSome? f l₁ = some b → List.findSome? f l₂ = some b := by
|
||||
rw [IsPrefix] at h
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
simp (config := {contextual := true}) [findSome?_append]
|
||||
simp +contextual [findSome?_append]
|
||||
|
||||
theorem IsPrefix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (h : l₁ <+: l₂) :
|
||||
List.findSome? f l₂ = none → List.findSome? f l₁ = none :=
|
||||
@@ -206,7 +207,8 @@ theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
induction l <;> simp [find?_cons]; split <;> simp [*]
|
||||
|
||||
theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
theorem find?_eq_some_iff_append :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
@@ -242,6 +244,9 @@ theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b
|
||||
cases h₁
|
||||
simp
|
||||
|
||||
@[deprecated find?_eq_some_iff_append (since := "2024-11-06")]
|
||||
abbrev find?_eq_some := @find?_eq_some_iff_append
|
||||
|
||||
@[simp]
|
||||
theorem find?_cons_eq_some : (a :: xs).find? p = some b ↔ (p a ∧ a = b) ∨ (!p a ∧ xs.find? p = some b) := by
|
||||
rw [find?_cons]
|
||||
@@ -287,18 +292,18 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
|
||||
· simp only [find?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem filter_head? (p : α → Bool) (l : List α) : (l.filter p).head? = l.find? p := by
|
||||
rw [← filterMap_eq_filter, filterMap_head?, findSome?_guard]
|
||||
@[simp] theorem head?_filter (p : α → Bool) (l : List α) : (l.filter p).head? = l.find? p := by
|
||||
rw [← filterMap_eq_filter, head?_filterMap, findSome?_guard]
|
||||
|
||||
@[simp] theorem filter_head (p : α → Bool) (l : List α) (h) :
|
||||
@[simp] theorem head_filter (p : α → Bool) (l : List α) (h) :
|
||||
(l.filter p).head h = (l.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem filter_getLast? (p : α → Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
@[simp] theorem getLast?_filter (p : α → Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filter_reverse]
|
||||
|
||||
@[simp] theorem filter_getLast (p : α → Bool) (l : List α) (h) :
|
||||
@[simp] theorem getLast_filter (p : α → Bool) (l : List α) (h) :
|
||||
(l.filter p).getLast h = (l.reverse.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast_eq_some]
|
||||
|
||||
@@ -347,7 +352,7 @@ theorem find?_flatten_eq_some {xs : List (List α)} {p : α → Bool} {a : α} :
|
||||
xs.flatten.find? p = some a ↔
|
||||
p a ∧ ∃ as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
constructor
|
||||
· rintro ⟨h, ⟨ys, zs, h₁, h₂⟩⟩
|
||||
refine ⟨h, ?_⟩
|
||||
@@ -436,7 +441,7 @@ theorem IsPrefix.find?_eq_some {l₁ l₂ : List α} {p : α → Bool} (h : l₁
|
||||
List.find? p l₁ = some b → List.find? p l₂ = some b := by
|
||||
rw [IsPrefix] at h
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
simp (config := {contextual := true}) [find?_append]
|
||||
simp +contextual [find?_append]
|
||||
|
||||
theorem IsPrefix.find?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂) :
|
||||
List.find? p l₂ = none → List.find? p l₁ = none :=
|
||||
@@ -562,7 +567,7 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
| inr e =>
|
||||
have ipm := Nat.succ_pred_eq_of_pos e
|
||||
have ilt := Nat.le_trans ho (findIdx_le_length p)
|
||||
simp (config := { singlePass := true }) only [← ipm, getElem_cons_succ]
|
||||
simp +singlePass only [← ipm, getElem_cons_succ]
|
||||
rw [← ipm, Nat.succ_lt_succ_iff] at h
|
||||
simpa using ih h
|
||||
|
||||
@@ -595,15 +600,14 @@ theorem findIdx_eq {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length
|
||||
|
||||
theorem findIdx_append (p : α → Bool) (l₁ l₂ : List α) :
|
||||
(l₁ ++ l₂).findIdx p =
|
||||
if ∃ x, x ∈ l₁ ∧ p x = true then l₁.findIdx p else l₂.findIdx p + l₁.length := by
|
||||
if l₁.findIdx p < l₁.length then l₁.findIdx p else l₂.findIdx p + l₁.length := by
|
||||
induction l₁ with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx_cons, length_cons, cons_append]
|
||||
by_cases h : p x
|
||||
· simp [h]
|
||||
· simp only [h, ih, cond_eq_if, Bool.false_eq_true, ↓reduceIte, mem_cons, exists_eq_or_imp,
|
||||
false_or]
|
||||
· simp only [h, ih, cond_eq_if, Bool.false_eq_true, ↓reduceIte, add_one_lt_add_one_iff]
|
||||
split <;> simp [Nat.add_assoc]
|
||||
|
||||
theorem IsPrefix.findIdx_le {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂) :
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace List
|
||||
The following operations are already tail-recursive, and do not need `@[csimp]` replacements:
|
||||
`get`, `foldl`, `beq`, `isEqv`, `reverse`, `elem` (and hence `contains`), `drop`, `dropWhile`,
|
||||
`partition`, `isPrefixOf`, `isPrefixOf?`, `find?`, `findSome?`, `lookup`, `any` (and hence `or`),
|
||||
`all` (and hence `and`) , `range`, `eraseDups`, `eraseReps`, `span`, `groupBy`.
|
||||
`all` (and hence `and`) , `range`, `eraseDups`, `eraseReps`, `span`, `splitBy`.
|
||||
|
||||
The following operations are still missing `@[csimp]` replacements:
|
||||
`concat`, `zipWithAll`.
|
||||
@@ -38,7 +38,7 @@ The following operations were already given `@[csimp]` replacements in `Init/Dat
|
||||
|
||||
The following operations are given `@[csimp]` replacements below:
|
||||
`set`, `filterMap`, `foldr`, `append`, `bind`, `join`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `insertIdx`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`enumFrom`, and `intercalate`.
|
||||
|
||||
-/
|
||||
@@ -91,7 +91,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_toList, -Array.size_toArray]
|
||||
funext α β f init l; simp [foldrTR, ← Array.foldr_toList, -Array.size_toArray]
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
@@ -197,6 +197,41 @@ The following operations are given `@[csimp]` replacements below:
|
||||
· simp [*]
|
||||
· intro h; rw [IH] <;> simp_all
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
/-- Tail-recursive version of `modify`. -/
|
||||
def modifyTR (f : α → α) (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `modifyTR`: `modifyTR.go f l n acc = acc.toList ++ modify f n l`. -/
|
||||
go : List α → Nat → Array α → List α
|
||||
| [], _, acc => acc.toList
|
||||
| a :: l, 0, acc => acc.toListAppend (f a :: l)
|
||||
| a :: l, n+1, acc => go l n (acc.push a)
|
||||
|
||||
theorem modifyTR_go_eq : ∀ l n, modifyTR.go f l n acc = acc.toList ++ modify f n l
|
||||
| [], n => by cases n <;> simp [modifyTR.go, modify]
|
||||
| a :: l, 0 => by simp [modifyTR.go, modify]
|
||||
| a :: l, n+1 => by simp [modifyTR.go, modify, modifyTR_go_eq l]
|
||||
|
||||
@[csimp] theorem modify_eq_modifyTR : @modify = @modifyTR := by
|
||||
funext α f n l; simp [modifyTR, modifyTR_go_eq]
|
||||
|
||||
/-! ### insertIdx -/
|
||||
|
||||
/-- Tail-recursive version of `insertIdx`. -/
|
||||
@[inline] def insertIdxTR (n : Nat) (a : α) (l : List α) : List α := go n l #[] where
|
||||
/-- Auxiliary for `insertIdxTR`: `insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l`. -/
|
||||
go : Nat → List α → Array α → List α
|
||||
| 0, l, acc => acc.toListAppend (a :: l)
|
||||
| _, [], acc => acc.toList
|
||||
| n+1, a :: l, acc => go n l (acc.push a)
|
||||
|
||||
theorem insertIdxTR_go_eq : ∀ n l, insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l
|
||||
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
|
||||
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
|
||||
|
||||
@[csimp] theorem insertIdx_eq_insertIdxTR : @insertIdx = @insertIdxTR := by
|
||||
funext α f n l; simp [insertIdxTR, insertIdxTR_go_eq]
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/-- Tail recursive version of `List.erase`. -/
|
||||
@@ -296,7 +331,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [Array.foldr_eq_foldr_toList]
|
||||
rw [← Array.foldr_toList]
|
||||
simp [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
@@ -83,44 +83,12 @@ open Nat
|
||||
@[simp] theorem nil_eq {α} {xs : List α} : [] = xs ↔ xs = [] := by
|
||||
cases xs <;> simp
|
||||
|
||||
/-! ### cons -/
|
||||
|
||||
theorem cons_ne_nil (a : α) (l : List α) : a :: l ≠ [] := nofun
|
||||
|
||||
@[simp]
|
||||
theorem cons_ne_self (a : α) (l : List α) : a :: l ≠ l := mt (congrArg length) (Nat.succ_ne_self _)
|
||||
|
||||
@[simp] theorem ne_cons_self {a : α} {l : List α} : l ≠ a :: l := by
|
||||
rw [ne_eq, eq_comm]
|
||||
simp
|
||||
|
||||
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
|
||||
|
||||
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
|
||||
|
||||
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' :=
|
||||
⟨tail_eq_of_cons_eq, congrArg _⟩
|
||||
|
||||
@[deprecated (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
|
||||
|
||||
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l' :=
|
||||
List.cons.injEq .. ▸ .rfl
|
||||
|
||||
theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ [] → ∃ b L, l = b :: L
|
||||
| c :: l', _ => ⟨c, l', rfl⟩
|
||||
|
||||
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
|
||||
simp
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
theorem eq_nil_of_length_eq_zero (_ : length l = 0) : l = [] := match l with | [] => rfl
|
||||
|
||||
theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l ≠ [] := fun _ => nomatch l
|
||||
|
||||
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
|
||||
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
|
||||
|
||||
theorem ne_nil_of_length_pos (_ : 0 < length l) : l ≠ [] := fun _ => nomatch l
|
||||
|
||||
@[simp] theorem length_eq_zero : length l = 0 ↔ l = [] :=
|
||||
@@ -156,6 +124,36 @@ theorem length_pos {l : List α} : 0 < length l ↔ l ≠ [] :=
|
||||
theorem length_eq_one {l : List α} : length l = 1 ↔ ∃ a, l = [a] :=
|
||||
⟨fun h => match l, h with | [_], _ => ⟨_, rfl⟩, fun ⟨_, h⟩ => by simp [h]⟩
|
||||
|
||||
/-! ### cons -/
|
||||
|
||||
theorem cons_ne_nil (a : α) (l : List α) : a :: l ≠ [] := nofun
|
||||
|
||||
@[simp]
|
||||
theorem cons_ne_self (a : α) (l : List α) : a :: l ≠ l := mt (congrArg length) (Nat.succ_ne_self _)
|
||||
|
||||
@[simp] theorem ne_cons_self {a : α} {l : List α} : l ≠ a :: l := by
|
||||
rw [ne_eq, eq_comm]
|
||||
simp
|
||||
|
||||
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
|
||||
|
||||
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
|
||||
|
||||
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' :=
|
||||
⟨tail_eq_of_cons_eq, congrArg _⟩
|
||||
|
||||
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l' :=
|
||||
List.cons.injEq .. ▸ .rfl
|
||||
|
||||
theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ [] → ∃ b L, l = b :: L
|
||||
| c :: l', _ => ⟨c, l', rfl⟩
|
||||
|
||||
theorem ne_nil_iff_exists_cons {l : List α} : l ≠ [] ↔ ∃ b L, l = b :: L :=
|
||||
⟨exists_cons_of_ne_nil, fun ⟨_, _, eq⟩ => eq.symm ▸ cons_ne_nil _ _⟩
|
||||
|
||||
theorem singleton_inj {α : Type _} {a b : α} : [a] = [b] ↔ a = b := by
|
||||
simp
|
||||
|
||||
/-! ## L[i] and L[i]? -/
|
||||
|
||||
/-! ### `get` and `get?`.
|
||||
@@ -163,57 +161,29 @@ theorem length_eq_one {l : List α} : length l = 1 ↔ ∃ a, l = [a] :=
|
||||
We simplify `l.get i` to `l[i.1]'i.2` and `l.get? i` to `l[i]?`.
|
||||
-/
|
||||
|
||||
theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
|
||||
@[simp] theorem get_eq_getElem (l : List α) (i : Fin l.length) : l.get i = l[i.1]'i.2 := rfl
|
||||
|
||||
theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
|
||||
(a :: as).get ⟨i+1, h⟩ = as.get ⟨i, Nat.lt_of_succ_lt_succ h⟩ := rfl
|
||||
|
||||
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
|
||||
(a :: as).get i.succ = as.get i := rfl
|
||||
|
||||
@[deprecated (since := "2024-07-09")]
|
||||
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
|
||||
|
||||
theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos.mp h)
|
||||
| _::_, _ => rfl
|
||||
|
||||
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
|
||||
|
||||
theorem get?_len_le : ∀ {l : List α} {n}, length l ≤ n → l.get? n = none
|
||||
theorem get?_eq_none : ∀ {l : List α} {n}, length l ≤ n → l.get? n = none
|
||||
| [], _, _ => rfl
|
||||
| _ :: l, _+1, h => get?_len_le (l := l) <| Nat.le_of_succ_le_succ h
|
||||
| _ :: l, _+1, h => get?_eq_none (l := l) <| Nat.le_of_succ_le_succ h
|
||||
|
||||
theorem get?_eq_get : ∀ {l : List α} {n} (h : n < l.length), l.get? n = some (get l ⟨n, h⟩)
|
||||
| _ :: _, 0, _ => rfl
|
||||
| _ :: l, _+1, _ => get?_eq_get (l := l) _
|
||||
|
||||
theorem get?_eq_some : l.get? n = some a ↔ ∃ h, get l ⟨n, h⟩ = a :=
|
||||
theorem get?_eq_some_iff : l.get? n = some a ↔ ∃ h, get l ⟨n, h⟩ = a :=
|
||||
⟨fun e =>
|
||||
have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_len_le hn ▸ e
|
||||
have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_eq_none hn ▸ e
|
||||
⟨this, by rwa [get?_eq_get this, Option.some.injEq] at e⟩,
|
||||
fun ⟨_, e⟩ => e ▸ get?_eq_get _⟩
|
||||
|
||||
theorem get?_eq_none : l.get? n = none ↔ length l ≤ n :=
|
||||
⟨fun e => Nat.ge_of_not_lt (fun h' => by cases e ▸ get?_eq_some.2 ⟨h', rfl⟩), get?_len_le⟩
|
||||
theorem get?_eq_none_iff : l.get? n = none ↔ length l ≤ n :=
|
||||
⟨fun e => Nat.ge_of_not_lt (fun h' => by cases e ▸ get?_eq_some_iff.2 ⟨h', rfl⟩), get?_eq_none⟩
|
||||
|
||||
@[simp] theorem get?_eq_getElem? (l : List α) (i : Nat) : l.get? i = l[i]? := by
|
||||
simp only [getElem?, decidableGetElem?]; split
|
||||
simp only [getElem?_def]; split
|
||||
· exact (get?_eq_get ‹_›)
|
||||
· exact (get?_eq_none.2 <| Nat.not_lt.1 ‹_›)
|
||||
|
||||
@[simp] theorem get_eq_getElem (l : List α) (i : Fin l.length) : l.get i = l[i.1]'i.2 := rfl
|
||||
|
||||
theorem getElem?_eq_some {l : List α} : l[i]? = some a ↔ ∃ h : i < l.length, l[i]'h = a := by
|
||||
simpa using get?_eq_some
|
||||
|
||||
/--
|
||||
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
|
||||
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
|
||||
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
|
||||
such a rewrite, with `rw [get_of_eq h]`.
|
||||
-/
|
||||
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
|
||||
get l i = get l' ⟨i, h ▸ i.2⟩ := by cases h; rfl
|
||||
· exact (get?_eq_none_iff.2 <| Nat.not_lt.1 ‹_›)
|
||||
|
||||
/-! ### getD
|
||||
|
||||
@@ -224,71 +194,54 @@ Because of this, there is only minimal API for `getD`.
|
||||
@[simp] theorem getD_eq_getElem?_getD (l) (n) (a : α) : getD l n a = (l[n]?).getD a := by
|
||||
simp [getD]
|
||||
|
||||
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
|
||||
theorem getD_eq_get? : ∀ l n (a : α), getD l n a = (get? l n).getD a := by simp
|
||||
|
||||
/-! ### get!
|
||||
|
||||
We simplify `l.get! n` to `l[n]!`.
|
||||
-/
|
||||
|
||||
theorem get!_of_get? [Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a
|
||||
| _a::_, 0, rfl => rfl
|
||||
| _::l, _+1, e => get!_of_get? (l := l) e
|
||||
|
||||
theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) n, l.get! n = l.getD n default
|
||||
| [], _ => rfl
|
||||
| _a::_, 0 => rfl
|
||||
| _a::l, n+1 => get!_eq_getD l n
|
||||
|
||||
theorem get!_len_le [Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α)
|
||||
| [], _, _ => rfl
|
||||
| _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
|
||||
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited α] (l : List α) (n) : l.get! n = l[n]! := by
|
||||
simp [get!_eq_getD]
|
||||
rfl
|
||||
|
||||
/-! ### getElem! -/
|
||||
/-! ### getElem!
|
||||
|
||||
@[simp] theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
|
||||
We simplify `l[n]!` to `(l[n]?).getD default`.
|
||||
-/
|
||||
|
||||
@[simp] theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
|
||||
rw [getElem!_pos] <;> simp
|
||||
|
||||
@[simp] theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
|
||||
by_cases h : n < l.length
|
||||
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
@[simp] theorem getElem!_eq_getElem?_getD [Inhabited α] (l : List α) (n : Nat) :
|
||||
l[n]! = (l[n]?).getD (default : α) := by
|
||||
simp only [getElem!_def]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### getElem? and getElem -/
|
||||
|
||||
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] := by
|
||||
simp only [getElem?_def, h, ↓reduceDIte]
|
||||
|
||||
theorem getElem?_eq_some_iff {l : List α} : l[n]? = some a ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_some, get_eq_getElem]
|
||||
|
||||
theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem getElem?_eq_none_iff : l[n]? = none ↔ length l ≤ n := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_none]
|
||||
simp only [← get?_eq_getElem?, get?_eq_none_iff]
|
||||
|
||||
@[simp] theorem none_eq_getElem?_iff {l : List α} {n : Nat} : none = l[n]? ↔ length l ≤ n := by
|
||||
simp [eq_comm (a := none)]
|
||||
|
||||
theorem getElem?_eq_none (h : length l ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
theorem getElem?_eq (l : List α) (i : Nat) :
|
||||
l[i]? = if h : i < l.length then some l[i] else none := by
|
||||
split <;> simp_all
|
||||
@[simp] theorem getElem?_eq_getElem {l : List α} {n} (h : n < l.length) : l[n]? = some l[n] :=
|
||||
getElem?_pos ..
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
theorem getElem?_eq_some_iff {l : List α} : l[n]? = some a ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
simp only [← get?_eq_getElem?, get?_eq_some_iff, get_eq_getElem]
|
||||
|
||||
theorem some_eq_getElem?_iff {l : List α} : some a = l[n]? ↔ ∃ h : n < l.length, l[n] = a := by
|
||||
rw [eq_comm, getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem some_getElem_eq_getElem?_iff (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
(some xs[i] = xs[i]?) ↔ True := by
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff {α} (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
@[simp] theorem getElem?_eq_some_getElem_iff (xs : List α) (i : Nat) (h : i < xs.length) :
|
||||
(xs[i]? = some xs[i]) ↔ True := by
|
||||
simp [h]
|
||||
|
||||
@@ -300,11 +253,13 @@ theorem getElem_eq_getElem?_get (l : List α) (i : Nat) (h : i < l.length) :
|
||||
l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
|
||||
simp [getElem_eq_iff]
|
||||
|
||||
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
|
||||
@getElem_eq_getElem?_get
|
||||
|
||||
@[simp] theorem getElem?_nil {n : Nat} : ([] : List α)[n]? = none := rfl
|
||||
|
||||
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
|
||||
(a :: l)[i] =
|
||||
if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
|
||||
cases i <;> simp
|
||||
|
||||
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
|
||||
|
||||
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[n+1]? = l[n]? := by
|
||||
@@ -314,10 +269,12 @@ theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := by simp
|
||||
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
||||
cases i <;> simp
|
||||
|
||||
theorem getElem?_len_le : ∀ {l : List α} {n}, length l ≤ n → l[n]? = none
|
||||
| [], _, _ => rfl
|
||||
| _ :: l, _+1, h => by
|
||||
rw [getElem?_cons_succ, getElem?_len_le (l := l) <| Nat.le_of_succ_le_succ h]
|
||||
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
theorem getElem?_singleton (a : α) (i : Nat) : [a][i]? = if i = 0 then some a else none := by
|
||||
simp [getElem?_cons]
|
||||
|
||||
/--
|
||||
If one has `l[i]` in an expression and `h : l = l'`,
|
||||
@@ -328,24 +285,10 @@ such a rewrite, with `rw [getElem_of_eq h]`.
|
||||
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
|
||||
l[i] = l'[i]'(h ▸ w) := by cases h; rfl
|
||||
|
||||
@[simp] theorem getElem_singleton (a : α) (h : i < 1) : [a][i] = a :=
|
||||
match i, h with
|
||||
| 0, _ => rfl
|
||||
|
||||
@[deprecated getElem_singleton (since := "2024-06-12")]
|
||||
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
|
||||
|
||||
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos.mp h) :=
|
||||
match l, h with
|
||||
| _ :: _, _ => rfl
|
||||
|
||||
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {n : Nat}, l[n]? = some a → l[n]! = a
|
||||
| _a::_, 0, _ => by
|
||||
rw [getElem!_pos] <;> simp_all
|
||||
| _::l, _+1, e => by
|
||||
simp at e
|
||||
simp_all [getElem!_of_getElem? (l := l) e]
|
||||
|
||||
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : ∀ n : Nat, l₁[n]? = l₂[n]?) : l₁ = l₂ :=
|
||||
ext_get? fun n => by simp_all
|
||||
|
||||
@@ -356,11 +299,7 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
simp_all [getElem?_eq_getElem]
|
||||
else by
|
||||
have h₁ := Nat.le_of_not_lt h₁
|
||||
rw [getElem?_len_le h₁, getElem?_len_le]; rwa [← hl]
|
||||
|
||||
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
|
||||
ext_getElem hl (by simp_all)
|
||||
rw [getElem?_eq_none h₁, getElem?_eq_none]; rwa [← hl]
|
||||
|
||||
@[simp] theorem getElem_concat_length : ∀ (l : List α) (a : α) (i) (_ : i = l.length) (w), (l ++ [a])[i]'w = a
|
||||
| [], a, _, h, _ => by subst h; simp
|
||||
@@ -369,9 +308,6 @@ theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? = some a := by
|
||||
simp
|
||||
|
||||
@[deprecated getElem?_concat_length (since := "2024-06-12")]
|
||||
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
|
||||
@@ -383,9 +319,9 @@ theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = s
|
||||
theorem mem_cons_self (a : α) (l : List α) : a ∈ a :: l := .head ..
|
||||
|
||||
theorem mem_concat_self (xs : List α) (a : α) : a ∈ xs ++ [a] :=
|
||||
mem_append_of_mem_right xs (mem_cons_self a _)
|
||||
mem_append_right xs (mem_cons_self a _)
|
||||
|
||||
theorem mem_append_cons_self : a ∈ xs ++ a :: ys := mem_append_of_mem_right _ (mem_cons_self _ _)
|
||||
theorem mem_append_cons_self : a ∈ xs ++ a :: ys := mem_append_right _ (mem_cons_self _ _)
|
||||
|
||||
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
∃ as bs, xs = as ++ a :: bs ∧ a ∉ as := by
|
||||
@@ -482,42 +418,19 @@ theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l → ∃ (n : Nat) (h : n
|
||||
| _, _ :: _, .head .. => ⟨0, Nat.succ_pos _, rfl⟩
|
||||
| _, _ :: _, .tail _ m => let ⟨n, h, e⟩ := getElem_of_mem m; ⟨n+1, Nat.succ_lt_succ h, e⟩
|
||||
|
||||
theorem get_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, get l n = a := by
|
||||
obtain ⟨n, h, e⟩ := getElem_of_mem h
|
||||
exact ⟨⟨n, h⟩, e⟩
|
||||
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a := by
|
||||
let ⟨n, _, e⟩ := getElem_of_mem h
|
||||
exact ⟨n, e ▸ getElem?_eq_getElem _⟩
|
||||
|
||||
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = some a :=
|
||||
let ⟨n, _, e⟩ := getElem_of_mem h; ⟨n, e ▸ getElem?_eq_getElem _⟩
|
||||
|
||||
theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a :=
|
||||
let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩
|
||||
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
theorem get_mem : ∀ (l : List α) n h, get l ⟨n, h⟩ ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (get_mem l ..)
|
||||
|
||||
theorem getElem?_mem {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||
theorem mem_of_getElem? {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
||||
|
||||
theorem get?_mem {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := get?_eq_some.1 e; e ▸ get_mem ..
|
||||
|
||||
theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (n : Nat) (h : n < l.length), l[n]'h = a :=
|
||||
⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
|
||||
|
||||
theorem mem_iff_get {a} {l : List α} : a ∈ l ↔ ∃ n, get l n = a :=
|
||||
⟨get_of_mem, fun ⟨_, e⟩ => e ▸ get_mem ..⟩
|
||||
|
||||
theorem mem_iff_getElem? {a} {l : List α} : a ∈ l ↔ ∃ n : Nat, l[n]? = some a := by
|
||||
simp [getElem?_eq_some_iff, mem_iff_getElem]
|
||||
|
||||
theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a := by
|
||||
simp [getElem?_eq_some_iff, Fin.exists_iff, mem_iff_get]
|
||||
|
||||
theorem forall_getElem {l : List α} {p : α → Prop} :
|
||||
(∀ (n : Nat) h, p (l[n]'h)) ↔ ∀ a, a ∈ l → p a := by
|
||||
induction l with
|
||||
@@ -554,7 +467,7 @@ theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
|
||||
(List.isEmpty xs = false) ↔ ∃ x, x ∈ xs := by
|
||||
xs.isEmpty = false ↔ ∃ x, x ∈ xs := by
|
||||
cases xs <;> simp
|
||||
|
||||
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
|
||||
@@ -568,18 +481,6 @@ theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 :=
|
||||
|
||||
/-! ### any / all -/
|
||||
|
||||
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) ↔ a ∈ l := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) ↔ a ∈ l := by
|
||||
induction l <;> simp_all [eq_comm (a := a)]
|
||||
|
||||
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) ↔ a ∉ l := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) ↔ a ∉ l := by
|
||||
induction l <;> simp_all [eq_comm (a := a)]
|
||||
|
||||
theorem any_eq {l : List α} : l.any p = decide (∃ x, x ∈ l ∧ p x) := by induction l <;> simp [*]
|
||||
|
||||
theorem all_eq {l : List α} : l.all p = decide (∀ x, x ∈ l → p x) := by induction l <;> simp [*]
|
||||
@@ -604,6 +505,18 @@ 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]
|
||||
|
||||
theorem any_beq [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => a == x) ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
theorem any_beq' [BEq α] [LawfulBEq α] {l : List α} : (l.any fun x => x == a) ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
theorem all_bne [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => a != x) ↔ a ∉ l := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem all_bne' [BEq α] [LawfulBEq α] {l : List α} : (l.all fun x => x != a) ↔ a ∉ l := by
|
||||
induction l <;> simp_all [eq_comm (a := a)]
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@@ -621,19 +534,10 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
|
||||
| _ :: _, 0 => by simp
|
||||
| _ :: l, i + 1 => by simp [getElem_set_self]
|
||||
|
||||
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
|
||||
|
||||
@[deprecated getElem_set_self (since := "2024-06-12")]
|
||||
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
|
||||
(l.set i a).get ⟨i, h⟩ = a := by
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_set_self {l : List α} {i : Nat} {a : α} (h : i < l.length) :
|
||||
(l.set i a)[i]? = some a := by
|
||||
simp_all [getElem?_eq_some_iff]
|
||||
|
||||
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
|
||||
|
||||
/-- This differs from `getElem?_set_self` by monadically mapping `Function.const _ a` over the `Option`
|
||||
returned by `l[i]?`. -/
|
||||
theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
@@ -655,12 +559,6 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
have g : i ≠ j := h ∘ congrArg (· + 1)
|
||||
simp [getElem_set_ne g]
|
||||
|
||||
@[deprecated getElem_set_ne (since := "2024-06-12")]
|
||||
theorem get_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
|
||||
(hj : j < (l.set i a).length) :
|
||||
(l.set i a).get ⟨j, hj⟩ = l.get ⟨j, by simp at hj; exact hj⟩ := by
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem?_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α} :
|
||||
(l.set i a)[j]? = l[j]? := by
|
||||
by_cases hj : j < (l.set i a).length
|
||||
@@ -675,11 +573,6 @@ theorem getElem_set {l : List α} {m n} {a} (h) :
|
||||
else
|
||||
simp [h]
|
||||
|
||||
@[deprecated getElem_set (since := "2024-06-12")]
|
||||
theorem get_set {l : List α} {m n} {a : α} (h) :
|
||||
(set l m a).get ⟨n, h⟩ = if m = n then a else l.get ⟨n, length_set .. ▸ h⟩ := by
|
||||
simp [getElem_set]
|
||||
|
||||
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
|
||||
@@ -699,6 +592,14 @@ theorem getElem?_set' {l : List α} {i j : Nat} {a : α} :
|
||||
· simp only [getElem?_set_self', Option.map_eq_map, ↓reduceIte, *]
|
||||
· simp only [ne_eq, not_false_eq_true, getElem?_set_ne, ↓reduceIte, *]
|
||||
|
||||
@[simp] theorem set_getElem_self {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as.set i as[i] = as := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_set]
|
||||
split <;> simp_all
|
||||
|
||||
theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length ≤ n) {a : α} :
|
||||
l.set n a = l := by
|
||||
induction l generalizing n with
|
||||
@@ -713,8 +614,6 @@ theorem set_eq_of_length_le {l : List α} {n : Nat} (h : l.length ≤ n) {a : α
|
||||
@[simp] theorem set_eq_nil_iff {l : List α} (n : Nat) (a : α) : l.set n a = [] ↔ l = [] := by
|
||||
cases l <;> cases n <;> simp [set]
|
||||
|
||||
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
|
||||
|
||||
theorem set_comm (a b : α) : ∀ {n m : Nat} (l : List α), n ≠ m →
|
||||
(l.set n a).set m b = (l.set m b).set n a
|
||||
| _, _, [], _ => by simp
|
||||
@@ -780,6 +679,24 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
|
||||
· intro a
|
||||
simp
|
||||
|
||||
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
|
||||
match l₁, l₂ with
|
||||
| [], [] => rfl
|
||||
| [], _ :: _ => by simp [beq_nil_iff] at h
|
||||
| _ :: _, [] => by simp [nil_beq_iff] at h
|
||||
| a :: l₁, b :: l₂ => by
|
||||
simp at h
|
||||
simpa [Nat.add_one_inj]using length_eq_of_beq h.2
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
protected theorem lt_irrefl [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by
|
||||
@@ -845,6 +762,12 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
|
||||
l.foldr f b = l.foldrM (m := Id) f b := by
|
||||
induction l <;> simp [*, foldr]
|
||||
|
||||
@[simp] theorem id_run_foldlM (f : β → α → Id β) (b) (l : List α) :
|
||||
Id.run (l.foldlM f b) = l.foldl f b := (foldl_eq_foldlM f b l).symm
|
||||
|
||||
@[simp] theorem id_run_foldrM (f : α → β → Id β) (b) (l : List α) :
|
||||
Id.run (l.foldrM f b) = l.foldr f b := (foldr_eq_foldrM f b l).symm
|
||||
|
||||
/-! ### foldl and foldr -/
|
||||
|
||||
@[simp] theorem foldr_cons_eq_append (l : List α) : l.foldr cons l' = l ++ l' := by
|
||||
@@ -867,14 +790,30 @@ theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α
|
||||
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldl_filterMap (f : α → Option β) (g : γ → β → γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldl_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldr_filterMap (f : α → Option β) (g : β → γ → γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldr_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldl_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldr_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
@@ -987,6 +926,21 @@ theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} (r : β →
|
||||
· simp
|
||||
· exact ih h fun a m c c' h => h' _ (by simp_all) _ _ h
|
||||
|
||||
@[simp] theorem foldl_add_const (l : List α) (a b : Nat) :
|
||||
l.foldl (fun x _ => x + a) b = b + a * l.length := by
|
||||
induction l generalizing b with
|
||||
| nil => simp
|
||||
| cons y l ih =>
|
||||
simp only [foldl_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc,
|
||||
Nat.add_comm a]
|
||||
|
||||
@[simp] theorem foldr_add_const (l : List α) (a b : Nat) :
|
||||
l.foldr (fun _ x => x + a) b = b + a * l.length := by
|
||||
induction l generalizing b with
|
||||
| nil => simp
|
||||
| cons y l ih =>
|
||||
simp only [foldr_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc]
|
||||
|
||||
/-! ### getLast -/
|
||||
|
||||
theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
||||
@@ -998,6 +952,10 @@ theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
||||
| _ :: _ :: _, _ => by
|
||||
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
|
||||
|
||||
theorem getElem_length_sub_one_eq_getLast (l : List α) (h : l.length - 1 < l.length) :
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@[deprecated getLast_eq_getElem (since := "2024-07-15")]
|
||||
theorem getLast_eq_get (l : List α) (h : l ≠ []) :
|
||||
getLast l h = l.get ⟨l.length - 1, by
|
||||
@@ -1018,7 +976,7 @@ theorem getLast_eq_getLastD (a l h) : @getLast α (a::l) h = getLastD l a := by
|
||||
|
||||
@[simp] theorem getLast_singleton (a h) : @getLast α [a] h = a := rfl
|
||||
|
||||
theorem getLast!_cons [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
simp [getLast!, getLast_eq_getLastD]
|
||||
|
||||
@[simp] theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
|
||||
@@ -1082,7 +1040,12 @@ theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by
|
||||
|
||||
/-! ### getLast! -/
|
||||
|
||||
@[simp] theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
|
||||
@[simp] theorem getLast!_eq_getLast?_getD [Inhabited α] {l : List α} : getLast! l = (getLast? l).getD default := by
|
||||
cases l with
|
||||
| nil => simp [getLast!_nil]
|
||||
| cons _ _ => simp [getLast!, getLast?_eq_getLast]
|
||||
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
@@ -1117,6 +1080,12 @@ theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_p
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem getElem_zero_eq_head (l : List α) (h : 0 < l.length) :
|
||||
l[0] = head l (by simpa [length_pos] using h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem head_eq_iff_head?_eq_some {xs : List α} (h) : xs.head h = a ↔ xs.head? = some a := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
@@ -1461,6 +1430,22 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
|
||||
| [] => rfl
|
||||
| a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter _ l]
|
||||
|
||||
theorem foldl_filter (p : α → Bool) (f : β → α → β) (l : List α) (init : β) :
|
||||
(l.filter p).foldl f init = l.foldl (fun x y => if p y then f x y else x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldl_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem foldr_filter (p : α → Bool) (f : α → β → β) (l : List α) (init : β) :
|
||||
(l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldr_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem filter_map (f : β → α) (l : List β) : filter p (map f l) = map f (filter (p ∘ f) l) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -1688,7 +1673,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
|
||||
|
||||
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h) :
|
||||
theorem getElem_append {l₁ l₂ : List α} (n : Nat) (h : n < (l₁ ++ l₂).length) :
|
||||
(l₁ ++ l₂)[n] = if h' : n < l₁.length then l₁[n] else l₂[n - 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']
|
||||
@@ -1728,7 +1713,7 @@ theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {n : Nat} (hn :
|
||||
l₂[n] = (l₁ ++ l₂)[n + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hn _) := by
|
||||
rw [getElem_append_right] <;> simp [*, le_add_left]
|
||||
|
||||
@[deprecated (since := "2024-06-12")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
|
||||
(h₁ : l₁.length ≤ n) (h₂ : n < (l₁ ++ l₂).length) : n - l₁.length < l₂.length := by
|
||||
rw [length_append] at h₂
|
||||
@@ -1745,7 +1730,7 @@ theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.l
|
||||
rw [← getElem?_eq_getElem, eq, getElem?_append_right (h ▸ Nat.le_refl _), h]
|
||||
simp
|
||||
|
||||
@[deprecated (since := "2024-06-12")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_of_append_proof {l : List α}
|
||||
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : n < length l := eq ▸ h ▸ by simp_arith
|
||||
|
||||
@@ -1929,11 +1914,8 @@ theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t
|
||||
theorem mem_append_eq (a : α) (s t : List α) : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
theorem mem_append_left {a : α} {l₁ : List α} (l₂ : List α) (h : a ∈ l₁) : a ∈ l₁ ++ l₂ :=
|
||||
mem_append.2 (Or.inl h)
|
||||
|
||||
theorem mem_append_right {a : α} (l₁ : List α) {l₂ : List α} (h : a ∈ l₂) : a ∈ l₁ ++ l₂ :=
|
||||
mem_append.2 (Or.inr h)
|
||||
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
|
||||
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
|
||||
|
||||
theorem mem_iff_append {a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t :=
|
||||
⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩
|
||||
@@ -2233,6 +2215,11 @@ theorem flatMap_def (l : List α) (f : α → List β) : l.flatMap f = flatten (
|
||||
|
||||
@[simp] theorem flatMap_id (l : List (List α)) : List.flatMap l id = l.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp]
|
||||
theorem length_flatMap (l : List α) (f : α → List β) :
|
||||
length (l.flatMap f) = sum (map (length ∘ f) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map]
|
||||
|
||||
@[simp] 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₂⟩⟩
|
||||
@@ -2347,7 +2334,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
|
||||
@[simp] theorem getElem_replicate (a : α) {n : Nat} {m} (h : m < (replicate n a).length) :
|
||||
(replicate n a)[m] = a :=
|
||||
eq_of_mem_replicate (get_mem _ _ _)
|
||||
eq_of_mem_replicate (getElem_mem _)
|
||||
|
||||
@[deprecated getElem_replicate (since := "2024-06-12")]
|
||||
theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := by
|
||||
@@ -2704,6 +2691,12 @@ theorem flatMap_reverse {β} (l : List α) (f : α → List β) : (l.reverse.fla
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
theorem foldl_eq_foldr_reverse (l : List α) (f : β → α → β) (b) :
|
||||
l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
|
||||
|
||||
theorem foldr_eq_foldl_reverse (l : List α) (f : α → β → β) (b) :
|
||||
l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
|
||||
|
||||
@[simp] theorem reverse_replicate (n) (a : α) : reverse (replicate n a) = replicate n a :=
|
||||
eq_replicate_iff.2
|
||||
⟨by rw [length_reverse, length_replicate],
|
||||
@@ -2847,6 +2840,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ ∃ a' ∈ l, a == a' := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
/-! ## Sublists -/
|
||||
|
||||
/-! ### partition
|
||||
@@ -2879,7 +2876,7 @@ are often used for theorems about `Array.pop`.
|
||||
@[simp] 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
|
||||
| _::_::_, i+1, _ => getElem_dropLast _ i _
|
||||
| _::_::_, i+1, h => getElem_dropLast _ i (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_dropLast (since := "2024-06-12")]
|
||||
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
|
||||
@@ -3254,10 +3251,10 @@ theorem any_eq_not_all_not (l : List α) (p : α → Bool) : l.any p = !l.all (!
|
||||
theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!p .) := by
|
||||
simp only [not_any_eq_all_not, Bool.not_not]
|
||||
|
||||
@[simp] theorem any_map {l : List α} {p : α → Bool} : (l.map f).any p = l.any (p ∘ f) := by
|
||||
@[simp] theorem any_map {l : List α} {p : β → Bool} : (l.map f).any p = l.any (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
@[simp] theorem all_map {l : List α} {p : α → Bool} : (l.map f).all p = l.all (p ∘ f) := by
|
||||
@[simp] theorem all_map {l : List α} {p : β → Bool} : (l.map f).all p = l.all (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
@[simp] theorem any_filter {l : List α} {p q : α → Bool} :
|
||||
@@ -3332,7 +3329,7 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
|
||||
|
||||
@[simp] theorem all_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).all f = if n = 0 then true else f a := by
|
||||
cases n <;> simp (config := {contextual := true}) [replicate_succ]
|
||||
cases n <;> simp +contextual [replicate_succ]
|
||||
|
||||
@[simp] theorem any_insert [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.insert a).any f = (f a || l.any f) := by
|
||||
@@ -3342,17 +3339,137 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
|
||||
(l.insert a).all f = (f a && l.all f) := by
|
||||
simp [all_eq]
|
||||
|
||||
/-! ### Legacy lemmas about `get`, `get?`, and `get!`.
|
||||
|
||||
Hopefully these should not be needed, in favour of lemmas about `xs[i]`, `xs[i]?`, and `xs[i]!`,
|
||||
to which these simplify.
|
||||
|
||||
We may consider deprecating or downstreaming these lemmas.
|
||||
-/
|
||||
|
||||
theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
|
||||
|
||||
theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
|
||||
(a :: as).get ⟨i+1, h⟩ = as.get ⟨i, Nat.lt_of_succ_lt_succ h⟩ := rfl
|
||||
|
||||
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
|
||||
(a :: as).get i.succ = as.get i := rfl
|
||||
|
||||
theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos.mp h)
|
||||
| _::_, _ => rfl
|
||||
|
||||
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
|
||||
|
||||
/--
|
||||
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
|
||||
`rw [h]` will give a "motive is not type correct" error, as it cannot rewrite the
|
||||
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
|
||||
such a rewrite, with `rw [get_of_eq h]`.
|
||||
-/
|
||||
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
|
||||
get l i = get l' ⟨i, h ▸ i.2⟩ := by cases h; rfl
|
||||
|
||||
theorem get!_of_get? [Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a
|
||||
| _a::_, 0, rfl => rfl
|
||||
| _::l, _+1, e => get!_of_get? (l := l) e
|
||||
|
||||
theorem get!_len_le [Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α)
|
||||
| [], _, _ => rfl
|
||||
| _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
|
||||
|
||||
theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
|
||||
|
||||
theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
|
||||
rw [getElem!_pos] <;> simp
|
||||
|
||||
theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[n+1]! = l[n]! := by
|
||||
by_cases h : n < l.length
|
||||
· rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
· rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
|
||||
|
||||
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {n : Nat}, l[n]? = some a → l[n]! = a
|
||||
| _a::_, 0, _ => by
|
||||
rw [getElem!_pos] <;> simp_all
|
||||
| _::l, _+1, e => by
|
||||
simp at e
|
||||
simp_all [getElem!_of_getElem? (l := l) e]
|
||||
|
||||
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
|
||||
ext_getElem hl (by simp_all)
|
||||
|
||||
theorem get_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, get l n = a := by
|
||||
obtain ⟨n, h, e⟩ := getElem_of_mem h
|
||||
exact ⟨⟨n, h⟩, e⟩
|
||||
|
||||
theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a :=
|
||||
let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩
|
||||
|
||||
theorem get_mem : ∀ (l : List α) n, get l n ∈ l
|
||||
| _ :: _, ⟨0, _⟩ => .head ..
|
||||
| _ :: l, ⟨_+1, _⟩ => .tail _ (get_mem l ..)
|
||||
|
||||
theorem mem_of_get? {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := get?_eq_some_iff.1 e; e ▸ get_mem ..
|
||||
|
||||
theorem mem_iff_get {a} {l : List α} : a ∈ l ↔ ∃ n, get l n = a :=
|
||||
⟨get_of_mem, fun ⟨_, e⟩ => e ▸ get_mem ..⟩
|
||||
|
||||
theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a := by
|
||||
simp [getElem?_eq_some_iff, Fin.exists_iff, mem_iff_get]
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
|
||||
theorem getD_eq_get? : ∀ l n (a : α), getD l n a = (get? l n).getD a := by simp
|
||||
@[deprecated getElem_singleton (since := "2024-06-12")]
|
||||
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
|
||||
@[deprecated getElem?_concat_length (since := "2024-06-12")]
|
||||
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
|
||||
@[deprecated getElem_set_self (since := "2024-06-12")]
|
||||
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
|
||||
(l.set i a).get ⟨i, h⟩ = a := by
|
||||
simp
|
||||
@[deprecated getElem_set_ne (since := "2024-06-12")]
|
||||
theorem get_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
|
||||
(hj : j < (l.set i a).length) :
|
||||
(l.set i a).get ⟨j, hj⟩ = l.get ⟨j, by simp at hj; exact hj⟩ := by
|
||||
simp [h]
|
||||
@[deprecated getElem_set (since := "2024-06-12")]
|
||||
theorem get_set {l : List α} {m n} {a : α} (h) :
|
||||
(set l m a).get ⟨n, h⟩ = if m = n then a else l.get ⟨n, length_set .. ▸ h⟩ := by
|
||||
simp [getElem_set]
|
||||
@[deprecated cons_inj_right (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
|
||||
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
|
||||
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-07-09")]
|
||||
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
|
||||
|
||||
@[deprecated filter_flatten (since := "2024-08-26")]
|
||||
theorem join_map_filter (p : α → Bool) (l : List (List α)) :
|
||||
(l.map (filter p)).flatten = (l.flatten).filter p := by
|
||||
rw [filter_flatten]
|
||||
|
||||
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
|
||||
@getElem_eq_getElem?_get
|
||||
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
|
||||
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
|
||||
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
|
||||
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
|
||||
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
|
||||
@[deprecated mem_of_getElem? (since := "2024-09-06")] abbrev getElem?_mem := @mem_of_getElem?
|
||||
@[deprecated mem_of_get? (since := "2024-09-06")] abbrev get?_mem := @mem_of_get?
|
||||
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
|
||||
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
|
||||
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
|
||||
|
||||
@[deprecated flatten_nil (since := "2024-10-14")] abbrev join_nil := @flatten_nil
|
||||
@[deprecated flatten_cons (since := "2024-10-14")] abbrev join_cons := @flatten_cons
|
||||
@[deprecated length_flatten (since := "2024-10-14")] abbrev length_join := @length_flatten
|
||||
@[deprecated flatten_singleton (since := "2024-10-14")] abbrev join_singleton := @flatten_singleton
|
||||
@[deprecated mem_flatten (since := "2024-10-14")] abbrev mem_join := @mem_flatten
|
||||
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
|
||||
@[deprecated flatten_eq_nil_iff (since := "2024-10-14")] abbrev join_eq_nil_iff := @flatten_eq_nil_iff
|
||||
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
|
||||
@[deprecated flatten_ne_nil_iff (since := "2024-10-14")] abbrev join_ne_nil_iff := @flatten_ne_nil_iff
|
||||
@[deprecated exists_of_mem_flatten (since := "2024-10-14")] abbrev exists_of_mem_join := @exists_of_mem_flatten
|
||||
@[deprecated mem_flatten_of_mem (since := "2024-10-14")] abbrev mem_join_of_mem := @mem_flatten_of_mem
|
||||
@@ -3366,16 +3483,9 @@ theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!
|
||||
@[deprecated filter_flatten (since := "2024-10-14")] abbrev filter_join := @filter_flatten
|
||||
@[deprecated flatten_filter_not_isEmpty (since := "2024-10-14")] abbrev join_filter_not_isEmpty := @flatten_filter_not_isEmpty
|
||||
@[deprecated flatten_filter_ne_nil (since := "2024-10-14")] abbrev join_filter_ne_nil := @flatten_filter_ne_nil
|
||||
@[deprecated filter_flatten (since := "2024-08-26")]
|
||||
theorem join_map_filter (p : α → Bool) (l : List (List α)) :
|
||||
(l.map (filter p)).flatten = (l.flatten).filter p := by
|
||||
rw [filter_flatten]
|
||||
@[deprecated flatten_append (since := "2024-10-14")] abbrev join_append := @flatten_append
|
||||
@[deprecated flatten_concat (since := "2024-10-14")] abbrev join_concat := @flatten_concat
|
||||
@[deprecated flatten_flatten (since := "2024-10-14")] abbrev join_join := @flatten_flatten
|
||||
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
|
||||
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
|
||||
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
|
||||
@[deprecated flatten_eq_append_iff (since := "2024-10-14")] abbrev join_eq_append_iff := @flatten_eq_append_iff
|
||||
@[deprecated eq_iff_flatten_eq (since := "2024-10-14")] abbrev eq_iff_join_eq := @eq_iff_flatten_eq
|
||||
@[deprecated flatten_replicate_nil (since := "2024-10-14")] abbrev join_replicate_nil := @flatten_replicate_nil
|
||||
@@ -3410,4 +3520,23 @@ theorem join_map_filter (p : α → Bool) (l : List (List α)) :
|
||||
@[deprecated any_flatMap (since := "2024-10-16")] abbrev any_bind := @any_flatMap
|
||||
@[deprecated all_flatMap (since := "2024-10-16")] abbrev all_bind := @all_flatMap
|
||||
|
||||
@[deprecated get?_eq_none (since := "2024-11-29")] abbrev get?_len_le := @get?_eq_none
|
||||
@[deprecated getElem?_eq_some_iff (since := "2024-11-29")]
|
||||
abbrev getElem?_eq_some := @getElem?_eq_some_iff
|
||||
@[deprecated get?_eq_some_iff (since := "2024-11-29")]
|
||||
abbrev get?_eq_some := @get?_eq_some_iff
|
||||
@[deprecated LawfulGetElem.getElem?_def (since := "2024-11-29")]
|
||||
theorem getElem?_eq (l : List α) (i : Nat) :
|
||||
l[i]? = if h : i < l.length then some l[i] else none :=
|
||||
getElem?_def _ _
|
||||
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
|
||||
|
||||
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
|
||||
theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome ↔ n < l.length := by
|
||||
simp
|
||||
|
||||
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
|
||||
theorem isNone_getElem? {l : List α} {n : Nat} : l[n]?.isNone ↔ l.length ≤ n := by
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -7,6 +7,9 @@ Authors: Kim Morrison, Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.Range
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.Fin.Lemmas
|
||||
import Init.Data.Option.Attach
|
||||
|
||||
namespace List
|
||||
|
||||
@@ -14,8 +17,21 @@ namespace List
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
|
||||
/--
|
||||
Given a function `f : Nat → α → β` and `as : list α`, `as = [a₀, a₁, ...]`, returns the list
|
||||
Given a list `as = [a₀, a₁, ...]` function `f : Fin as.length → α → β`, returns the list
|
||||
`[f 0 a₀, f 1 a₁, ...]`.
|
||||
-/
|
||||
@[inline] def mapFinIdx (as : List α) (f : Fin as.length → α → β) : List β := go as #[] (by simp) where
|
||||
/-- Auxiliary for `mapFinIdx`:
|
||||
`mapFinIdx.go [a₀, a₁, ...] acc = acc.toList ++ [f 0 a₀, f 1 a₁, ...]` -/
|
||||
@[specialize] go : (bs : List α) → (acc : Array β) → bs.length + acc.size = as.length → List β
|
||||
| [], acc, h => acc.toList
|
||||
| a :: as, acc, h =>
|
||||
go as (acc.push (f ⟨acc.size, by simp at h; omega⟩ a)) (by simp at h ⊢; omega)
|
||||
|
||||
/--
|
||||
Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list
|
||||
`[f 0 a₀, f 1 a₁, ...]`.
|
||||
-/
|
||||
@[inline] def mapIdx (f : Nat → α → β) (as : List α) : List β := go as #[] where
|
||||
@@ -25,34 +41,178 @@ Given a function `f : Nat → α → β` and `as : list α`, `as = [a₀, a₁,
|
||||
| [], acc => acc.toList
|
||||
| a :: as, acc => go as (acc.push (f acc.size a))
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_nil {f : Fin 0 → α → β} : mapFinIdx [] f = [] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_mapFinIdx_go :
|
||||
(mapFinIdx.go as f bs acc h).length = as.length := by
|
||||
induction bs generalizing acc with
|
||||
| nil => simpa using h
|
||||
| cons _ _ ih => simp [mapFinIdx.go, ih]
|
||||
|
||||
@[simp] theorem length_mapFinIdx {as : List α} {f : Fin as.length → α → β} :
|
||||
(as.mapFinIdx f).length = as.length := by
|
||||
simp [mapFinIdx, length_mapFinIdx_go]
|
||||
|
||||
theorem getElem_mapFinIdx_go {as : List α} {f : Fin as.length → α → β} {i : Nat} {h} {w} :
|
||||
(mapFinIdx.go as f bs acc h)[i] =
|
||||
if w' : i < acc.size then acc[i] else f ⟨i, by simp at w; omega⟩ (bs[i - acc.size]'(by simp at w; omega)) := by
|
||||
induction bs generalizing acc with
|
||||
| nil =>
|
||||
simp only [length_mapFinIdx_go, length_nil, Nat.zero_add] at w h
|
||||
simp only [mapFinIdx.go, Array.getElem_toList]
|
||||
rw [dif_pos]
|
||||
| cons _ _ ih =>
|
||||
simp [mapFinIdx.go]
|
||||
rw [ih]
|
||||
simp
|
||||
split <;> rename_i h₁ <;> split <;> rename_i h₂
|
||||
· rw [Array.getElem_push_lt]
|
||||
· have h₃ : i = acc.size := by omega
|
||||
subst h₃
|
||||
simp
|
||||
· omega
|
||||
· have h₃ : i - acc.size = (i - (acc.size + 1)) + 1 := by omega
|
||||
simp [h₃]
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx {as : List α} {f : Fin as.length → α → β} {i : Nat} {h} :
|
||||
(as.mapFinIdx f)[i] = f ⟨i, by simp at h; omega⟩ (as[i]'(by simp at h; omega)) := by
|
||||
simp [mapFinIdx, getElem_mapFinIdx_go]
|
||||
|
||||
theorem mapFinIdx_eq_ofFn {as : List α} {f : Fin as.length → α → β} :
|
||||
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : Fin l.length → α → β} {i : Nat} :
|
||||
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f ⟨i, by simp [getElem?_eq_some_iff] at m; exact m.1⟩ x := by
|
||||
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_cons {l : List α} {a : α} {f : Fin (l.length + 1) → α → β} :
|
||||
mapFinIdx (a :: l) f = f 0 a :: mapFinIdx l (fun i => f i.succ) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· rintro (_|i) h₁ h₂ <;> simp
|
||||
|
||||
theorem mapFinIdx_append {K L : List α} {f : Fin (K ++ L).length → α → β} :
|
||||
(K ++ L).mapFinIdx f =
|
||||
K.mapFinIdx (fun i => f (i.castLE (by simp))) ++ L.mapFinIdx (fun i => f ((i.natAdd K.length).cast (by simp))) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
rw [getElem_append]
|
||||
simp only [getElem_mapFinIdx, length_mapFinIdx]
|
||||
split <;> rename_i h
|
||||
· rw [getElem_append_left]
|
||||
congr
|
||||
· simp only [Nat.not_lt] at h
|
||||
rw [getElem_append_right h]
|
||||
congr
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : Fin (l ++ [e]).length → α → β}:
|
||||
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i => f (i.castLE (by simp))) ++ [f ⟨l.length, by simp⟩ e] := by
|
||||
simp [mapFinIdx_append]
|
||||
congr
|
||||
|
||||
theorem mapFinIdx_singleton {a : α} {f : Fin 1 → α → β} :
|
||||
[a].mapFinIdx f = [f ⟨0, by simp⟩ a] := by
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_enum_map {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l.enum.attach.map
|
||||
fun ⟨⟨i, x⟩, m⟩ =>
|
||||
f ⟨i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1⟩ x := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_nil_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = [] ↔ l = [] := by
|
||||
rw [mapFinIdx_eq_enum_map, map_eq_nil_iff, attach_eq_nil_iff, enum_eq_nil_iff]
|
||||
|
||||
theorem mapFinIdx_ne_nil_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f ≠ [] ↔ l ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length → α → β}
|
||||
(h : b ∈ l.mapFinIdx f) : ∃ (i : Fin l.length), f i l[i] = b := by
|
||||
rw [mapFinIdx_eq_enum_map] at h
|
||||
replace h := exists_of_mem_map h
|
||||
simp only [mem_attach, true_and, Subtype.exists, Prod.exists, mk_mem_enum_iff_getElem?] at h
|
||||
obtain ⟨i, b, h, rfl⟩ := h
|
||||
rw [getElem?_eq_some_iff] at h
|
||||
obtain ⟨h', rfl⟩ := h
|
||||
exact ⟨⟨i, h'⟩, rfl⟩
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length → α → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Fin l.length), f i l[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
exact exists_of_mem_mapFinIdx h
|
||||
· rintro ⟨i, h, rfl⟩
|
||||
rw [mem_iff_getElem]
|
||||
exact ⟨i, by simp⟩
|
||||
|
||||
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = b :: l₂ ↔
|
||||
∃ (a : α) (l₁ : List α) (h : l = a :: l₁),
|
||||
f ⟨0, by simp [h]⟩ a = b ∧ l₁.mapFinIdx (fun i => f (i.succ.cast (by simp [h]))) = l₂ := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons x l' =>
|
||||
simp only [mapFinIdx_cons, cons.injEq, length_cons, Fin.zero_eta, Fin.cast_succ_eq,
|
||||
exists_and_left]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
refine ⟨x, rfl, l', by simp⟩
|
||||
· rintro ⟨a, ⟨rfl, h⟩, ⟨_, ⟨rfl, rfl⟩, h⟩⟩
|
||||
exact ⟨rfl, h⟩
|
||||
|
||||
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = b :: l₂ ↔
|
||||
l.head?.pbind (fun x m => (f ⟨0, by cases l <;> simp_all⟩ x)) = some b ∧
|
||||
l.tail?.attach.map (fun ⟨t, m⟩ => t.mapFinIdx fun i => f (i.succ.cast (by cases l <;> simp_all))) = some l₂ := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem mapFinIdx_eq_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l' ↔ ∃ h : l'.length = l.length, ∀ (i : Nat) (h : i < l.length), l'[i] = f ⟨i, h⟩ l[i] := by
|
||||
constructor
|
||||
· rintro rfl
|
||||
simp
|
||||
· rintro ⟨h, w⟩
|
||||
apply ext_getElem <;> simp_all
|
||||
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Fin l.length), f i l[i] = g i l[i] := by
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp [Fin.forall_iff]
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : List α} {f : Fin l.length → α → β} {g : Fin _ → β → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i => g (i.cast (by simp)) ∘ f i) := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : Fin l.length → α → β} {b : β} :
|
||||
l.mapFinIdx f = replicate l.length b ↔ ∀ (i : Fin l.length), f i l[i] = b := by
|
||||
simp [eq_replicate_iff, length_mapFinIdx, mem_mapFinIdx, forall_exists_index, true_and]
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {l : List α} {f : Fin l.reverse.length → α → β} :
|
||||
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i => f ⟨l.length - 1 - i, by simp; omega⟩)).reverse := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
intro i h
|
||||
congr
|
||||
omega
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_nil {f : Nat → α → β} : mapIdx f [] = [] :=
|
||||
rfl
|
||||
|
||||
theorem mapIdx_go_append {l₁ l₂ : List α} {arr : Array β} :
|
||||
mapIdx.go f (l₁ ++ l₂) arr = mapIdx.go f l₂ (List.toArray (mapIdx.go f l₁ arr)) := by
|
||||
generalize h : (l₁ ++ l₂).length = len
|
||||
induction len generalizing l₁ arr with
|
||||
| zero =>
|
||||
have l₁_nil : l₁ = [] := by
|
||||
cases l₁
|
||||
· rfl
|
||||
· contradiction
|
||||
have l₂_nil : l₂ = [] := by
|
||||
cases l₂
|
||||
· rfl
|
||||
· rw [List.length_append] at h; contradiction
|
||||
rw [l₁_nil, l₂_nil]; simp only [mapIdx.go, List.toArray_toList]
|
||||
| succ len ih =>
|
||||
cases l₁ with
|
||||
| nil =>
|
||||
simp only [mapIdx.go, nil_append, List.toArray_toList]
|
||||
| cons head tail =>
|
||||
simp only [mapIdx.go, List.append_eq]
|
||||
rw [ih]
|
||||
· simp only [cons_append, length_cons, length_append, Nat.succ.injEq] at h
|
||||
simp only [length_append, h]
|
||||
|
||||
theorem mapIdx_go_length {arr : Array β} :
|
||||
length (mapIdx.go f l arr) = length l + arr.size := by
|
||||
induction l generalizing arr with
|
||||
@@ -60,16 +220,6 @@ theorem mapIdx_go_length {arr : Array β} :
|
||||
| cons _ _ ih =>
|
||||
simp only [mapIdx.go, ih, Array.size_push, Nat.add_succ, length_cons, Nat.add_comm]
|
||||
|
||||
@[simp] theorem mapIdx_concat {l : List α} {e : α} :
|
||||
mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by
|
||||
unfold mapIdx
|
||||
rw [mapIdx_go_append]
|
||||
simp only [mapIdx.go, Array.size_toArray, mapIdx_go_length, length_nil, Nat.add_zero,
|
||||
Array.push_toList]
|
||||
|
||||
@[simp] theorem mapIdx_singleton {a : α} : mapIdx f [a] = [f 0 a] := by
|
||||
simpa using mapIdx_concat (l := [])
|
||||
|
||||
theorem length_mapIdx_go : ∀ {l : List α} {arr : Array β},
|
||||
(mapIdx.go f l arr).length = l.length + arr.size
|
||||
| [], _ => by simp [mapIdx.go]
|
||||
@@ -86,16 +236,16 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
|
||||
(mapIdx.go f l arr)[i]? =
|
||||
if h : i < arr.size then some arr[i] else Option.map (f i) l[i - arr.size]?
|
||||
| [], arr, i => by
|
||||
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_eq, Array.length_toList,
|
||||
Array.getElem_eq_getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none']
|
||||
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
|
||||
← Array.getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none']
|
||||
| a :: l, arr, i => by
|
||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||
simp only [Array.size_push]
|
||||
split <;> split
|
||||
· simp only [Option.some.injEq]
|
||||
rw [Array.getElem_eq_getElem_toList]
|
||||
rw [← Array.getElem_toList]
|
||||
simp only [Array.push_toList]
|
||||
rw [getElem_append_left, Array.getElem_eq_getElem_toList]
|
||||
rw [getElem_append_left, ← Array.getElem_toList]
|
||||
· have : i = arr.size := by omega
|
||||
simp_all
|
||||
· omega
|
||||
@@ -112,6 +262,15 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
|
||||
rw [← getElem?_eq_getElem, getElem?_mapIdx, getElem?_eq_getElem (by simpa using h)]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : Fin l.length → α → β} {g : Nat → α → β}
|
||||
(h : ∀ (i : Fin l.length), f i l[i] = g i l[i]) :
|
||||
l.mapFinIdx f = l.mapIdx g := by
|
||||
simp_all [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mapFinIdx {l : List α} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.mapFinIdx (fun i => f i) := by
|
||||
simp [mapFinIdx_eq_mapIdx]
|
||||
|
||||
theorem mapIdx_eq_enum_map {l : List α} :
|
||||
l.mapIdx f = l.enum.map (Function.uncurry f) := by
|
||||
ext1 i
|
||||
@@ -130,9 +289,16 @@ theorem mapIdx_append {K L : List α} :
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp [ih (f := fun i => f (i + 1)), Nat.add_assoc]
|
||||
|
||||
@[simp] theorem mapIdx_concat {l : List α} {e : α} :
|
||||
mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by
|
||||
simp [mapIdx_append]
|
||||
|
||||
theorem mapIdx_singleton {a : α} : mapIdx f [a] = [f 0 a] := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_eq_nil_iff {l : List α} : List.mapIdx f l = [] ↔ l = [] := by
|
||||
rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil]
|
||||
rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil_iff]
|
||||
|
||||
theorem mapIdx_ne_nil_iff {l : List α} :
|
||||
List.mapIdx f l ≠ [] ↔ l ≠ [] := by
|
||||
@@ -140,13 +306,8 @@ theorem mapIdx_ne_nil_iff {l : List α} :
|
||||
|
||||
theorem exists_of_mem_mapIdx {b : β} {l : List α}
|
||||
(h : b ∈ mapIdx f l) : ∃ (i : Nat) (h : i < l.length), f i l[i] = b := by
|
||||
rw [mapIdx_eq_enum_map] at h
|
||||
replace h := exists_of_mem_map h
|
||||
simp only [Prod.exists, mk_mem_enum_iff_getElem?, Function.uncurry_apply_pair] at h
|
||||
obtain ⟨i, b, h, rfl⟩ := h
|
||||
rw [getElem?_eq_some_iff] at h
|
||||
obtain ⟨h, rfl⟩ := h
|
||||
exact ⟨i, h, rfl⟩
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {l : List α} :
|
||||
b ∈ mapIdx f l ↔ ∃ (i : Nat) (h : i < l.length), f i l[i] = b := by
|
||||
|
||||
@@ -5,6 +5,7 @@ Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, M
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.TakeDrop
|
||||
import Init.Data.List.Attach
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.mapM` and `List.forM`.
|
||||
@@ -48,6 +49,9 @@ theorem mapM'_eq_mapM [Monad m] [LawfulMonad m] (f : α → m β) (l : List α)
|
||||
@[simp] theorem mapM_cons [Monad m] [LawfulMonad m] (f : α → m β) :
|
||||
(a :: l).mapM f = (return (← f a) :: (← l.mapM f)) := by simp [← mapM'_eq_mapM, mapM']
|
||||
|
||||
@[simp] theorem mapM_id {l : List α} {f : α → Id β} : l.mapM f = l.map f := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] (f : α → m β) {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).mapM f = (return (← l₁.mapM f) ++ (← l₂.mapM f)) := by induction l₁ <;> simp [*]
|
||||
|
||||
@@ -72,6 +76,52 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] (f : α → m β)
|
||||
reverse_cons, reverse_nil, nil_append, singleton_append]
|
||||
simp [bind_pure_comp]
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : List β₁) (init : α) :
|
||||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : List β₁)
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldlM g init =
|
||||
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldlM_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldrM g init =
|
||||
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldrM_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : List α) (init : β) :
|
||||
(l.filter p).foldlM g init =
|
||||
l.foldlM (fun x y => if p y then g x y else pure x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldlM_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : List α) (init : β) :
|
||||
(l.filter p).foldrM g init =
|
||||
l.foldrM (fun x y => if p x then g x y else pure y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldrM_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
-- We use `List.forM` as the simp normal form, rather that `ForM.forM`.
|
||||
@@ -87,6 +137,176 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] (f : α → m β)
|
||||
(l₁ ++ l₂).forM f = (do l₁.forM f; l₂.forM f) := by
|
||||
induction l₁ <;> simp [*]
|
||||
|
||||
/-! ### forIn' -/
|
||||
|
||||
theorem forIn'_loop_congr [Monad m] {as bs : List α}
|
||||
{f : (a' : α) → a' ∈ as → β → m (ForInStep β)}
|
||||
{g : (a' : α) → a' ∈ bs → β → m (ForInStep β)}
|
||||
{b : β} (ha : ∃ ys, ys ++ xs = as) (hb : ∃ ys, ys ++ xs = bs)
|
||||
(h : ∀ a m m' b, f a m b = g a m' b) : forIn'.loop as f xs b ha = forIn'.loop bs g xs b hb := by
|
||||
induction xs generalizing b with
|
||||
| nil => simp [forIn'.loop]
|
||||
| cons a xs ih =>
|
||||
simp only [forIn'.loop] at *
|
||||
congr 1
|
||||
· rw [h]
|
||||
· funext s
|
||||
obtain b | b := s
|
||||
· rfl
|
||||
· simp
|
||||
rw [ih]
|
||||
|
||||
@[simp] theorem forIn'_cons [Monad m] {a : α} {as : List α}
|
||||
(f : (a' : α) → a' ∈ a :: as → β → m (ForInStep β)) (b : β) :
|
||||
forIn' (a::as) b f = f a (mem_cons_self a as) b >>=
|
||||
fun | ForInStep.done b => pure b | ForInStep.yield b => forIn' as b fun a' m b => f a' (mem_cons_of_mem a m) b := by
|
||||
simp only [forIn', List.forIn', forIn'.loop]
|
||||
congr 1
|
||||
funext s
|
||||
obtain b | b := s
|
||||
· rfl
|
||||
· apply forIn'_loop_congr
|
||||
intros
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_cons [Monad m] (f : α → β → m (ForInStep β)) (a : α) (as : List α) (b : β) :
|
||||
forIn (a::as) b f = f a b >>= fun | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f := by
|
||||
have := forIn'_cons (a := a) (as := as) (fun a' _ b => f a' b) b
|
||||
simpa only [forIn'_eq_forIn]
|
||||
|
||||
@[congr] theorem forIn'_congr [Monad m] {as bs : List α} (w : as = bs)
|
||||
{b b' : β} (hb : b = b')
|
||||
{f : (a' : α) → a' ∈ as → β → m (ForInStep β)}
|
||||
{g : (a' : α) → a' ∈ bs → β → m (ForInStep β)}
|
||||
(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
|
||||
induction bs generalizing as b b' with
|
||||
| nil =>
|
||||
subst w
|
||||
simp [hb, forIn'_nil]
|
||||
| cons b bs ih =>
|
||||
cases as with
|
||||
| nil => simp at w
|
||||
| cons a as =>
|
||||
simp only [cons.injEq] at w
|
||||
obtain ⟨rfl, rfl⟩ := w
|
||||
simp only [forIn'_cons]
|
||||
congr 1
|
||||
· simp [h, hb]
|
||||
· funext s
|
||||
obtain b | b := s
|
||||
· rfl
|
||||
· simp
|
||||
rw [ih rfl rfl]
|
||||
intro a m b
|
||||
exact h a (mem_cons_of_mem _ m) b
|
||||
|
||||
/--
|
||||
We can express a for loop over a list as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
|
||||
forIn' l init f = ForInStep.value <$>
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => match b with
|
||||
| .yield b => f a m b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
induction l generalizing init with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [forIn'_cons, attach_cons, foldlM_cons, _root_.map_bind]
|
||||
congr 1
|
||||
funext x
|
||||
match x with
|
||||
| .done b =>
|
||||
clear ih
|
||||
dsimp
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [attach_cons, map_cons, map_map, Function.comp_def, foldlM_cons, pure_bind]
|
||||
specialize ih (fun a m b => f a (by
|
||||
simp only [mem_cons] at m
|
||||
rcases m with rfl|m
|
||||
· apply mem_cons_self
|
||||
· exact mem_cons_of_mem _ (mem_cons_of_mem _ m)) b)
|
||||
simp [ih, List.foldlM_map]
|
||||
| .yield b =>
|
||||
simp [ih, List.foldlM_map]
|
||||
|
||||
/-- We can express a for loop over a list which always yields as a fold. -/
|
||||
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
|
||||
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => g a m b <$> f a m b) init := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' l init (fun a m b => pure (.yield (f a m b))) =
|
||||
pure (f := m) (l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init) := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
/--
|
||||
We can express a for loop over a list as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(f : α → β → m (ForInStep β)) (init : β) (l : List α) :
|
||||
forIn l init f = ForInStep.value <$>
|
||||
l.foldlM (fun b a => match b with
|
||||
| .yield b => f a b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
induction l generalizing init with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [foldlM_cons, bind_pure_comp, forIn_cons, _root_.map_bind]
|
||||
congr 1
|
||||
funext x
|
||||
match x with
|
||||
| .done b =>
|
||||
clear ih
|
||||
dsimp
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih => simp [ih]
|
||||
| .yield b =>
|
||||
simp [ih]
|
||||
|
||||
/-- We can express a for loop over a list which always yields as a fold. -/
|
||||
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
|
||||
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
l.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : α → β → β) (init : β) :
|
||||
forIn l init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (l.foldl (fun b a => f a b) init) := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
(l : List α) (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
/-! ### allM -/
|
||||
|
||||
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
@@ -99,14 +319,4 @@ theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as :
|
||||
funext b
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : List β₁) (init : α) :
|
||||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : List β₁)
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
end List
|
||||
|
||||
@@ -13,3 +13,6 @@ import Init.Data.List.Nat.Count
|
||||
import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Nat.Find
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.Data.List.Nat.Modify
|
||||
import Init.Data.List.Nat.InsertIdx
|
||||
import Init.Data.List.Nat.Perm
|
||||
|
||||
@@ -9,7 +9,7 @@ import Init.Data.List.Basic
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ### isEqv-/
|
||||
/-! ### isEqv -/
|
||||
|
||||
theorem isEqv_eq_decide (a b : List α) (r) :
|
||||
isEqv a b r = if h : a.length = b.length then
|
||||
|
||||
@@ -64,3 +64,82 @@ theorem getElem_eraseIdx_of_ge (l : List α) (i : Nat) (j : Nat) (h : j < (l.era
|
||||
(l.eraseIdx i)[j] = l[j + 1]'(by rw [length_eraseIdx] at h; split at h <;> omega) := by
|
||||
rw [getElem_eraseIdx, dif_neg]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_eq {l : List α} {i : Nat} {a : α} :
|
||||
(l.set i a).eraseIdx i = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx, getElem_eraseIdx]
|
||||
split <;>
|
||||
· rw [getElem_set_ne]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_lt {l : List α} {i : Nat} {j : Nat} {a : α} (h : j < i) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set (i - 1) a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· split
|
||||
· omega
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i - 1 ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set i a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{l : List α} {i : Nat} (h : i + 1 < l.length) :
|
||||
(l.eraseIdx (i + 1)).set i l[i + 1] = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp only [length_set, length_eraseIdx, h, ↓reduceIte]
|
||||
rw [if_pos]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
simp [getElem_set, getElem_eraseIdx]
|
||||
split
|
||||
· split
|
||||
· omega
|
||||
· simp_all
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : ¬ n < i := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem eraseIdx_length_sub_one (l : List α) :
|
||||
(l.eraseIdx (l.length - 1)) = l.dropLast := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx_of_lt, getElem_dropLast]
|
||||
simp_all
|
||||
|
||||
end List
|
||||
|
||||
@@ -9,6 +9,32 @@ import Init.Data.List.Find
|
||||
|
||||
namespace List
|
||||
|
||||
open Nat
|
||||
|
||||
theorem find?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {b : α} :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ i h, xs[i] = b ∧ ∀ j : Nat, (hj : j < i) → !p xs[j] := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ⟨bs, rfl⟩, h⟩
|
||||
refine ⟨as.length, ⟨?_, ?_, ?_⟩⟩
|
||||
· simp only [length_append, length_cons]
|
||||
refine Nat.lt_add_of_pos_right (zero_lt_succ bs.length)
|
||||
· rw [getElem_append_right (Nat.le_refl as.length)]
|
||||
simp
|
||||
· intro j h'
|
||||
rw [getElem_append_left h']
|
||||
exact h _ (getElem_mem h')
|
||||
· rintro ⟨i, h, rfl, h'⟩
|
||||
refine ⟨xs.take i, ⟨xs.drop (i+1), ?_⟩, ?_⟩
|
||||
· rw [getElem_cons_drop, take_append_drop]
|
||||
· intro a m
|
||||
rw [mem_take_iff_getElem] at m
|
||||
obtain ⟨j, h, rfl⟩ := m
|
||||
apply h'
|
||||
omega
|
||||
|
||||
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {p q : α → Bool} (w : ∀ x ∈ xs, p x → q x) {i : Nat}
|
||||
(h : xs.findIdx? p = some i) : ∃ j, j ≤ i ∧ xs.findIdx? q = some j := by
|
||||
simp only [findIdx?_eq_findSome?_enum] at h
|
||||
|
||||
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
@@ -0,0 +1,242 @@
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Nat.Modify
|
||||
|
||||
/-!
|
||||
# insertIdx
|
||||
|
||||
Proves various lemmas about `List.insertIdx`.
|
||||
-/
|
||||
|
||||
open Function
|
||||
|
||||
open Nat
|
||||
|
||||
namespace List
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type u}
|
||||
|
||||
section InsertIdx
|
||||
|
||||
variable {a : α}
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_zero (s : List α) (x : α) : insertIdx 0 x s = x :: s :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_nil (n : Nat) (a : α) : insertIdx (n + 1) a [] = [] :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : Nat) :
|
||||
insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s :=
|
||||
rfl
|
||||
|
||||
theorem length_insertIdx : ∀ n as, (insertIdx n a as).length = if n ≤ as.length then as.length + 1 else as.length
|
||||
| 0, _ => by simp
|
||||
| n + 1, [] => by simp
|
||||
| n + 1, a :: as => by
|
||||
simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_le_add_iff_right]
|
||||
split <;> rfl
|
||||
|
||||
theorem length_insertIdx_of_le_length (h : n ≤ length as) : length (insertIdx n a as) = length as + 1 := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge :
|
||||
∀ n m as,
|
||||
n < length as → n ≤ m → insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n
|
||||
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
|
||||
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
|
||||
| 0, _ + 1, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_eraseIdx_of_le :
|
||||
∀ n m as,
|
||||
n < length as → m ≤ n → insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1)
|
||||
| _, 0, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_comm (a b : α) :
|
||||
∀ (i j : Nat) (l : List α) (_ : i ≤ j) (_ : j ≤ length l),
|
||||
(l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a
|
||||
| 0, j, l => by simp [insertIdx]
|
||||
| _ + 1, 0, _ => fun h => (Nat.not_lt_zero _ h).elim
|
||||
| i + 1, j + 1, [] => by simp
|
||||
| i + 1, j + 1, c :: l => fun h₀ h₁ => by
|
||||
simp only [insertIdx_succ_cons, cons.injEq, true_and]
|
||||
exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁)
|
||||
|
||||
theorem mem_insertIdx {a b : α} :
|
||||
∀ {n : Nat} {l : List α} (_ : n ≤ l.length), a ∈ l.insertIdx n b ↔ a = b ∨ a ∈ l
|
||||
| 0, as, _ => by simp
|
||||
| _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim
|
||||
| n + 1, a' :: as, h => by
|
||||
rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h),
|
||||
← or_assoc, @or_comm (a = a'), or_assoc, mem_cons]
|
||||
|
||||
theorem insertIdx_of_length_lt (l : List α) (x : α) (n : Nat) (h : l.length < n) :
|
||||
insertIdx n x l = l := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp
|
||||
| cons x l ih =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp only [Nat.succ_lt_succ_iff, length] at h
|
||||
simpa using ih _ h
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l = l ++ [x] := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih => simpa using ih
|
||||
|
||||
theorem length_le_length_insertIdx (l : List α) (x : α) (n : Nat) :
|
||||
l.length ≤ (insertIdx n x l).length := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem length_insertIdx_le_succ (l : List α) (x : α) (n : Nat) :
|
||||
(insertIdx n x l).length ≤ l.length + 1 := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (hn : k < n)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction n generalizing k l with
|
||||
| zero => simp at hn
|
||||
| succ n ih =>
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons _ _=>
|
||||
cases k
|
||||
· simp [get]
|
||||
· rw [Nat.succ_lt_succ_iff] at hn
|
||||
simpa using ih hn _
|
||||
|
||||
@[simp]
|
||||
theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[n] = x := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
simp [length_insertIdx] at hn
|
||||
split at hn
|
||||
· simp_all
|
||||
· omega
|
||||
| cons _ _ ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
|
||||
simpa using ih hn
|
||||
|
||||
theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1 ≤ k)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction l generalizing n k with
|
||||
| nil =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero, length_singleton, lt_one_iff] at hk
|
||||
omega
|
||||
| succ n => simp at hk
|
||||
| cons _ _ ih =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero] at hk
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
| succ n =>
|
||||
cases k with
|
||||
| zero => simp
|
||||
| succ k =>
|
||||
simp only [insertIdx_succ_cons, getElem_cons_succ]
|
||||
rw [ih (by omega)]
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] =
|
||||
if h₁ : k < n then
|
||||
l[k]'(by simp [length_insertIdx] at h; split at h <;> omega)
|
||||
else
|
||||
if h₂ : k = n then
|
||||
x
|
||||
else
|
||||
l[k-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem_insertIdx_of_lt h₁]
|
||||
· split <;> rename_i h₂
|
||||
· subst h₂
|
||||
rw [getElem_insertIdx_self h]
|
||||
· rw [getElem_insertIdx_of_ge (by omega)]
|
||||
|
||||
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
|
||||
(insertIdx n x l)[k]? =
|
||||
if k < n then
|
||||
l[k]?
|
||||
else
|
||||
if k = n then
|
||||
if k ≤ l.length then some x else none
|
||||
else
|
||||
l[k-1]? := by
|
||||
rw [getElem?_def]
|
||||
split <;> rename_i h
|
||||
· rw [getElem_insertIdx h]
|
||||
simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_def, dif_pos]
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_pos]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_def]
|
||||
simp only [Option.some_eq_dite_none_right, exists_prop, and_true]
|
||||
split at h <;> omega
|
||||
· simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_neg]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
|
||||
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (h : k < n) :
|
||||
(insertIdx n x l)[k]? = l[k]? := by
|
||||
rw [getElem?_insertIdx, if_pos h]
|
||||
|
||||
theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
|
||||
(insertIdx n x l)[n]? = if n ≤ l.length then some x else none := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega)]
|
||||
simp
|
||||
|
||||
theorem getElem?_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (h : n + 1 ≤ k) :
|
||||
(insertIdx n x l)[k]? = l[k - 1]? := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
|
||||
|
||||
end InsertIdx
|
||||
|
||||
end List
|
||||
314
src/Init/Data/List/Nat/Modify.lean
Normal file
314
src/Init/Data/List/Nat/Modify.lean
Normal file
@@ -0,0 +1,314 @@
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
import Init.Data.List.Nat.Erase
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ### modifyHead -/
|
||||
|
||||
@[simp] theorem length_modifyHead {f : α → α} {l : List α} : (l.modifyHead f).length = l.length := by
|
||||
cases l <;> simp [modifyHead]
|
||||
|
||||
theorem modifyHead_eq_set [Inhabited α] (f : α → α) (l : List α) :
|
||||
l.modifyHead f = l.set 0 (f (l[0]?.getD default)) := by cases l <;> simp [modifyHead]
|
||||
|
||||
@[simp] theorem modifyHead_eq_nil_iff {f : α → α} {l : List α} :
|
||||
l.modifyHead f = [] ↔ l = [] := by cases l <;> simp [modifyHead]
|
||||
|
||||
@[simp] theorem modifyHead_modifyHead {l : List α} {f g : α → α} :
|
||||
(l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> simp [modifyHead]
|
||||
|
||||
theorem getElem_modifyHead {l : List α} {f : α → α} {n} (h : n < (l.modifyHead f).length) :
|
||||
(l.modifyHead f)[n] = if h' : n = 0 then f (l[0]'(by simp at h; omega)) else l[n]'(by simpa using h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons hd tl => cases n <;> simp
|
||||
|
||||
@[simp] theorem getElem_modifyHead_zero {l : List α} {f : α → α} {h} :
|
||||
(l.modifyHead f)[0] = f (l[0]'(by simpa using h)) := by simp [getElem_modifyHead]
|
||||
|
||||
@[simp] theorem getElem_modifyHead_succ {l : List α} {f : α → α} {n} (h : n + 1 < (l.modifyHead f).length) :
|
||||
(l.modifyHead f)[n + 1] = l[n + 1]'(by simpa using h) := by simp [getElem_modifyHead]
|
||||
|
||||
theorem getElem?_modifyHead {l : List α} {f : α → α} {n} :
|
||||
(l.modifyHead f)[n]? = if n = 0 then l[n]?.map f else l[n]? := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons hd tl => cases n <;> simp
|
||||
|
||||
@[simp] theorem getElem?_modifyHead_zero {l : List α} {f : α → α} :
|
||||
(l.modifyHead f)[0]? = l[0]?.map f := by simp [getElem?_modifyHead]
|
||||
|
||||
@[simp] theorem getElem?_modifyHead_succ {l : List α} {f : α → α} {n} :
|
||||
(l.modifyHead f)[n + 1]? = l[n + 1]? := by simp [getElem?_modifyHead]
|
||||
|
||||
@[simp] theorem head_modifyHead (f : α → α) (l : List α) (h) :
|
||||
(l.modifyHead f).head h = f (l.head (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons hd tl => simp
|
||||
|
||||
@[simp] theorem head?_modifyHead {l : List α} {f : α → α} :
|
||||
(l.modifyHead f).head? = l.head?.map f := by cases l <;> simp
|
||||
|
||||
@[simp] theorem tail_modifyHead {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).tail = l.tail := by cases l <;> simp
|
||||
|
||||
@[simp] theorem take_modifyHead {f : α → α} {l : List α} {n} :
|
||||
(l.modifyHead f).take n = (l.take n).modifyHead f := by
|
||||
cases l <;> cases n <;> simp
|
||||
|
||||
@[simp] theorem drop_modifyHead_of_pos {f : α → α} {l : List α} {n} (h : 0 < n) :
|
||||
(l.modifyHead f).drop n = l.drop n := by
|
||||
cases l <;> cases n <;> simp_all
|
||||
|
||||
@[simp] theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by cases l <;> simp
|
||||
|
||||
@[simp] theorem eraseIdx_modifyHead_of_pos {f : α → α} {l : List α} {n} (h : 0 < n) :
|
||||
(l.modifyHead f).eraseIdx n = (l.eraseIdx n).modifyHead f := by cases l <;> cases n <;> simp_all
|
||||
|
||||
@[simp] theorem modifyHead_id : modifyHead (id : α → α) = id := by funext l; cases l <;> simp
|
||||
|
||||
/-! ### modifyTailIdx -/
|
||||
|
||||
@[simp] theorem modifyTailIdx_id : ∀ n (l : List α), l.modifyTailIdx id n = l
|
||||
| 0, _ => rfl
|
||||
| _+1, [] => rfl
|
||||
| n+1, a :: l => congrArg (cons a) (modifyTailIdx_id n l)
|
||||
|
||||
theorem eraseIdx_eq_modifyTailIdx : ∀ n (l : List α), eraseIdx l n = modifyTailIdx tail n l
|
||||
| 0, l => by cases l <;> rfl
|
||||
| _+1, [] => rfl
|
||||
| _+1, _ :: _ => congrArg (cons _) (eraseIdx_eq_modifyTailIdx _ _)
|
||||
|
||||
@[simp] theorem length_modifyTailIdx (f : List α → List α) (H : ∀ l, length (f l) = length l) :
|
||||
∀ n l, length (modifyTailIdx f n l) = length l
|
||||
| 0, _ => H _
|
||||
| _+1, [] => rfl
|
||||
| _+1, _ :: _ => congrArg (·+1) (length_modifyTailIdx _ H _ _)
|
||||
|
||||
theorem modifyTailIdx_add (f : List α → List α) (n) (l₁ l₂ : List α) :
|
||||
modifyTailIdx f (l₁.length + n) (l₁ ++ l₂) = l₁ ++ modifyTailIdx f n l₂ := by
|
||||
induction l₁ <;> simp [*, Nat.succ_add]
|
||||
|
||||
theorem modifyTailIdx_eq_take_drop (f : List α → List α) (H : f [] = []) :
|
||||
∀ n l, modifyTailIdx f n l = take n l ++ f (drop n l)
|
||||
| 0, _ => rfl
|
||||
| _ + 1, [] => H.symm
|
||||
| n + 1, b :: l => congrArg (cons b) (modifyTailIdx_eq_take_drop f H n l)
|
||||
|
||||
theorem exists_of_modifyTailIdx (f : List α → List α) {n} {l : List α} (h : n ≤ l.length) :
|
||||
∃ l₁ l₂, l = l₁ ++ l₂ ∧ l₁.length = n ∧ modifyTailIdx f n l = l₁ ++ f l₂ :=
|
||||
have ⟨_, _, eq, hl⟩ : ∃ l₁ l₂, l = l₁ ++ l₂ ∧ l₁.length = n :=
|
||||
⟨_, _, (take_append_drop n l).symm, length_take_of_le h⟩
|
||||
⟨_, _, eq, hl, hl ▸ eq ▸ modifyTailIdx_add (n := 0) ..⟩
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx {f g : List α → List α} (m : Nat) :
|
||||
∀ (n) (l : List α),
|
||||
(l.modifyTailIdx f n).modifyTailIdx g (m + n) =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g m) n
|
||||
| 0, _ => rfl
|
||||
| _ + 1, [] => rfl
|
||||
| n + 1, a :: l => congrArg (List.cons a) (modifyTailIdx_modifyTailIdx m n l)
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : Nat) (l : List α)
|
||||
(h : n ≤ m) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g m =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g (m - n)) n := by
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨m, rfl⟩
|
||||
rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel]
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (l : List α) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g ∘ f) n := by
|
||||
rw [modifyTailIdx_modifyTailIdx_le n n l (Nat.le_refl n), Nat.sub_self]; rfl
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem modify_nil (f : α → α) (n) : [].modify f n = [] := by cases n <;> rfl
|
||||
|
||||
@[simp] theorem modify_zero_cons (f : α → α) (a : α) (l : List α) :
|
||||
(a :: l).modify f 0 = f a :: l := rfl
|
||||
|
||||
@[simp] theorem modify_succ_cons (f : α → α) (a : α) (l : List α) (n) :
|
||||
(a :: l).modify f (n + 1) = a :: l.modify f n := by rfl
|
||||
|
||||
theorem modifyHead_eq_modify_zero (f : α → α) (l : List α) :
|
||||
l.modifyHead f = l.modify f 0 := by cases l <;> simp
|
||||
|
||||
@[simp] theorem modify_eq_nil_iff (f : α → α) (n) (l : List α) :
|
||||
l.modify f n = [] ↔ l = [] := by cases l <;> cases n <;> simp
|
||||
|
||||
theorem getElem?_modify (f : α → α) :
|
||||
∀ n (l : List α) m, (modify f n l)[m]? = (fun a => if n = m then f a else a) <$> l[m]?
|
||||
| n, l, 0 => by cases l <;> cases n <;> simp
|
||||
| n, [], _+1 => by cases n <;> rfl
|
||||
| 0, _ :: l, m+1 => by cases h : l[m]? <;> simp [h, modify, m.succ_ne_zero.symm]
|
||||
| n+1, a :: l, m+1 => by
|
||||
simp only [modify_succ_cons, getElem?_cons_succ, Nat.reduceEqDiff, Option.map_eq_map]
|
||||
refine (getElem?_modify f n l m).trans ?_
|
||||
cases h' : l[m]? <;> by_cases h : n = m <;>
|
||||
simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h']
|
||||
|
||||
@[simp] theorem length_modify (f : α → α) : ∀ n l, length (modify f n l) = length l :=
|
||||
length_modifyTailIdx _ fun l => by cases l <;> rfl
|
||||
|
||||
@[simp] theorem getElem?_modify_eq (f : α → α) (n) (l : List α) :
|
||||
(modify f n l)[n]? = f <$> l[n]? := by
|
||||
simp only [getElem?_modify, if_pos]
|
||||
|
||||
@[simp] theorem getElem?_modify_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) :
|
||||
(modify f m l)[n]? = l[n]? := by
|
||||
simp only [getElem?_modify, if_neg h, id_map']
|
||||
|
||||
theorem getElem_modify (f : α → α) (n) (l : List α) (m) (h : m < (modify f n l).length) :
|
||||
(modify f n l)[m] =
|
||||
if n = m then f (l[m]'(by simp at h; omega)) else l[m]'(by simp at h; omega) := by
|
||||
rw [getElem_eq_iff, getElem?_modify]
|
||||
simp at h
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem_modify_eq (f : α → α) (n) (l : List α) (h) :
|
||||
(modify f n l)[n] = f (l[n]'(by simpa using h)) := by simp [getElem_modify]
|
||||
|
||||
@[simp] theorem getElem_modify_ne (f : α → α) {m n} (l : List α) (h : m ≠ n) (h') :
|
||||
(modify f m l)[n] = l[n]'(by simpa using h') := by simp [getElem_modify, h]
|
||||
|
||||
theorem modify_eq_self {f : α → α} {n} {l : List α} (h : l.length ≤ n) :
|
||||
l.modify f n = l := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m h₁ h₂
|
||||
simp only [getElem_modify, ite_eq_right_iff]
|
||||
intro h
|
||||
omega
|
||||
|
||||
theorem modify_modify_eq (f g : α → α) (n) (l : List α) :
|
||||
(modify f n l).modify g n = modify (g ∘ f) n l := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m h₁ h₂
|
||||
simp only [getElem_modify, Function.comp_apply]
|
||||
split <;> simp
|
||||
|
||||
theorem modify_modify_ne (f g : α → α) {m n} (l : List α) (h : m ≠ n) :
|
||||
(modify f m l).modify g n = (l.modify g n).modify f m := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m' h₁ h₂
|
||||
simp only [getElem_modify, getElem_modify_ne, h₂]
|
||||
split <;> split <;> first | rfl | omega
|
||||
|
||||
theorem modify_eq_set [Inhabited α] (f : α → α) (n) (l : List α) :
|
||||
modify f n l = l.set n (f (l[n]?.getD default)) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m h₁ h₂
|
||||
simp [getElem_modify, getElem_set, h₂]
|
||||
split <;> rename_i h
|
||||
· subst h
|
||||
simp only [length_modify] at h₁
|
||||
simp [h₁]
|
||||
· rfl
|
||||
|
||||
theorem modify_eq_take_drop (f : α → α) :
|
||||
∀ n l, modify f n l = take n l ++ modifyHead f (drop n l) :=
|
||||
modifyTailIdx_eq_take_drop _ rfl
|
||||
|
||||
theorem modify_eq_take_cons_drop {f : α → α} {n} {l : List α} (h : n < l.length) :
|
||||
modify f n l = take n l ++ f l[n] :: drop (n + 1) l := by
|
||||
rw [modify_eq_take_drop, drop_eq_getElem_cons h]; rfl
|
||||
|
||||
theorem exists_of_modify (f : α → α) {n} {l : List α} (h : n < l.length) :
|
||||
∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ l₁.length = n ∧ modify f n l = l₁ ++ f a :: l₂ :=
|
||||
match exists_of_modifyTailIdx _ (Nat.le_of_lt h) with
|
||||
| ⟨_, _::_, eq, hl, H⟩ => ⟨_, _, _, eq, hl, H⟩
|
||||
| ⟨_, [], eq, hl, _⟩ => nomatch Nat.ne_of_gt h (eq ▸ append_nil _ ▸ hl)
|
||||
|
||||
@[simp] theorem modify_id (n) (l : List α) : l.modify id n = l := by
|
||||
simp [modify]
|
||||
|
||||
theorem take_modify (f : α → α) (n m) (l : List α) :
|
||||
(modify f m l).take n = (take n l).modify f m := by
|
||||
induction n generalizing l m with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons hd tl =>
|
||||
cases m with
|
||||
| zero => simp
|
||||
| succ m => simp [ih]
|
||||
|
||||
theorem drop_modify_of_lt (f : α → α) (n m) (l : List α) (h : n < m) :
|
||||
(modify f n l).drop m = l.drop m := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m' h₁ h₂
|
||||
simp only [getElem_drop, getElem_modify, ite_eq_right_iff]
|
||||
intro h'
|
||||
omega
|
||||
|
||||
theorem drop_modify_of_ge (f : α → α) (n m) (l : List α) (h : n ≥ m) :
|
||||
(modify f n l).drop m = modify f (n - m) (drop m l) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m' h₁ h₂
|
||||
simp [getElem_drop, getElem_modify, ite_eq_right_iff]
|
||||
split <;> split <;> first | rfl | omega
|
||||
|
||||
theorem eraseIdx_modify_of_eq (f : α → α) (n) (l : List α) :
|
||||
(modify f n l).eraseIdx n = l.eraseIdx n := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro m h₁ h₂
|
||||
simp only [getElem_eraseIdx, getElem_modify]
|
||||
split <;> split <;> first | rfl | omega
|
||||
|
||||
theorem eraseIdx_modify_of_lt (f : α → α) (i j) (l : List α) (h : j < i) :
|
||||
(modify f i l).eraseIdx j = (l.eraseIdx j).modify f (i - 1) := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro k h₁ h₂
|
||||
simp only [getElem_eraseIdx, getElem_modify]
|
||||
by_cases h' : i - 1 = k
|
||||
repeat' split
|
||||
all_goals (first | rfl | omega)
|
||||
|
||||
theorem eraseIdx_modify_of_gt (f : α → α) (i j) (l : List α) (h : j > i) :
|
||||
(modify f i l).eraseIdx j = (l.eraseIdx j).modify f i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro k h₁ h₂
|
||||
simp only [getElem_eraseIdx, getElem_modify]
|
||||
by_cases h' : i = k
|
||||
repeat' split
|
||||
all_goals (first | rfl | omega)
|
||||
|
||||
theorem modify_eraseIdx_of_lt (f : α → α) (i j) (l : List α) (h : j < i) :
|
||||
(l.eraseIdx i).modify f j = (l.modify f j).eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro k h₁ h₂
|
||||
simp only [getElem_eraseIdx, getElem_modify]
|
||||
by_cases h' : j = k + 1
|
||||
repeat' split
|
||||
all_goals (first | rfl | omega)
|
||||
|
||||
theorem modify_eraseIdx_of_ge (f : α → α) (i j) (l : List α) (h : j ≥ i) :
|
||||
(l.eraseIdx i).modify f j = (l.modify f (j + 1)).eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro k h₁ h₂
|
||||
simp only [getElem_eraseIdx, getElem_modify]
|
||||
by_cases h' : j + 1 = k + 1
|
||||
repeat' split
|
||||
all_goals (first | rfl | omega)
|
||||
|
||||
end List
|
||||
54
src/Init/Data/List/Nat/Perm.lean
Normal file
54
src/Init/Data/List/Nat/Perm.lean
Normal file
@@ -0,0 +1,54 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
import Init.Data.List.Perm
|
||||
|
||||
namespace List
|
||||
|
||||
/-- Helper lemma for `set_set_perm`-/
|
||||
private theorem set_set_perm' {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : i + j < as.length)
|
||||
(hj : 0 < j) :
|
||||
(as.set i as[i + j]).set (i + j) as[i] ~ as := by
|
||||
have : as =
|
||||
as.take i ++ as[i] :: (as.take (i + j)).drop (i + 1) ++ as[i + j] :: as.drop (i + j + 1) := by
|
||||
simp only [getElem_cons_drop, append_assoc, cons_append]
|
||||
rw [← drop_append_of_le_length]
|
||||
· simp
|
||||
· simp; omega
|
||||
conv => lhs; congr; congr; rw [this]
|
||||
conv => rhs; rw [this]
|
||||
rw [set_append_left _ _ (by simp; omega)]
|
||||
rw [set_append_right _ _ (by simp; omega)]
|
||||
rw [set_append_right _ _ (by simp; omega)]
|
||||
simp only [length_append, length_take, length_set, length_cons, length_drop]
|
||||
rw [(show i - min i as.length = 0 by omega)]
|
||||
rw [(show i + j - (min i as.length + (min (i + j) as.length - (i + 1) + 1)) = 0 by omega)]
|
||||
simp only [set_cons_zero]
|
||||
simp only [append_assoc]
|
||||
apply Perm.append_left
|
||||
apply cons_append_cons_perm
|
||||
|
||||
theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j < as.length) :
|
||||
(as.set i as[j]).set j as[i] ~ as := by
|
||||
if h₃ : i = j then
|
||||
simp [h₃]
|
||||
else
|
||||
if h₃ : i < j then
|
||||
let j' := j - i
|
||||
have t : j = i + j' := by omega
|
||||
generalize j' = j' at t
|
||||
subst t
|
||||
exact set_set_perm' _ _ (by omega)
|
||||
else
|
||||
rw [set_comm _ _ _ (by omega)]
|
||||
let i' := i - j
|
||||
have t : i = j + i' := by omega
|
||||
generalize i' = i' at t
|
||||
subst t
|
||||
apply set_set_perm' _ _ (by omega)
|
||||
|
||||
end List
|
||||
@@ -108,7 +108,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 [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
simp only [range'_eq_append_iff, eq_comm (a := i :: _), range'_eq_cons_iff]
|
||||
@@ -169,7 +169,7 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp
|
||||
theorem self_mem_range_succ (n : Nat) : n ∈ range (n + 1) := by simp
|
||||
|
||||
theorem pairwise_lt_range (n : Nat) : Pairwise (· < ·) (range n) := by
|
||||
simp (config := {decide := true}) only [range_eq_range', pairwise_lt_range']
|
||||
simp +decide only [range_eq_range', pairwise_lt_range']
|
||||
|
||||
theorem pairwise_le_range (n : Nat) : Pairwise (· ≤ ·) (range n) :=
|
||||
Pairwise.imp Nat.le_of_lt (pairwise_lt_range _)
|
||||
@@ -177,10 +177,10 @@ theorem pairwise_le_range (n : Nat) : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem take_range (m n : Nat) : take m (range n) = range (min m n) := by
|
||||
apply List.ext_getElem
|
||||
· simp
|
||||
· simp (config := { contextual := true }) [getElem_take, Nat.lt_min]
|
||||
· simp +contextual [getElem_take, Nat.lt_min]
|
||||
|
||||
theorem nodup_range (n : Nat) : Nodup (range n) := by
|
||||
simp (config := {decide := true}) only [range_eq_range', nodup_range']
|
||||
simp +decide only [range_eq_range', nodup_range']
|
||||
|
||||
@[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
|
||||
@@ -282,7 +282,7 @@ theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
@@ -430,7 +430,10 @@ theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
/-! ### enum -/
|
||||
|
||||
@[simp]
|
||||
theorem enum_eq_nil {l : List α} : List.enum l = [] ↔ l = [] := enumFrom_eq_nil
|
||||
theorem enum_eq_nil_iff {l : List α} : List.enum l = [] ↔ l = [] := enumFrom_eq_nil
|
||||
|
||||
@[deprecated enum_eq_nil_iff (since := "2024-11-04")]
|
||||
theorem enum_eq_nil {l : List α} : List.enum l = [] ↔ l = [] := enum_eq_nil_iff
|
||||
|
||||
@[simp] theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl
|
||||
|
||||
|
||||
@@ -187,6 +187,9 @@ theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.dro
|
||||
· apply length_take_le
|
||||
· apply Nat.le_add_right
|
||||
|
||||
theorem take_one {l : List α} : l.take 1 = l.head?.toList := by
|
||||
induction l <;> simp
|
||||
|
||||
theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||||
(l.take n).dropLast = l.take (n - 1) := by
|
||||
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, Nat.min_eq_left, take_take, sub_le]
|
||||
@@ -282,14 +285,14 @@ theorem mem_drop_iff_getElem {l : List α} {a : α} :
|
||||
· rintro ⟨i, hm, rfl⟩
|
||||
refine ⟨i, by simp; omega, by rw [getElem_drop]⟩
|
||||
|
||||
theorem head?_drop (l : List α) (n : Nat) :
|
||||
@[simp] theorem head?_drop (l : List α) (n : Nat) :
|
||||
(l.drop n).head? = l[n]? := by
|
||||
rw [head?_eq_getElem?, getElem?_drop, Nat.add_zero]
|
||||
|
||||
theorem head_drop {l : List α} {n : Nat} (h : l.drop n ≠ []) :
|
||||
@[simp] theorem head_drop {l : List α} {n : Nat} (h : l.drop n ≠ []) :
|
||||
(l.drop n).head h = l[n]'(by simp_all) := by
|
||||
have w : n < l.length := length_lt_of_drop_ne_nil h
|
||||
simpa [getElem?_eq_getElem, h, w, head_eq_iff_head?_eq_some] using head?_drop l n
|
||||
simp [getElem?_eq_getElem, h, w, head_eq_iff_head?_eq_some]
|
||||
|
||||
theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length ≤ n then none else l.getLast? := by
|
||||
rw [getLast?_eq_getElem?, getElem?_drop]
|
||||
@@ -300,7 +303,7 @@ theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length ≤ n th
|
||||
congr
|
||||
omega
|
||||
|
||||
theorem getLast_drop {l : List α} (h : l.drop n ≠ []) :
|
||||
@[simp] theorem getLast_drop {l : List α} (h : l.drop n ≠ []) :
|
||||
(l.drop n).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
|
||||
simp only [ne_eq, drop_eq_nil_iff] at h
|
||||
apply Option.some_inj.1
|
||||
@@ -342,7 +345,7 @@ theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l
|
||||
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
|
||||
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
|
||||
|
||||
theorem set_eq_take_append_cons_drop {l : List α} {n : Nat} {a : α} :
|
||||
theorem set_eq_take_append_cons_drop (l : List α) (n : Nat) (a : α) :
|
||||
l.set n a = if n < l.length then l.take n ++ a :: l.drop (n + 1) else l := by
|
||||
split <;> rename_i h
|
||||
· ext1 m
|
||||
@@ -449,6 +452,26 @@ theorem reverse_drop {l : List α} {n : Nat} :
|
||||
rw [w, take_zero, drop_of_length_le, reverse_nil]
|
||||
omega
|
||||
|
||||
theorem take_add_one {l : List α} {n : Nat} :
|
||||
l.take (n + 1) = l.take n ++ l[n]?.toList := by
|
||||
simp [take_add, take_one]
|
||||
|
||||
theorem drop_eq_getElem?_toList_append {l : List α} {n : Nat} :
|
||||
l.drop n = l[n]?.toList ++ l.drop (n + 1) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons hd tl ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [drop_succ_cons, getElem?_cons_succ]
|
||||
rw [ih]
|
||||
|
||||
theorem drop_sub_one {l : List α} {n : Nat} (h : 0 < n) :
|
||||
l.drop (n - 1) = l[n - 1]?.toList ++ l.drop n := by
|
||||
rw [drop_eq_getElem?_toList_append]
|
||||
congr
|
||||
omega
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs.take (xs.findIdx p)) :
|
||||
|
||||
80
src/Init/Data/List/OfFn.lean
Normal file
80
src/Init/Data/List/OfFn.lean
Normal file
@@ -0,0 +1,80 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Basic
|
||||
import Init.Data.Fin.Fold
|
||||
|
||||
/-!
|
||||
# Theorems about `List.ofFn`
|
||||
-/
|
||||
|
||||
namespace List
|
||||
|
||||
/--
|
||||
`ofFn f` with `f : fin n → α` returns the list whose ith element is `f i`
|
||||
```
|
||||
ofFn f = [f 0, f 1, ... , f (n - 1)]
|
||||
```
|
||||
-/
|
||||
def ofFn {n} (f : Fin n → α) : List α := Fin.foldr n (f · :: ·) []
|
||||
|
||||
@[simp]
|
||||
theorem length_ofFn (f : Fin n → α) : (ofFn f).length = n := by
|
||||
simp only [ofFn]
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [Fin.foldr_succ, ih]
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem_ofFn (f : Fin n → α) (i : Nat) (h : i < (ofFn f).length) :
|
||||
(ofFn f)[i] = f ⟨i, by simp_all⟩ := by
|
||||
simp only [ofFn]
|
||||
induction n generalizing i with
|
||||
| zero => simp at h
|
||||
| succ n ih =>
|
||||
match i with
|
||||
| 0 => simp [Fin.foldr_succ]
|
||||
| i+1 =>
|
||||
simp only [Fin.foldr_succ]
|
||||
apply ih
|
||||
simp_all
|
||||
|
||||
@[simp]
|
||||
protected theorem getElem?_ofFn (f : Fin n → α) (i) : (ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none :=
|
||||
if h : i < (ofFn f).length
|
||||
then by
|
||||
rw [getElem?_eq_getElem h, List.getElem_ofFn]
|
||||
· simp only [length_ofFn] at h; simp [h]
|
||||
else by
|
||||
rw [dif_neg] <;>
|
||||
simpa using h
|
||||
|
||||
/-- `ofFn` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
theorem ofFn_zero (f : Fin 0 → α) : ofFn f = [] :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by contradiction)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_succ {n} (f : Fin (n + 1) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by
|
||||
cases i
|
||||
· simp
|
||||
· simp)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
theorem head_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn _ ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
List.getElem_ofFn]
|
||||
|
||||
theorem getLast_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
|
||||
|
||||
end List
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user