mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-25 22:34:12 +00:00
Compare commits
358 Commits
grind_spli
...
joachim/av
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4428b621a | ||
|
|
c42c1c3299 | ||
|
|
b0cceddcc4 | ||
|
|
0cb364d5e8 | ||
|
|
c9d16a7cff | ||
|
|
0dcb99d6be | ||
|
|
1c3a8b6ac9 | ||
|
|
07c7dab663 | ||
|
|
66a69b028c | ||
|
|
3987c64f64 | ||
|
|
68902add3f | ||
|
|
2798df51c9 | ||
|
|
96dc2e5e02 | ||
|
|
37da550e9e | ||
|
|
d737bf483c | ||
|
|
874a2d5214 | ||
|
|
a106ea053f | ||
|
|
00600806ad | ||
|
|
5c8ebd8868 | ||
|
|
47228b94fd | ||
|
|
126fca1ec8 | ||
|
|
2ed025ade8 | ||
|
|
827a96ade3 | ||
|
|
e0f96208e4 | ||
|
|
5cc0a10346 | ||
|
|
1b6fba49c2 | ||
|
|
63bd0b5e77 | ||
|
|
75342961fc | ||
|
|
52b687cab4 | ||
|
|
63272c6c6f | ||
|
|
75570f327f | ||
|
|
52d05b6972 | ||
|
|
f7031c7aa9 | ||
|
|
9fc90488ce | ||
|
|
59949f89ee | ||
|
|
61186629d6 | ||
|
|
d5ecca995f | ||
|
|
f81e64936a | ||
|
|
5bb9839887 | ||
|
|
687698e79d | ||
|
|
8a0ee9aac7 | ||
|
|
6dd8ad13e5 | ||
|
|
fa5d08b7de | ||
|
|
03eb2f73ac | ||
|
|
36a6844625 | ||
|
|
4296f8deee | ||
|
|
e301f86c6c | ||
|
|
4c972ba0d6 | ||
|
|
f6e580ccf8 | ||
|
|
51ed5f247c | ||
|
|
1759b83929 | ||
|
|
e35d65174c | ||
|
|
1a4c3ca35d | ||
|
|
1f807969b7 | ||
|
|
f46c17fa1d | ||
|
|
155db16572 | ||
|
|
f6a9059709 | ||
|
|
59d2d00132 | ||
|
|
5a4226f2bd | ||
|
|
81d716069c | ||
|
|
033fa8c585 | ||
|
|
09001ecad6 | ||
|
|
1c82929c34 | ||
|
|
b67e8a15d0 | ||
|
|
be6457284a | ||
|
|
07e6b99e2e | ||
|
|
8eb0293098 | ||
|
|
8671f81aa5 | ||
|
|
5ce1f67261 | ||
|
|
bef8574b93 | ||
|
|
27e5e21bfe | ||
|
|
eba5a5a6ef | ||
|
|
bba399eefe | ||
|
|
8b575dcbf2 | ||
|
|
d6f3ca24d3 | ||
|
|
8c7604f550 | ||
|
|
4b28713a44 | ||
|
|
4c189bc8f2 | ||
|
|
0b93b3f182 | ||
|
|
ed34ee0cd5 | ||
|
|
8ef742647e | ||
|
|
65a41c38a0 | ||
|
|
bf60550ce5 | ||
|
|
ef1dc21f1c | ||
|
|
31f09da88a | ||
|
|
2f3939f1ea | ||
|
|
f4cd97ce04 | ||
|
|
e39894e62d | ||
|
|
100006fdd0 | ||
|
|
a6f4e9156e | ||
|
|
14625ec114 | ||
|
|
6f2c04b6a2 | ||
|
|
06f457b48a | ||
|
|
8ad0a61169 | ||
|
|
d963d33985 | ||
|
|
3f4e85413e | ||
|
|
bc2aae380c | ||
|
|
b5b34ee054 | ||
|
|
5011b7bd89 | ||
|
|
4602586b6a | ||
|
|
36ee331ce2 | ||
|
|
aca297d1c5 | ||
|
|
de073706c5 | ||
|
|
f7ead9667b | ||
|
|
ffbd744c85 | ||
|
|
833aaa823e | ||
|
|
7b29d976ed | ||
|
|
1e84b6dff9 | ||
|
|
bc9cc05082 | ||
|
|
46ff76aabd | ||
|
|
eb01aaeee4 | ||
|
|
2b85e29cc9 | ||
|
|
ceb86b1293 | ||
|
|
a00c78beea | ||
|
|
ff9c35d6ef | ||
|
|
eb675f708b | ||
|
|
b39ee8a84b | ||
|
|
9a3fb90e40 | ||
|
|
7f7a4d3eaf | ||
|
|
09cf07b71c | ||
|
|
d464b13569 | ||
|
|
f2b3f90724 | ||
|
|
bc60b1c19d | ||
|
|
fa3c85ee84 | ||
|
|
34f9798b4b | ||
|
|
e0af5122f7 | ||
|
|
f1224277e2 | ||
|
|
c2647cdbf5 | ||
|
|
aaceb3dbf5 | ||
|
|
3ae409cf81 | ||
|
|
a7f47db134 | ||
|
|
2c2fcff4f8 | ||
|
|
d1e19f2aa0 | ||
|
|
838be605ac | ||
|
|
02b141ca15 | ||
|
|
fe8238c76c | ||
|
|
7f77bfef4c | ||
|
|
e7e85e5e17 | ||
|
|
1b5fb2fa50 | ||
|
|
0e455f5347 | ||
|
|
f74e21e302 | ||
|
|
c08fcf6c28 | ||
|
|
ecae85e77b | ||
|
|
6008c0d523 | ||
|
|
d47b474e41 | ||
|
|
c7652413db | ||
|
|
08d0ae1e8a | ||
|
|
6fc48d14c0 | ||
|
|
80409a9ceb | ||
|
|
590ff23e71 | ||
|
|
f843837bfa | ||
|
|
d41f39fb10 | ||
|
|
7459304e98 | ||
|
|
e6b1f1984c | ||
|
|
6d2af21aa0 | ||
|
|
3a4e64fe94 | ||
|
|
0d7ca700ad | ||
|
|
f401f8b46e | ||
|
|
ae86c18ac1 | ||
|
|
ea2b745e57 | ||
|
|
28a3cf9a6c | ||
|
|
343887e480 | ||
|
|
d8a67095d6 | ||
|
|
0cb79868f4 | ||
|
|
ccecac5a56 | ||
|
|
8b43fc54b2 | ||
|
|
e7f4f98071 | ||
|
|
52e37e0d55 | ||
|
|
a4e073f565 | ||
|
|
18131de438 | ||
|
|
e430626d8a | ||
|
|
e76bbef79b | ||
|
|
04d72fe346 | ||
|
|
e4fb780f8a | ||
|
|
00e29075f3 | ||
|
|
ec775907e4 | ||
|
|
8d603d34dc | ||
|
|
528c0dd2e4 | ||
|
|
b8bd91d92b | ||
|
|
e05b0e097c | ||
|
|
d23dcc88ea | ||
|
|
1aca181fe2 | ||
|
|
2c45d55683 | ||
|
|
f4c71f6ec8 | ||
|
|
823173a761 | ||
|
|
3e86729ee0 | ||
|
|
2da124d469 | ||
|
|
1d00dee392 | ||
|
|
e5a6901161 | ||
|
|
cf871a892c | ||
|
|
d24ece1396 | ||
|
|
faed852c2f | ||
|
|
4939f447a3 | ||
|
|
3d307925b7 | ||
|
|
1fa67d0d47 | ||
|
|
51ef1dcc5e | ||
|
|
282b583f1d | ||
|
|
4a111501eb | ||
|
|
16d0005991 | ||
|
|
377f149862 | ||
|
|
c41cb64ca7 | ||
|
|
1ce05b2a17 | ||
|
|
0db89d65b2 | ||
|
|
00d41d64e5 | ||
|
|
40e1e097c1 | ||
|
|
d7e4f32d75 | ||
|
|
c7f57d6a0b | ||
|
|
275f9077b6 | ||
|
|
8b28467655 | ||
|
|
c0ad969b14 | ||
|
|
e73e0901f8 | ||
|
|
cc046e0c18 | ||
|
|
e11ef3ee4e | ||
|
|
b2b385b456 | ||
|
|
7a8c2daf96 | ||
|
|
33e92677ba | ||
|
|
5af12df54b | ||
|
|
705084d9ba | ||
|
|
e2f5938e74 | ||
|
|
d3c9056d2b | ||
|
|
2f0f0a3018 | ||
|
|
1587d02dfb | ||
|
|
a51822ead2 | ||
|
|
2cfd980528 | ||
|
|
2497cf0b40 | ||
|
|
167429501b | ||
|
|
d427423917 | ||
|
|
106b0fa661 | ||
|
|
335e34df19 | ||
|
|
d436619c6d | ||
|
|
19533ab1d4 | ||
|
|
28310a77ad | ||
|
|
8ff5b8ec2c | ||
|
|
99ff606d58 | ||
|
|
8862d23453 | ||
|
|
d8335bd661 | ||
|
|
1981c62604 | ||
|
|
bb3dd13f72 | ||
|
|
808d123e6f | ||
|
|
14d76cc062 | ||
|
|
d2f76ade61 | ||
|
|
12750d25b5 | ||
|
|
334fa475b4 | ||
|
|
8fe260de55 | ||
|
|
7e1be20317 | ||
|
|
3a42ee0c30 | ||
|
|
30ecacd625 | ||
|
|
a0e742be5e | ||
|
|
50e2fdaa74 | ||
|
|
77ddfd49e6 | ||
|
|
4887eeb77c | ||
|
|
9cf2877945 | ||
|
|
97d63db52c | ||
|
|
f8b0beeba9 | ||
|
|
93c5bd0fdd | ||
|
|
feb864712f | ||
|
|
2f3211028b | ||
|
|
cdaa827b2a | ||
|
|
a9d6bc60d0 | ||
|
|
9166c71e08 | ||
|
|
43b2d41e81 | ||
|
|
e8620255a0 | ||
|
|
48f0eb206c | ||
|
|
962e7d5a30 | ||
|
|
aa59c01742 | ||
|
|
cd60d9c14a | ||
|
|
b3ef7c9f25 | ||
|
|
be2c2bcf9b | ||
|
|
d5ca0c7032 | ||
|
|
3c2ab0fefa | ||
|
|
1643fd7532 | ||
|
|
53442d48f5 | ||
|
|
96bace56fa | ||
|
|
b0127e01e3 | ||
|
|
e71d0abc7d | ||
|
|
a6d50a61b3 | ||
|
|
dec007693a | ||
|
|
1145498521 | ||
|
|
2f07b70870 | ||
|
|
09b36c332a | ||
|
|
955fff52c5 | ||
|
|
6d665f3e91 | ||
|
|
74fd46894f | ||
|
|
ffaadcc990 | ||
|
|
54175f3b99 | ||
|
|
59573646c2 | ||
|
|
ba7798b389 | ||
|
|
f1203f3d0d | ||
|
|
881a131ad3 | ||
|
|
fb3e2c15fd | ||
|
|
fad0e69cc7 | ||
|
|
cf22c367a1 | ||
|
|
291d238ec4 | ||
|
|
69e1eae480 | ||
|
|
b1d4c9b9d5 | ||
|
|
d748b0c8c9 | ||
|
|
90af66d64b | ||
|
|
3ce7d4ef5c | ||
|
|
63c06725bb | ||
|
|
b5dc11e8d3 | ||
|
|
08bc333705 | ||
|
|
52b1b342ab | ||
|
|
6ee8511ae3 | ||
|
|
6a1cc7d6b8 | ||
|
|
2fb4d4bac2 | ||
|
|
9b794befe0 | ||
|
|
38240612bc | ||
|
|
3768c07654 | ||
|
|
466b0f824c | ||
|
|
11eabdb000 | ||
|
|
bd05f87d01 | ||
|
|
56f3ca6fc7 | ||
|
|
94cb32bc46 | ||
|
|
2f90b1dadd | ||
|
|
2991c66c81 | ||
|
|
3f82b307aa | ||
|
|
bce47c6e0d | ||
|
|
b28daa6d60 | ||
|
|
196d50156a | ||
|
|
2eb44b3cdc | ||
|
|
916125ae1c | ||
|
|
bd0b91de07 | ||
|
|
37b78bd53d | ||
|
|
2e3d947e07 | ||
|
|
a5a8f2779c | ||
|
|
efbbb0b230 | ||
|
|
a366cbcd20 | ||
|
|
756fee3e96 | ||
|
|
2ead798d87 | ||
|
|
baacf86e7f | ||
|
|
e3a5369bd7 | ||
|
|
c981ebc546 | ||
|
|
71f1a6c164 | ||
|
|
0d5869bb71 | ||
|
|
135e7e7bd3 | ||
|
|
58a884ef06 | ||
|
|
77e72afe0a | ||
|
|
823671f744 | ||
|
|
681724a8cf | ||
|
|
28dd72d514 | ||
|
|
61ee3b2711 | ||
|
|
206eb73cd9 | ||
|
|
09f22203f8 | ||
|
|
ef23782608 | ||
|
|
e2b5747f4b | ||
|
|
dad541265c | ||
|
|
ca7a8e18b7 | ||
|
|
721ffe5713 | ||
|
|
c76411d6c5 | ||
|
|
c22100036c | ||
|
|
5800ce17b3 | ||
|
|
78ab60d045 | ||
|
|
f9adafe54d | ||
|
|
69d8d63d58 | ||
|
|
dc7c184ee2 | ||
|
|
e43ff50e76 | ||
|
|
4ce7ad19ce | ||
|
|
2a70da50c1 |
14
.claude/CLAUDE.md
Normal file
14
.claude/CLAUDE.md
Normal file
@@ -0,0 +1,14 @@
|
||||
When asked to implement new features:
|
||||
* begin by reviewing existing relevant code and tests
|
||||
* write comprehensive tests first (expecting that these will initially fail)
|
||||
* and then iterate on the implementation until the tests pass.
|
||||
|
||||
To build Lean you should use `make -j$(nproc) -C build/release`.
|
||||
|
||||
To run a test you should use `cd tests/lean/run && ./test_single.sh example_test.lean`.
|
||||
|
||||
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass. You have to keep working until you have verified both of these.
|
||||
|
||||
All new tests should go in `tests/lean/run/`. Note that these tests don't have expected output, and just run on a success or failure basis. So you should use `#guard_msgs` to check for specific messages.
|
||||
|
||||
If you are not following best practices specific to this repository and the user expresses frustration, stop and ask them to help update this `.claude/CLAUDE.md` file with the missing guidance.
|
||||
@@ -16,14 +16,26 @@ These comments explain the scripts' behavior, which repositories get special han
|
||||
## Process
|
||||
|
||||
1. Run `script/release_checklist.py {version}` to check the current status
|
||||
2. Create a todo list tracking all repositories that need updates
|
||||
3. For each repository that needs updating:
|
||||
2. **CRITICAL: If preliminary lean4 checks fail, STOP immediately and alert the user**
|
||||
- Check for: release branch exists, CMake version correct, tag exists, release page exists, release notes exist
|
||||
- **IMPORTANT**: The release page is created AUTOMATICALLY by CI after pushing the tag - DO NOT create it manually
|
||||
- Do NOT create any PRs or proceed with repository updates if these checks fail
|
||||
3. Create a todo list tracking all repositories that need updates
|
||||
4. **CRITICAL RULE: You can ONLY run `release_steps.py` for a repository if `release_checklist.py` explicitly says to do so**
|
||||
- The checklist output will say "Run `script/release_steps.py {version} {repo_name}` to create it"
|
||||
- If a repository shows "🟡 Dependencies not ready", you CANNOT create a PR for it yet
|
||||
- You MUST rerun `release_checklist.py` before attempting to create PRs for any new repositories
|
||||
5. For each repository that the checklist says needs updating:
|
||||
- Run `script/release_steps.py {version} {repo_name}` to create the PR
|
||||
- Mark it complete when the PR is created
|
||||
4. After creating PRs, notify the user which PRs need review and merging
|
||||
5. Continuously rerun `script/release_checklist.py {version}` to check progress
|
||||
6. As PRs are merged, dependent repositories will become ready - create PRs for those as well
|
||||
7. Continue until all repositories are updated and the release is complete
|
||||
6. After creating PRs, notify the user which PRs need review and merging
|
||||
7. **MANDATORY: Rerun `release_checklist.py` to check current status**
|
||||
- Do this after creating each batch of PRs
|
||||
- Do this after the user reports PRs have been merged
|
||||
- NEVER assume a repository is ready without checking the checklist output
|
||||
8. As PRs are merged and tagged, dependent repositories will become ready
|
||||
9. Continue the cycle: run checklist → create PRs for ready repos → wait for merges → repeat
|
||||
10. Continue until all repositories are updated and the release is complete
|
||||
|
||||
## Important Notes
|
||||
|
||||
|
||||
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -213,7 +213,7 @@ jobs:
|
||||
else
|
||||
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
|
||||
fi
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
if: matrix.release
|
||||
with:
|
||||
name: build-${{ matrix.name }}
|
||||
|
||||
2
.github/workflows/check-stage0.yml
vendored
2
.github/workflows/check-stage0.yml
vendored
@@ -11,8 +11,8 @@ jobs:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
filter: blob:none
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
|
||||
- name: Find base commit
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -116,6 +116,7 @@ jobs:
|
||||
# rerun the workflow run after setting the `release-ci`/`merge-ci` labels.
|
||||
run: |
|
||||
check_level=0
|
||||
fast=false
|
||||
|
||||
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
|
||||
check_level=2
|
||||
@@ -128,9 +129,13 @@ jobs:
|
||||
elif echo "$labels" | grep -q "merge-ci"; then
|
||||
check_level=1
|
||||
fi
|
||||
if echo "$labels" | grep -q "fast-ci"; then
|
||||
fast=true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "check-level=$check_level" >> "$GITHUB_OUTPUT"
|
||||
echo "fast=$fast" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
@@ -140,7 +145,8 @@ jobs:
|
||||
with:
|
||||
script: |
|
||||
const level = ${{ steps.set-level.outputs.check-level }};
|
||||
console.log(`level: ${level}`);
|
||||
const fast = ${{ steps.set-level.outputs.fast }};
|
||||
console.log(`level: ${level}, fast: ${fast}`);
|
||||
// use large runners where available (original repo)
|
||||
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||
const isPr = "${{ github.event_name }}" == "pull_request";
|
||||
@@ -165,7 +171,8 @@ jobs:
|
||||
{
|
||||
// portable release build: use channel with older glibc (2.26)
|
||||
"name": "Linux release",
|
||||
"os": "ubuntu-latest",
|
||||
// usually not a bottleneck so make exclusive to `fast-ci`
|
||||
"os": large && fast ? "nscloud-ubuntu-22.04-amd64-8x16-with-cache" : "ubuntu-latest",
|
||||
"release": true,
|
||||
// Special handling for release jobs. We want:
|
||||
// 1. To run it in PRs so developers get PR toolchains (so secondary without tests is sufficient)
|
||||
@@ -193,8 +200,8 @@ jobs:
|
||||
"test": true,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
// made explicit until it can be assumed to have propagated to PRs
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
// We are not warning-free yet on all platforms, start here
|
||||
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
|
||||
},
|
||||
{
|
||||
"name": "Linux Reldebug",
|
||||
@@ -230,10 +237,9 @@ jobs:
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
// standard GH runner only comes with 7GB so use large runner if possible when running tests
|
||||
"os": large && level >= 1 ? "nscloud-macos-sequoia-arm64-6x14" : "macos-15",
|
||||
"os": large && (fast || level >= 1) ? "nscloud-macos-sequoia-arm64-6x14" : "macos-15",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
|
||||
"release": true,
|
||||
"test": true,
|
||||
"shell": "bash -euxo pipefail {0}",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-aarch64-apple-darwin.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||
@@ -241,11 +247,12 @@ jobs:
|
||||
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
|
||||
// See "Linux release" for release job levels; Grove is not a concern here
|
||||
"enabled": isPr || level != 1,
|
||||
"test": level >= 1,
|
||||
"secondary": level == 0,
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"os": large && level == 2 ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
|
||||
"os": large && (fast || level == 2) ? "namespace-profile-windows-amd64-4x16" : "windows-2022",
|
||||
"release": true,
|
||||
"enabled": level >= 2,
|
||||
"test": true,
|
||||
@@ -368,11 +375,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -397,8 +404,10 @@ jobs:
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
# Doesn't seem to be working when additionally fetching from lean4-nightly
|
||||
#filter: tree:0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
@@ -416,7 +425,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@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
29
.github/workflows/pr-release.yml
vendored
29
.github/workflows/pr-release.yml
vendored
@@ -48,17 +48,17 @@ jobs:
|
||||
git -C lean4.git remote add origin https://github.com/${{ github.repository_owner }}/lean4.git
|
||||
git -C lean4.git fetch -n origin master
|
||||
git -C lean4.git fetch -n origin "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
|
||||
|
||||
# Create both the original tag and the SHA-suffixed tag
|
||||
SHORT_SHA="${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
SHORT_SHA="${SHORT_SHA:0:7}"
|
||||
|
||||
|
||||
# Export the short SHA for use in subsequent steps
|
||||
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"
|
||||
|
||||
git -C lean4.git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
git -C lean4.git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-"${SHORT_SHA}" "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
|
||||
|
||||
git -C lean4.git remote add pr-releases https://foo:'${{ secrets.PR_RELEASES_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-pr-releases.git
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-"${SHORT_SHA}"
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -200,7 +200,7 @@ jobs:
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/labels" \
|
||||
| jq -r '.[].name')"
|
||||
|
||||
|
||||
if echo "$LABELS" | grep -q "^force-mathlib-ci$"; then
|
||||
echo "force-mathlib-ci label detected, forcing CI despite issues"
|
||||
MESSAGE="Forcing Mathlib CI because the \`force-mathlib-ci\` label is present, despite problem: $MESSAGE"
|
||||
@@ -301,7 +301,7 @@ jobs:
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/labels" \
|
||||
| jq -r '.[].name')"
|
||||
|
||||
|
||||
if echo "$LABELS" | grep -q "^force-manual-ci$"; then
|
||||
echo "force-manual-ci label detected, forcing CI despite issues"
|
||||
MESSAGE="Forcing reference manual CI because the \`force-manual-ci\` label is present, despite problem: $MESSAGE"
|
||||
@@ -401,6 +401,7 @@ jobs:
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
filter: tree:0
|
||||
|
||||
- name: Check if tag exists
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
@@ -425,7 +426,7 @@ jobs:
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
@@ -434,7 +435,7 @@ jobs:
|
||||
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
@@ -460,6 +461,7 @@ jobs:
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
filter: tree:0
|
||||
|
||||
- name: install elan
|
||||
run: |
|
||||
@@ -494,7 +496,7 @@ jobs:
|
||||
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}",' lakefile.lean
|
||||
lake update batteries
|
||||
git add lakefile.lean lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain and bumping Batteries."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
@@ -505,7 +507,7 @@ jobs:
|
||||
git add lean-toolchain
|
||||
lake update batteries
|
||||
git add lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
@@ -530,6 +532,7 @@ jobs:
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
filter: tree:0
|
||||
|
||||
- name: Check if tag in reference manual exists
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
@@ -555,7 +558,7 @@ jobs:
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git add lakefile.lean lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
@@ -565,7 +568,7 @@ jobs:
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git add lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
|
||||
2
.github/workflows/pr-title.yml
vendored
2
.github/workflows/pr-title.yml
vendored
@@ -15,6 +15,6 @@ jobs:
|
||||
script: |
|
||||
const msg = context.payload.pull_request? context.payload.pull_request.title : context.payload.merge_group.head_commit.message;
|
||||
console.log(`Message: ${msg}`)
|
||||
if (!/^(feat|fix|doc|style|refactor|test|chore|perf): .*[^.]($|\n\n)/.test(msg)) {
|
||||
if (!/^(feat|fix|doc|style|refactor|test|chore|perf): (?![A-Z][a-z]).*[^.]($|\n\n)/.test(msg)) {
|
||||
core.setFailed('PR title does not follow the Commit Convention (https://leanprover.github.io/lean4/doc/dev/commit_convention.html).');
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ In the case of `@[extern]` all *irrelevant* types are removed first; see next se
|
||||
Similarly, the signed integer types `Int8`, ..., `Int64`, `ISize` are also represented by the unsigned C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively, because they have a trivial structure.
|
||||
* `Nat` and `Int` are represented by `lean_object *`.
|
||||
Their runtime values is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number or integer (`lean_box`/`lean_unbox`).
|
||||
* A universe `Sort u`, type constructor `... → Sort u`, or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
|
||||
* A universe `Sort u`, type constructor `... → Sort u`, `Void α` or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
|
||||
* Any other type is represented by `lean_object *`.
|
||||
Its runtime value is a pointer to an object of a subtype of `lean_object` (see the "Inductive types" section below) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
|
||||
|
||||
@@ -129,8 +129,7 @@ For all other modules imported by `lean`, the initializer is run without `builti
|
||||
Thus `[init]` functions are run iff their module is imported, regardless of whether they have native code available or not, while `[builtin_init]` functions are only run for native executable or plugins, regardless of whether their module is imported or not.
|
||||
`lean` uses built-in initializers for e.g. registering basic parsers that should be available even without importing their module (which is necessary for bootstrapping).
|
||||
|
||||
The initializer for module `A.B` is called `initialize_A_B` and will automatically initialize any imported modules.
|
||||
Module initializers are idempotent (when run with the same `builtin` flag), but not thread-safe.
|
||||
The initializer for module `A.B` in a package `foo` is called `initialize_foo_A_B`. For modules in the Lean core (e.g., `Init.Prelude`), the initializer is called `initialize_Init_Prelude`. Module initializers will automatically initialize any imported modules. They are also idempotent (when run with the same `builtin` flag), but not thread-safe.
|
||||
|
||||
**Important for process-related functionality**: If your application needs to use process-related functions from libuv, such as `Std.Internal.IO.Process.getProcessTitle` and `Std.Internal.IO.Process.setProcessTitle`, you must call `lean_setup_args(argc, argv)` (which returns a potentially modified `argv` that must be used in place of the original) **before** calling `lean_initialize()` or `lean_initialize_runtime_module()`. This sets up process handling capabilities correctly, which is essential for certain system-level operations that Lean's runtime may depend on.
|
||||
|
||||
@@ -141,8 +140,8 @@ void lean_initialize_runtime_module();
|
||||
void lean_initialize();
|
||||
char ** lean_setup_args(int argc, char ** argv);
|
||||
|
||||
lean_object * initialize_A_B(uint8_t builtin, lean_object *);
|
||||
lean_object * initialize_C(uint8_t builtin, lean_object *);
|
||||
lean_object * initialize_A_B(uint8_t builtin);
|
||||
lean_object * initialize_C(uint8_t builtin);
|
||||
...
|
||||
|
||||
argv = lean_setup_args(argc, argv); // if using process-related functionality
|
||||
@@ -152,7 +151,7 @@ lean_initialize_runtime_module();
|
||||
lean_object * res;
|
||||
// use same default as for Lean executables
|
||||
uint8_t builtin = 1;
|
||||
res = initialize_A_B(builtin, lean_io_mk_world());
|
||||
res = initialize_A_B(builtin);
|
||||
if (lean_io_result_is_ok(res)) {
|
||||
lean_dec_ref(res);
|
||||
} else {
|
||||
@@ -160,7 +159,7 @@ if (lean_io_result_is_ok(res)) {
|
||||
lean_dec(res);
|
||||
return ...; // do not access Lean declarations if initialization failed
|
||||
}
|
||||
res = initialize_C(builtin, lean_io_mk_world());
|
||||
res = initialize_C(builtin);
|
||||
if (lean_io_result_is_ok(res)) {
|
||||
...
|
||||
|
||||
|
||||
@@ -94,10 +94,8 @@ theorem List.palindrome_of_eq_reverse (h : as.reverse = as) : Palindrome as := b
|
||||
next => exact Palindrome.nil
|
||||
next a => exact Palindrome.single a
|
||||
next a b as ih =>
|
||||
have : a = b := by simp_all
|
||||
subst this
|
||||
have : as.reverse = as := by simp_all
|
||||
exact Palindrome.sandwich a (ih this)
|
||||
obtain ⟨rfl, h, -⟩ := by simpa using h
|
||||
exact Palindrome.sandwich b (ih h)
|
||||
|
||||
/-!
|
||||
We now define a function that returns `true` iff `as` is a palindrome.
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 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
|
||||
-/
|
||||
import Lean
|
||||
|
||||
namespace Lean.Meta.Grind.Analyzer
|
||||
|
||||
|
||||
/-!
|
||||
A simple E-matching annotation analyzer.
|
||||
For each theorem annotated as an E-matching candidate, it creates an artificial goal, executes `grind` and shows the
|
||||
number of instances created.
|
||||
For a theorem of the form `params -> type`, the artificial goal is of the form `params -> type -> False`.
|
||||
-/
|
||||
|
||||
/--
|
||||
`grind` configuration for the analyzer. We disable case-splits and lookahead,
|
||||
increase the number of generations, and limit the number of instances generated.
|
||||
-/
|
||||
def config : Grind.Config := {
|
||||
splits := 0
|
||||
lookahead := false
|
||||
mbtc := false
|
||||
ematch := 20
|
||||
instances := 100
|
||||
gen := 10
|
||||
}
|
||||
|
||||
structure Config where
|
||||
/-- Minimum number of instantiations to trigger summary report -/
|
||||
min : Nat := 10
|
||||
/-- Minimum number of instantiations to trigger detailed report -/
|
||||
detailed : Nat := 50
|
||||
|
||||
def mkParams : MetaM Params := do
|
||||
let params ← Grind.mkParams config
|
||||
let ematch ← getEMatchTheorems
|
||||
let casesTypes ← Grind.getCasesTypes
|
||||
return { params with ematch, casesTypes }
|
||||
|
||||
/-- Returns the total number of generated instances. -/
|
||||
private def sum (cs : PHashMap Origin Nat) : Nat := Id.run do
|
||||
let mut r := 0
|
||||
for (_, c) in cs do
|
||||
r := r + c
|
||||
return r
|
||||
|
||||
private def thmsToMessageData (thms : PHashMap Origin Nat) : MetaM MessageData := do
|
||||
let data := thms.toArray.filterMap fun (origin, c) =>
|
||||
match origin with
|
||||
| .decl declName => some (declName, c)
|
||||
| _ => none
|
||||
let data := data.qsort fun (d₁, c₁) (d₂, c₂) => if c₁ == c₂ then Name.lt d₁ d₂ else c₁ > c₂
|
||||
let data ← data.mapM fun (declName, counter) =>
|
||||
return .trace { cls := `thm } m!"{.ofConst (← mkConstWithLevelParams declName)} ↦ {counter}" #[]
|
||||
return .trace { cls := `thm } "instances" data
|
||||
|
||||
/--
|
||||
Analyzes theorem `declName`. That is, creates the artificial goal based on `declName` type,
|
||||
and invokes `grind` on it.
|
||||
-/
|
||||
def analyzeEMatchTheorem (declName : Name) (c : Config) : MetaM Unit := do
|
||||
let info ← getConstInfo declName
|
||||
let mvarId ← forallTelescope info.type fun _ type => do
|
||||
withLocalDeclD `h type fun _ => do
|
||||
return (← mkFreshExprMVar (mkConst ``False)).mvarId!
|
||||
let result ← Grind.main mvarId (← mkParams) (pure ())
|
||||
let thms := result.counters.thm
|
||||
let s := sum thms
|
||||
if s > c.min then
|
||||
IO.println s!"{declName} : {s}"
|
||||
if s > c.detailed then
|
||||
logInfo m!"{declName}\n{← thmsToMessageData thms}"
|
||||
|
||||
-- Not sure why this is failing: `down_pure` perhaps has an unnecessary universe parameter?
|
||||
run_meta analyzeEMatchTheorem ``Std.Do.SPred.down_pure {}
|
||||
|
||||
/-- Analyzes all theorems in the standard library marked as E-matching theorems. -/
|
||||
def analyzeEMatchTheorems (c : Config := {}) : MetaM Unit := do
|
||||
let origins := (← getEMatchTheorems).getOrigins
|
||||
let decls := origins.filterMap fun | .decl declName => some declName | _ => none
|
||||
for declName in decls.mergeSort Name.lt do
|
||||
try
|
||||
analyzeEMatchTheorem declName c
|
||||
catch e =>
|
||||
logError m!"{declName} failed with {e.toMessageData}"
|
||||
logInfo m!"Finished analyzing {decls.length} theorems"
|
||||
|
||||
/-- Macro for analyzing E-match theorems with unlimited heartbeats -/
|
||||
macro "#analyzeEMatchTheorems" : command => `(
|
||||
set_option maxHeartbeats 0 in
|
||||
run_meta analyzeEMatchTheorems
|
||||
)
|
||||
|
||||
#analyzeEMatchTheorems
|
||||
|
||||
-- -- We can analyze specific theorems using commands such as
|
||||
set_option trace.grind.ematch.instance true
|
||||
|
||||
-- 1. grind immediately sees `(#[] : Array α) = ([] : List α).toArray` but probably this should be hidden.
|
||||
-- 2. `Vector.toArray_empty` keys on `Array.mk []` rather than `#v[].toArray`
|
||||
-- I guess we could add `(#[].extract _ _).extract _ _` as a stop pattern.
|
||||
run_meta analyzeEMatchTheorem ``Array.extract_empty {}
|
||||
|
||||
-- Neither `Option.bind_some` nor `Option.bind_fun_some` fire, because the terms appear inside
|
||||
-- lambdas. So we get crazy things like:
|
||||
-- `fun x => ((some x).bind some).bind fun x => (some x).bind fun x => (some x).bind some`
|
||||
-- We could consider replacing `filterMap_some` with
|
||||
-- `filterMap g (filterMap f xs) = filterMap (f >=> g) xs`
|
||||
-- to avoid the lambda that `grind` struggles with, but this would require more API around the fish.
|
||||
run_meta analyzeEMatchTheorem ``Array.filterMap_some {}
|
||||
|
||||
-- Not entirely certain what is wrong here, but certainly
|
||||
-- `eq_empty_of_append_eq_empty` is firing too often.
|
||||
-- Ideally we could instantiate this is we fine `xs ++ ys` in the same equivalence class,
|
||||
-- note just as soon as we see `xs ++ ys`.
|
||||
-- I've tried removing this in https://github.com/leanprover/lean4/pull/10162
|
||||
run_meta analyzeEMatchTheorem ``Array.range'_succ {}
|
||||
|
||||
-- Perhaps the same story here.
|
||||
run_meta analyzeEMatchTheorem ``Array.range_succ {}
|
||||
|
||||
-- `zip_map_left` and `zip_map_right` are bad grind lemmas,
|
||||
-- checking if they can be removed in https://github.com/leanprover/lean4/pull/10163
|
||||
run_meta analyzeEMatchTheorem ``Array.zip_map {}
|
||||
|
||||
-- It seems crazy to me that as soon as we have `0 >>> n = 0`, we instantiate based on the
|
||||
-- pattern `0 >>> n >>> m` by substituting `0` into `0 >>> n` to produce the `0 >>> n >>> n`.
|
||||
-- I don't think any forbidden subterms can help us here. I don't know what to do. :-(
|
||||
run_meta analyzeEMatchTheorem ``Int.zero_shiftRight {}
|
||||
@@ -57,19 +57,19 @@ def main (args : List String) : IO Unit := do
|
||||
sec := "\n\n" ++ sec
|
||||
if insertPos?.isNone then
|
||||
sec := sec ++ "\n\n"
|
||||
text := text.extract 0 insertPos ++ sec ++ text.extract insertPos text.endPos
|
||||
text := text.extract 0 insertPos ++ sec ++ text.extract insertPos text.rawEndPos
|
||||
|
||||
-- prepend each import with `public `
|
||||
for imp in imps.reverse do
|
||||
let insertPos := imp.raw.getPos?.get!
|
||||
let prfx := if doMeta then "public meta " else "public "
|
||||
text := text.extract 0 insertPos ++ prfx ++ text.extract insertPos text.endPos
|
||||
text := text.extract 0 insertPos ++ prfx ++ text.extract insertPos text.rawEndPos
|
||||
|
||||
-- insert `module` header
|
||||
let mut initText := text.extract 0 startPos
|
||||
if !initText.trim.isEmpty then
|
||||
-- If there is a header comment, preserve it and put `module` in the line after
|
||||
initText := initText.trimRight ++ "\n"
|
||||
text := initText ++ "module\n\n" ++ text.extract startPos text.endPos
|
||||
text := initText ++ "module\n\n" ++ text.extract startPos text.rawEndPos
|
||||
|
||||
IO.FS.writeFile path text
|
||||
|
||||
@@ -131,10 +131,11 @@ structure State where
|
||||
`transDeps[i]` is the (non-reflexive) transitive closure of `mods[i].imports`. More specifically,
|
||||
* `j ∈ transDeps[i].pub` if `i -(public import)->+ j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
|
||||
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
* `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
|
||||
* `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
|
||||
* `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
|
||||
-/
|
||||
transDeps : Array Needs := #[]
|
||||
/--
|
||||
@@ -162,10 +163,10 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import ...)-> _ -(public import)->* j`
|
||||
transImps := transImps.union .priv {j} |>.union .priv (impTransImps.get .pub)
|
||||
if imp.importAll then
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ -(public import ...)-> _ -(public import)->* j`
|
||||
transImps := transImps.union .priv (impTransImps.get .pub)
|
||||
-- `j ∈ transDeps[i].priv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].pub/priv`
|
||||
transImps := transImps.union .priv (impTransImps.get .pub ∪ impTransImps.get .priv)
|
||||
|
||||
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPub` if `i -(public (meta)? import)->* _ -(public meta import)-> _ -(public (meta)? import)->* j`
|
||||
if imp.isExported then
|
||||
transImps := transImps.union .metaPub (impTransImps.get .metaPub)
|
||||
if imp.isMeta then
|
||||
@@ -173,10 +174,13 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
|
||||
if !imp.isExported then
|
||||
if imp.isMeta then
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(meta import ...)-> _ -(public (meta)? import)->* j`
|
||||
transImps := transImps.union .metaPriv {j} |>.union .metaPriv (impTransImps.get .pub ∪ impTransImps.get .metaPub)
|
||||
if imp.importAll then
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ -(public meta import ...)-> _ -(public (meta)? import ...)->* j`
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import all)->+ i'` and `j ∈ transDeps[i'].metaPub/metaPriv`
|
||||
transImps := transImps.union .metaPriv (impTransImps.get .metaPub ∪ impTransImps.get .metaPriv)
|
||||
else
|
||||
-- `j ∈ transDeps[i].metaPriv` if `i -(import ...)-> i'` and `j ∈ transDeps[i'].metaPub`
|
||||
transImps := transImps.union .metaPriv (impTransImps.get .metaPub)
|
||||
|
||||
transImps
|
||||
@@ -185,7 +189,8 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
|
||||
let mut needs := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
let pubCI? := env.setExporting true |>.find? ci.name
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
needs := visitExpr k ci.type needs
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
@@ -216,7 +221,8 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
|
||||
let mut deps := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
let pubCI? := env.setExporting true |>.find? ci.name
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
deps := visitExpr k ci.name ci.type deps
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
@@ -286,7 +292,7 @@ and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeaderFromString (text path : String) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntaxArray ``Parser.Module.import × String.Pos) := do
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
let inputCtx := Parser.mkInputContext text path
|
||||
let (header, parserState, msgs) ← Parser.parseHeader inputCtx
|
||||
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
|
||||
@@ -294,8 +300,8 @@ def parseHeaderFromString (text path : String) :
|
||||
throw <| .userError "parse errors in file"
|
||||
-- the insertion point for `add` is the first newline after the imports
|
||||
let insertion := header.raw.getTailPos?.getD parserState.pos
|
||||
let insertion := text.findAux (· == '\n') text.endPos insertion + ⟨1⟩
|
||||
pure (path, inputCtx, .mk header.raw[2].getArgs, insertion)
|
||||
let insertion := text.findAux (· == '\n') text.endPos insertion + '\n'
|
||||
pure (path, inputCtx, header, insertion)
|
||||
|
||||
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
|
||||
|
||||
@@ -304,13 +310,18 @@ and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntaxArray ``Parser.Module.import × String.Pos) := do
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
-- Parse the input file
|
||||
let some path ← srcSearchPath.findModuleWithExt "lean" mod
|
||||
| throw <| .userError s!"error: failed to find source file for {mod}"
|
||||
let text ← IO.FS.readFile path
|
||||
parseHeaderFromString text path.toString
|
||||
|
||||
def decodeHeader : TSyntax ``Parser.Module.header → Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
|
||||
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
|
||||
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
|
||||
| _ => unreachable!
|
||||
|
||||
def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
|
||||
{ module := id.getId, isExported := pubTk?.isSome, isMeta := metaTk?.isSome, importAll := allTk?.isSome }
|
||||
@@ -326,11 +337,20 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
* `addOnly`: if true, only add missing imports, do not remove unused ones
|
||||
-/
|
||||
def visitModule (srcSearchPath : SearchPath)
|
||||
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits)
|
||||
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
|
||||
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
|
||||
let s ← get
|
||||
-- Do transitive reduction of `needs` in `deps`.
|
||||
let mut deps := needs
|
||||
let (_, prelude?, imports) := decodeHeader headerStx
|
||||
if prelude?.isNone then
|
||||
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
|
||||
for imp in imports do
|
||||
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
|
||||
let imp := decodeImport imp
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
let k := NeedsKind.ofImport imp
|
||||
deps := deps.union k {j}
|
||||
for j in [0:s.mods.size] do
|
||||
let transDeps := s.transDeps[j]!
|
||||
for k in NeedsKind.all do
|
||||
@@ -354,7 +374,8 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
else
|
||||
let k := NeedsKind.ofImport imp
|
||||
if !addOnly && !deps.has k j && !deps.has { k with isExported := false } j then
|
||||
-- A private import should also be removed if the public version is needed
|
||||
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
|
||||
toRemove := toRemove.push imp
|
||||
else
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
@@ -385,7 +406,8 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
|
||||
if githubStyle then
|
||||
try
|
||||
let (path, inputCtx, imports, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let (path, inputCtx, stx, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
for stx in imports do
|
||||
if toRemove.any fun imp => imp == decodeImport stx then
|
||||
let pos := inputCtx.fileMap.toPosition stx.raw.getPos?.get!
|
||||
@@ -529,33 +551,43 @@ def main (args : List String) : IO UInt32 := do
|
||||
let needs := s.mods.mapIdx fun i _ =>
|
||||
Task.spawn fun _ => calcNeeds s.env i
|
||||
|
||||
-- Parse headers in parallel
|
||||
let headers ← s.mods.mapIdxM fun i _ =>
|
||||
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
|
||||
|
||||
if args.fix then
|
||||
println! "The following changes will be made automatically:"
|
||||
|
||||
-- Check all selected modules
|
||||
let mut edits : Edits := ∅
|
||||
let mut revNeeds : Needs := default
|
||||
for i in [0:s.mods.size], t in needs do
|
||||
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!) srcSearchPath i t.get revNeeds edits args.githubStyle args.explain
|
||||
if isExtraRevModUse s.env i then
|
||||
revNeeds := revNeeds.union .priv {i}
|
||||
for i in [0:s.mods.size], t in needs, header in headers do
|
||||
match header.get with
|
||||
| .ok (_, _, stx, _) =>
|
||||
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
|
||||
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
|
||||
if isExtraRevModUse s.env i then
|
||||
revNeeds := revNeeds.union .priv {i}
|
||||
| .error e =>
|
||||
println! e.toString
|
||||
|
||||
if !args.fix then
|
||||
-- return error if any issues were found
|
||||
return if edits.isEmpty then 0 else 1
|
||||
|
||||
-- Apply the edits to existing files
|
||||
let count ← edits.foldM (init := 0) fun count mod (remove, add) => do
|
||||
let mut count := 0
|
||||
for mod in s.modNames, header? in headers do
|
||||
let some (remove, add) := edits[mod]? | continue
|
||||
let add : Array Import := add.qsortOrd
|
||||
|
||||
-- Parse the input file
|
||||
let (path, inputCtx, imports, insertion) ←
|
||||
try parseHeader srcSearchPath mod
|
||||
catch e => println! e.toString; return count
|
||||
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
let text := inputCtx.fileMap.source
|
||||
|
||||
-- Calculate the edit result
|
||||
let mut pos : String.Pos := 0
|
||||
let mut pos : String.Pos.Raw := 0
|
||||
let mut out : String := ""
|
||||
let mut seen : Std.HashSet Import := {}
|
||||
for stx in imports do
|
||||
@@ -563,17 +595,17 @@ def main (args : List String) : IO UInt32 := do
|
||||
if remove.contains mod || seen.contains mod then
|
||||
out := out ++ text.extract pos stx.raw.getPos?.get!
|
||||
-- We use the end position of the syntax, but include whitespace up to the first newline
|
||||
pos := text.findAux (· == '\n') text.endPos stx.raw.getTailPos?.get! + ⟨1⟩
|
||||
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
|
||||
seen := seen.insert mod
|
||||
out := out ++ text.extract pos insertion
|
||||
for mod in add do
|
||||
if !seen.contains mod then
|
||||
seen := seen.insert mod
|
||||
out := out ++ s!"{mod}\n"
|
||||
out := out ++ text.extract insertion text.endPos
|
||||
out := out ++ text.extract insertion text.rawEndPos
|
||||
|
||||
IO.FS.writeFile path out
|
||||
return count + 1
|
||||
count := count + 1
|
||||
|
||||
-- Since we throw an error upon encountering issues, we can be sure that everything worked
|
||||
-- if we reach this point of the script.
|
||||
|
||||
@@ -60,7 +60,7 @@ if (arity == fixed + {n}) \{
|
||||
for j in [n:max + 1] do
|
||||
let fs := mkFsArgs (j - n)
|
||||
let sep := if j = n then "" else ", "
|
||||
emit s!" case {j}: \{ obj* r = FN{j}(f)({fs}{sep}{args}); lean_free_small_object(f); return r; }\n"
|
||||
emit s!" case {j}: \{ obj* r = FN{j}(f)({fs}{sep}{args}); lean_free_object(f); return r; }\n"
|
||||
emit " }
|
||||
}
|
||||
switch (arity) {\n"
|
||||
@@ -162,7 +162,7 @@ static obj* fix_args(obj* f, unsigned n, obj*const* as) {
|
||||
for (unsigned i = 0; i < fixed; i++, source++, target++) {
|
||||
*target = *source;
|
||||
}
|
||||
lean_free_small_object(f);
|
||||
lean_free_object(f);
|
||||
}
|
||||
for (unsigned i = 0; i < n; i++, as++, target++) {
|
||||
*target = *as;
|
||||
|
||||
@@ -13,8 +13,15 @@ What this script does:
|
||||
- Checks that the release branch (releases/vX.Y.0) exists
|
||||
- Verifies CMake version settings are correct
|
||||
- Confirms the release tag exists
|
||||
- Validates the release page exists on GitHub
|
||||
- Checks the release notes page on lean-lang.org
|
||||
- Validates the release page exists on GitHub (created automatically by CI after tag push)
|
||||
- Checks the release notes page on lean-lang.org (updated while bumping the `reference-manual` repository)
|
||||
|
||||
**IMPORTANT: If the release page doesn't exist, the script will skip checking
|
||||
downstream repositories and the master branch configuration. The preliminary
|
||||
infrastructure must be in place before the release process can proceed.**
|
||||
|
||||
**NOTE: The GitHub release page is created AUTOMATICALLY by CI after the tag is pushed.
|
||||
DO NOT create it manually. Wait for CI to complete after pushing the tag.**
|
||||
|
||||
2. For each downstream repository (batteries, mathlib4, etc.):
|
||||
- Checks if dependencies are ready (e.g., mathlib4 depends on batteries)
|
||||
@@ -122,6 +129,39 @@ def release_page_exists(repo_url, tag_name, github_token):
|
||||
response = requests.get(api_url, headers=headers)
|
||||
return response.status_code == 200
|
||||
|
||||
def get_tag_workflow_status(repo_url, tag_name, github_token):
|
||||
"""Get the status of CI workflows running for a specific tag."""
|
||||
api_base = repo_url.replace("https://github.com/", "https://api.github.com/repos/")
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
|
||||
# Get workflow runs for the tag
|
||||
# GitHub's workflow runs API uses the branch/tag name in the 'head_branch' field
|
||||
api_url = f"{api_base}/actions/runs?event=push&head_branch={tag_name}"
|
||||
response = requests.get(api_url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
return None
|
||||
|
||||
data = response.json()
|
||||
workflow_runs = data.get('workflow_runs', [])
|
||||
|
||||
if not workflow_runs:
|
||||
return None
|
||||
|
||||
# Get the most recent workflow run for this tag
|
||||
run = workflow_runs[0]
|
||||
status = run.get('status')
|
||||
conclusion = run.get('conclusion')
|
||||
workflow_name = run.get('name', 'CI')
|
||||
run_id = run.get('id')
|
||||
|
||||
return {
|
||||
'status': status,
|
||||
'conclusion': conclusion,
|
||||
'workflow_name': workflow_name,
|
||||
'run_id': run_id
|
||||
}
|
||||
|
||||
def get_release_notes(tag_name):
|
||||
"""Fetch release notes page title from lean-lang.org."""
|
||||
# Strip -rcX suffix if present for the URL
|
||||
@@ -130,20 +170,17 @@ def get_release_notes(tag_name):
|
||||
try:
|
||||
response = requests.get(reference_url)
|
||||
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
|
||||
|
||||
|
||||
# Extract title using regex
|
||||
match = re.search(r"<title>(.*?)</title>", response.text, re.IGNORECASE | re.DOTALL)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
else:
|
||||
print(f" ⚠️ Could not find <title> tag in {reference_url}")
|
||||
return None
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f" ❌ Error fetching release notes from {reference_url}: {e}")
|
||||
|
||||
except requests.exceptions.RequestException:
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f" ❌ An unexpected error occurred while processing release notes: {e}")
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def get_branch_content(repo_url, branch, file_path, github_token):
|
||||
@@ -512,30 +549,57 @@ def main():
|
||||
print(f" ❌ Short commit hash {commit_hash[:SHORT_HASH_LENGTH]} is numeric and starts with 0, causing issues for version parsing. Try regenerating the last commit to get a new hash.")
|
||||
lean4_success = False
|
||||
|
||||
if not release_page_exists(lean_repo_url, toolchain, github_token):
|
||||
print(f" ❌ Release page for {toolchain} does not exist")
|
||||
release_page_ready = release_page_exists(lean_repo_url, toolchain, github_token)
|
||||
if not release_page_ready:
|
||||
print(f" ❌ Release page for {toolchain} does not exist (This will be created by CI.)")
|
||||
|
||||
# Check CI workflow status
|
||||
workflow_status = get_tag_workflow_status(lean_repo_url, toolchain, github_token)
|
||||
if workflow_status:
|
||||
status = workflow_status['status']
|
||||
conclusion = workflow_status['conclusion']
|
||||
workflow_name = workflow_status['workflow_name']
|
||||
run_id = workflow_status['run_id']
|
||||
workflow_url = f"{lean_repo_url}/actions/runs/{run_id}"
|
||||
|
||||
if status == 'in_progress' or status == 'queued':
|
||||
print(f" 🔄 {workflow_name} workflow is {status}: {workflow_url}")
|
||||
elif status == 'completed':
|
||||
if conclusion == 'success':
|
||||
print(f" ✅ {workflow_name} workflow completed successfully: {workflow_url}")
|
||||
elif conclusion == 'failure':
|
||||
print(f" ❌ {workflow_name} workflow failed: {workflow_url}")
|
||||
else:
|
||||
print(f" ⚠️ {workflow_name} workflow completed with status: {conclusion}: {workflow_url}")
|
||||
else:
|
||||
print(f" ℹ️ {workflow_name} workflow status: {status}: {workflow_url}")
|
||||
|
||||
lean4_success = False
|
||||
else:
|
||||
print(f" ✅ Release page for {toolchain} exists")
|
||||
|
||||
# Check the actual release notes page title
|
||||
|
||||
# Check the actual release notes page title (informational only - does not block)
|
||||
actual_title = get_release_notes(toolchain)
|
||||
expected_title_prefix = f"Lean {toolchain.lstrip('v')}" # e.g., "Lean 4.19.0" or "Lean 4.19.0-rc1"
|
||||
base_tag = toolchain.split('-')[0]
|
||||
release_notes_url = f"https://lean-lang.org/doc/reference/latest/releases/{base_tag}/"
|
||||
|
||||
if actual_title is None:
|
||||
# Error already printed by get_release_notes
|
||||
lean4_success = False
|
||||
print(f" ⚠️ Release notes not found at {release_notes_url} (this will be fixed while updating the reference-manual repository)")
|
||||
elif not actual_title.startswith(expected_title_prefix):
|
||||
# Construct URL for the error message (using the base tag)
|
||||
base_tag = toolchain.split('-')[0]
|
||||
check_url = f"https://lean-lang.org/doc/reference/latest/releases/{base_tag}/"
|
||||
print(f" ❌ Release notes page title mismatch. Expected prefix '{expected_title_prefix}', got '{actual_title}'. Check {check_url}")
|
||||
lean4_success = False
|
||||
print(f" ⚠️ Release notes page title mismatch. Expected prefix '{expected_title_prefix}', got '{actual_title}'. Check {release_notes_url}")
|
||||
else:
|
||||
print(f" ✅ Release notes page title looks good ('{actual_title}').")
|
||||
|
||||
repo_status["lean4"] = lean4_success
|
||||
|
||||
# If the release page doesn't exist, skip repository checks and master branch checks
|
||||
# The preliminary infrastructure must be in place first
|
||||
if not release_page_exists(lean_repo_url, toolchain, github_token):
|
||||
print("\n⚠️ Release process blocked: preliminary Lean4 infrastructure incomplete.")
|
||||
print(" Complete the steps above, then rerun this script to proceed with downstream repositories.")
|
||||
return
|
||||
|
||||
# Load repositories and perform further checks
|
||||
print("\nChecking repositories...")
|
||||
|
||||
|
||||
@@ -589,8 +589,19 @@ def execute_release_steps(repo, version, config):
|
||||
|
||||
# Clean lake cache for a fresh build
|
||||
print(blue("Cleaning lake cache..."))
|
||||
run_command("rm -rf .lake", cwd=repo_path)
|
||||
|
||||
run_command("lake clean", cwd=repo_path)
|
||||
|
||||
# Check if downstream of Mathlib and get cache if so
|
||||
mathlib_package_dir = repo_path / ".lake" / "packages" / "mathlib"
|
||||
if mathlib_package_dir.exists():
|
||||
print(blue("Project is downstream of Mathlib, fetching cache..."))
|
||||
try:
|
||||
run_command("lake exe cache get", cwd=repo_path, stream_output=True)
|
||||
print(green("Cache fetched successfully"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(yellow("Failed to fetch cache, continuing anyway..."))
|
||||
print(yellow(f"Cache fetch error: {e}"))
|
||||
|
||||
try:
|
||||
run_command("lake build", cwd=repo_path, stream_output=True)
|
||||
print(green("Build completed successfully"))
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 25)
|
||||
set(LEAN_VERSION_MINOR 27)
|
||||
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'")
|
||||
|
||||
@@ -14,7 +14,6 @@ public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Core
|
||||
public import Init.Control
|
||||
public import Init.Data.Basic
|
||||
public import Init.WF
|
||||
public import Init.WFTactics
|
||||
public import Init.Data
|
||||
|
||||
@@ -44,3 +44,10 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
|
||||
/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/
|
||||
@[simp] theorem dite_eq_ite [Decidable P] :
|
||||
(dite P (fun _ => a) (fun _ => b)) = ite P a b := rfl
|
||||
|
||||
-- Remark: dite and ite are "defally equal" when we ignore the proofs.
|
||||
@[deprecated dite_eq_ite (since := "2025-10-29")]
|
||||
theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
| isFalse _ => rfl
|
||||
|
||||
@@ -181,9 +181,6 @@ theorem not_imp_iff_and_not : ¬(a → b) ↔ a ∧ ¬b := Decidable.not_imp_iff
|
||||
|
||||
theorem not_and_iff_not_or_not : ¬(a ∧ b) ↔ ¬a ∨ ¬b := Decidable.not_and_iff_not_or_not
|
||||
|
||||
@[deprecated not_and_iff_not_or_not (since := "2025-03-18")]
|
||||
abbrev not_and_iff_or_not_not := @not_and_iff_not_or_not
|
||||
|
||||
theorem not_iff : ¬(a ↔ b) ↔ (¬a ↔ b) := Decidable.not_iff
|
||||
|
||||
@[simp] theorem imp_iff_left_iff : (b ↔ a → b) ↔ a ∨ b := Decidable.imp_iff_left_iff
|
||||
|
||||
@@ -45,9 +45,6 @@ instance (priority := 500) instForInOfForIn' [ForIn' m ρ α d] : ForIn m ρ α
|
||||
forIn x b f = forIn' x b (fun x h => binderNameHint x f <| binderNameHint h () <| f x) := by
|
||||
rfl
|
||||
|
||||
@[deprecated forIn_eq_forIn' (since := "2025-04-04")]
|
||||
abbrev forIn_eq_forin' := @forIn_eq_forIn'
|
||||
|
||||
/--
|
||||
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
|
||||
-/
|
||||
|
||||
@@ -148,6 +148,23 @@ This is the inverse of `ExceptT.mk`.
|
||||
@[always_inline, inline, expose]
|
||||
def ExceptT.run {ε : Type u} {m : Type u → Type v} {α : Type u} (x : ExceptT ε m α) : m (Except ε α) := x
|
||||
|
||||
/--
|
||||
Use a monadic action that may throw an exception by providing explicit success and failure
|
||||
continuations.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def ExceptT.runK [Monad m] (x : ExceptT ε m α) (ok : α → m β) (error : ε → m β) : m β :=
|
||||
x.run >>= (·.casesOn error ok)
|
||||
|
||||
/--
|
||||
Returns the value of a computation, forgetting whether it was an exception or a success.
|
||||
|
||||
This corresponds to early return.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def ExceptT.runCatch [Monad m] (x : ExceptT α m α) : m α :=
|
||||
x.runK pure pure
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
variable {ε : Type u} {m : Type u → Type v} [Monad m]
|
||||
|
||||
@@ -170,6 +170,7 @@ theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ =>
|
||||
theorem map_congr [Functor m] {x : m α} {f g : α → β} (h : ∀ a, f a = g a) : (f <$> x : m β) = g <$> x := by
|
||||
simp [funext h]
|
||||
|
||||
@[deprecated seq_eq_bind_map (since := "2025-10-26")]
|
||||
theorem seq_eq_bind {α β : Type u} [Monad m] [LawfulMonad m] (mf : m (α → β)) (x : m α) : mf <*> x = mf >>= fun f => f <$> x := by
|
||||
rw [bind_map]
|
||||
|
||||
@@ -255,20 +256,4 @@ instance : LawfulMonad Id := by
|
||||
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
|
||||
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
|
||||
|
||||
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
|
||||
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
|
||||
end Id
|
||||
|
||||
/-! # Option -/
|
||||
|
||||
instance : LawfulMonad Option := LawfulMonad.mk'
|
||||
(id_map := fun x => by cases x <;> rfl)
|
||||
(pure_bind := fun _ _ => rfl)
|
||||
(bind_assoc := fun x _ _ => by cases x <;> rfl)
|
||||
(bind_pure_comp := fun _ x => by cases x <;> rfl)
|
||||
|
||||
instance : LawfulApplicative Option := inferInstance
|
||||
instance : LawfulFunctor Option := inferInstance
|
||||
|
||||
@@ -189,12 +189,12 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (OptionT m) where
|
||||
|
||||
@[simp] theorem run_seq [Monad m] [LawfulMonad m] (f : OptionT m (α → β)) (x : OptionT m α) :
|
||||
(f <*> x).run = Option.elimM f.run (pure none) (fun f => Option.map f <$> x.run) := by
|
||||
simp [seq_eq_bind, Option.elimM, Option.elim]
|
||||
simp [seq_eq_bind_map, Option.elimM, Option.elim]
|
||||
|
||||
@[simp] theorem run_seqLeft [Monad m] [LawfulMonad m] (x : OptionT m α) (y : OptionT m β) :
|
||||
(x <* y).run = Option.elimM x.run (pure none)
|
||||
(fun x => Option.map (Function.const β x) <$> y.run) := by
|
||||
simp [seqLeft_eq, seq_eq_bind, Option.elimM, OptionT.run_bind]
|
||||
simp [seqLeft_eq, seq_eq_bind_map, Option.elimM, OptionT.run_bind]
|
||||
|
||||
@[simp] theorem run_seqRight [Monad m] [LawfulMonad m] (x : OptionT m α) (y : OptionT m β) :
|
||||
(x *> y).run = Option.elimM x.run (pure none) (Function.const α y.run) := by
|
||||
@@ -219,7 +219,7 @@ instance : LawfulMonad Option := LawfulMonad.mk'
|
||||
(id_map := fun x => by cases x <;> rfl)
|
||||
(pure_bind := fun _ _ => by rfl)
|
||||
(bind_assoc := fun a _ _ => by cases a <;> rfl)
|
||||
(bind_pure_comp := bind_pure_comp)
|
||||
(bind_pure_comp := fun _ x => by cases x <;> rfl)
|
||||
|
||||
instance : LawfulApplicative Option := inferInstance
|
||||
instance : LawfulFunctor Option := inferInstance
|
||||
|
||||
@@ -23,7 +23,7 @@ theorem monadLift_map [LawfulMonad m] [LawfulMonad n] (f : α → β) (ma : m α
|
||||
|
||||
theorem monadLift_seq [LawfulMonad m] [LawfulMonad n] (mf : m (α → β)) (ma : m α) :
|
||||
monadLift (mf <*> ma) = monadLift mf <*> (monadLift ma : n α) := by
|
||||
simp only [seq_eq_bind, monadLift_map, monadLift_bind]
|
||||
simp only [seq_eq_bind_map, monadLift_map, monadLift_bind]
|
||||
|
||||
theorem monadLift_seqLeft [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
|
||||
monadLift (x <* y) = (monadLift x : n α) <* (monadLift y : n β) := by
|
||||
|
||||
@@ -27,7 +27,7 @@ failure occurred.
|
||||
/--
|
||||
Executes an action that might fail in the underlying monad `m`, returning `none` in case of failure.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def OptionT.run {m : Type u → Type v} {α : Type u} (x : OptionT m α) : m (Option α) :=
|
||||
x
|
||||
|
||||
@@ -69,7 +69,7 @@ instance {m : Type u → Type v} [Pure m] : Inhabited (OptionT m α) where
|
||||
/--
|
||||
Recovers from failures. Typically used via the `<|>` operator.
|
||||
-/
|
||||
@[always_inline, inline] protected def orElse (x : OptionT m α) (y : Unit → OptionT m α) : OptionT m α := OptionT.mk do
|
||||
@[always_inline, inline, expose] protected def orElse (x : OptionT m α) (y : Unit → OptionT m α) : OptionT m α := OptionT.mk do
|
||||
match (← x) with
|
||||
| some a => pure (some a)
|
||||
| _ => y ()
|
||||
@@ -77,7 +77,7 @@ Recovers from failures. Typically used via the `<|>` operator.
|
||||
/--
|
||||
A recoverable failure.
|
||||
-/
|
||||
@[always_inline, inline] protected def fail : OptionT m α := OptionT.mk do
|
||||
@[always_inline, inline, expose] protected def fail : OptionT m α := OptionT.mk do
|
||||
pure none
|
||||
|
||||
instance : Alternative (OptionT m) where
|
||||
@@ -90,7 +90,7 @@ Converts a computation from the underlying monad into one that could fail, even
|
||||
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
|
||||
lifting](lean-manual://section/monad-lifting).
|
||||
-/
|
||||
@[always_inline, inline] protected def lift (x : m α) : OptionT m α := OptionT.mk do
|
||||
@[always_inline, inline, expose] protected def lift (x : m α) : OptionT m α := OptionT.mk do
|
||||
return some (← x)
|
||||
|
||||
instance : MonadLift m (OptionT m) := ⟨OptionT.lift⟩
|
||||
@@ -100,11 +100,11 @@ instance : MonadFunctor m (OptionT m) := ⟨fun f x => f x⟩
|
||||
/--
|
||||
Handles failures by treating them as exceptions of type `Unit`.
|
||||
-/
|
||||
@[always_inline, inline] protected def tryCatch (x : OptionT m α) (handle : Unit → OptionT m α) : OptionT m α := OptionT.mk do
|
||||
let some a ← x | handle ()
|
||||
@[always_inline, inline, expose] protected def tryCatch (x : OptionT m α) (handle : PUnit → OptionT m α) : OptionT m α := OptionT.mk do
|
||||
let some a ← x | handle ⟨⟩
|
||||
pure <| some a
|
||||
|
||||
instance : MonadExceptOf Unit (OptionT m) where
|
||||
instance : MonadExceptOf PUnit (OptionT m) where
|
||||
throw := fun _ => OptionT.fail
|
||||
tryCatch := OptionT.tryCatch
|
||||
|
||||
|
||||
@@ -600,17 +600,6 @@ export LawfulSingleton (insert_empty_eq)
|
||||
|
||||
attribute [simp] insert_empty_eq
|
||||
|
||||
@[deprecated insert_empty_eq (since := "2025-03-12")]
|
||||
theorem insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
|
||||
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
|
||||
insert_empty_eq _
|
||||
|
||||
@[deprecated insert_empty_eq (since := "2025-03-12")]
|
||||
theorem LawfulSingleton.insert_emptyc_eq [EmptyCollection β] [Insert α β] [Singleton α β]
|
||||
[LawfulSingleton α β] (x : α) : (insert x ∅ : β) = singleton x :=
|
||||
insert_empty_eq _
|
||||
|
||||
|
||||
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
|
||||
class Sep (α : outParam <| Type u) (γ : Type v) where
|
||||
/-- Computes `{ a ∈ c | p a }`. -/
|
||||
@@ -1095,14 +1084,6 @@ theorem of_toBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d =
|
||||
theorem of_toBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬p :=
|
||||
of_decide_eq_false h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated of_toBoolUsing_eq_true (since := "2025-04-04")]
|
||||
abbrev ofBoolUsing_eq_true := @of_toBoolUsing_eq_true
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated of_toBoolUsing_eq_false (since := "2025-04-04")]
|
||||
abbrev ofBoolUsing_eq_false := @of_toBoolUsing_eq_false
|
||||
|
||||
instance : Decidable True :=
|
||||
isTrue trivial
|
||||
|
||||
@@ -1165,6 +1146,7 @@ end
|
||||
else isFalse (fun h => absurd (h hp) hq)
|
||||
else isTrue (fun h => absurd h hp)
|
||||
|
||||
@[inline]
|
||||
instance {p q} [Decidable p] [Decidable q] : Decidable (p ↔ q) :=
|
||||
if hp : p then
|
||||
if hq : q then
|
||||
@@ -1206,17 +1188,13 @@ theorem dif_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t : c
|
||||
| isTrue hc => absurd hc hnc
|
||||
| isFalse _ => rfl
|
||||
|
||||
-- Remark: dite and ite are "defally equal" when we ignore the proofs.
|
||||
theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
| isFalse _ => rfl
|
||||
|
||||
@[macro_inline]
|
||||
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
|
||||
match dC with
|
||||
| isTrue _ => dT
|
||||
| isFalse _ => dE
|
||||
|
||||
@[inline]
|
||||
instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
|
||||
match dC with
|
||||
| isTrue hc => dT hc
|
||||
@@ -1367,12 +1345,12 @@ namespace Subtype
|
||||
theorem exists_of_subtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
|
||||
| ⟨a, h⟩ => ⟨a, h⟩
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated exists_of_subtype (since := "2025-04-04")]
|
||||
abbrev existsOfSubtype := @exists_of_subtype
|
||||
variable {α : Sort u} {p : α → Prop}
|
||||
|
||||
variable {α : Type u} {p : α → Prop}
|
||||
protected theorem ext : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
@[deprecated Subtype.ext (since := "2025-10-26")]
|
||||
protected theorem eq : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
@@ -1387,9 +1365,9 @@ instance {α : Type u} {p : α → Prop} [BEq α] [ReflBEq α] : ReflBEq {x : α
|
||||
rfl {x} := BEq.refl x.1
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [BEq α] [LawfulBEq α] : LawfulBEq {x : α // p x} where
|
||||
eq_of_beq h := Subtype.eq (eq_of_beq h)
|
||||
eq_of_beq h := Subtype.ext (eq_of_beq h)
|
||||
|
||||
instance {α : Type u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
|
||||
instance {α : Sort u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
|
||||
fun ⟨a, h₁⟩ ⟨b, h₂⟩ =>
|
||||
if h : a = b then isTrue (by subst h; exact rfl)
|
||||
else isFalse (fun h' => Subtype.noConfusion h' (fun h' => absurd h' h))
|
||||
@@ -1490,6 +1468,8 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
|
||||
|
||||
@[simp] theorem Prod.map_apply (f : α → β) (g : γ → δ) (x) (y) :
|
||||
Prod.map f g (x, y) = (f x, g y) := rfl
|
||||
|
||||
-- We add `@[grind =]` to these in `Init.Data.Prod`.
|
||||
@[simp] theorem Prod.map_fst (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).1 = f x.1 := rfl
|
||||
@[simp] theorem Prod.map_snd (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).2 = g x.2 := rfl
|
||||
|
||||
@@ -1506,20 +1486,24 @@ protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α}
|
||||
|
||||
/-! # Universe polymorphic unit -/
|
||||
|
||||
theorem PUnit.ext (a b : PUnit) : a = b := by
|
||||
cases a; cases b; exact rfl
|
||||
|
||||
@[deprecated PUnit.ext (since := "2025-10-26")]
|
||||
theorem PUnit.subsingleton (a b : PUnit) : a = b := by
|
||||
cases a; cases b; exact rfl
|
||||
|
||||
theorem PUnit.eq_punit (a : PUnit) : a = ⟨⟩ :=
|
||||
PUnit.subsingleton a ⟨⟩
|
||||
PUnit.ext a ⟨⟩
|
||||
|
||||
instance : Subsingleton PUnit :=
|
||||
Subsingleton.intro PUnit.subsingleton
|
||||
Subsingleton.intro PUnit.ext
|
||||
|
||||
instance : Inhabited PUnit where
|
||||
default := ⟨⟩
|
||||
|
||||
instance : DecidableEq PUnit :=
|
||||
fun a b => isTrue (PUnit.subsingleton a b)
|
||||
fun a b => isTrue (PUnit.ext a b)
|
||||
|
||||
/-! # Setoid -/
|
||||
|
||||
@@ -1606,7 +1590,7 @@ gen_injective_theorems% PSum
|
||||
gen_injective_theorems% Sigma
|
||||
gen_injective_theorems% String
|
||||
gen_injective_theorems% String.Pos.Raw
|
||||
gen_injective_theorems% Substring
|
||||
gen_injective_theorems% Substring.Raw
|
||||
gen_injective_theorems% Subtype
|
||||
gen_injective_theorems% Sum
|
||||
gen_injective_theorems% Task
|
||||
@@ -2523,8 +2507,7 @@ class Antisymm (r : α → α → Prop) : Prop where
|
||||
/-- An antisymmetric relation `r` satisfies `r a b → r b a → a = b`. -/
|
||||
antisymm (a b : α) : r a b → r b a → a = b
|
||||
|
||||
/-- `Asymm r` means that the binary relation `r` is asymmetric, that is,
|
||||
`r a b → ¬ r b a`. -/
|
||||
/-- `Asymm r` means that the binary relation `r` is asymmetric, that is, `r a b → ¬ r b a`. -/
|
||||
class Asymm (r : α → α → Prop) : Prop where
|
||||
/-- An asymmetric relation satisfies `r a b → ¬ r b a`. -/
|
||||
asymm : ∀ a b, r a b → ¬r b a
|
||||
@@ -2534,16 +2517,19 @@ class Symm (r : α → α → Prop) : Prop where
|
||||
/-- A symmetric relation satisfies `r a b → r b a`. -/
|
||||
symm : ∀ a b, r a b → r b a
|
||||
|
||||
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, that for any
|
||||
`x y : X` we have `r x y` or `r y x`. -/
|
||||
/-- `Total X r` means that the binary relation `r` on `X` is total, that is, `r a b` or `r b a`. -/
|
||||
class Total (r : α → α → Prop) : Prop where
|
||||
/-- A total relation satisfies `r a b ∨ r b a`. -/
|
||||
/-- A total relation satisfies `r a b` or `r b a`. -/
|
||||
total : ∀ a b, r a b ∨ r b a
|
||||
|
||||
/-- `Irrefl r` means the binary relation `r` is irreflexive, that is, `r x x` never
|
||||
holds. -/
|
||||
/-- `Irrefl r` means the binary relation `r` is irreflexive, that is, `r x x` never holds. -/
|
||||
class Irrefl (r : α → α → Prop) : Prop where
|
||||
/-- An irreflexive relation satisfies `¬ r a a`. -/
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
/-- `Trichotomous r` says that `r` is trichotomous, that is, `¬ r a b → ¬ r b a → a = b`. -/
|
||||
class Trichotomous (r : α → α → Prop) : Prop where
|
||||
/-- An trichotomous relation `r` satisfies `¬ r a b → ¬ r b a → a = b`. -/
|
||||
trichotomous (a b : α) : ¬ r a b → ¬ r b a → a = b
|
||||
|
||||
end Std
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Basic
|
||||
public import Init.Data.Nat
|
||||
public import Init.Data.Bool
|
||||
public import Init.Data.BitVec
|
||||
|
||||
@@ -749,9 +749,6 @@ and simplifies these to the function directly taking the value.
|
||||
(Array.replicate n x).unattach = Array.replicate n x.1 := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_replicate (since := "2025-03-18")]
|
||||
abbrev unattach_mkArray := @unattach_replicate
|
||||
|
||||
/-! ### Well-founded recursion preprocessing setup -/
|
||||
|
||||
@[wf_preprocess] theorem map_wfParam {xs : Array α} {f : α → β} :
|
||||
|
||||
@@ -209,20 +209,6 @@ Examples:
|
||||
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
/--
|
||||
Creates an array that contains `n` repetitions of `v`.
|
||||
|
||||
The corresponding `List` function is `List.replicate`.
|
||||
|
||||
Examples:
|
||||
* `Array.mkArray 2 true = #[true, true]`
|
||||
* `Array.mkArray 3 () = #[(), (), ()]`
|
||||
* `Array.mkArray 0 "anything" = #[]`
|
||||
-/
|
||||
@[extern "lean_mk_array", deprecated replicate (since := "2025-03-18")]
|
||||
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
/--
|
||||
Swaps two elements of an array. The modification is performed in-place when the reference to the
|
||||
array is unique.
|
||||
@@ -240,7 +226,7 @@ def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic)
|
||||
let xs' := xs.set i v₂
|
||||
xs'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set _).symm)
|
||||
|
||||
@[simp] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
|
||||
@[simp, grind =] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
|
||||
change ((xs.set i xs[j]).set j xs[i]
|
||||
(Nat.lt_of_lt_of_eq hj (size_set _).symm)).size = xs.size
|
||||
rw [size_set, size_set]
|
||||
@@ -462,7 +448,7 @@ Examples:
|
||||
-/
|
||||
abbrev take (xs : Array α) (i : Nat) : Array α := extract xs 0 i
|
||||
|
||||
@[simp] theorem take_eq_extract {xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i := rfl
|
||||
@[simp, grind =] theorem take_eq_extract {xs : Array α} {i : Nat} : xs.take i = xs.extract 0 i := rfl
|
||||
|
||||
/--
|
||||
Removes the first `i` elements of `xs`. If `xs` has fewer than `i` elements, the new array is empty.
|
||||
@@ -476,7 +462,7 @@ Examples:
|
||||
-/
|
||||
abbrev drop (xs : Array α) (i : Nat) : Array α := extract xs i xs.size
|
||||
|
||||
@[simp] theorem drop_eq_extract {xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size := rfl
|
||||
@[simp, grind =] theorem drop_eq_extract {xs : Array α} {i : Nat} : xs.drop i = xs.extract i xs.size := rfl
|
||||
|
||||
@[inline]
|
||||
unsafe def modifyMUnsafe [Monad m] (xs : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||||
@@ -1309,7 +1295,7 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
|
||||
/--
|
||||
Returns the index of the first element equal to `a`, or the size of the array if no element is equal
|
||||
Returns the index of the first element equal to `a`, or `none` if no element is equal
|
||||
to `a`. The index is returned as a `Fin`, which guarantees that it is in bounds.
|
||||
|
||||
Examples:
|
||||
@@ -1718,7 +1704,7 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
as
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[simp] theorem popWhile_empty {p : α → Bool} :
|
||||
@[simp, grind =] theorem popWhile_empty {p : α → Bool} :
|
||||
popWhile p #[] = #[] := by
|
||||
simp [popWhile]
|
||||
|
||||
@@ -1765,7 +1751,8 @@ termination_by xs.size - i
|
||||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
|
||||
-- This is required in `Lean.Data.PersistentHashMap`.
|
||||
@[simp] theorem size_eraseIdx {xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
|
||||
@[simp, grind =]
|
||||
theorem size_eraseIdx {xs : Array α} (i : Nat) (h) : (xs.eraseIdx i h).size = xs.size - 1 := by
|
||||
induction xs, i, h using Array.eraseIdx.induct with
|
||||
| @case1 xs i h h' xs' ih =>
|
||||
unfold eraseIdx
|
||||
@@ -2147,5 +2134,3 @@ instance [ToString α] : ToString (Array α) where
|
||||
toString xs := String.Internal.append "#" (toString xs.toList)
|
||||
|
||||
end Array
|
||||
|
||||
export Array (mkArray)
|
||||
|
||||
@@ -31,7 +31,7 @@ theorem foldlM_toList.aux [Monad m]
|
||||
· cases Nat.not_le_of_gt ‹_› (Nat.zero_add _ ▸ H)
|
||||
· rename_i i; rw [Nat.succ_add] at H
|
||||
simp [foldlM_toList.aux (j := j+1) H]
|
||||
rw (occs := [2]) [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
rw (occs := [2]) [← List.getElem_cons_drop ‹_›]
|
||||
simp
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; simp
|
||||
|
||||
@@ -100,9 +100,15 @@ abbrev push_toList := @toList_push
|
||||
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
|
||||
apply ext'; simp only [toList_append, List.nil_append]
|
||||
|
||||
@[simp, grind _=_] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
|
||||
@[simp] theorem append_assoc {xs ys zs : Array α} : xs ++ ys ++ zs = xs ++ (ys ++ zs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
grind_pattern append_assoc => (xs ++ ys) ++ zs where
|
||||
xs =/= #[]; ys =/= #[]; zs =/= #[]
|
||||
|
||||
grind_pattern append_assoc => xs ++ (ys ++ zs) where
|
||||
xs =/= #[]; ys =/= #[]; zs =/= #[]
|
||||
|
||||
@[simp] theorem appendList_eq_append {xs : Array α} {l : List α} : xs.appendList l = xs ++ l := rfl
|
||||
|
||||
@[simp, grind =] theorem toList_appendList {xs : Array α} {l : List α} :
|
||||
@@ -110,6 +116,4 @@ abbrev push_toList := @toList_push
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
|
||||
|
||||
end Array
|
||||
|
||||
@@ -99,9 +99,6 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
|
||||
theorem countP_replicate {a : α} {n : Nat} : countP p (replicate n a) = if p a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.countP_replicate]
|
||||
|
||||
@[deprecated countP_replicate (since := "2025-03-18")]
|
||||
abbrev countP_mkArray := @countP_replicate
|
||||
|
||||
theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
(if p xs[i] then 1 else 0) ≤ xs.countP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -262,15 +259,9 @@ theorem count_eq_size {xs : Array α} : count a xs = xs.size ↔ ∀ b ∈ xs, a
|
||||
@[simp] theorem count_replicate_self {a : α} {n : Nat} : count a (replicate n a) = n := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated count_replicate_self (since := "2025-03-18")]
|
||||
abbrev count_mkArray_self := @count_replicate_self
|
||||
|
||||
theorem count_replicate {a b : α} {n : Nat} : count a (replicate n b) = if b == a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.count_replicate]
|
||||
|
||||
@[deprecated count_replicate (since := "2025-03-18")]
|
||||
abbrev count_mkArray := @count_replicate
|
||||
|
||||
theorem filter_beq {xs : Array α} (a : α) : xs.filter (· == a) = replicate (count a xs) a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.filter_beq]
|
||||
@@ -284,9 +275,6 @@ theorem replicate_count_eq_of_count_eq_size {xs : Array α} (h : count a xs = xs
|
||||
rw [← toList_inj]
|
||||
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
|
||||
|
||||
@[deprecated replicate_count_eq_of_count_eq_size (since := "2025-03-18")]
|
||||
abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
|
||||
|
||||
@[simp] theorem count_filter {xs : Array α} (h : p a) : count a (filter p xs) = count a xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_filter, h]
|
||||
|
||||
@@ -139,25 +139,16 @@ theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated eraseP_replicate (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray := @eraseP_replicate
|
||||
|
||||
@[simp] theorem eraseP_replicate_of_pos {n : Nat} {a : α} (h : p a) :
|
||||
(replicate n a).eraseP p = replicate (n - 1) a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray]
|
||||
simp [h]
|
||||
|
||||
@[deprecated eraseP_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray_of_pos := @eraseP_replicate_of_pos
|
||||
|
||||
@[simp] theorem eraseP_replicate_of_neg {n : Nat} {a : α} (h : ¬p a) :
|
||||
(replicate n a).eraseP p = replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray]
|
||||
simp [h]
|
||||
|
||||
@[deprecated eraseP_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev eraseP_mkArray_of_neg := @eraseP_replicate_of_neg
|
||||
|
||||
theorem eraseP_eq_iff {p} {xs : Array α} :
|
||||
xs.eraseP p = ys ↔
|
||||
((∀ a ∈ xs, ¬ p a) ∧ xs = ys) ∨
|
||||
@@ -278,9 +269,6 @@ theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
simp only [List.erase_replicate, beq_iff_eq, List.toArray_replicate]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated erase_replicate (since := "2025-03-18")]
|
||||
abbrev erase_mkArray := @erase_replicate
|
||||
|
||||
-- The arguments `a b` are explicit,
|
||||
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
|
||||
@[grind =]
|
||||
@@ -308,17 +296,11 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated erase_replicate_self (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_self := @erase_replicate_self
|
||||
|
||||
@[simp] theorem erase_replicate_ne [LawfulBEq α] {a b : α} (h : !b == a) :
|
||||
(replicate n a).erase b = replicate n a := by
|
||||
rw [erase_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[deprecated erase_replicate_ne (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_ne := @erase_replicate_ne
|
||||
|
||||
end erase
|
||||
|
||||
/-! ### eraseIdxIfInBounds -/
|
||||
@@ -429,9 +411,6 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
simp only [← List.toArray_replicate, List.eraseIdx_toArray]
|
||||
simp [List.eraseIdx_replicate, h]
|
||||
|
||||
@[deprecated eraseIdx_replicate (since := "2025-03-18")]
|
||||
abbrev eraseIdx_mkArray := @eraseIdx_replicate
|
||||
|
||||
theorem mem_eraseIdx_iff_getElem {x : α} {xs : Array α} {k} {h} : x ∈ xs.eraseIdx k h ↔ ∃ i w, i ≠ k ∧ xs[i]'w = x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mem_eraseIdx_iff_getElem, *]
|
||||
|
||||
@@ -200,7 +200,7 @@ theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
|
||||
simp [getElem?_extract]
|
||||
omega
|
||||
|
||||
@[simp, grind =] theorem extract_extract {as : Array α} {i j k l : Nat} :
|
||||
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
|
||||
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := by
|
||||
ext m h₁ h₂
|
||||
· simp
|
||||
@@ -208,6 +208,9 @@ theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
|
||||
· simp only [size_extract] at h₁ h₂
|
||||
simp [Nat.add_assoc]
|
||||
|
||||
grind_pattern extract_extract => (as.extract i j).extract k l where
|
||||
as =/= #[]
|
||||
|
||||
theorem extract_eq_empty_of_eq_empty {as : Array α} {i j : Nat} (h : as = #[]) :
|
||||
as.extract i j = #[] := by
|
||||
simp [h]
|
||||
@@ -289,9 +292,6 @@ theorem extract_append_right {as bs : Array α} :
|
||||
· simp only [size_extract, size_replicate] at h₁ h₂
|
||||
simp only [getElem_extract, getElem_replicate]
|
||||
|
||||
@[deprecated extract_replicate (since := "2025-03-18")]
|
||||
abbrev extract_mkArray := @extract_replicate
|
||||
|
||||
theorem extract_eq_extract_right {as : Array α} {i j j' : Nat} :
|
||||
as.extract i j = as.extract i j' ↔ min (j - i) (as.size - i) = min (j' - i) (as.size - i) := by
|
||||
rcases as with ⟨as⟩
|
||||
@@ -429,32 +429,20 @@ theorem popWhile_append {xs ys : Array α} :
|
||||
(replicate n a).takeWhile p = (replicate n a).filter p := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated takeWhile_replicate_eq_filter (since := "2025-03-18")]
|
||||
abbrev takeWhile_mkArray_eq_filter := @takeWhile_replicate_eq_filter
|
||||
|
||||
theorem takeWhile_replicate {p : α → Bool} :
|
||||
(replicate n a).takeWhile p = if p a then replicate n a else #[] := by
|
||||
simp [takeWhile_replicate_eq_filter, filter_replicate]
|
||||
|
||||
@[deprecated takeWhile_replicate (since := "2025-03-18")]
|
||||
abbrev takeWhile_mkArray := @takeWhile_replicate
|
||||
|
||||
@[simp] theorem popWhile_replicate_eq_filter_not {p : α → Bool} :
|
||||
(replicate n a).popWhile p = (replicate n a).filter (fun a => !p a) := by
|
||||
simp [← List.toArray_replicate, ← List.filter_reverse]
|
||||
|
||||
@[deprecated popWhile_replicate_eq_filter_not (since := "2025-03-18")]
|
||||
abbrev popWhile_mkArray_eq_filter_not := @popWhile_replicate_eq_filter_not
|
||||
|
||||
theorem popWhile_replicate {p : α → Bool} :
|
||||
(replicate n a).popWhile p = if p a then #[] else replicate n a := by
|
||||
simp only [popWhile_replicate_eq_filter_not, size_replicate, filter_replicate, Bool.not_eq_eq_eq_not,
|
||||
Bool.not_true]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated popWhile_replicate (since := "2025-03-18")]
|
||||
abbrev popWhile_mkArray := @popWhile_replicate
|
||||
|
||||
theorem extract_takeWhile {as : Array α} {i : Nat} :
|
||||
(as.takeWhile p).extract 0 i = (as.extract 0 i).takeWhile p := by
|
||||
rcases as with ⟨as⟩
|
||||
|
||||
@@ -129,31 +129,19 @@ theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [← List.toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray := @findSome?_replicate
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_pos (h : 0 < n) : findSome? f (replicate n a) = f a := by
|
||||
simp [findSome?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_pos := @findSome?_replicate_of_pos
|
||||
|
||||
-- Argument is unused, but used to decide whether `simp` should unfold.
|
||||
@[simp] theorem findSome?_replicate_of_isSome (_ : (f a).isSome) :
|
||||
findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [findSome?_replicate]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_isSome := @findSome?_replicate_of_isSome
|
||||
|
||||
@[simp] theorem findSome?_replicate_of_isNone (h : (f a).isNone) :
|
||||
findSome? f (replicate n a) = none := by
|
||||
rw [Option.isNone_iff_eq_none] at h
|
||||
simp [findSome?_replicate, h]
|
||||
|
||||
@[deprecated findSome?_replicate_of_isNone (since := "2025-03-18")]
|
||||
abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp, grind =] theorem find?_empty : find? p #[] = none := rfl
|
||||
@@ -318,16 +306,10 @@ theorem find?_replicate :
|
||||
find? p (replicate n a) = if p a then some a else none := by
|
||||
simp [find?_replicate, Nat.ne_of_gt h]
|
||||
|
||||
@[deprecated find?_replicate_of_size_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_length_pos := @find?_replicate_of_size_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_pos (h : p a) :
|
||||
find? p (replicate n a) = if n = 0 then none else some a := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
|
||||
|
||||
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@@ -583,9 +565,6 @@ theorem findIdx?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
simp only [List.findIdx?_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated findIdx?_replicate (since := "2025-03-18")]
|
||||
abbrev findIdx?_mkArray := @findIdx?_replicate
|
||||
|
||||
theorem findIdx?_eq_findSome?_zipIdx {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = xs.zipIdx.findSome? fun ⟨a, i⟩ => if p a then some i else none := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -50,6 +50,6 @@ where
|
||||
getLit_eq (xs : Array α) (i : Nat) (h₁ : xs.size = n) (h₂ : i < n) : xs.getLit i h₁ h₂ = getElem xs.toList i ((id (α := xs.toList.length = n) h₁) ▸ h₂) :=
|
||||
rfl
|
||||
go (i : Nat) (hi : i ≤ xs.size) : toListLitAux xs n hsz i hi (xs.toList.drop i) = xs.toList := by
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop, *]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -245,12 +245,13 @@ theorem back_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.pus
|
||||
replace h := List.append_inj_right' h (by simp)
|
||||
simpa using h
|
||||
|
||||
theorem pop_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys := by
|
||||
theorem push_eq_push {a b : α} {xs ys : Array α} : xs.push a = ys.push b ↔ a = b ∧ xs = ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp at h
|
||||
replace h := List.append_inj_left' h (by simp)
|
||||
simp [h]
|
||||
simp [And.comm]
|
||||
|
||||
theorem pop_eq_of_push_eq {a b : α} {xs ys : Array α} (h : xs.push a = ys.push b) : xs = ys :=
|
||||
(push_eq_push.1 h).2
|
||||
|
||||
theorem push_inj_left {a : α} {xs ys : Array α} : xs.push a = ys.push a ↔ xs = ys :=
|
||||
⟨pop_eq_of_push_eq, fun h => by simp [h]⟩
|
||||
@@ -258,15 +259,6 @@ theorem push_inj_left {a : α} {xs ys : Array α} : xs.push a = ys.push a ↔ xs
|
||||
theorem push_inj_right {a b : α} {xs : Array α} : xs.push a = xs.push b ↔ a = b :=
|
||||
⟨back_eq_of_push_eq, fun h => by simp [h]⟩
|
||||
|
||||
theorem push_eq_push {a b : α} {xs ys : Array α} : xs.push a = ys.push b ↔ a = b ∧ xs = ys := by
|
||||
constructor
|
||||
· intro h
|
||||
exact ⟨back_eq_of_push_eq h, pop_eq_of_push_eq h⟩
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
rfl
|
||||
|
||||
theorem push_eq_append_singleton {as : Array α} {x : α} : as.push x = as ++ #[x] := rfl
|
||||
|
||||
theorem exists_push_of_ne_empty {xs : Array α} (h : xs ≠ #[]) :
|
||||
∃ (ys : Array α) (a : α), xs = ys.push a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -317,41 +309,23 @@ theorem singleton_inj : #[a] = #[b] ↔ a = b := by
|
||||
@[simp, grind =] theorem size_replicate {n : Nat} {v : α} : (replicate n v).size = n :=
|
||||
List.length_replicate ..
|
||||
|
||||
@[deprecated size_replicate (since := "2025-03-18")]
|
||||
abbrev size_mkArray := @size_replicate
|
||||
|
||||
@[simp] theorem toList_replicate : (replicate n a).toList = List.replicate n a := by
|
||||
simp only [replicate]
|
||||
|
||||
@[deprecated toList_replicate (since := "2025-03-18")]
|
||||
abbrev toList_mkArray := @toList_replicate
|
||||
|
||||
@[simp, grind =] theorem replicate_zero : replicate 0 a = #[] := rfl
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-03-18")]
|
||||
abbrev mkArray_zero := @replicate_zero
|
||||
|
||||
@[grind =]
|
||||
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
|
||||
apply toList_inj.1
|
||||
simp [List.replicate_succ']
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-03-18")]
|
||||
abbrev mkArray_succ := @replicate_succ
|
||||
|
||||
@[simp, grind =] theorem getElem_replicate {n : Nat} {v : α} {i : Nat} (h : i < (replicate n v).size) :
|
||||
(replicate n v)[i] = v := by simp [← getElem_toList]
|
||||
|
||||
@[deprecated getElem_replicate (since := "2025-03-18")]
|
||||
abbrev getElem_mkArray := @getElem_replicate
|
||||
|
||||
@[grind =] theorem getElem?_replicate {n : Nat} {v : α} {i : Nat} :
|
||||
(replicate n v)[i]? = if i < n then some v else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[deprecated getElem?_replicate (since := "2025-03-18")]
|
||||
abbrev getElem?_mkArray := @getElem?_replicate
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[grind ←]
|
||||
@@ -835,6 +809,11 @@ theorem contains_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : Array α} (
|
||||
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
elem a xs = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
|
||||
@[grind =]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
|
||||
@[deprecated contains_iff_mem (since := "2025-10-26")]
|
||||
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
xs.contains a = true ↔ a ∈ xs := ⟨mem_of_contains_eq_true, contains_eq_true_of_mem⟩
|
||||
|
||||
@@ -1074,12 +1053,6 @@ theorem mem_or_eq_of_mem_setIfInBounds
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated beq_empty_eq (since := "2025-04-04")]
|
||||
abbrev beq_empty_iff := @beq_empty_eq
|
||||
|
||||
@[deprecated empty_beq_eq (since := "2025-04-04")]
|
||||
abbrev empty_beq_iff := @empty_beq_eq
|
||||
|
||||
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {xs ys : Array α} :
|
||||
(xs.push a == ys.push b) = (xs == ys && a == b) := by
|
||||
cases xs
|
||||
@@ -1100,9 +1073,6 @@ theorem size_eq_of_beq [BEq α] {xs ys : Array α} (h : xs == ys) : xs.size = ys
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp +contextual
|
||||
|
||||
@[deprecated replicate_beq_replicate (since := "2025-03-18")]
|
||||
abbrev mkArray_beq_mkArray := @replicate_beq_replicate
|
||||
|
||||
private theorem beq_of_beq_singleton [BEq α] {a b : α} : #[a] == #[b] → a == b := by
|
||||
intro h
|
||||
have : isEqv #[a] #[b] BEq.beq = true := h
|
||||
@@ -1166,7 +1136,7 @@ where
|
||||
aux (i bs) :
|
||||
mapM.map f xs i bs = (xs.toList.drop i).foldlM (fun bs a => bs.push <$> f a) bs := by
|
||||
unfold mapM.map; split
|
||||
· rw [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
· rw [← List.getElem_cons_drop ‹_›]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, List.foldlM_cons, bind_assoc,
|
||||
pure_bind]
|
||||
rfl
|
||||
@@ -1658,12 +1628,15 @@ theorem filterMap_eq_filter {p : α → Bool} (w : stop = as.size) :
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {xs : Array α} :
|
||||
filterMap g (filterMap f xs) = filterMap (fun x => (f x).bind g) xs := by
|
||||
cases xs
|
||||
simp [List.filterMap_filterMap]
|
||||
|
||||
grind_pattern filterMap_filterMap => filterMap g (filterMap f xs) where
|
||||
f =/= some
|
||||
g =/= some
|
||||
|
||||
@[grind =]
|
||||
theorem map_filterMap {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
map g (filterMap f xs) = filterMap (fun x => (f x).map g) xs := by
|
||||
@@ -1718,9 +1691,6 @@ theorem forall_none_of_filterMap_eq_empty (h : filterMap f xs = #[]) : ∀ x ∈
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated filterMap_eq_empty_iff (since := "2025-04-04")]
|
||||
abbrev filterMap_eq_nil_iff := @filterMap_eq_empty_iff
|
||||
|
||||
theorem filterMap_eq_push_iff {f : α → Option β} {xs : Array α} {ys : Array β} {b : β} :
|
||||
filterMap f xs = ys.push b ↔ ∃ as a bs,
|
||||
xs = as.push a ++ bs ∧ filterMap f as = ys ∧ f a = some b ∧ (∀ x, x ∈ bs → f x = none) := by
|
||||
@@ -1883,6 +1853,9 @@ theorem getElem_of_append {xs ys zs : Array α} (eq : xs = ys.push a ++ zs) (h :
|
||||
|
||||
theorem push_eq_append {a : α} {as : Array α} : as.push a = as ++ #[a] := rfl
|
||||
|
||||
@[deprecated push_eq_append (since := "2025-10-26")]
|
||||
theorem push_eq_append_singleton {as : Array α} {x : α} : as.push x = as ++ #[x] := rfl
|
||||
|
||||
theorem append_inj {xs₁ xs₂ ys₁ ys₂ : Array α} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) :
|
||||
xs₁ = xs₂ ∧ ys₁ = ys₂ := by
|
||||
rcases xs₁ with ⟨s₁⟩
|
||||
@@ -2083,11 +2056,22 @@ theorem append_eq_map_iff {f : α → β} :
|
||||
| nil => simp
|
||||
| cons as => induction as.toList <;> simp [*]
|
||||
|
||||
@[simp] theorem flatten_toArray_map {L : List (List α)} :
|
||||
@[simp] theorem flatten_toArray_map_toArray {L : List (List α)} :
|
||||
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
|
||||
apply ext'
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[deprecated flatten_toArray_map_toArray (since := "2025-10-26")]
|
||||
theorem flatten_toArray_map {L : List (List α)} :
|
||||
(L.map List.toArray).toArray.flatten = L.flatten.toArray := by
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem flatten_map_toArray_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
simp
|
||||
|
||||
@[deprecated flatten_map_toArray_toArray (since := "2025-10-26")]
|
||||
theorem flatten_map_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
simp
|
||||
@@ -2134,32 +2118,33 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Array (Array α)} :
|
||||
|
||||
theorem flatten_eq_flatMap {xss : Array (Array α)} : flatten xss = xss.flatMap id := by
|
||||
induction xss using array₂_induction
|
||||
rw [flatten_toArray_map, List.flatten_eq_flatMap]
|
||||
rw [flatten_toArray_map_toArray, List.flatten_eq_flatMap]
|
||||
simp [List.flatMap_map]
|
||||
|
||||
@[simp, grind _=_] theorem map_flatten {f : α → β} {xss : Array (Array α)} :
|
||||
(flatten xss).map f = (map (map f) xss).flatten := by
|
||||
induction xss using array₂_induction with
|
||||
| of xss =>
|
||||
simp only [flatten_toArray_map, List.map_toArray, List.map_flatten, List.map_map,
|
||||
simp only [flatten_toArray_map_toArray, List.map_toArray, List.map_flatten, List.map_map,
|
||||
Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map_toArray]
|
||||
|
||||
@[simp, grind =] theorem filterMap_flatten {f : α → Option β} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filterMap f (flatten xss) 0 stop = flatten (map (filterMap f) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filterMap_toArray',
|
||||
List.filterMap_flatten, List.map_toArray, List.map_map, Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
|
||||
List.filterMap_toArray', List.filterMap_flatten, List.map_toArray, List.map_map,
|
||||
Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map_toArray]
|
||||
|
||||
@[simp, grind =] theorem filter_flatten {p : α → Bool} {xss : Array (Array α)} {stop : Nat} (w : stop = xss.flatten.size) :
|
||||
filter p (flatten xss) 0 stop = flatten (map (filter p) xss) := by
|
||||
subst w
|
||||
induction xss using array₂_induction
|
||||
simp only [flatten_toArray_map, List.size_toArray, List.length_flatten, List.filter_toArray',
|
||||
List.filter_flatten, List.map_toArray, List.map_map, Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
simp only [flatten_toArray_map_toArray, List.size_toArray, List.length_flatten,
|
||||
List.filter_toArray', List.filter_flatten, List.map_toArray, List.map_map, Function.comp_def]
|
||||
rw [← Function.comp_def, ← List.map_map, flatten_toArray_map_toArray]
|
||||
|
||||
theorem flatten_filter_not_isEmpty {xss : Array (Array α)} :
|
||||
flatten (xss.filter fun xs => !xs.isEmpty) = xss.flatten := by
|
||||
@@ -2182,23 +2167,23 @@ theorem flatten_filter_ne_empty [DecidablePred fun xs : Array α => xs ≠ #[]]
|
||||
induction xss using array₂_induction
|
||||
rcases xs with ⟨l⟩
|
||||
have this : [l.toArray] = [l].map List.toArray := by simp
|
||||
simp only [List.push_toArray, flatten_toArray_map, List.append_toArray]
|
||||
rw [this, ← List.map_append, flatten_toArray_map]
|
||||
simp only [List.push_toArray, flatten_toArray_map_toArray, List.append_toArray]
|
||||
rw [this, ← List.map_append, flatten_toArray_map_toArray]
|
||||
simp
|
||||
|
||||
theorem flatten_flatten {xss : Array (Array (Array α))} : flatten (flatten xss) = flatten (map flatten xss) := by
|
||||
induction xss using array₃_induction with
|
||||
| of xss =>
|
||||
rw [flatten_toArray_map]
|
||||
rw [flatten_toArray_map_toArray]
|
||||
have : (xss.map (fun xs => xs.map List.toArray)).flatten = xss.flatten.map List.toArray := by
|
||||
induction xss with
|
||||
| nil => simp
|
||||
| cons xs xss ih =>
|
||||
simp only [List.map_cons, List.flatten_cons, ih, List.map_append]
|
||||
rw [this, flatten_toArray_map, List.flatten_flatten, ← List.map_toArray, Array.map_map,
|
||||
rw [this, flatten_toArray_map_toArray, List.flatten_flatten, ← List.map_toArray, Array.map_map,
|
||||
← List.map_toArray, map_map, Function.comp_def]
|
||||
simp only [Function.comp_apply, flatten_toArray_map]
|
||||
rw [List.map_toArray, ← Function.comp_def, ← List.map_map, flatten_toArray_map]
|
||||
simp only [Function.comp_apply, flatten_toArray_map_toArray]
|
||||
rw [List.map_toArray, ← Function.comp_def, ← List.map_map, flatten_toArray_map_toArray]
|
||||
|
||||
theorem flatten_eq_push_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
|
||||
xss.flatten = ys.push y ↔
|
||||
@@ -2207,13 +2192,13 @@ theorem flatten_eq_push_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
|
||||
induction xss using array₂_induction with
|
||||
| of xs =>
|
||||
rcases ys with ⟨ys⟩
|
||||
rw [flatten_toArray_map, List.push_toArray, mk.injEq, List.flatten_eq_append_iff]
|
||||
rw [flatten_toArray_map_toArray, List.push_toArray, mk.injEq, List.flatten_eq_append_iff]
|
||||
constructor
|
||||
· rintro (⟨as, bs, rfl, rfl, h⟩ | ⟨as, bs, c, cs, ds, rfl, rfl, h⟩)
|
||||
· rw [List.singleton_eq_flatten_iff] at h
|
||||
obtain ⟨xs, ys, rfl, h₁, h₂⟩ := h
|
||||
exact ⟨((as ++ xs).map List.toArray).toArray, #[], (ys.map List.toArray).toArray, by simp,
|
||||
by simpa using h₂, by rw [flatten_toArray_map]; simpa⟩
|
||||
by simpa using h₂, by rw [flatten_toArray_map_toArray]; simpa⟩
|
||||
· rw [List.singleton_eq_append_iff] at h
|
||||
obtain (⟨h₁, h₂⟩ | ⟨h₁, h₂⟩) := h
|
||||
· simp at h₁
|
||||
@@ -2246,8 +2231,8 @@ theorem push_eq_flatten_iff {xss : Array (Array α)} {ys : Array α} {y : α} :
|
||||
-- zs = cs ++ ds.flatten := by sorry
|
||||
|
||||
|
||||
/-- Two arrays of subarrays are equal iff their flattens coincide, as well as the sizes of the
|
||||
subarrays. -/
|
||||
/-- Two arrays of arrays are equal iff their flattens coincide, as well as the sizes of the
|
||||
arrays. -/
|
||||
theorem eq_iff_flatten_eq {xss₁ xss₂ : Array (Array α)} :
|
||||
xss₁ = xss₂ ↔ xss₁.flatten = xss₂.flatten ∧ map size xss₁ = map size xss₂ := by
|
||||
cases xss₁ using array₂_induction with
|
||||
@@ -2258,18 +2243,12 @@ theorem eq_iff_flatten_eq {xss₁ xss₂ : Array (Array α)} :
|
||||
rw [List.map_inj_right]
|
||||
simp +contextual
|
||||
|
||||
theorem flatten_toArray_map_toArray {xss : List (List α)} :
|
||||
(xss.map List.toArray).toArray.flatten = xss.flatten.toArray := by
|
||||
simp
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
theorem flatMap_def {xs : Array α} {f : α → Array β} : xs.flatMap f = flatten (map f xs) := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [flatten_toArray, Function.comp_def, List.flatMap_def]
|
||||
|
||||
@[simp, grind =] theorem flatMap_empty {β} {f : α → Array β} : (#[] : Array α).flatMap f = #[] := rfl
|
||||
|
||||
theorem flatMap_toList {xs : Array α} {f : α → List β} :
|
||||
xs.toList.flatMap f = (xs.flatMap (fun a => (f a).toArray)).toList := by
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -2280,6 +2259,7 @@ theorem flatMap_toList {xs : Array α} {f : α → List β} :
|
||||
rcases xs with ⟨l⟩
|
||||
simp
|
||||
|
||||
@[deprecated List.flatMap_toArray_cons (since := "2025-10-29")]
|
||||
theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α} :
|
||||
(a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f := by
|
||||
simp [flatMap]
|
||||
@@ -2290,6 +2270,7 @@ theorem flatMap_toArray_cons {β} {f : α → Array β} {a : α} {as : List α}
|
||||
intro cs
|
||||
induction as generalizing cs <;> simp_all
|
||||
|
||||
@[deprecated List.flatMap_toArray (since := "2025-10-29")]
|
||||
theorem flatMap_toArray {β} {f : α → Array β} {as : List α} :
|
||||
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
|
||||
simp
|
||||
@@ -2390,77 +2371,44 @@ theorem flatMap_eq_foldl {f : α → Array β} {xs : Array α} :
|
||||
|
||||
@[simp] theorem replicate_one : replicate 1 a = #[a] := rfl
|
||||
|
||||
@[deprecated replicate_one (since := "2025-03-18")]
|
||||
abbrev mkArray_one := @replicate_one
|
||||
|
||||
/-- Variant of `replicate_succ` that prepends `a` at the beginning of the array. -/
|
||||
theorem replicate_succ' : replicate (n + 1) a = #[a] ++ replicate n a := by
|
||||
apply Array.ext'
|
||||
simp [List.replicate_succ]
|
||||
|
||||
@[deprecated replicate_succ' (since := "2025-03-18")]
|
||||
abbrev mkArray_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [List.mem_toArray, List.mem_replicate]
|
||||
|
||||
@[deprecated mem_replicate (since := "2025-03-18")]
|
||||
abbrev mem_mkArray := @mem_replicate
|
||||
|
||||
@[grind →] theorem eq_of_mem_replicate {a b : α} {n} (h : b ∈ replicate n a) : b = a := (mem_replicate.1 h).2
|
||||
|
||||
@[deprecated eq_of_mem_mkArray (since := "2025-03-18")]
|
||||
abbrev eq_of_mem_mkArray := @eq_of_mem_replicate
|
||||
|
||||
theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
(∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a := by
|
||||
cases n <;> simp [mem_replicate]
|
||||
|
||||
@[deprecated forall_mem_replicate (since := "2025-03-18")]
|
||||
abbrev forall_mem_mkArray := @forall_mem_replicate
|
||||
|
||||
@[simp] theorem replicate_succ_ne_empty {n : Nat} {a : α} : replicate (n+1) a ≠ #[] := by
|
||||
simp [replicate_succ]
|
||||
|
||||
@[deprecated replicate_succ_ne_empty (since := "2025-03-18")]
|
||||
abbrev mkArray_succ_ne_empty := @replicate_succ_ne_empty
|
||||
|
||||
@[simp] theorem replicate_eq_empty_iff {n : Nat} {a : α} : replicate n a = #[] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated replicate_eq_empty_iff (since := "2025-03-18")]
|
||||
abbrev mkArray_eq_empty_iff := @replicate_eq_empty_iff
|
||||
|
||||
@[simp] theorem replicate_inj : replicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b) := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated replicate_inj (since := "2025-03-18")]
|
||||
abbrev mkArray_inj := @replicate_inj
|
||||
|
||||
theorem eq_replicate_of_mem {a : α} {xs : Array α} (h : ∀ (b) (_ : b ∈ xs), b = a) : xs = replicate xs.size a := by
|
||||
rw [← toList_inj]
|
||||
simpa using List.eq_replicate_of_mem (by simpa using h)
|
||||
|
||||
@[deprecated eq_replicate_of_mem (since := "2025-03-18")]
|
||||
abbrev eq_mkArray_of_mem := @eq_replicate_of_mem
|
||||
|
||||
theorem eq_replicate_iff {a : α} {n} {xs : Array α} :
|
||||
xs = replicate n a ↔ xs.size = n ∧ ∀ (b) (_ : b ∈ xs), b = a := by
|
||||
rw [← toList_inj]
|
||||
simpa using List.eq_replicate_iff (l := xs.toList)
|
||||
|
||||
@[deprecated eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev eq_mkArray_iff := @eq_replicate_iff
|
||||
|
||||
theorem map_eq_replicate_iff {xs : Array α} {f : α → β} {b : β} :
|
||||
xs.map f = replicate xs.size b ↔ ∀ x ∈ xs, f x = b := by
|
||||
simp [eq_replicate_iff]
|
||||
|
||||
@[deprecated map_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev map_eq_mkArray_iff := @map_eq_replicate_iff
|
||||
|
||||
@[simp] theorem map_const {xs : Array α} {b : β} : map (Function.const α b) xs = replicate xs.size b :=
|
||||
map_eq_replicate_iff.mpr fun _ _ => rfl
|
||||
|
||||
@@ -2477,143 +2425,86 @@ theorem map_const' {xs : Array α} {b : β} : map (fun _ => b) xs = replicate xs
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated set_replicate_self (since := "2025-03-18")]
|
||||
abbrev set_mkArray_self := @set_replicate_self
|
||||
|
||||
@[simp] theorem setIfInBounds_replicate_self : (replicate n a).setIfInBounds i a = replicate n a := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated setIfInBounds_replicate_self (since := "2025-03-18")]
|
||||
abbrev setIfInBounds_mkArray_self := @setIfInBounds_replicate_self
|
||||
|
||||
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-03-18")]
|
||||
abbrev mkArray_append_mkArray := @replicate_append_replicate
|
||||
|
||||
theorem append_eq_replicate_iff {xs ys : Array α} {a : α} :
|
||||
xs ++ ys = replicate n a ↔
|
||||
xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
|
||||
simp [← toList_inj, List.append_eq_replicate_iff]
|
||||
|
||||
@[deprecated append_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev append_eq_mkArray_iff := @append_eq_replicate_iff
|
||||
|
||||
theorem replicate_eq_append_iff {xs ys : Array α} {a : α} :
|
||||
replicate n a = xs ++ ys ↔
|
||||
xs.size + ys.size = n ∧ xs = replicate xs.size a ∧ ys = replicate ys.size a := by
|
||||
rw [eq_comm, append_eq_replicate_iff]
|
||||
|
||||
@[deprecated replicate_eq_append_iff (since := "2025-03-18")]
|
||||
abbrev replicate_eq_mkArray_iff := @replicate_eq_append_iff
|
||||
|
||||
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
|
||||
apply Array.ext'
|
||||
simp
|
||||
|
||||
@[deprecated map_replicate (since := "2025-03-18")]
|
||||
abbrev map_mkArray := @map_replicate
|
||||
|
||||
@[grind =] theorem filter_replicate (w : stop = n) :
|
||||
(replicate n a).filter p 0 stop = if p a then replicate n a else #[] := by
|
||||
apply Array.ext'
|
||||
simp only [w]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filter_replicate (since := "2025-03-18")]
|
||||
abbrev filter_mkArray := @filter_replicate
|
||||
|
||||
@[simp] theorem filter_replicate_of_pos (w : stop = n) (h : p a) :
|
||||
(replicate n a).filter p 0 stop = replicate n a := by
|
||||
simp [filter_replicate, h, w]
|
||||
|
||||
@[deprecated filter_replicate_of_pos (since := "2025-03-18")]
|
||||
abbrev filter_mkArray_of_pos := @filter_replicate_of_pos
|
||||
|
||||
@[simp] theorem filter_replicate_of_neg (w : stop = n) (h : ¬ p a) :
|
||||
(replicate n a).filter p 0 stop = #[] := by
|
||||
simp [filter_replicate, h, w]
|
||||
|
||||
@[deprecated filter_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev filter_mkArray_of_neg := @filter_replicate_of_neg
|
||||
|
||||
theorem filterMap_replicate {f : α → Option β} (w : stop = n := by simp) :
|
||||
(replicate n a).filterMap f 0 stop = match f a with | none => #[] | .some b => replicate n b := by
|
||||
apply Array.ext'
|
||||
simp only [w, size_replicate, toList_filterMap', toList_replicate, List.filterMap_replicate]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filterMap_replicate (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray := @filterMap_replicate
|
||||
|
||||
-- This is not a useful `simp` lemma because `b` is unknown.
|
||||
theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
|
||||
(replicate n a).filterMap f = replicate n b := by
|
||||
simp [filterMap_replicate, h]
|
||||
|
||||
@[deprecated filterMap_replicate_of_some (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_some := @filterMap_replicate_of_some
|
||||
|
||||
@[simp] theorem filterMap_replicate_of_isSome {f : α → Option β} (h : (f a).isSome) :
|
||||
(replicate n a).filterMap f = replicate n (Option.get _ h) := by
|
||||
match w : f a, h with
|
||||
| some b, _ => simp [filterMap_replicate, w]
|
||||
|
||||
@[deprecated filterMap_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_isSome := @filterMap_replicate_of_isSome
|
||||
|
||||
@[simp] theorem filterMap_replicate_of_none {f : α → Option β} (h : f a = none) :
|
||||
(replicate n a).filterMap f = #[] := by
|
||||
simp [filterMap_replicate, h]
|
||||
|
||||
@[deprecated filterMap_replicate_of_none (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_none := @filterMap_replicate_of_none
|
||||
|
||||
@[simp] theorem flatten_replicate_empty : (replicate n (#[] : Array α)).flatten = #[] := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_empty (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_empty := @flatten_replicate_empty
|
||||
|
||||
@[simp] theorem flatten_replicate_singleton : (replicate n #[a]).flatten = replicate n a := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_singleton (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_singleton := @flatten_replicate_singleton
|
||||
|
||||
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated flatten_replicate_replicate (since := "2025-03-18")]
|
||||
abbrev flatten_mkArray_replicate := @flatten_replicate_replicate
|
||||
|
||||
theorem flatMap_replicate {f : α → Array β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
|
||||
rw [← toList_inj]
|
||||
simp [List.flatMap_replicate]
|
||||
|
||||
@[deprecated flatMap_replicate (since := "2025-03-18")]
|
||||
abbrev flatMap_mkArray := @flatMap_replicate
|
||||
|
||||
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
|
||||
rw [← List.toArray_replicate, List.isEmpty_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated isEmpty_replicate (since := "2025-03-18")]
|
||||
abbrev isEmpty_mkArray := @isEmpty_replicate
|
||||
|
||||
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
|
||||
rw [← List.toArray_replicate, List.sum_toArray]
|
||||
simp
|
||||
|
||||
@[deprecated sum_replicate_nat (since := "2025-03-18")]
|
||||
abbrev sum_mkArray_nat := @sum_replicate_nat
|
||||
|
||||
/-! ### Preliminaries about `swap` needed for `reverse`. -/
|
||||
|
||||
@[grind =]
|
||||
@@ -2655,8 +2546,8 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
split <;> rename_i h₃
|
||||
· simp only [← h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
|
||||
exact (List.getElem?_reverse' (Eq.trans (by simp +arith) h)).symm
|
||||
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
|
||||
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
|
||||
simp only [Nat.succ_le_iff, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
|
||||
Nat.lt_succ_iff.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
|
||||
· rw [H]; split <;> rename_i h₂
|
||||
· cases Nat.le_antisymm (Nat.not_lt.1 h₁) (Nat.le_trans h₂.1 h₂.2)
|
||||
cases Nat.le_antisymm h₂.1 h₂.2
|
||||
@@ -2671,7 +2562,7 @@ theorem getElem?_swap {xs : Array α} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i
|
||||
split
|
||||
· rfl
|
||||
· rename_i h
|
||||
simp only [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := xs.size - 1), this, Nat.zero_le,
|
||||
simp only [← show k < _ + 1 ↔ _ from Nat.lt_succ_iff (n := xs.size - 1), this, Nat.zero_le,
|
||||
true_and, Nat.not_lt] at h
|
||||
rw [List.getElem?_eq_none_iff.2 ‹_›, List.getElem?_eq_none_iff.2 (xs.toList.length_reverse ▸ ‹_›)]
|
||||
|
||||
@@ -2800,9 +2691,6 @@ theorem flatten_reverse {xss : Array (Array α)} :
|
||||
rw [← toList_inj]
|
||||
simp
|
||||
|
||||
@[deprecated reverse_replicate (since := "2025-03-18")]
|
||||
abbrev reverse_mkArray := @reverse_replicate
|
||||
|
||||
/-! ### extract -/
|
||||
|
||||
theorem extract_loop_zero {xs ys : Array α} {start : Nat} : extract.loop xs 0 start ys = ys := by
|
||||
@@ -2822,8 +2710,8 @@ theorem extract_loop_eq_aux {xs ys : Array α} {size start : Nat} :
|
||||
| zero => rw [extract_loop_zero, extract_loop_zero, append_empty]
|
||||
| succ size ih =>
|
||||
if h : start < xs.size then
|
||||
rw [extract_loop_succ (h := h), ih, push_eq_append_singleton]
|
||||
rw [extract_loop_succ (h := h), ih (ys := #[].push _), push_eq_append_singleton, empty_append]
|
||||
rw [extract_loop_succ (h := h), ih, push_eq_append]
|
||||
rw [extract_loop_succ (h := h), ih (ys := #[].push _), push_eq_append, empty_append]
|
||||
rw [append_assoc]
|
||||
else
|
||||
rw [extract_loop_of_ge (h := Nat.le_of_not_lt h)]
|
||||
@@ -3440,6 +3328,16 @@ theorem foldr_filterMap {f : α → Option β} {g : β → γ → γ} {xs : Arra
|
||||
(xs.filterMap f).foldr g init = xs.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
|
||||
simp [foldr_filterMap']
|
||||
|
||||
theorem foldl_flatMap {f : α → Array β} {g : γ → β → γ} {xs : Array α} {init : γ} :
|
||||
(xs.flatMap f).foldl g init = xs.foldl (fun acc x => (f x).foldl g acc) init := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.foldl_flatMap]
|
||||
|
||||
theorem foldr_flatMap {f : α → Array β} {g : β → γ → γ} {xs : Array α} {init : γ} :
|
||||
(xs.flatMap f).foldr g init = xs.foldr (fun x acc => (f x).foldr g acc) init := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.foldr_flatMap]
|
||||
|
||||
theorem foldl_map_hom' {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {xs : Array α}
|
||||
{stop : Nat} (h : ∀ x y, f' (g x) (g y) = g (f x y)) (w : stop = xs.size) :
|
||||
(xs.map g).foldl f' (g a) 0 stop = g (xs.foldl f a) := by
|
||||
@@ -3712,15 +3610,9 @@ theorem back?_replicate {a : α} {n : Nat} :
|
||||
rw [replicate_eq_toArray_replicate]
|
||||
simp only [List.back?_toArray, List.getLast?_replicate]
|
||||
|
||||
@[deprecated back?_replicate (since := "2025-03-18")]
|
||||
abbrev back?_mkArray := @back?_replicate
|
||||
|
||||
@[simp] theorem back_replicate {xs : Array α} (w : 0 < n) : (replicate n xs).back (by simpa using w) = xs := by
|
||||
simp [back_eq_getElem]
|
||||
|
||||
@[deprecated back_replicate (since := "2025-03-18")]
|
||||
abbrev back_mkArray := @back_replicate
|
||||
|
||||
/-! ## Additional operations -/
|
||||
|
||||
/-! ### leftpad -/
|
||||
@@ -3738,9 +3630,6 @@ theorem size_rightpad {n : Nat} {a : α} {xs : Array α} :
|
||||
|
||||
theorem elem_push_self [BEq α] [LawfulBEq α] {xs : Array α} {a : α} : (xs.push a).elem a = true := by simp
|
||||
|
||||
@[deprecated elem_push_self (since := "2025-04-04")]
|
||||
abbrev elem_cons_self := @elem_push_self
|
||||
|
||||
theorem contains_eq_any_beq [BEq α] {xs : Array α} {a : α} : xs.contains a = xs.any (a == ·) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.contains_eq_any_beq]
|
||||
@@ -3754,11 +3643,6 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Array α} {a : α} :
|
||||
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
|
||||
grind_pattern contains_iff_exists_mem_beq => xs.contains a
|
||||
|
||||
@[grind =]
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.contains a ↔ a ∈ xs := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem contains_toList [BEq α] {xs : Array α} {x : α} :
|
||||
xs.toList.contains x = xs.contains x := by
|
||||
@@ -3818,9 +3702,6 @@ theorem pop_append {xs ys : Array α} :
|
||||
@[simp, grind =] theorem pop_replicate {n : Nat} {a : α} : (replicate n a).pop = replicate (n - 1) a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated pop_replicate (since := "2025-03-18")]
|
||||
abbrev pop_mkArray := @pop_replicate
|
||||
|
||||
/-! ## Logic -/
|
||||
|
||||
/-! ### any / all -/
|
||||
@@ -4050,16 +3931,10 @@ theorem all_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
(replicate n a).any f = if n = 0 then false else f a := by
|
||||
induction n <;> simp_all [replicate_succ']
|
||||
|
||||
@[deprecated any_replicate (since := "2025-03-18")]
|
||||
abbrev any_mkArray := @any_replicate
|
||||
|
||||
@[simp] theorem all_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).all f = if n = 0 then true else f a := by
|
||||
induction n <;> simp_all +contextual [replicate_succ']
|
||||
|
||||
@[deprecated all_replicate (since := "2025-03-18")]
|
||||
abbrev all_mkArray := @all_replicate
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp, grind =] theorem size_modify {xs : Array α} {i : Nat} {f : α → α} : (xs.modify i f).size = xs.size := by
|
||||
@@ -4234,17 +4109,11 @@ theorem replace_extract {xs : Array α} {i : Nat} :
|
||||
(replicate n a).replace a b = #[b] ++ replicate (n - 1) a := by
|
||||
cases n <;> simp_all [replicate_succ', replace_append]
|
||||
|
||||
@[deprecated replace_replicate_self (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_self := @replace_replicate_self
|
||||
|
||||
@[simp] theorem replace_replicate_ne {a b c : α} (h : !b == a) :
|
||||
(replicate n a).replace b c = replicate n a := by
|
||||
rw [replace_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[deprecated replace_replicate_ne (since := "2025-03-18")]
|
||||
abbrev replace_mkArray_ne := @replace_replicate_ne
|
||||
|
||||
end replace
|
||||
|
||||
/-! ### toListRev -/
|
||||
@@ -4412,9 +4281,6 @@ theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i
|
||||
@[deprecated mem_toList_iff (since := "2025-05-26")]
|
||||
theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs := mem_def.symm
|
||||
|
||||
@[deprecated not_mem_empty (since := "2025-03-25")]
|
||||
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||
|
||||
/-! # get lemmas -/
|
||||
|
||||
theorem lt_of_getElem {x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) :
|
||||
@@ -4426,6 +4292,7 @@ theorem getElem_fin_eq_getElem_toList {xs : Array α} {i : Fin xs.size} : xs[i]
|
||||
@[simp] theorem ugetElem_eq_getElem {xs : Array α} {i : USize} (h : i.toNat < xs.size) :
|
||||
xs[i] = xs[i.toNat] := rfl
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2025-10-26")]
|
||||
theorem getElem?_size_le {xs : Array α} {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [getElem?_neg, h]
|
||||
|
||||
@@ -4445,6 +4312,7 @@ theorem getElem?_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
|
||||
(xs.push x)[i]? = some xs[i] := by
|
||||
rw [getElem?_pos (xs.push x) i (size_push _ ▸ Nat.lt_succ_of_lt h), getElem_push_lt]
|
||||
|
||||
@[deprecated getElem?_push_size (since := "2025-10-26")]
|
||||
theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x := by
|
||||
rw [getElem?_pos (xs.push x) xs.size (size_push _ ▸ Nat.lt_succ_self xs.size), getElem_push_eq]
|
||||
|
||||
@@ -4463,12 +4331,6 @@ theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ### contains -/
|
||||
|
||||
@[deprecated contains_iff (since := "2025-04-07")]
|
||||
abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a ↔ a ∈ xs :=
|
||||
contains_iff
|
||||
|
||||
/-! ### isPrefixOf -/
|
||||
|
||||
@[simp, grind =] theorem isPrefixOf_toList [BEq α] {xs ys : Array α} :
|
||||
@@ -4582,7 +4444,8 @@ theorem uset_toArray {l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem flatten_toArray {L : List (List α)} :
|
||||
@[deprecated Array.flatten_map_toArray_toArray (since := "2025-10-26")]
|
||||
theorem flatten_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@@ -34,7 +34,18 @@ grind_pattern _root_.List.le_toArray => l₁.toArray ≤ l₂.toArray
|
||||
grind_pattern lt_toList => xs.toList < ys.toList
|
||||
grind_pattern le_toList => xs.toList ≤ ys.toList
|
||||
|
||||
@[simp]
|
||||
protected theorem not_lt [LT α] {xs ys : Array α} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
|
||||
@[deprecated Array.not_lt (since := "2025-10-26")]
|
||||
protected theorem not_lt_iff_ge [LT α] {xs ys : Array α} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
|
||||
@[simp]
|
||||
protected theorem not_le [LT α] {xs ys : Array α} :
|
||||
¬ xs ≤ ys ↔ ys < xs :=
|
||||
Classical.not_not
|
||||
|
||||
@[deprecated Array.not_le (since := "2025-10-26")]
|
||||
protected theorem not_le_iff_gt [LT α] {xs ys : Array α} :
|
||||
¬ xs ≤ ys ↔ ys < xs :=
|
||||
Classical.not_not
|
||||
@@ -64,11 +75,11 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
Nat.add_min_add_left, Nat.add_lt_add_iff_left, Std.Rco.forIn'_eq_forIn'_toList]
|
||||
conv =>
|
||||
lhs; congr; congr
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.Rco.toList_eq_if rfl (fun _ _ _ => rfl)]
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.Rco.toList_eq_if_roo rfl (fun _ _ _ => rfl)]
|
||||
simp only [bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.toList_Roo_eq_toList_Rco_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
|
||||
simp only [Std.toList_roo_eq_toList_rco_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_rco_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
@@ -140,7 +151,7 @@ protected theorem lt_of_le_of_lt [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrd
|
||||
@[deprecated Array.lt_of_le_of_lt (since := "2025-08-01")]
|
||||
protected theorem lt_of_le_of_lt' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₂ : Std.Trichotomous (· < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
letI := LE.ofLT α
|
||||
@@ -154,7 +165,7 @@ protected theorem le_trans [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
|
||||
@[deprecated Array.le_trans (since := "2025-08-01")]
|
||||
protected theorem le_trans' [LT α]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[i₂ : Std.Trichotomous (· < · : α → α → Prop)]
|
||||
[i₃ : Trans (¬ · < · : α → α → Prop) (¬ · < ·) (¬ · < ·)]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
letI := LE.ofLT α
|
||||
@@ -178,12 +189,6 @@ protected theorem le_total [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
List.le_total xs.toList ys.toList
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{xs ys : Array α} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le [LT α]
|
||||
{xs ys : Array α} : ¬ ys ≤ xs ↔ xs < ys := Classical.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} (h : xs < ys) : xs ≤ ys :=
|
||||
@@ -191,7 +196,7 @@ protected theorem le_of_lt [LT α]
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Trichotomous (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} : xs ≤ ys ↔ xs < ys ∨ xs = ys := by
|
||||
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
|
||||
@@ -280,7 +285,7 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {xs ys : Array α} :
|
||||
[Std.Trichotomous (· < · : α → α → Prop)] {xs ys : Array α} :
|
||||
xs ≤ ys ↔
|
||||
(xs = ys.take xs.size) ∨
|
||||
(∃ (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
|
||||
@@ -299,7 +304,7 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Trichotomous (· < · : α → α → Prop)]
|
||||
{xs ys zs : Array α} (h : ys ≤ zs) :
|
||||
xs ++ ys ≤ xs ++ zs := by
|
||||
cases xs
|
||||
@@ -322,9 +327,9 @@ protected theorem map_lt [LT α] [LT β]
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Trichotomous (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : β → β → Prop)]
|
||||
[Std.Antisymm (¬ · < · : β → β → Prop)]
|
||||
[Std.Trichotomous (· < · : β → β → Prop)]
|
||||
{xs ys : Array α} {f : α → β} (w : ∀ x y, x < y → f x < f y) (h : xs ≤ ys) :
|
||||
map f xs ≤ map f ys := by
|
||||
cases xs
|
||||
|
||||
@@ -296,9 +296,6 @@ theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h
|
||||
rw [← toList_inj]
|
||||
simp [List.mapFinIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
|
||||
rcases xs with ⟨l⟩
|
||||
@@ -438,9 +435,6 @@ theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β}
|
||||
rw [← toList_inj]
|
||||
simp [List.mapIdx_eq_replicate_iff]
|
||||
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||||
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -84,9 +84,6 @@ theorem Perm.size_eq {xs ys : Array α} (p : xs ~ ys) : xs.size = ys.size := by
|
||||
simp only [perm_iff_toList_perm] at p
|
||||
simpa using p.length_eq
|
||||
|
||||
@[deprecated Perm.size_eq (since := "2025-04-17")]
|
||||
abbrev Perm.length_eq := @Perm.size_eq
|
||||
|
||||
theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a ∈ xs ↔ a ∈ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
@@ -107,7 +104,7 @@ grind_pattern Perm.append => xs ~ ys, as ~ bs, ys ++ bs
|
||||
|
||||
theorem Perm.push (x : α) {xs ys : Array α} (p : xs ~ ys) :
|
||||
xs.push x ~ ys.push x := by
|
||||
rw [push_eq_append_singleton]
|
||||
rw [push_eq_append]
|
||||
exact p.append .rfl
|
||||
|
||||
grind_pattern Perm.push => xs ~ ys, xs.push x
|
||||
|
||||
@@ -166,9 +166,6 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Array α} {bs : Array
|
||||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zipWith_replicate (since := "2025-03-18")]
|
||||
abbrev zipWith_mkArray := @zipWith_replicate
|
||||
|
||||
theorem map_uncurry_zip_eq_zipWith {f : α → β → γ} {as : Array α} {bs : Array β} :
|
||||
map (Function.uncurry f) (as.zip bs) = zipWith f as bs := by
|
||||
cases as
|
||||
@@ -294,9 +291,6 @@ theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
|
||||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zip_replicate (since := "2025-03-18")]
|
||||
abbrev zip_mkArray := @zip_replicate
|
||||
|
||||
theorem zip_eq_zip_take_min {as : Array α} {bs : Array β} :
|
||||
zip as bs = zip (as.take (min as.size bs.size)) (bs.take (min as.size bs.size)) := by
|
||||
cases as
|
||||
@@ -348,9 +342,6 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
|
||||
zipWithAll f (replicate n a) (replicate n b) = replicate n (f (some a) (some b)) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated zipWithAll_replicate (since := "2025-03-18")]
|
||||
abbrev zipWithAll_mkArray := @zipWithAll_replicate
|
||||
|
||||
/-! ### zipWithM -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -408,7 +399,4 @@ theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
@[deprecated unzip_replicate (since := "2025-03-18")]
|
||||
abbrev unzip_mkArray := @unzip_replicate
|
||||
|
||||
end Array
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.UInt
|
||||
public import Init.Data.String.Extra
|
||||
@@ -203,8 +203,8 @@ If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits
|
||||
-- `Internal` string functions by moving this definition out to a separate file that can live
|
||||
-- downstream of `Init.Data.String.Basic`.
|
||||
protected def toHex {n : Nat} (x : BitVec n) : String :=
|
||||
let s := (Nat.toDigits 16 x.toNat).asString
|
||||
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
|
||||
let s := String.ofList (Nat.toDigits 16 x.toNat)
|
||||
let t := String.ofList (List.replicate ((n+3) / 4 - String.Internal.length s) '0')
|
||||
String.Internal.append t s
|
||||
|
||||
/-- `BitVec` representation. -/
|
||||
|
||||
@@ -635,12 +635,11 @@ theorem mulRec_eq_mul_signExtend_setWidth (x y : BitVec w) (s : Nat) :
|
||||
simp only [mulRec_zero_eq, ofNat_eq_ofNat, Nat.reduceAdd]
|
||||
by_cases y.getLsbD 0
|
||||
case pos hy =>
|
||||
simp only [hy, ↓reduceIte, setWidth_one_eq_ofBool_getLsb_zero,
|
||||
ofBool_true, ofNat_eq_ofNat]
|
||||
simp only [hy, ↓reduceIte, setWidth_one, ofBool_true, ofNat_eq_ofNat]
|
||||
rw [setWidth_ofNat_one_eq_ofNat_one_of_lt (by omega)]
|
||||
simp
|
||||
case neg hy =>
|
||||
simp [hy, setWidth_one_eq_ofBool_getLsb_zero]
|
||||
simp [hy, setWidth_one]
|
||||
case succ s' hs =>
|
||||
rw [mulRec_succ_eq, hs]
|
||||
have heq :
|
||||
@@ -1025,7 +1024,7 @@ theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
|
||||
case neg.hrWidth =>
|
||||
simp only
|
||||
have hdr' : d ≤ (qr.r.shiftConcat (n.getLsbD (qr.wn - 1))) :=
|
||||
BitVec.not_lt_iff_le.mp rltd
|
||||
BitVec.not_lt.mp rltd
|
||||
have hr' : ((qr.r.shiftConcat (n.getLsbD (qr.wn - 1)))).toNat < 2 ^ (qr.wr + 1) := by
|
||||
apply toNat_shiftConcat_lt_of_lt <;> bv_omega
|
||||
rw [BitVec.toNat_sub_of_le hdr']
|
||||
@@ -1033,7 +1032,7 @@ theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
|
||||
case neg.hqWidth =>
|
||||
apply toNat_shiftConcat_lt_of_lt <;> omega
|
||||
case neg.hdiv =>
|
||||
have rltd' := (BitVec.not_lt_iff_le.mp rltd)
|
||||
have rltd' := (BitVec.not_lt.mp rltd)
|
||||
simp only [qr.toNat_shiftRight_sub_one_eq h,
|
||||
BitVec.toNat_sub_of_le rltd',
|
||||
toNat_shiftConcat_eq_of_lt (qr.wr_lt_w h) h.hrWidth]
|
||||
@@ -1407,7 +1406,7 @@ theorem eq_iff_eq_of_inv (f : α → BitVec w) (g : BitVec w → α) (h : ∀ x,
|
||||
have := congrArg g h'
|
||||
simpa [h] using this
|
||||
|
||||
@[simp]
|
||||
@[deprecated BitVec.ne_intMin_of_msb_eq_false (since := "2025-10-26")]
|
||||
theorem ne_intMin_of_lt_of_msb_false {x : BitVec w} (hw : 0 < w) (hx : x.msb = false) :
|
||||
x ≠ intMin w := by
|
||||
have := toNat_lt_of_msb_false hx
|
||||
@@ -1512,7 +1511,7 @@ theorem sdiv_ne_intMin_of_ne_intMin {x y : BitVec w} (h : x ≠ intMin w) :
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp only [hx, hy, neg_ne_intMin_inj]
|
||||
<;> simp only [Bool.not_eq_true] at hx hy
|
||||
<;> apply ne_intMin_of_lt_of_msb_false (by omega)
|
||||
<;> apply ne_intMin_of_msb_eq_false (by omega)
|
||||
<;> rw [msb_udiv]
|
||||
<;> try simp only [hx, Bool.false_and]
|
||||
· simp [h, ne_zero_of_msb_true, hx]
|
||||
@@ -1624,7 +1623,7 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w ∨ b ≠ -1
|
||||
· have ry := (intMin_udiv_eq_intMin_iff b).mp
|
||||
simp only [hb1, imp_false] at ry
|
||||
simp [msb_udiv, ha_intMin, hb1, ry, intMin_udiv_ne_zero_of_ne_zero, hb, hb0]
|
||||
· have := @BitVec.ne_intMin_of_lt_of_msb_false w ((-a) / b) wpos (by simp [ha, ha0, ha_intMin])
|
||||
· have := @BitVec.ne_intMin_of_msb_eq_false w wpos ((-a) / b) (by simp [ha, ha0, ha_intMin])
|
||||
simp [msb_neg, h', this, ha, ha_intMin]
|
||||
rw [toInt_eq_toNat_of_msb hb, toInt_eq_neg_toNat_neg_of_msb_true ha, Int.neg_tdiv,
|
||||
Int.tdiv_eq_ediv_of_nonneg (by omega), sdiv_toInt_of_msb_true_of_msb_false]
|
||||
@@ -1635,7 +1634,7 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w ∨ b ≠ -1
|
||||
rw [toInt_udiv_of_msb ha, toInt_eq_toNat_of_msb ha]
|
||||
rw [toInt_eq_neg_toNat_neg_of_msb_true hb, Int.tdiv_neg, Int.tdiv_eq_ediv_of_nonneg (by omega)]
|
||||
· apply sdiv_ne_intMin_of_ne_intMin
|
||||
apply ne_intMin_of_lt_of_msb_false (by omega) ha
|
||||
apply ne_intMin_of_msb_eq_false (by omega) ha
|
||||
· rw [sdiv, Int.tdiv_cases, udiv_eq, neg_eq, if_pos (toInt_nonneg_of_msb_false ha),
|
||||
if_pos (toInt_nonneg_of_msb_false hb), ha, hb, toInt_udiv_of_msb ha,
|
||||
toInt_eq_toNat_of_msb ha, toInt_eq_toNat_of_msb hb]
|
||||
@@ -1927,7 +1926,7 @@ theorem toInt_sub_neg_umod {x y : BitVec w} (hxmsb : x.msb = true) (hymsb : y.ms
|
||||
rw [Int.bmod_eq_of_le (by omega) (by omega)]
|
||||
simp only [toInt_eq_toNat_of_msb hymsb, BitVec.toInt_eq_neg_toNat_neg_of_msb_true hxmsb,
|
||||
Int.dvd_neg] at hdvd
|
||||
simp only [hdvd, ↓reduceIte, Int.natAbs_cast]
|
||||
simp only [hdvd, ↓reduceIte, Int.natAbs_natCast]
|
||||
|
||||
theorem srem_zero_of_dvd {x y : BitVec w} (h : y.toInt ∣ x.toInt) :
|
||||
x.srem y = 0#w := by
|
||||
|
||||
@@ -82,7 +82,7 @@ theorem iunfoldr_getLsbD' {f : Fin w → α → α × Bool} (state : Nat → α)
|
||||
intro i
|
||||
simp only [getLsbD_cons]
|
||||
have hj2 : j.val ≤ w := by simp
|
||||
cases (Nat.lt_or_eq_of_le (Nat.lt_succ.mp i.isLt)) with
|
||||
cases (Nat.lt_or_eq_of_le (Nat.lt_succ_iff.mp i.isLt)) with
|
||||
| inl h3 => simp [(Nat.ne_of_lt h3)]
|
||||
exact (ih hj2).1 ⟨i.val, h3⟩
|
||||
| inr h3 => simp [h3]
|
||||
|
||||
@@ -34,14 +34,6 @@ namespace BitVec
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_ge := @getLsbD_of_ge
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsbD_of_ge (since := "2025-04-04")]
|
||||
abbrev getMsbD_ge := @getMsbD_of_ge
|
||||
|
||||
theorem lt_of_getLsbD {x : BitVec w} {i : Nat} : getLsbD x i = true → i < w := by
|
||||
if h : i < w then
|
||||
simp [h]
|
||||
@@ -72,6 +64,7 @@ theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
|
||||
theorem none_eq_getElem?_iff {l : BitVec w} : none = l[n]? ↔ w ≤ n := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_eq_none {l : BitVec w} (h : w ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
theorem getElem?_eq (l : BitVec w) (i : Nat) :
|
||||
@@ -140,9 +133,6 @@ theorem two_pow_le_toNat_of_getElem_eq_true {i : Nat} {x : BitVec w}
|
||||
rw [← getElem_eq_testBit_toNat x i hi]
|
||||
exact hx
|
||||
|
||||
@[grind =] theorem msb_eq_getMsbD (x : BitVec w) : x.msb = x.getMsbD 0 := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@[grind =] theorem getMsb_eq_getLsb (x : BitVec w) (i : Fin w) :
|
||||
x.getMsb i = x.getLsb ⟨w - 1 - i, by omega⟩ := by
|
||||
simp only [getMsb, getLsb]
|
||||
@@ -169,18 +159,13 @@ theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i <
|
||||
apply getLsbD_of_ge
|
||||
omega
|
||||
|
||||
@[simp] theorem getElem?_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : x[i]? = none := by
|
||||
@[deprecated getElem?_eq_none (since := "2025-10-29")]
|
||||
theorem getElem?_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : x[i]? = none := by
|
||||
simp [ge]
|
||||
|
||||
@[simp] theorem getMsb?_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsb? x i = none := by
|
||||
simp [getMsb?_eq_getLsb?]; omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_of_ge (since := "2025-04-04")] abbrev getLsb?_ge := @getElem?_of_ge
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsb?_of_ge (since := "2025-04-04")] abbrev getMsb?_ge := @getMsb?_of_ge
|
||||
|
||||
theorem lt_of_getElem?_eq_some (x : BitVec w) (i : Nat) : x[i]? = some b → i < w := by
|
||||
cases h : x[i]? with
|
||||
| none => simp
|
||||
@@ -203,18 +188,6 @@ theorem lt_of_isSome_getMsb? (x : BitVec w) (i : Nat) : (getMsb? x i).isSome →
|
||||
else
|
||||
simp [Nat.ge_of_not_lt h]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_getElem?_eq_some (since := "2025-04-04")]
|
||||
abbrev lt_of_getLsb?_eq_some := @lt_of_getElem?_eq_some
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_isSome_getElem? (since := "2025-04-04")]
|
||||
abbrev lt_of_getLsb?_isSome := @lt_of_isSome_getElem?
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated lt_of_isSome_getMsb? (since := "2025-04-04")]
|
||||
abbrev lt_of_getMsb?_isSome := @lt_of_isSome_getMsb?
|
||||
|
||||
theorem getMsbD_eq_getMsb?_getD (x : BitVec w) (i : Nat) :
|
||||
x.getMsbD i = (x.getMsb? i).getD false := by
|
||||
rw [getMsbD_eq_getLsbD]
|
||||
@@ -444,12 +417,18 @@ theorem getElem?_zero_ofNat_one : (BitVec.ofNat (w+1) 1)[0]? = some true := by
|
||||
|
||||
-- This does not need to be a `@[simp]` theorem as it is already handled by `getElem?_eq_getElem`.
|
||||
theorem getElem?_zero_ofBool (b : Bool) : (ofBool b)[0]? = some b := by
|
||||
simp only [ofBool, ofNat_eq_ofNat, cond_eq_if]
|
||||
simp only [ofBool, ofNat_eq_ofNat, cond_eq_ite]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind =] theorem getElem_zero_ofBool (b : Bool) : (ofBool b)[0] = b := by
|
||||
@[simp, grind =]
|
||||
theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by
|
||||
rw [getElem_eq_iff, getElem?_zero_ofBool]
|
||||
|
||||
|
||||
@[deprecated getElem_ofBool_zero (since := "2025-10-29")]
|
||||
theorem getElem_zero_ofBool (b : Bool) : (ofBool b)[0] = b := by
|
||||
simp
|
||||
|
||||
theorem getElem?_succ_ofBool (b : Bool) (i : Nat) : (ofBool b)[i + 1]? = none := by
|
||||
simp
|
||||
|
||||
@@ -460,8 +439,6 @@ theorem getLsbD_ofBool (b : Bool) (i : Nat) : (ofBool b).getLsbD i = ((i = 0) &&
|
||||
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsbD_ofNat, Bool.and_true]
|
||||
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
||||
|
||||
theorem getElem_ofBool_zero {b : Bool} : (ofBool b)[0] = b := by simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_ofBool {b : Bool} {h : i < 1}: (ofBool b)[i] = b := by
|
||||
simp [← getLsbD_eq_getElem]
|
||||
@@ -544,6 +521,10 @@ theorem toNat_ge_of_msb_true {x : BitVec n} (p : BitVec.msb x = true) : x.toNat
|
||||
@[grind _=_] theorem msb_eq_getMsbD_zero (x : BitVec w) : x.msb = x.getMsbD 0 := by
|
||||
cases w <;> simp [getMsbD_eq_getLsbD, msb_eq_getLsbD_last]
|
||||
|
||||
@[deprecated msb_eq_getMsbD_zero (since := "2025-10-26")]
|
||||
theorem msb_eq_getMsbD (x : BitVec w) : x.msb = x.getMsbD 0 := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp, grind =] theorem toFin_cast (h : w = v) (x : BitVec w) :
|
||||
@@ -605,7 +586,7 @@ theorem toInt_eq_toNat_bmod (x : BitVec n) : x.toInt = Int.bmod x.toNat (2^n) :=
|
||||
simp only [toInt_eq_toNat_cond]
|
||||
split
|
||||
next g =>
|
||||
rw [Int.bmod_pos] <;> simp only [←Int.natCast_emod, toNat_mod_cancel]
|
||||
rw [Int.bmod_eq_emod_of_lt] <;> simp only [←Int.natCast_emod, toNat_mod_cancel]
|
||||
omega
|
||||
next g =>
|
||||
rw [Int.bmod_neg] <;> simp only [←Int.natCast_emod, toNat_mod_cancel]
|
||||
@@ -1013,7 +994,14 @@ theorem msb_setWidth' (x : BitVec w) (h : w ≤ v) : (x.setWidth' h).msb = (deci
|
||||
theorem msb_setWidth'' (x : BitVec w) : (x.setWidth (k + 1)).msb = x.getLsbD k := by
|
||||
simp [BitVec.msb, getMsbD]
|
||||
|
||||
/-- Truncating to width 1 produces a bitvector equal to the least significant bit. -/
|
||||
theorem setWidth_one {x : BitVec w} :
|
||||
x.setWidth 1 = ofBool (x.getLsbD 0) := by
|
||||
ext i
|
||||
simp [show i = 0 by omega]
|
||||
|
||||
/-- zero extending a bitvector to width 1 equals the boolean of the lsb. -/
|
||||
@[deprecated setWidth_one (since := "2025-10-29")]
|
||||
theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||
x.setWidth 1 = BitVec.ofBool (x.getLsbD 0) := by
|
||||
ext i h
|
||||
@@ -1029,12 +1017,6 @@ theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
have hv := (@Nat.testBit_one_eq_true_iff_self_eq_zero i)
|
||||
by_cases h : Nat.testBit 1 i = true <;> simp_all
|
||||
|
||||
/-- Truncating to width 1 produces a bitvector equal to the least significant bit. -/
|
||||
theorem setWidth_one {x : BitVec w} :
|
||||
x.setWidth 1 = ofBool (x.getLsbD 0) := by
|
||||
ext i
|
||||
simp [show i = 0 by omega]
|
||||
|
||||
@[simp, grind =] theorem setWidth_ofNat_of_le (h : v ≤ w) (x : Nat) : setWidth v (BitVec.ofNat w x) = BitVec.ofNat v x := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
simp only [toNat_setWidth, toNat_ofNat]
|
||||
@@ -1208,7 +1190,7 @@ let x' = x.extractLsb' 7 5 = _ _ 9 8 7
|
||||
|
||||
@[simp] theorem getLsbD_extract (hi lo : Nat) (x : BitVec n) (i : Nat) :
|
||||
getLsbD (extractLsb hi lo x) i = (i ≤ (hi-lo) && getLsbD x (lo+i)) := by
|
||||
simp [getLsbD, Nat.lt_succ]
|
||||
simp [getLsbD, Nat.lt_succ_iff]
|
||||
|
||||
@[simp] theorem getLsbD_extractLsb {hi lo : Nat} {x : BitVec n} {i : Nat} :
|
||||
(extractLsb hi lo x).getLsbD i = (decide (i < hi - lo + 1) && x.getLsbD (lo + i)) := by
|
||||
@@ -1664,11 +1646,11 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
|
||||
@[simp] theorem ofInt_negSucc_eq_not_ofNat {w n : Nat} :
|
||||
BitVec.ofInt w (Int.negSucc n) = ~~~.ofNat w n := by
|
||||
simp only [BitVec.ofInt, Int.toNat, Int.ofNat_eq_coe, toNat_eq, toNat_ofNatLT, toNat_not,
|
||||
simp only [BitVec.ofInt, Int.toNat, Int.ofNat_eq_natCast, toNat_eq, toNat_ofNatLT, toNat_not,
|
||||
toNat_ofNat]
|
||||
cases h : Int.negSucc n % ((2 ^ w : Nat) : Int)
|
||||
case ofNat =>
|
||||
rw [Int.ofNat_eq_coe, Int.negSucc_emod] at h
|
||||
rw [Int.ofNat_eq_natCast, Int.negSucc_emod] at h
|
||||
· dsimp only
|
||||
omega
|
||||
· omega
|
||||
@@ -1750,9 +1732,6 @@ theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||
rw [h]
|
||||
simp
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getMsbD_not (since := "2025-04-04")] abbrev getMsb_not := @getMsbD_not
|
||||
|
||||
@[simp] theorem msb_not {x : BitVec w} : (~~~x).msb = (decide (0 < w) && !x.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
@@ -2572,10 +2551,6 @@ theorem signExtend_eq_setWidth_of_le (x : BitVec w) {v : Nat} (hv : v ≤ w) :
|
||||
ext i h
|
||||
simp [getElem_signExtend, show i < w by omega]
|
||||
|
||||
@[deprecated signExtend_eq_setWidth_of_le (since := "2025-03-07")]
|
||||
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w) :
|
||||
x.signExtend v = x.setWidth v := signExtend_eq_setWidth_of_le x hv
|
||||
|
||||
/-- Sign extending to the same bitwidth is a no op. -/
|
||||
@[simp] theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
|
||||
rw [signExtend_eq_setWidth_of_le _ (Nat.le_refl _), setWidth_eq]
|
||||
@@ -3635,9 +3610,6 @@ theorem sub_eq_add_neg {n} (x y : BitVec n) : x - y = x + - y := by
|
||||
simp only [toNat_sub, toNat_add, toNat_neg, Nat.add_mod_mod]
|
||||
rw [Nat.add_comm]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated sub_eq_add_neg (since := "2025-04-04")] abbrev sub_toAdd := @sub_eq_add_neg
|
||||
|
||||
theorem add_left_neg (x : BitVec w) : -x + x = 0#w := by
|
||||
apply toInt_inj.mp
|
||||
simp [toInt_neg, Int.add_left_neg]
|
||||
@@ -3677,10 +3649,6 @@ theorem neg_one_eq_allOnes : -1#w = allOnes w := by
|
||||
have r : (2^w - 1) < 2^w := by omega
|
||||
simp [Nat.mod_eq_of_lt q, Nat.mod_eq_of_lt r]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated neg_one_eq_allOnes (since := "2025-04-04")]
|
||||
abbrev negOne_eq_allOnes := @neg_one_eq_allOnes
|
||||
|
||||
theorem neg_eq_not_add (x : BitVec w) : -x = ~~~x + 1#w := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_neg, toNat_add, toNat_not, toNat_ofNat, Nat.add_mod_mod]
|
||||
@@ -4097,6 +4065,7 @@ protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y :=
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
|
||||
apply Nat.mod_lt
|
||||
|
||||
@[deprecated BitVec.not_lt (since := "2025-10-26")]
|
||||
theorem not_lt_iff_le {x y : BitVec w} : (¬ x < y) ↔ y ≤ x := by
|
||||
constructor <;>
|
||||
(intro h; simp only [lt_def, Nat.not_lt, le_def] at h ⊢; omega)
|
||||
@@ -4113,7 +4082,7 @@ theorem not_lt_zero {x : BitVec w} : ¬x < 0#w := of_decide_eq_false rfl
|
||||
theorem le_zero_iff {x : BitVec w} : x ≤ 0#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro h
|
||||
have : x ≥ 0 := not_lt_iff_le.mp not_lt_zero
|
||||
have : x ≥ 0 := BitVec.not_lt.mp not_lt_zero
|
||||
exact Eq.symm (BitVec.le_antisymm this h)
|
||||
· simp_all
|
||||
|
||||
@@ -4136,7 +4105,7 @@ theorem not_allOnes_lt {x : BitVec w} : ¬allOnes w < x := by
|
||||
theorem allOnes_le_iff {x : BitVec w} : allOnes w ≤ x ↔ x = allOnes w := by
|
||||
constructor
|
||||
· intro h
|
||||
have : x ≤ allOnes w := not_lt_iff_le.mp not_allOnes_lt
|
||||
have : x ≤ allOnes w := BitVec.not_lt.mp not_allOnes_lt
|
||||
exact Eq.symm (BitVec.le_antisymm h this)
|
||||
· simp_all
|
||||
|
||||
@@ -4682,9 +4651,6 @@ theorem zero_smod {x : BitVec w} : (0#w).smod x = 0#w := by
|
||||
@[simp, grind =] theorem getLsbD_ofBoolListLE : (ofBoolListLE bs).getLsbD i = bs.getD i false := by
|
||||
induction bs generalizing i <;> cases i <;> simp_all [ofBoolListLE]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_ofBoolListLE (since := "2025-04-04")] abbrev getLsb_ofBoolListLE := @getLsbD_ofBoolListLE
|
||||
|
||||
@[simp, grind =] theorem getMsbD_ofBoolListLE :
|
||||
(ofBoolListLE bs).getMsbD i = (decide (i < bs.length) && bs.getD (bs.length - 1 - i) false) := by
|
||||
simp [getMsbD_eq_getLsbD]
|
||||
@@ -4755,14 +4721,6 @@ theorem getLsbD_rotateLeftAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
apply getLsbD_of_ge
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateLeftAux_of_lt (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateLeftAux_of_le := @getLsbD_rotateLeftAux_of_lt
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateLeftAux_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateLeftAux_of_geq := @getLsbD_rotateLeftAux_of_ge
|
||||
|
||||
/-- When `r < w`, we give a formula for `(x.rotateLeft r).getLsbD i`. -/
|
||||
theorem getLsbD_rotateLeft_of_le {x : BitVec w} {r i : Nat} (hr: r < w) :
|
||||
(x.rotateLeft r).getLsbD i =
|
||||
@@ -4919,14 +4877,6 @@ theorem getLsbD_rotateRightAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
apply getLsbD_of_ge
|
||||
omega
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateRightAux_of_lt (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateRightAux_of_le := @getLsbD_rotateRightAux_of_lt
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getLsbD_rotateRightAux_of_ge (since := "2025-04-04")]
|
||||
abbrev getLsbD_rotateRightAux_of_geq := @getLsbD_rotateRightAux_of_ge
|
||||
|
||||
/-- `rotateRight` equals the bit fiddling definition of `rotateRightAux` when the rotation amount is
|
||||
smaller than the bitwidth. -/
|
||||
theorem rotateRight_eq_rotateRightAux_of_lt {x : BitVec w} {r : Nat} (hr : r < w) :
|
||||
|
||||
@@ -111,35 +111,11 @@ Needed for confluence of term `(a && b) ↔ a` which reduces to `(a && b) = a` v
|
||||
@[simp] theorem eq_self_and : ∀ {a b : Bool}, (a = (a && b)) ↔ (a → b) := by decide
|
||||
@[simp] theorem eq_and_self : ∀ {a b : Bool}, (b = (a && b)) ↔ (b → a) := by decide
|
||||
|
||||
@[deprecated and_eq_left_iff_imp (since := "2025-04-04")]
|
||||
abbrev and_iff_left_iff_imp := @and_eq_left_iff_imp
|
||||
|
||||
@[deprecated and_eq_right_iff_imp (since := "2025-04-04")]
|
||||
abbrev and_iff_right_iff_imp := @and_eq_right_iff_imp
|
||||
|
||||
@[deprecated eq_self_and (since := "2025-04-04")]
|
||||
abbrev iff_self_and := @eq_self_and
|
||||
|
||||
@[deprecated eq_and_self (since := "2025-04-04")]
|
||||
abbrev iff_and_self := @eq_and_self
|
||||
|
||||
@[simp] theorem not_and_eq_left_iff_and : ∀ {a b : Bool}, ((!a && b) = a) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem and_not_eq_right_iff_and : ∀ {a b : Bool}, ((a && !b) = b) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem eq_not_self_and : ∀ {a b : Bool}, (a = (!a && b)) ↔ !a ∧ !b := by decide
|
||||
@[simp] theorem eq_and_not_self : ∀ {a b : Bool}, (b = (a && !b)) ↔ !a ∧ !b := by decide
|
||||
|
||||
@[deprecated not_and_eq_left_iff_and (since := "2025-04-04")]
|
||||
abbrev not_and_iff_left_iff_imp := @not_and_eq_left_iff_and
|
||||
|
||||
@[deprecated and_not_eq_right_iff_and (since := "2025-04-04")]
|
||||
abbrev and_not_iff_right_iff_imp := @and_not_eq_right_iff_and
|
||||
|
||||
@[deprecated eq_not_self_and (since := "2025-04-04")]
|
||||
abbrev iff_not_self_and := @eq_not_self_and
|
||||
|
||||
@[deprecated eq_and_not_self (since := "2025-04-04")]
|
||||
abbrev iff_and_not_self := @eq_and_not_self
|
||||
|
||||
/-! ### or -/
|
||||
|
||||
@[simp] theorem or_self_left : ∀ (a b : Bool), (a || (a || b)) = (a || b) := by decide
|
||||
@@ -169,35 +145,11 @@ Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` v
|
||||
@[simp] theorem eq_self_or : ∀ {a b : Bool}, (a = (a || b)) ↔ (b → a) := by decide
|
||||
@[simp] theorem eq_or_self : ∀ {a b : Bool}, (b = (a || b)) ↔ (a → b) := by decide
|
||||
|
||||
@[deprecated or_eq_left_iff_imp (since := "2025-04-04")]
|
||||
abbrev or_iff_left_iff_imp := @or_eq_left_iff_imp
|
||||
|
||||
@[deprecated or_eq_right_iff_imp (since := "2025-04-04")]
|
||||
abbrev or_iff_right_iff_imp := @or_eq_right_iff_imp
|
||||
|
||||
@[deprecated eq_self_or (since := "2025-04-04")]
|
||||
abbrev iff_self_or := @eq_self_or
|
||||
|
||||
@[deprecated eq_or_self (since := "2025-04-04")]
|
||||
abbrev iff_or_self := @eq_or_self
|
||||
|
||||
@[simp] theorem not_or_eq_left_iff_and : ∀ {a b : Bool}, ((!a || b) = a) ↔ a ∧ b := by decide
|
||||
@[simp] theorem or_not_eq_right_iff_and : ∀ {a b : Bool}, ((a || !b) = b) ↔ a ∧ b := by decide
|
||||
@[simp] theorem eq_not_self_or : ∀ {a b : Bool}, (a = (!a || b)) ↔ a ∧ b := by decide
|
||||
@[simp] theorem eq_or_not_self : ∀ {a b : Bool}, (b = (a || !b)) ↔ a ∧ b := by decide
|
||||
|
||||
@[deprecated not_or_eq_left_iff_and (since := "2025-04-04")]
|
||||
abbrev not_or_iff_left_iff_imp := @not_or_eq_left_iff_and
|
||||
|
||||
@[deprecated or_not_eq_right_iff_and (since := "2025-04-04")]
|
||||
abbrev or_not_iff_right_iff_imp := @or_not_eq_right_iff_and
|
||||
|
||||
@[deprecated eq_not_self_or (since := "2025-04-04")]
|
||||
abbrev iff_not_self_or := @eq_not_self_or
|
||||
|
||||
@[deprecated eq_or_not_self (since := "2025-04-04")]
|
||||
abbrev iff_or_not_self := @eq_or_not_self
|
||||
|
||||
theorem or_comm : ∀ (x y : Bool), (x || y) = (y || x) := by decide
|
||||
instance : Std.Commutative (· || ·) := ⟨or_comm⟩
|
||||
|
||||
@@ -562,6 +514,7 @@ theorem exists_bool {p : Bool → Prop} : (∃ b, p b) ↔ p false ∨ p true :=
|
||||
theorem cond_eq_ite {α} (b : Bool) (t e : α) : cond b t e = if b then t else e := by
|
||||
cases b <;> simp
|
||||
|
||||
@[deprecated cond_eq_ite (since := "2025-10-29")]
|
||||
theorem cond_eq_if : (bif b then x else y) = (if b then x else y) := cond_eq_ite b x y
|
||||
|
||||
@[simp] theorem cond_not (b : Bool) (t e : α) : cond (!b) t e = cond b e t := by
|
||||
@@ -621,11 +574,6 @@ protected theorem cond_false {α : Sort u} {a b : α} : cond false a b = b := co
|
||||
@[simp] theorem cond_then_self : ∀ (c b : Bool), cond c c b = (c || b) := by decide
|
||||
@[simp] theorem cond_else_self : ∀ (c b : Bool), cond c b c = (c && b) := by decide
|
||||
|
||||
@[deprecated cond_then_not_self (since := "2025-04-04")] abbrev cond_true_not_same := @cond_then_not_self
|
||||
@[deprecated cond_else_not_self (since := "2025-04-04")] abbrev cond_false_not_same := @cond_else_not_self
|
||||
@[deprecated cond_then_self (since := "2025-04-04")] abbrev cond_true_same := @cond_then_self
|
||||
@[deprecated cond_else_self (since := "2025-04-04")] abbrev cond_false_same := @cond_else_self
|
||||
|
||||
theorem cond_pos {b : Bool} {a a' : α} (h : b = true) : (bif b then a else a') = a := by
|
||||
rw [h, cond_true]
|
||||
|
||||
@@ -665,7 +613,7 @@ theorem decide_beq_decide (p q : Prop) [dpq : Decidable (p ↔ q)] [dp : Decidab
|
||||
|
||||
end Bool
|
||||
|
||||
export Bool (cond_eq_if xor and or not)
|
||||
export Bool (cond_eq_if cond_eq_ite xor and or not)
|
||||
|
||||
/-! ### decide -/
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ attribute [ext] ByteArray
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
instance : Inhabited ByteArray where
|
||||
default := empty
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ public import Init.Data.ByteArray.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
|
||||
@[simp]
|
||||
theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
@@ -18,10 +20,10 @@ theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
|
||||
theorem data_empty : ByteArray.empty.data = #[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
theorem data_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).data = a.data.extract b e := by
|
||||
simp [extract, copySlice]
|
||||
by_cases b ≤ e
|
||||
@@ -29,39 +31,39 @@ theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
theorem extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
theorem extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
ext1
|
||||
simp [Nat.min_le_left]
|
||||
|
||||
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
theorem fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_append {l l' : List UInt8} :
|
||||
theorem _root_.List.toByteArray_append {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
|
||||
simp [List.toByteArray_append']
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_data_append {l l' : ByteArray} :
|
||||
theorem toList_data_append {l l' : ByteArray} :
|
||||
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
|
||||
simp [← append_eq]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_append {l l' : ByteArray} :
|
||||
theorem data_append {l l' : ByteArray} :
|
||||
(l ++ l').data = l.data ++ l'.data := by
|
||||
simp [← Array.toList_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
|
||||
theorem size_empty : ByteArray.empty.size = 0 := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.data_toByteArray {l : List UInt8} :
|
||||
theorem _root_.List.data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data = l.toArray := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
|
||||
@@ -70,153 +72,159 @@ theorem List.data_toByteArray {l : List UInt8} :
|
||||
fun_induction List.toByteArray.loop a b with simp_all
|
||||
|
||||
@[simp]
|
||||
theorem List.size_toByteArray {l : List UInt8} :
|
||||
theorem _root_.List.size_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.size = l.length := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
theorem _root_.List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
theorem empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
theorem append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
theorem size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
theorem size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ ByteArray.size_empty⟩
|
||||
ext1
|
||||
simp [← Array.size_eq_zero_iff, h]
|
||||
|
||||
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
theorem getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
a[i] = a.data[i]'(by simpa [← size_data]) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
theorem getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_left (by simpa)]
|
||||
|
||||
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
theorem getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hle : a.size ≤ i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_right (by simpa)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
theorem _root_.List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
l.toByteArray[i]'h = l[i]'(by simp_all) := by
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
theorem _root_.List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
l[i]'h = l.toByteArray[i]'(by simp_all) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
|
||||
theorem size_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).size = min e a.size - b := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
theorem extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
rw [← size_eq_zero_iff, size_extract]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
theorem extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
simp only [extract_eq_empty_iff]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
|
||||
theorem append_eq_empty_iff {a b : ByteArray} :
|
||||
a ++ b = ByteArray.empty ↔ a = ByteArray.empty ∧ b = ByteArray.empty := by
|
||||
simp [← size_eq_zero_iff, size_append]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_eq_empty {l : List UInt8} :
|
||||
theorem toByteArray_eq_empty {l : List UInt8} :
|
||||
l.toByteArray = ByteArray.empty ↔ l = [] := by
|
||||
simp [← ByteArray.size_eq_zero_iff]
|
||||
|
||||
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
@[simp]
|
||||
theorem append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_right_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
theorem append_left_inj {xs₁ xs₂ : ByteArray} (ys : ByteArray) :
|
||||
xs₁ ++ ys = xs₂ ++ ys ↔ xs₁ = xs₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_left_inj]
|
||||
|
||||
@[simp]
|
||||
theorem extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
theorem extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
(hi : i ≤ j) (hk : j ≤ k) :
|
||||
a.extract i k = a.extract i j ++ a.extract j k := by
|
||||
simp
|
||||
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
|
||||
|
||||
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
theorem append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
simp only [ByteArray.ext_iff, ← ByteArray.size_data, ByteArray.data_append] at *
|
||||
exact Array.append_inj_left h hl
|
||||
|
||||
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
|
||||
theorem extract_append_eq_right {a b : ByteArray} {i j : Nat} (hi : i = a.size) (hj : j = a.size + b.size) :
|
||||
(a ++ b).extract i j = b := by
|
||||
subst hi hj
|
||||
ext1
|
||||
simp [← size_data]
|
||||
|
||||
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
theorem extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract 0 i = a := by
|
||||
subst hi
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
theorem extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
(a ++ b).extract i a.size = a.extract i a.size := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
theorem extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
theorem extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
theorem extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
|
||||
cases h
|
||||
rw [extract_append_size_add]
|
||||
|
||||
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
theorem extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
theorem getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
start + i < xs.size := by
|
||||
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
|
||||
apply Nat.sub_le_sub_right; apply Nat.min_le_right
|
||||
|
||||
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
theorem getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
|
||||
simp [getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
theorem extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
a.extract i j = a.extract i' j ↔ min j a.size - i = min j a.size - i' := by
|
||||
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
|
||||
|
||||
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
theorem extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
a.extract i (i + 1) = [a[i]].toByteArray := by
|
||||
ext
|
||||
· simp
|
||||
@@ -225,34 +233,57 @@ theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.si
|
||||
obtain rfl : j = 0 := by simpa using hj'
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
theorem extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_one (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
theorem extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_two (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
theorem extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_three (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
theorem append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
|
||||
theorem toList_empty : ByteArray.empty.toList = [] := by
|
||||
simp [ByteArray.toList, ByteArray.toList.loop]
|
||||
|
||||
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
theorem copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
ByteArray.copySlice src srcOff dest destOff len exact =
|
||||
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
|
||||
ext1
|
||||
simp [copySlice]
|
||||
|
||||
@[simp]
|
||||
theorem data_set {as : ByteArray} {i : Nat} {h : i < as.size} {a : UInt8} :
|
||||
(as.set i a h).data = as.data.set i a (by simpa) := by
|
||||
simp [set]
|
||||
|
||||
theorem set_eq_push_extract_append_extract {as : ByteArray} {i : Nat} (h : i < as.size) {a : UInt8} :
|
||||
as.set i a h = (as.extract 0 i).push a ++ as.extract (i + 1) as.size := by
|
||||
ext1
|
||||
simpa using Array.set_eq_push_extract_append_extract _
|
||||
|
||||
@[simp]
|
||||
theorem append_toByteArray_singleton {as : ByteArray} {a : UInt8} :
|
||||
as ++ [a].toByteArray = as.push a := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem extract_zero_max_size {a : ByteArray} {i : Nat} : a.extract 0 (max i a.size) = a := by
|
||||
ext1
|
||||
simp [Nat.le_max_right]
|
||||
|
||||
end ByteArray
|
||||
|
||||
@@ -13,12 +13,16 @@ public section
|
||||
|
||||
namespace Char
|
||||
|
||||
@[ext] protected theorem ext : {a b : Char} → a.val = b.val → a = b
|
||||
@[deprecated Char.ext (since := "2025-10-26")]
|
||||
protected theorem eq_of_val_eq : {a b : Char} → a.val = b.val → a = b
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl => rfl
|
||||
|
||||
theorem le_def {a b : Char} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
|
||||
theorem lt_def {a b : Char} : a < b ↔ a.1 < b.1 := .rfl
|
||||
|
||||
@[deprecated lt_def (since := "2025-10-26")]
|
||||
theorem lt_iff_val_lt_val {a b : Char} : a < b ↔ a.val < b.val := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le {a b : Char} : ¬ a ≤ b ↔ b < a := UInt32.not_le
|
||||
@[simp] protected theorem not_lt {a b : Char} : ¬ a < b ↔ b ≤ a := UInt32.not_lt
|
||||
@[simp] protected theorem le_refl (a : Char) : a ≤ a := by simp [le_def]
|
||||
@@ -51,8 +55,12 @@ instance leAntisymm : Std.Antisymm (· ≤ · : Char → Char → Prop) where
|
||||
antisymm _ _ := Char.le_antisymm
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
instance ltTrichotomous : Std.Trichotomous (· < · : Char → Char → Prop) where
|
||||
trichotomous _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
|
||||
|
||||
@[deprecated ltTrichotomous (since := "2025-10-27")]
|
||||
def notLTAntisymm : Std.Antisymm (¬ · < · : Char → Char → Prop) where
|
||||
antisymm _ _ h₁ h₂ := Char.le_antisymm (by simpa using h₂) (by simpa using h₁)
|
||||
antisymm := Char.ltTrichotomous.trichotomous
|
||||
|
||||
instance ltAsymm : Std.Asymm (· < · : Char → Char → Prop) where
|
||||
asymm _ _ := Char.lt_asymm
|
||||
@@ -69,4 +77,9 @@ def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem toUInt8_val {c : Char} : c.val.toUInt8 = c.toUInt8 := rfl
|
||||
|
||||
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
|
||||
|
||||
end Char
|
||||
|
||||
@@ -287,7 +287,7 @@ theorem toRat_add (x y : Dyadic) : toRat (x + y) = toRat x + toRat y := by
|
||||
· rename_i h
|
||||
cases Int.sub_eq_iff_eq_add.mp h
|
||||
rw [toRat_ofOdd_eq_mkRat, Rat.mkRat_eq_iff (NeZero.ne _) (NeZero.ne _)]
|
||||
simp only [succ_eq_add_one, Int.ofNat_eq_coe, Int.add_shiftLeft, ← Int.shiftLeft_add,
|
||||
simp only [succ_eq_add_one, Int.ofNat_eq_natCast, Int.add_shiftLeft, ← Int.shiftLeft_add,
|
||||
Int.natCast_mul, Int.natCast_shiftLeft, Int.shiftLeft_mul_shiftLeft, Int.add_mul]
|
||||
congr 2 <;> omega
|
||||
· rename_i h
|
||||
@@ -438,13 +438,13 @@ theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
rcases h : mkRat a b with ⟨n, d, hnz, hr⟩
|
||||
obtain ⟨m, hm, rfl, rfl⟩ := Rat.mkRat_num_den hb h
|
||||
cases prec
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast,
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_natCast, Int.toNat_natCast, Int.toNat_neg_natCast,
|
||||
shiftLeft_zero, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.ediv_ediv (by simp), ← Int.shiftLeft_mul,
|
||||
rw [Int.mul_comm d, ← Int.ediv_ediv_of_nonneg (by simp), ← Int.shiftLeft_mul,
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
· simp only [Rat.toDyadic, Int.natCast_shiftLeft, Int.negSucc_eq, ← Int.natCast_add_one,
|
||||
Int.toNat_neg_natCast, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.mul_shiftLeft, ← Int.ediv_ediv (by simp),
|
||||
rw [Int.mul_comm d, ← Int.mul_shiftLeft, ← Int.ediv_ediv_of_nonneg (by simp),
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
|
||||
theorem toDyadic_eq_ofIntWithPrec (x : Rat) (prec : Int) :
|
||||
@@ -463,7 +463,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
rw [Rat.floor_def, Int.shiftLeft_eq, Nat.shiftLeft_eq]
|
||||
match prec with
|
||||
| .ofNat prec =>
|
||||
simp only [Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
|
||||
simp only [Int.ofNat_eq_natCast, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
|
||||
Nat.mul_one]
|
||||
have : (2 ^ prec : Rat) = ((2 ^ prec : Nat) : Rat) := by simp
|
||||
rw [Rat.zpow_natCast, this, Rat.mul_def']
|
||||
@@ -472,7 +472,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
Rat.den_ofNat, Nat.one_pow, Nat.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
· rw [Int.ediv_ediv_of_nonneg (Int.natCast_nonneg _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
rw [Int.natCast_dvd_natCast]
|
||||
@@ -495,7 +495,7 @@ theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
simp only [this, Int.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
· rw [Int.ediv_ediv_of_nonneg (Int.natCast_nonneg _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
· simp
|
||||
@@ -682,9 +682,11 @@ instance : LE Dyadic where
|
||||
instance : DecidableLT Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
|
||||
instance : DecidableLE Dyadic := fun _ _ => inferInstanceAs (Decidable (_ = true))
|
||||
|
||||
theorem lt_iff_toRat {x y : Dyadic} : x < y ↔ x.toRat < y.toRat := blt_iff_toRat
|
||||
@[simp]
|
||||
theorem toRat_lt_toRat_iff {x y : Dyadic} : x.toRat < y.toRat ↔ x < y := blt_iff_toRat.symm
|
||||
|
||||
theorem le_iff_toRat {x y : Dyadic} : x ≤ y ↔ x.toRat ≤ y.toRat := ble_iff_toRat
|
||||
@[simp]
|
||||
theorem toRat_le_toRat_iff {x y : Dyadic} : x.toRat ≤ y.toRat ↔ x ≤ y := ble_iff_toRat.symm
|
||||
|
||||
@[simp]
|
||||
protected theorem not_le {x y : Dyadic} : ¬x < y ↔ y ≤ x := by
|
||||
@@ -696,20 +698,20 @@ protected theorem not_lt {x y : Dyadic} : ¬x ≤ y ↔ y < x := by
|
||||
|
||||
@[simp]
|
||||
protected theorem le_refl (x : Dyadic) : x ≤ x := by
|
||||
rw [le_iff_toRat]
|
||||
rw [← toRat_le_toRat_iff]
|
||||
exact Rat.le_refl
|
||||
|
||||
protected theorem le_trans {x y z : Dyadic} (h : x ≤ y) (h' : y ≤ z) : x ≤ z := by
|
||||
rw [le_iff_toRat] at h h' ⊢
|
||||
rw [← toRat_le_toRat_iff] at h h' ⊢
|
||||
exact Rat.le_trans h h'
|
||||
|
||||
protected theorem le_antisymm {x y : Dyadic} (h : x ≤ y) (h' : y ≤ x) : x = y := by
|
||||
rw [le_iff_toRat] at h h'
|
||||
rw [← toRat_le_toRat_iff] at h h'
|
||||
rw [← toRat_inj]
|
||||
exact Rat.le_antisymm h h'
|
||||
|
||||
protected theorem le_total (x y : Dyadic) : x ≤ y ∨ y ≤ x := by
|
||||
rw [le_iff_toRat, le_iff_toRat]
|
||||
rw [← toRat_le_toRat_iff, ← toRat_le_toRat_iff]
|
||||
exact Rat.le_total
|
||||
|
||||
instance : Std.LawfulOrderLT Dyadic where
|
||||
|
||||
@@ -52,8 +52,8 @@ instance : NoNatZeroDivisors Dyadic where
|
||||
|
||||
instance : OrderedRing Dyadic where
|
||||
zero_lt_one := by decide
|
||||
add_le_left_iff _ := by simp [le_iff_toRat, Rat.add_le_add_right]
|
||||
mul_lt_mul_of_pos_left {_ _ _} := by simpa [lt_iff_toRat] using Rat.mul_lt_mul_of_pos_left
|
||||
mul_lt_mul_of_pos_right {_ _ _} := by simpa [lt_iff_toRat] using Rat.mul_lt_mul_of_pos_right
|
||||
add_le_left_iff _ := by simp [← toRat_le_toRat_iff, Rat.add_le_add_right]
|
||||
mul_lt_mul_of_pos_left {_ _ _} := by simpa [← toRat_lt_toRat_iff] using Rat.mul_lt_mul_of_pos_left
|
||||
mul_lt_mul_of_pos_right {_ _ _} := by simpa [← toRat_lt_toRat_iff] using Rat.mul_lt_mul_of_pos_right
|
||||
|
||||
end Dyadic
|
||||
|
||||
@@ -27,7 +27,7 @@ def invAtPrec (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
/-- For a positive dyadic `x`, `invAtPrec x prec * x ≤ 1`. -/
|
||||
theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
invAtPrec x prec * x ≤ 1 := by
|
||||
rw [le_iff_toRat]
|
||||
rw [← toRat_le_toRat_iff]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
@@ -39,19 +39,19 @@ theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
simp only
|
||||
have h_le : ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat ≤ (ofOdd n k hn).toRat.inv := Rat.toRat_toDyadic_le
|
||||
have h_pos : 0 ≤ (ofOdd n k hn).toRat := by
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
rw [← toRat_lt_toRat_iff, toRat_zero] at hx
|
||||
exact Rat.le_of_lt hx
|
||||
calc ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat * (ofOdd n k hn).toRat
|
||||
≤ (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := Rat.mul_le_mul_of_nonneg_right h_le h_pos
|
||||
_ = 1 := by
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
rw [← toRat_lt_toRat_iff, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
|
||||
/-- For a positive dyadic `x`, `1 < (invAtPrec x prec + 2^(-prec)) * x`. -/
|
||||
theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
1 < (invAtPrec x prec + ofIntWithPrec 1 prec) * x := by
|
||||
rw [lt_iff_toRat]
|
||||
rw [← toRat_lt_toRat_iff]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
@@ -64,12 +64,12 @@ theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
have h_le : (ofOdd n k hn).toRat.inv < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat :=
|
||||
Rat.lt_toRat_toDyadic_add
|
||||
have h_pos : 0 < (ofOdd n k hn).toRat := by
|
||||
rwa [lt_iff_toRat, toRat_zero] at hx
|
||||
rwa [← toRat_lt_toRat_iff, toRat_zero] at hx
|
||||
calc
|
||||
1 = (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := by
|
||||
symm
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
rw [← toRat_lt_toRat_iff, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
_ < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat * (ofOdd n k hn).toRat :=
|
||||
Rat.mul_lt_mul_of_pos_right h_le h_pos
|
||||
|
||||
@@ -28,7 +28,7 @@ theorem roundDown_le {x : Dyadic} {prec : Int} : roundDown x prec ≤ x :=
|
||||
match h : k - prec with
|
||||
| .ofNat l =>
|
||||
dsimp
|
||||
rw [ofOdd_eq_ofIntWithPrec, le_iff_toRat]
|
||||
rw [ofOdd_eq_ofIntWithPrec, ← toRat_le_toRat_iff]
|
||||
replace h : k = Int.ofNat l + prec := by omega
|
||||
subst h
|
||||
simp only [toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
@@ -36,7 +36,7 @@ theorem roundDown_le {x : Dyadic} {prec : Int} : roundDown x prec ≤ x :=
|
||||
refine Lean.Grind.OrderedRing.mul_le_mul_of_nonneg_right ?_ (Rat.zpow_nonneg (by decide))
|
||||
rw [Int.shiftRight_eq_div_pow]
|
||||
rw [← Lean.Grind.Field.IsOrdered.mul_le_mul_iff_of_pos_right (c := 2^(Int.ofNat l)) (Rat.zpow_pos (by decide))]
|
||||
simp only [Int.natCast_pow, Int.cast_ofNat_Int, Int.ofNat_eq_coe]
|
||||
simp only [Int.natCast_pow, Int.cast_ofNat_Int, Int.ofNat_eq_natCast]
|
||||
rw [Rat.mul_assoc, ← Rat.zpow_add (by decide), Int.add_left_neg, Rat.zpow_zero, Rat.mul_one]
|
||||
have : (2 : Rat) ^ (l : Int) = (2 ^ l : Int) := by
|
||||
rw [Rat.zpow_natCast, Rat.intCast_pow, Rat.intCast_ofNat]
|
||||
|
||||
@@ -157,6 +157,7 @@ theorem le_def {a b : Fin n} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
|
||||
|
||||
theorem lt_def {a b : Fin n} : a < b ↔ a.1 < b.1 := .rfl
|
||||
|
||||
@[deprecated lt_def (since := "2025-10-26")]
|
||||
theorem lt_iff_val_lt_val {a b : Fin n} : a < b ↔ a.val < b.val := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le {a b : Fin n} : ¬ a ≤ b ↔ b < a := Nat.not_le
|
||||
@@ -264,7 +265,7 @@ instance : LawfulOrderLT (Fin n) where
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem rev_le_rev {i j : Fin n} : rev i ≤ rev j ↔ j ≤ i := by
|
||||
simp only [le_def, val_rev, Nat.sub_le_sub_iff_left (Nat.succ_le.2 j.is_lt)]
|
||||
simp only [le_def, val_rev, Nat.sub_le_sub_iff_left (Nat.succ_le_iff.2 j.is_lt)]
|
||||
exact Nat.succ_le_succ_iff
|
||||
|
||||
@[simp] theorem rev_inj {i j : Fin n} : rev i = rev j ↔ i = j :=
|
||||
@@ -383,9 +384,10 @@ theorem add_one_pos (i : Fin (n + 1)) (h : i < Fin.last n) : (0 : Fin (n + 1)) <
|
||||
rw [Fin.lt_def, val_add, val_zero, val_one, Nat.mod_eq_of_lt h]
|
||||
exact Nat.zero_lt_succ _
|
||||
|
||||
@[deprecated zero_lt_one (since := "2025-10-26")]
|
||||
theorem one_pos : (0 : Fin (n + 2)) < 1 := Nat.succ_pos 0
|
||||
|
||||
theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt one_pos
|
||||
theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt zero_lt_one
|
||||
|
||||
/-! ### succ and casts into larger Fin types -/
|
||||
|
||||
@@ -540,12 +542,12 @@ theorem succ_cast_eq {n' : Nat} (i : Fin n) (h : n = n') :
|
||||
|
||||
@[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 castSucc_mk (n i : Nat) (h : i < n) : castSucc ⟨i, h⟩ = ⟨i, Nat.lt_succ_of_lt h⟩ := rfl
|
||||
|
||||
@[simp] theorem cast_castSucc {n' : Nat} {h : n + 1 = n' + 1} {i : Fin n} :
|
||||
i.castSucc.cast h = (i.cast (Nat.succ.inj h)).castSucc := rfl
|
||||
|
||||
theorem castSucc_lt_succ (i : Fin n) : i.castSucc < 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 ≤ j.castSucc ↔ i < j.succ := by
|
||||
@@ -585,8 +587,12 @@ theorem castSucc_pos [NeZero n] {i : Fin n} (h : 0 < i) : 0 < i.castSucc := by
|
||||
theorem castSucc_ne_zero_iff [NeZero n] {a : Fin n} : a.castSucc ≠ 0 ↔ a ≠ 0 :=
|
||||
not_congr <| castSucc_eq_zero_iff
|
||||
|
||||
@[simp, grind _=_]
|
||||
theorem castSucc_succ (i : Fin n) : i.succ.castSucc = i.castSucc.succ := rfl
|
||||
|
||||
@[deprecated castSucc_succ (since := "2025-10-29")]
|
||||
theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
||||
j.succ.castSucc = (j.castSucc).succ := by simp [Fin.ext_iff]
|
||||
j.succ.castSucc = (j.castSucc).succ := by simp
|
||||
|
||||
@[simp]
|
||||
theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
|
||||
@@ -594,6 +600,7 @@ theorem coeSucc_eq_succ {a : Fin n} : a.castSucc + 1 = a.succ := by
|
||||
· exact a.elim0
|
||||
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||
|
||||
@[deprecated castSucc_lt_succ (since := "2025-10-29")]
|
||||
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
|
||||
|
||||
@@ -697,9 +704,6 @@ theorem rev_castSucc (k : Fin n) : rev (castSucc k) = succ (rev k) := k.rev_cast
|
||||
|
||||
theorem rev_succ (k : Fin n) : rev (succ k) = castSucc (rev k) := k.rev_addNat 1
|
||||
|
||||
@[simp, grind _=_]
|
||||
theorem castSucc_succ (i : Fin n) : i.succ.castSucc = i.castSucc.succ := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
theorem castLE_refl (h : n ≤ n) (i : Fin n) : i.castLE h = i := rfl
|
||||
|
||||
@@ -754,7 +758,7 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [Fin.ext_iff]
|
||||
|
||||
@[simp] theorem pred_one {n : Nat} :
|
||||
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
|
||||
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt zero_lt_one)) = 0 := rfl
|
||||
|
||||
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
|
||||
@@ -1137,6 +1141,7 @@ theorem mul_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
theorem val_mul {n : Nat} : ∀ a b : Fin n, (a * b).val = a.val * b.val % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
@[deprecated val_mul (since := "2025-10-26")]
|
||||
theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
|
||||
@@ -29,9 +29,6 @@ attribute [ext] FloatArray
|
||||
def emptyWithCapacity (c : @& Nat) : FloatArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
def empty : FloatArray :=
|
||||
emptyWithCapacity 0
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
|
||||
| text s, flatten, _, _ =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let off := String.Internal.offsetOfPos s p
|
||||
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
|
||||
{ foundLine := p != s.rawEndPos, foundFlattenedHardLine := flatten && p != s.rawEndPos, space := off }
|
||||
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
|
||||
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
|
||||
| group f _, _, m, w => spaceUptoLine f true m w
|
||||
@@ -264,14 +264,14 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
| nest n f => be w (gs' ({ i with f, indent := i.indent + n }::is))
|
||||
| text s =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
if p == s.endPos then
|
||||
if p == s.rawEndPos then
|
||||
pushOutput s
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
pushOutput (String.Internal.extract s {} p)
|
||||
pushNewline i.indent.toNat
|
||||
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.endPos) }::is
|
||||
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.rawEndPos) }::is
|
||||
-- after a hard line break, re-evaluate whether to flatten the remaining group
|
||||
-- note that we shouldn't start flattening after a hard break outside a group
|
||||
if g.fla == .disallow then
|
||||
@@ -411,7 +411,6 @@ Renders a `Format` to a string.
|
||||
* `column`: begin the first line wrap `column` characters earlier than usual
|
||||
(this is useful when the output String will be printed starting at `column`)
|
||||
-/
|
||||
@[export lean_format_pretty]
|
||||
def pretty (f : Format) (width : Nat := defWidth) (indent : Nat := 0) (column := 0) : String :=
|
||||
let act : StateM State Unit := prettyM f width indent
|
||||
State.out <| act (State.mk "" column) |>.snd
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.String.Search
|
||||
|
||||
public section
|
||||
|
||||
@@ -47,7 +47,7 @@ Converts a string to a pretty-printer document, replacing newlines in the string
|
||||
`Std.Format.line`.
|
||||
-/
|
||||
def String.toFormat (s : String) : Std.Format :=
|
||||
Std.Format.joinSep (s.splitOn "\n") Std.Format.line
|
||||
Std.Format.joinSep (s.split '\n').toList Std.Format.line
|
||||
|
||||
instance : ToFormat String.Pos.Raw where
|
||||
format p := format p.byteIdx
|
||||
|
||||
@@ -80,7 +80,10 @@ protected theorem zero_ne_one : (0 : Int) ≠ 1 := nofun
|
||||
|
||||
/-! ## Coercions -/
|
||||
|
||||
@[simp] theorem ofNat_eq_coe : Int.ofNat n = Nat.cast n := rfl
|
||||
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
|
||||
|
||||
@[deprecated ofNat_eq_natCast (since := "2025-10-29")]
|
||||
theorem ofNat_eq_coe : Int.ofNat n = Nat.cast n := rfl
|
||||
|
||||
@[simp] theorem ofNat_zero : ((0 : Nat) : Int) = 0 := rfl
|
||||
|
||||
@@ -313,7 +316,7 @@ the logical model.
|
||||
Examples:
|
||||
* `(7 : Int).natAbs = 7`
|
||||
* `(0 : Int).natAbs = 0`
|
||||
* `((-11 : Int).natAbs = 11`
|
||||
* `(-11 : Int).natAbs = 11`
|
||||
-/
|
||||
@[extern "lean_nat_abs", expose]
|
||||
def natAbs (m : @& Int) : Nat :=
|
||||
@@ -369,9 +372,6 @@ def toNat? : Int → Option Nat
|
||||
| (n : Nat) => some n
|
||||
| -[_+1] => none
|
||||
|
||||
@[deprecated toNat? (since := "2025-03-11"), inherit_doc toNat?]
|
||||
abbrev toNat' := toNat?
|
||||
|
||||
/-! ## divisibility -/
|
||||
|
||||
/--
|
||||
@@ -392,9 +392,9 @@ Examples:
|
||||
* `(0 : Int) ^ 10 = 0`
|
||||
* `(-7 : Int) ^ 3 = -343`
|
||||
-/
|
||||
protected def pow (m : Int) : Nat → Int
|
||||
| 0 => 1
|
||||
| succ n => Int.pow m n * m
|
||||
protected def pow : Int → Nat → Int
|
||||
| (m : Nat), n => Int.ofNat (m ^ n)
|
||||
| m@-[_+1], n => if n % 2 = 0 then Int.ofNat (m.natAbs ^ n) else - Int.ofNat (m.natAbs ^ n)
|
||||
|
||||
instance : NatPow Int where
|
||||
pow := Int.pow
|
||||
|
||||
@@ -24,12 +24,17 @@ theorem natCast_shiftRight (n s : Nat) : n >>> s = (n : Int) >>> s := rfl
|
||||
theorem negSucc_shiftRight (m n : Nat) :
|
||||
-[m+1] >>> n = -[m >>>n +1] := rfl
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftRight_add (i : Int) (m n : Nat) :
|
||||
i >>> (m + n) = i >>> m >>> n := by
|
||||
simp only [shiftRight_eq, Int.shiftRight]
|
||||
cases i <;> simp [Nat.shiftRight_add]
|
||||
|
||||
grind_pattern shiftRight_add => i >>> (m + n) where
|
||||
i =/= 0
|
||||
|
||||
grind_pattern shiftRight_add => i >>> m >>> n where
|
||||
i =/= 0
|
||||
|
||||
theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||
m >>> n = m / ((2 ^ n) : Nat) := by
|
||||
simp only [shiftRight_eq, Int.shiftRight, Nat.shiftRight_eq_div_pow]
|
||||
@@ -47,10 +52,10 @@ theorem shiftRight_zero (n : Int) : n >>> 0 = n := by
|
||||
simp [Int.shiftRight_eq_div_pow]
|
||||
|
||||
theorem le_shiftRight_of_nonpos {n : Int} {s : Nat} (h : n ≤ 0) : n ≤ n >>> s := by
|
||||
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_coe]
|
||||
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_natCast]
|
||||
split
|
||||
case _ _ _ m =>
|
||||
simp only [ofNat_eq_coe] at h
|
||||
simp only [ofNat_eq_natCast] at h
|
||||
by_cases hm : m = 0
|
||||
· simp [hm]
|
||||
· omega
|
||||
@@ -61,14 +66,14 @@ theorem le_shiftRight_of_nonpos {n : Int} {s : Nat} (h : n ≤ 0) : n ≤ n >>>
|
||||
omega
|
||||
|
||||
theorem shiftRight_le_of_nonneg {n : Int} {s : Nat} (h : 0 ≤ n) : n >>> s ≤ n := by
|
||||
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_coe]
|
||||
simp only [Int.shiftRight_eq, Int.shiftRight, Int.ofNat_eq_natCast]
|
||||
split
|
||||
case _ _ _ m =>
|
||||
simp only [Int.ofNat_eq_coe] at h
|
||||
simp only [Int.ofNat_eq_natCast] at h
|
||||
by_cases hm : m = 0
|
||||
· simp [hm]
|
||||
· have := Nat.shiftRight_le m s
|
||||
rw [ofNat_eq_coe]
|
||||
rw [ofNat_eq_natCast]
|
||||
omega
|
||||
case _ _ _ m =>
|
||||
omega
|
||||
@@ -108,7 +113,7 @@ theorem shiftLeft_succ (m : Int) (n : Nat) : m <<< (n + 1) = (m <<< n) * 2 := by
|
||||
change Int.shiftLeft _ _ = Int.shiftLeft _ _ * 2
|
||||
match m with
|
||||
| (m : Nat) =>
|
||||
dsimp only [Int.shiftLeft, Int.ofNat_eq_coe]
|
||||
dsimp only [Int.shiftLeft, Int.ofNat_eq_natCast]
|
||||
rw [Nat.shiftLeft_succ, Nat.mul_comm, natCast_mul, ofNat_two]
|
||||
| Int.negSucc m =>
|
||||
dsimp only [Int.shiftLeft]
|
||||
|
||||
@@ -9,3 +9,4 @@ prelude
|
||||
public import Init.Data.Int.DivMod.Basic
|
||||
public import Init.Data.Int.DivMod.Bootstrap
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
public import Init.Data.Int.DivMod.Pow
|
||||
|
||||
@@ -118,9 +118,6 @@ instance : Mod Int where
|
||||
|
||||
@[simp, norm_cast] theorem natCast_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := rfl
|
||||
|
||||
@[deprecated natCast_ediv (since := "2025-04-17")]
|
||||
theorem ofNat_ediv (m n : Nat) : (↑(m / n) : Int) = ↑m / ↑n := natCast_ediv m n
|
||||
|
||||
theorem ofNat_ediv_ofNat {a b : Nat} : (↑a / ↑b : Int) = (a / b : Nat) := rfl
|
||||
@[norm_cast]
|
||||
theorem negSucc_ediv_ofNat_succ {a b : Nat} : ((-[a+1]) / ↑(b+1) : Int) = -[a / succ b +1] := rfl
|
||||
|
||||
@@ -38,7 +38,7 @@ protected theorem dvd_trans : ∀ {a b c : Int}, a ∣ b → b ∣ c → a ∣ c
|
||||
refine ⟨fun ⟨a, ae⟩ => ?_, fun ⟨k, e⟩ => ⟨k, by rw [e, Int.natCast_mul]⟩⟩
|
||||
match Int.le_total a 0 with
|
||||
| .inl h =>
|
||||
have := ae.symm ▸ Int.mul_nonpos_of_nonneg_of_nonpos (ofNat_zero_le _) h
|
||||
have := ae.symm ▸ Int.mul_nonpos_of_nonneg_of_nonpos (natCast_nonneg _) h
|
||||
rw [Nat.le_antisymm (ofNat_le.1 this) (Nat.zero_le _)]
|
||||
apply Nat.dvd_zero
|
||||
| .inr h => match a, eq_ofNat_of_zero_le h with
|
||||
@@ -92,9 +92,6 @@ theorem ofNat_dvd_left {n : Nat} {z : Int} : (↑n : Int) ∣ z ↔ n ∣ z.natA
|
||||
|
||||
@[simp, norm_cast] theorem natCast_emod (m n : Nat) : (↑(m % n) : Int) = m % n := rfl
|
||||
|
||||
@[deprecated natCast_emod (since := "2025-04-17")]
|
||||
theorem ofNat_emod (m n : Nat) : (↑(m % n) : Int) = m % n := natCast_emod m n
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem emod_add_mul_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
@@ -209,7 +206,7 @@ theorem ediv_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : 0 ≤ a / b ↔ 0 ≤ a
|
||||
/-! ### emod -/
|
||||
|
||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||
| ofNat _, _, _ => ofNat_zero_le _
|
||||
| ofNat _, _, _ => natCast_nonneg _
|
||||
| -[_+1], _, H => Int.sub_nonneg_of_le <| ofNat_le.2 <| Nat.mod_lt _ (natAbs_pos.2 H)
|
||||
|
||||
theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
|
||||
@@ -233,10 +230,6 @@ theorem emod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a % b < b :=
|
||||
@[simp] theorem mul_add_emod_self_left (a b c : Int) : (a * b + c) % a = c % a := by
|
||||
rw [Int.add_comm, add_mul_emod_self_left]
|
||||
|
||||
@[deprecated add_mul_emod_self_right (since := "2025-04-11")]
|
||||
theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
add_mul_emod_self_right ..
|
||||
|
||||
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
|
||||
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
|
||||
rwa [Int.add_right_comm, emod_add_mul_ediv] at this
|
||||
|
||||
@@ -73,7 +73,7 @@ protected theorem dvd_iff_dvd_of_dvd_add {a b c : Int} (H : a ∣ b + c) : a ∣
|
||||
theorem le_of_dvd {a b : Int} (bpos : 0 < b) (H : a ∣ b) : a ≤ b :=
|
||||
match a, b, eq_succ_of_zero_lt bpos, H with
|
||||
| ofNat _, _, ⟨n, rfl⟩, H => ofNat_le.2 <| Nat.le_of_dvd n.succ_pos <| ofNat_dvd.1 H
|
||||
| -[_+1], _, ⟨_, rfl⟩, _ => Int.le_trans (Int.le_of_lt <| negSucc_lt_zero _) (ofNat_zero_le _)
|
||||
| -[_+1], _, ⟨_, rfl⟩, _ => Int.le_trans (Int.le_of_lt <| negSucc_lt_zero _) (natCast_nonneg _)
|
||||
|
||||
theorem natAbs_dvd {a b : Int} : (a.natAbs : Int) ∣ b ↔ a ∣ b :=
|
||||
match natAbs_eq a with
|
||||
@@ -145,6 +145,12 @@ theorem dvd_of_mul_dvd_mul_left {a m n : Int} (ha : a ≠ 0) (h : a * m ∣ a *
|
||||
theorem dvd_of_mul_dvd_mul_right {a m n : Int} (ha : a ≠ 0) (h : m * a ∣ n * a) : m ∣ n :=
|
||||
dvd_of_mul_dvd_mul_left ha (by simpa [Int.mul_comm] using h)
|
||||
|
||||
theorem dvd_mul_of_dvd_right {a b c : Int} (h : a ∣ c) : a ∣ b * c :=
|
||||
Int.dvd_trans h (Int.dvd_mul_left b c)
|
||||
|
||||
theorem dvd_mul_of_dvd_left {a b c : Int} (h : a ∣ b) : a ∣ b * c :=
|
||||
Int.dvd_trans h (Int.dvd_mul_right b c)
|
||||
|
||||
@[norm_cast] theorem natCast_dvd_natCast {m n : Nat} : (↑m : Int) ∣ ↑n ↔ m ∣ n where
|
||||
mp := by
|
||||
rintro ⟨a, h⟩
|
||||
@@ -214,8 +220,8 @@ theorem tdiv_eq_ediv {a b : Int} :
|
||||
| ofNat a, -[b+1] => simp [tdiv_eq_ediv_of_nonneg]
|
||||
| -[a+1], 0 => simp
|
||||
| -[a+1], ofNat (succ b) =>
|
||||
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int,
|
||||
negSucc_not_nonneg, sign_of_add_one]
|
||||
simp only [tdiv, Nat.succ_eq_add_one, ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int,
|
||||
negSucc_not_nonneg, sign_natCast_add_one]
|
||||
simp only [negSucc_emod_ofNat_succ_eq_zero_iff]
|
||||
norm_cast
|
||||
simp only [Nat.succ_eq_add_one, false_or]
|
||||
@@ -225,7 +231,7 @@ theorem tdiv_eq_ediv {a b : Int} :
|
||||
· rw [neg_ofNat_eq_negSucc_add_one_iff]
|
||||
exact Nat.succ_div_of_mod_ne_zero h
|
||||
| -[a+1], -[b+1] =>
|
||||
simp only [tdiv, ofNat_eq_coe, negSucc_not_nonneg, false_or, sign_negSucc]
|
||||
simp only [tdiv, ofNat_eq_natCast, negSucc_not_nonneg, false_or, sign_negSucc]
|
||||
norm_cast
|
||||
simp only [negSucc_ediv_negSucc]
|
||||
rw [Int.natCast_add, Int.natCast_one]
|
||||
@@ -256,7 +262,7 @@ theorem fdiv_eq_ediv {a b : Int} :
|
||||
| 0, -[b+1] => simp
|
||||
| ofNat (a + 1), -[b+1] =>
|
||||
simp only [fdiv, ofNat_ediv_negSucc, negSucc_not_nonneg, negSucc_dvd, false_or]
|
||||
simp only [ofNat_eq_coe, ofNat_dvd]
|
||||
simp only [ofNat_eq_natCast, ofNat_dvd]
|
||||
norm_cast
|
||||
rw [Nat.succ_div, negSucc_eq]
|
||||
split <;> rename_i h
|
||||
@@ -264,7 +270,7 @@ theorem fdiv_eq_ediv {a b : Int} :
|
||||
· simp [Int.neg_add]
|
||||
norm_cast
|
||||
| -[a+1], -[b+1] =>
|
||||
simp only [fdiv, ofNat_eq_coe, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
|
||||
simp only [fdiv, ofNat_eq_natCast, negSucc_ediv_negSucc, negSucc_not_nonneg, dvd_negSucc, negSucc_dvd,
|
||||
false_or]
|
||||
norm_cast
|
||||
rw [Int.natCast_add, Int.natCast_one, Nat.succ_div]
|
||||
@@ -510,32 +516,29 @@ theorem ediv_neg_of_neg_of_pos {a b : Int} (Ha : a < 0) (Hb : 0 < b) : a / b < 0
|
||||
match a, b, eq_negSucc_of_lt_zero Ha, eq_succ_of_zero_lt Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => negSucc_lt_zero _
|
||||
|
||||
@[deprecated ediv_neg_of_neg_of_pos (since := "2025-03-04")]
|
||||
abbrev ediv_neg' := @ediv_neg_of_neg_of_pos
|
||||
|
||||
theorem negSucc_ediv (m : Nat) {b : Int} (H : 0 < b) : -[m+1] / b = -(ediv m b + 1) :=
|
||||
match b, eq_succ_of_zero_lt H with
|
||||
| _, ⟨_, rfl⟩ => rfl
|
||||
|
||||
theorem ediv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a / b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_zero_le _
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => natCast_nonneg _
|
||||
|
||||
theorem ediv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0) : 0 ≤ a / b := by
|
||||
match a, b with
|
||||
| ofNat a, b =>
|
||||
match Int.le_antisymm Ha (ofNat_zero_le a) with
|
||||
match Int.le_antisymm Ha (natCast_nonneg a) with
|
||||
| h1 =>
|
||||
rw [h1, zero_ediv]
|
||||
exact Int.le_refl 0
|
||||
| a, ofNat b =>
|
||||
match Int.le_antisymm Hb (ofNat_zero_le b) with
|
||||
match Int.le_antisymm Hb (natCast_nonneg b) with
|
||||
| h1 =>
|
||||
rw [h1, Int.ediv_zero]
|
||||
exact Int.le_refl 0
|
||||
| negSucc a, negSucc b =>
|
||||
rw [Int.div_def, ediv]
|
||||
exact le_add_one (ediv_nonneg (ofNat_zero_le a) (Int.le_trans (ofNat_zero_le b) (le.intro 1 rfl)))
|
||||
exact le_add_one (ediv_nonneg (natCast_nonneg a) (Int.le_trans (natCast_nonneg b) (le.intro 1 rfl)))
|
||||
|
||||
theorem ediv_pos_of_neg_of_neg {a b : Int} (ha : a < 0) (hb : b < 0) : 0 < a / b := by
|
||||
rw [Int.div_def]
|
||||
@@ -545,9 +548,6 @@ theorem ediv_pos_of_neg_of_neg {a b : Int} (ha : a < 0) (hb : b < 0) : 0 < a / b
|
||||
theorem ediv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a / b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.ediv_neg .. ▸ Int.ediv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
@[deprecated ediv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev ediv_nonpos := @ediv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem ediv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a / b = 0 :=
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
@@ -565,7 +565,7 @@ theorem ediv_eq_one_of_neg_of_le {a b : Int} (H1 : a < 0) (H2 : b ≤ a) : a / b
|
||||
match a, b, H1, H2 with
|
||||
| negSucc a', ofNat n', H1, H2 => simp [Int.negSucc_eq] at H2; omega
|
||||
| negSucc a', negSucc b', H1, H2 =>
|
||||
rw [Int.div_def, ediv, ofNat_eq_coe]
|
||||
rw [Int.div_def, ediv, ofNat_eq_natCast]
|
||||
norm_cast
|
||||
rw [Nat.succ_eq_add_one, Nat.add_eq_right, Nat.div_eq_zero_iff_lt (by omega)]
|
||||
simp [Int.negSucc_eq] at H2
|
||||
@@ -585,7 +585,7 @@ theorem neg_one_ediv (b : Int) : -1 / b = -b.sign :=
|
||||
match b with
|
||||
| ofNat 0 => by simp
|
||||
| ofNat (b + 1) =>
|
||||
ediv_eq_neg_one_of_neg_of_le (by decide) (by simp [ofNat_eq_coe]; omega)
|
||||
ediv_eq_neg_one_of_neg_of_le (by decide) (by simp [ofNat_eq_natCast]; omega)
|
||||
| negSucc b =>
|
||||
ediv_eq_one_of_neg_of_le (by decide) (by omega)
|
||||
|
||||
@@ -652,7 +652,7 @@ theorem sign_ediv (a b : Int) : sign (a / b) = if 0 ≤ a ∧ a < b.natAbs then
|
||||
| (a + 1 : Nat) =>
|
||||
norm_cast
|
||||
simp only [Nat.le_add_left, Nat.add_lt_add_iff_right, true_and, Int.natCast_add,
|
||||
cast_ofNat_Int, sign_of_add_one, Int.mul_one]
|
||||
cast_ofNat_Int, sign_natCast_add_one, Int.mul_one]
|
||||
split
|
||||
· rw [Nat.div_eq_of_lt (by omega)]
|
||||
simp
|
||||
@@ -678,25 +678,15 @@ theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
|
||||
@[simp] theorem add_neg_mul_emod_self_right (a b c : Int) : (a + -(b * c)) % c = a % c := by
|
||||
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self_right]
|
||||
|
||||
@[deprecated add_neg_mul_emod_self_right (since := "2025-04-11")]
|
||||
theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c :=
|
||||
add_neg_mul_emod_self_right ..
|
||||
|
||||
@[simp] theorem add_neg_mul_emod_self_left (a b c : Int) : (a + -(b * c)) % b = a % b := by
|
||||
rw [Int.neg_mul_eq_mul_neg, add_mul_emod_self_left]
|
||||
|
||||
@[simp] theorem add_emod_right (a b : Int) : (a + b) % b = a % b := by
|
||||
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
|
||||
|
||||
@[deprecated add_emod_right (since := "2025-04-11")]
|
||||
theorem add_emod_self {a b : Int} : (a + b) % b = a % b := add_emod_right ..
|
||||
|
||||
@[simp] theorem add_emod_left (a b : Int) : (a + b) % a = b % a := by
|
||||
rw [Int.add_comm, add_emod_right]
|
||||
|
||||
@[deprecated add_emod_left (since := "2025-04-11")]
|
||||
theorem add_emod_self_left {a b : Int} : (a + b) % a = b % a := add_emod_left ..
|
||||
|
||||
@[simp] theorem sub_mul_emod_self_right (a b c : Int) : (a - b * c) % c = a % c := by
|
||||
simp [Int.sub_eq_add_neg]
|
||||
|
||||
@@ -937,9 +927,6 @@ where
|
||||
| -[_+1], 0 => Nat.zero_le _
|
||||
| -[_+1], succ _ => Nat.succ_le_succ (Nat.div_le_self _ _)
|
||||
|
||||
@[deprecated natAbs_ediv_le_natAbs (since := "2025-03-05")]
|
||||
abbrev natAbs_div_le_natAbs := natAbs_ediv_le_natAbs
|
||||
|
||||
theorem ediv_le_self {a : Int} (b : Int) (Ha : 0 ≤ a) : a / b ≤ a := by
|
||||
have := Int.le_trans le_natAbs (ofNat_le.2 <| natAbs_ediv_le_natAbs a b)
|
||||
rwa [natAbs_of_nonneg Ha] at this
|
||||
@@ -972,14 +959,6 @@ theorem emod_eq_iff {a b c : Int} (hb : b ≠ 0) : a % b = c ↔ 0 ≤ c ∧ c <
|
||||
rw [← dvd_iff_emod_eq_zero, Int.dvd_neg]
|
||||
exact Int.dvd_mul_right a b
|
||||
|
||||
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
|
||||
theorem neg_mul_ediv_cancel (a b : Int) (h : b ≠ 0) : -(a * b) / b = -a := by
|
||||
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
|
||||
|
||||
@[deprecated mul_ediv_cancel (since := "2025-03-05")]
|
||||
theorem neg_mul_ediv_cancel_left (a b : Int) (h : a ≠ 0) : -(a * b) / a = -b := by
|
||||
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
|
||||
|
||||
@[simp] theorem ediv_one : ∀ a : Int, a / 1 = a
|
||||
| (_:Nat) => congrArg Nat.cast (Nat.div_one _)
|
||||
| -[_+1] => congrArg negSucc (Nat.div_one _)
|
||||
@@ -993,10 +972,6 @@ theorem ediv_minus_one (a : Int) : a / (-1) = -a := by
|
||||
theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
|
||||
simp
|
||||
|
||||
@[deprecated sub_emod_right (since := "2025-04-11")]
|
||||
theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
|
||||
sub_emod_right ..
|
||||
|
||||
@[simp] theorem add_neg_emod_self (a b : Int) : (a + -b) % b = a % b := by
|
||||
rw [Int.add_neg_eq_sub, sub_emod_right]
|
||||
|
||||
@@ -1007,10 +982,6 @@ theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
|
||||
theorem dvd_self_sub_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ a - c
|
||||
| _, rfl => dvd_self_sub_emod
|
||||
|
||||
@[deprecated dvd_self_sub_of_emod_eq (since := "2025-04-12")]
|
||||
theorem dvd_sub_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ a - c :=
|
||||
dvd_self_sub_of_emod_eq
|
||||
|
||||
theorem dvd_sub_self_of_emod_eq {a b : Int} : {c : Int} → a % b = c → b ∣ c - a
|
||||
| _, rfl => dvd_emod_sub_self
|
||||
|
||||
@@ -1098,7 +1069,7 @@ theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n ≠ 0) :
|
||||
match x, h with
|
||||
| -(x + 1 : Nat), _ =>
|
||||
rw [Int.natAbs_neg]
|
||||
rw [Int.natAbs_cast]
|
||||
rw [Int.natAbs_natCast]
|
||||
rw [Int.neg_emod]
|
||||
simp only [Int.dvd_neg]
|
||||
simp only [Int.natCast_dvd_natCast]
|
||||
@@ -1264,7 +1235,7 @@ private theorem ediv_ediv_of_pos {x y z : Int} (hy : 0 < y) (hz : 0 < z) :
|
||||
· rw [Int.mul_comm y, ← Int.mul_assoc, ← Int.add_mul, Int.mul_comm _ z]
|
||||
exact Int.lt_mul_of_ediv_lt hy (Int.lt_mul_ediv_self_add hz)
|
||||
|
||||
theorem ediv_ediv {x y z : Int} (hy : 0 ≤ y) : x / y / z = x / (y * z) := by
|
||||
theorem ediv_ediv_of_nonneg {x y z : Int} (hy : 0 ≤ y) : x / y / z = x / (y * z) := by
|
||||
rcases y with (_ | a) | a
|
||||
· simp
|
||||
· rcases z with (_ | b) | b
|
||||
@@ -1273,6 +1244,21 @@ theorem ediv_ediv {x y z : Int} (hy : 0 ≤ y) : x / y / z = x / (y * z) := by
|
||||
· simp [Int.negSucc_eq, Int.mul_neg, ediv_ediv_of_pos]
|
||||
· simp at hy
|
||||
|
||||
theorem ediv_ediv {x y z : Int} : x / y / z = x / (y * z) - if y < 0 ∧ ¬ z ∣ x / y then z.sign else 0 := by
|
||||
rcases y with y | y
|
||||
· rw [ediv_ediv_of_nonneg (by simp), if_neg (by simp; omega)]
|
||||
simp
|
||||
· rw [Int.negSucc_eq, Int.ediv_neg, Int.neg_mul, Int.ediv_neg, Int.neg_ediv, ediv_ediv_of_nonneg (by omega)]
|
||||
simp
|
||||
|
||||
theorem ediv_mul {x y z : Int} : x / (y * z) = x / y / z + if y < 0 ∧ ¬ z ∣ x / y then z.sign else 0 := by
|
||||
have := ediv_ediv (x := x) (y := y) (z := z)
|
||||
omega
|
||||
|
||||
theorem ediv_mul_of_nonneg {x y z : Int} (hy : 0 ≤ y) : x / (y * z) = x / y / z := by
|
||||
have := ediv_ediv_of_nonneg (x := x) (y := y) (z := z) hy
|
||||
omega
|
||||
|
||||
/-! ### tdiv -/
|
||||
|
||||
-- `tdiv` analogues of `ediv` lemmas from `Bootstrap.lean`
|
||||
@@ -1306,7 +1292,7 @@ because these statements are all incorrect, and require awkward conditional off-
|
||||
|
||||
protected theorem tdiv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a.tdiv b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_zero_le _
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => natCast_nonneg _
|
||||
|
||||
theorem tdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0) : 0 ≤ a.tdiv b := by
|
||||
rw [tdiv_eq_ediv]
|
||||
@@ -1329,9 +1315,6 @@ theorem tdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0
|
||||
protected theorem tdiv_nonpos_of_nonneg_of_nonpos {a b : Int} (Ha : 0 ≤ a) (Hb : b ≤ 0) : a.tdiv b ≤ 0 :=
|
||||
Int.nonpos_of_neg_nonneg <| Int.tdiv_neg .. ▸ Int.tdiv_nonneg Ha (Int.neg_nonneg_of_nonpos Hb)
|
||||
|
||||
@[deprecated Int.tdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev tdiv_nonpos := @Int.tdiv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem tdiv_eq_zero_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.tdiv b = 0 :=
|
||||
match a, b, eq_ofNat_of_zero_le H1, eq_succ_of_zero_lt (Int.lt_of_le_of_lt H1 H2) with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => congrArg Nat.cast <| Nat.div_eq_of_lt <| ofNat_lt.1 H2
|
||||
@@ -1427,7 +1410,7 @@ theorem tmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : tmod a b < b :=
|
||||
|
||||
theorem lt_tmod_of_pos (a : Int) {b : Int} (H : 0 < b) : -b < tmod a b :=
|
||||
match a, b, eq_succ_of_zero_lt H with
|
||||
| ofNat _, _, ⟨n, rfl⟩ => by rw [ofNat_eq_coe, ← Int.natCast_succ, ← ofNat_tmod]; omega
|
||||
| ofNat _, _, ⟨n, rfl⟩ => by rw [ofNat_eq_natCast, ← Int.natCast_succ, ← ofNat_tmod]; omega
|
||||
| -[a+1], _, ⟨n, rfl⟩ => by
|
||||
rw [negSucc_eq, neg_tmod, ← Int.natCast_add_one, ← Int.natCast_add_one, ← ofNat_tmod]
|
||||
have : (a + 1) % (n + 1) < n + 1 := Nat.mod_lt _ (Nat.zero_lt_succ n)
|
||||
@@ -1874,7 +1857,7 @@ theorem le_emod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b
|
||||
match b, h with
|
||||
| .ofNat 1, h => simp
|
||||
| .ofNat (b + 2), h =>
|
||||
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int] at *
|
||||
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int] at *
|
||||
constructor
|
||||
· rw [dvd_iff_emod_eq_zero]
|
||||
intro w
|
||||
@@ -1890,16 +1873,12 @@ theorem le_emod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b
|
||||
sign_eq_one_of_pos (by omega), Int.mul_add]
|
||||
omega
|
||||
|
||||
@[deprecated le_emod_self_add_one_iff (since := "2025-04-12")]
|
||||
theorem le_mod_self_add_one_iff {a b : Int} (h : 0 < b) : b ≤ a % b + 1 ↔ b ∣ a + 1 :=
|
||||
le_emod_self_add_one_iff h
|
||||
|
||||
theorem add_one_tdiv_of_pos {a b : Int} (h : 0 < b) :
|
||||
(a + 1).tdiv b = a.tdiv b + if (0 < a + 1 ∧ b ∣ a + 1) ∨ (a < 0 ∧ b ∣ a) then 1 else 0 := by
|
||||
match b, h with
|
||||
| .ofNat 1, h => simp; omega
|
||||
| .ofNat (b + 2), h =>
|
||||
simp only [ofNat_eq_coe]
|
||||
simp only [ofNat_eq_natCast]
|
||||
rw [tdiv_eq_ediv, add_ediv (by omega), tdiv_eq_ediv]
|
||||
simp only [Int.natCast_add, cast_ofNat_Int]
|
||||
have : 1 / (b + 2 : Int) = 0 := by rw [one_ediv]; omega
|
||||
@@ -2014,7 +1993,7 @@ theorem add_fdiv_of_dvd_left {a b c : Int} (H : c ∣ a) : (a + b).fdiv c = a.fd
|
||||
|
||||
theorem fdiv_nonneg {a b : Int} (Ha : 0 ≤ a) (Hb : 0 ≤ b) : 0 ≤ a.fdiv b :=
|
||||
match a, b, eq_ofNat_of_zero_le Ha, eq_ofNat_of_zero_le Hb with
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_fdiv .. ▸ ofNat_zero_le _
|
||||
| _, _, ⟨_, rfl⟩, ⟨_, rfl⟩ => ofNat_fdiv .. ▸ natCast_nonneg _
|
||||
|
||||
theorem fdiv_nonneg_of_nonpos_of_nonpos {a b : Int} (Ha : a ≤ 0) (Hb : b ≤ 0) : 0 ≤ a.fdiv b := by
|
||||
rw [fdiv_eq_ediv]
|
||||
@@ -2029,9 +2008,6 @@ theorem fdiv_nonpos_of_nonneg_of_nonpos : ∀ {a b : Int}, 0 ≤ a → b ≤ 0
|
||||
| 0, 0, _, _ | 0, -[_+1], _, _ | succ _, 0, _, _ | succ _, -[_+1], _, _ => by
|
||||
simp [fdiv, negSucc_le_zero]
|
||||
|
||||
@[deprecated fdiv_nonpos_of_nonneg_of_nonpos (since := "2025-03-04")]
|
||||
abbrev fdiv_nonpos := @fdiv_nonpos_of_nonneg_of_nonpos
|
||||
|
||||
theorem fdiv_neg_of_neg_of_pos : ∀ {a b : Int}, a < 0 → 0 < b → a.fdiv b < 0
|
||||
| -[_+1], succ _, _, _ => negSucc_lt_zero _
|
||||
|
||||
@@ -2066,8 +2042,8 @@ protected theorem fdiv_eq_of_eq_mul_right {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = b * c) : a.fdiv b = c := by rw [H2, Int.mul_fdiv_cancel_left _ H1]
|
||||
|
||||
protected theorem eq_fdiv_of_mul_eq_right {a b c : Int}
|
||||
(H1 : a ≠ 0) (H2 : a * b = c) : b = c.tdiv a :=
|
||||
(Int.tdiv_eq_of_eq_mul_right H1 H2.symm).symm
|
||||
(H1 : a ≠ 0) (H2 : a * b = c) : b = c.fdiv a :=
|
||||
(Int.fdiv_eq_of_eq_mul_right H1 H2.symm).symm
|
||||
|
||||
protected theorem fdiv_eq_of_eq_mul_left {a b c : Int}
|
||||
(H1 : b ≠ 0) (H2 : a = c * b) : a.fdiv b = c :=
|
||||
@@ -2104,20 +2080,20 @@ theorem neg_fdiv {a b : Int} : (-a).fdiv b = -(a.fdiv b) - if b = 0 ∨ b ∣ a
|
||||
| ofNat (a + 1), 0 => simp
|
||||
| ofNat (a + 1), ofNat (b + 1) =>
|
||||
unfold fdiv
|
||||
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
rw [← negSucc_eq, ← negSucc_eq]
|
||||
| ofNat (a + 1), -[b+1] =>
|
||||
unfold fdiv
|
||||
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
rw [← negSucc_eq, neg_negSucc]
|
||||
| -[a+1], 0 => simp
|
||||
| -[a+1], ofNat (b + 1) =>
|
||||
unfold fdiv
|
||||
simp only [ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
simp only [ofNat_eq_natCast, Int.natCast_add, cast_ofNat_Int, Nat.succ_eq_add_one]
|
||||
rw [neg_negSucc, ← negSucc_eq]
|
||||
| -[a+1], -[b+1] =>
|
||||
unfold fdiv
|
||||
simp only [ofNat_eq_coe, natCast_ediv, Nat.succ_eq_add_one, Int.natCast_add, cast_ofNat_Int]
|
||||
simp only [ofNat_eq_natCast, natCast_ediv, Nat.succ_eq_add_one, Int.natCast_add, cast_ofNat_Int]
|
||||
rw [neg_negSucc, neg_negSucc]
|
||||
simp
|
||||
|
||||
@@ -2150,9 +2126,6 @@ theorem fmod_nonneg {a b : Int} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a.fmod b :
|
||||
theorem fmod_nonneg_of_pos (a : Int) {b : Int} (hb : 0 < b) : 0 ≤ a.fmod b :=
|
||||
fmod_eq_emod_of_nonneg _ (Int.le_of_lt hb) ▸ emod_nonneg _ (Int.ne_of_lt hb).symm
|
||||
|
||||
@[deprecated fmod_nonneg_of_pos (since := "2025-03-04")]
|
||||
abbrev fmod_nonneg' := @fmod_nonneg_of_pos
|
||||
|
||||
theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
fmod_eq_emod_of_nonneg _ (Int.le_of_lt H) ▸ emod_lt_of_pos a H
|
||||
|
||||
@@ -2162,10 +2135,6 @@ theorem fmod_lt_of_pos (a : Int) {b : Int} (H : 0 < b) : a.fmod b < b :=
|
||||
rw [fmod_eq_emod, add_mul_emod_self_right, fmod_eq_emod]
|
||||
simp
|
||||
|
||||
@[deprecated add_mul_fmod_self_right (since := "2025-04-11")]
|
||||
theorem add_mul_fmod_self {a b c : Int} : (a + b * c).fmod c = a.fmod c :=
|
||||
add_mul_fmod_self_right ..
|
||||
|
||||
@[simp] theorem add_mul_fmod_self_left (a b c : Int) : (a + b * c).fmod b = a.fmod b := by
|
||||
rw [Int.mul_comm, Int.add_mul_fmod_self_right]
|
||||
|
||||
@@ -2413,7 +2382,7 @@ theorem natAbs_fdiv_le_natAbs (a b : Int) : natAbs (a.fdiv b) ≤ natAbs a := by
|
||||
| 0, .negSucc b, h => simp at h
|
||||
| .ofNat (a + 1), .negSucc 0, h => simp at h
|
||||
| .ofNat (a + 1), .negSucc (b + 1), h =>
|
||||
rw [negSucc_eq, ofNat_eq_coe]
|
||||
rw [negSucc_eq, ofNat_eq_natCast]
|
||||
norm_cast
|
||||
rw [Int.ediv_neg, Int.sub_eq_add_neg, ← Int.neg_add, natAbs_neg]
|
||||
norm_cast
|
||||
@@ -2464,20 +2433,12 @@ theorem dvd_sub_self_of_fmod_eq {a b c : Int} (h : a.fmod b = c) :
|
||||
@[simp] theorem fmod_one (a : Int) : a.fmod 1 = 0 := by
|
||||
simp [fmod_def, Int.one_mul, Int.sub_self]
|
||||
|
||||
@[deprecated sub_fmod_right (since := "2025-04-12")]
|
||||
theorem fmod_sub_cancel (x y : Int) : (x - y).fmod y = x.fmod y :=
|
||||
sub_fmod_right _ _
|
||||
|
||||
@[simp] theorem add_neg_fmod_self (a b : Int) : (a + -b).fmod b = a.fmod b := by
|
||||
rw [Int.add_neg_eq_sub, sub_fmod_right]
|
||||
|
||||
@[simp] theorem neg_add_fmod_self (a b : Int) : (-a + b).fmod a = b.fmod a := by
|
||||
rw [Int.add_comm, add_neg_fmod_self]
|
||||
|
||||
@[deprecated dvd_self_sub_of_fmod_eq (since := "2025-04-12")]
|
||||
theorem dvd_sub_of_fmod_eq {a b c : Int} (h : a.fmod b = c) : b ∣ a - c :=
|
||||
dvd_self_sub_of_fmod_eq h
|
||||
|
||||
theorem fdiv_sign {a b : Int} : a.fdiv (sign b) = a * sign b := by
|
||||
rw [fdiv_eq_ediv]
|
||||
rcases sign_trichotomy b with h | h | h <;> simp [h]
|
||||
@@ -2511,10 +2472,6 @@ theorem lt_mul_fdiv_self_add {x k : Int} (h : 0 < k) : x < k * (x.fdiv k) + k :=
|
||||
theorem emod_bmod (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
|
||||
simp [bmod]
|
||||
|
||||
@[deprecated emod_bmod (since := "2025-04-11")]
|
||||
theorem emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n :=
|
||||
emod_bmod ..
|
||||
|
||||
theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
|
||||
unfold bdiv bmod
|
||||
split
|
||||
@@ -2541,6 +2498,10 @@ theorem bmod_eq_self_sub_mul_bdiv (x : Int) (m : Nat) : bmod x m = x - m * bdiv
|
||||
theorem bmod_eq_self_sub_bdiv_mul (x : Int) (m : Nat) : bmod x m = x - bdiv x m * m := by
|
||||
rw [← Int.add_sub_cancel (bmod x m), bmod_add_bdiv']
|
||||
|
||||
theorem bmod_eq_emod_of_lt {x : Int} {m : Nat} (hx : x % m < (m + 1) / 2) : bmod x m = x % m := by
|
||||
simp [bmod, hx]
|
||||
|
||||
@[deprecated Int.bmod_eq_emod_of_lt (since := "2025-10-29")]
|
||||
theorem bmod_pos (x : Int) (m : Nat) (p : x % m < (m + 1) / 2) : bmod x m = x % m := by
|
||||
simp [bmod_def, p]
|
||||
|
||||
@@ -2550,15 +2511,12 @@ theorem bmod_neg (x : Int) (m : Nat) (p : x % m ≥ (m + 1) / 2) : bmod x m = (x
|
||||
theorem bmod_eq_emod (x : Int) (m : Nat) : bmod x m = x % m - if x % m ≥ (m + 1) / 2 then m else 0 := by
|
||||
split
|
||||
· rwa [bmod_neg]
|
||||
· rw [bmod_pos] <;> simp_all
|
||||
· rw [bmod_eq_emod_of_lt] <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem bmod_one (x : Int) : Int.bmod x 1 = 0 := by
|
||||
simp [Int.bmod]
|
||||
|
||||
@[deprecated bmod_one (since := "2025-04-10")]
|
||||
abbrev bmod_one_is_zero := @bmod_one
|
||||
|
||||
@[simp] theorem add_bmod_right (a : Int) (b : Nat) : (a + b).bmod b = a.bmod b := by
|
||||
simp [bmod_def]
|
||||
|
||||
@@ -2601,76 +2559,36 @@ abbrev bmod_one_is_zero := @bmod_one
|
||||
@[simp] theorem add_neg_mul_bmod_self_left (a : Int) (b : Nat) (c : Int) : (a + -(b * c)).bmod b = a.bmod b := by
|
||||
simp [bmod_def]
|
||||
|
||||
@[deprecated add_bmod_right (since := "2025-04-10")]
|
||||
theorem bmod_add_cancel {x : Int} {n : Nat} : Int.bmod (x + n) n = Int.bmod x n :=
|
||||
add_bmod_right ..
|
||||
|
||||
@[deprecated add_mul_bmod_self_left (since := "2025-04-10")]
|
||||
theorem bmod_add_mul_cancel (x : Int) (n : Nat) (k : Int) : Int.bmod (x + n * k) n = Int.bmod x n :=
|
||||
add_mul_bmod_self_left ..
|
||||
|
||||
@[deprecated sub_bmod_right (since := "2025-04-10")]
|
||||
theorem bmod_sub_cancel (x : Int) (n : Nat) : Int.bmod (x - n) n = Int.bmod x n :=
|
||||
sub_bmod_right ..
|
||||
|
||||
@[deprecated sub_mul_bmod_self_left (since := "2025-04-10")]
|
||||
theorem Int.bmod_sub_mul_cancel (x : Int) (n : Nat) (k : Int) : (x - n * k).bmod n = x.bmod n :=
|
||||
sub_mul_bmod_self_left ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_add_bmod (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n := by
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_add_bmod (since := "2025-04-11")]
|
||||
theorem emod_add_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n + y) n = Int.bmod (x + y) n :=
|
||||
emod_add_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_sub_bmod (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n := by
|
||||
simp only [emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_right_comm, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_sub_bmod (since := "2025-04-11")]
|
||||
theorem emod_sub_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n - y) n = Int.bmod (x - y) n :=
|
||||
emod_sub_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem sub_emod_bmod (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n := by
|
||||
simp only [emod_def]
|
||||
rw [Int.sub_eq_add_neg, Int.neg_sub, Int.sub_eq_add_neg, ← Int.add_assoc, Int.add_right_comm,
|
||||
Int.add_mul_bmod_self_left, Int.sub_eq_add_neg]
|
||||
|
||||
@[deprecated sub_emod_bmod (since := "2025-04-11")]
|
||||
theorem sub_emod_bmod_congr (x : Int) (n : Nat) : Int.bmod (x - y % n) n = Int.bmod (x - y) n :=
|
||||
sub_emod_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem emod_mul_bmod (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n := by
|
||||
simp [Int.emod_def, Int.sub_eq_add_neg]
|
||||
rw [←Int.mul_neg, Int.add_mul, Int.mul_assoc, Int.add_mul_bmod_self_left]
|
||||
|
||||
@[deprecated emod_mul_bmod (since := "2025-04-11")]
|
||||
theorem emod_mul_bmod_congr (x : Int) (n : Nat) : Int.bmod (x % n * y) n = Int.bmod (x * y) n :=
|
||||
emod_mul_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem bmod_add_bmod : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
|
||||
have := (@add_mul_bmod_self_left (Int.bmod x n + y) n (bdiv x n)).symm
|
||||
rwa [Int.add_right_comm, bmod_add_bdiv] at this
|
||||
|
||||
@[deprecated bmod_add_bmod (since := "2025-04-11")]
|
||||
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n :=
|
||||
bmod_add_bmod ..
|
||||
|
||||
@[simp]
|
||||
theorem bmod_sub_bmod : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
|
||||
@bmod_add_bmod x n (-y)
|
||||
|
||||
@[deprecated bmod_sub_bmod (since := "2025-04-11")]
|
||||
theorem bmod_sub_bmod_congr : Int.bmod (Int.bmod x n - y) n = Int.bmod (x - y) n :=
|
||||
bmod_sub_bmod ..
|
||||
|
||||
theorem add_bmod_eq_add_bmod_right (i : Int)
|
||||
(H : bmod x n = bmod y n) : bmod (x + i) n = bmod (y + i) n := by
|
||||
rw [← bmod_add_bmod, ← @bmod_add_bmod y, H]
|
||||
@@ -2830,9 +2748,6 @@ theorem bmod_eq_iff {a : Int} {b : Nat} {c : Int} (hb : 0 < b) :
|
||||
have := bmod_lt (x := a) (m := b) hb
|
||||
omega
|
||||
|
||||
theorem bmod_eq_emod_of_lt {x : Int} {m : Nat} (hx : x % m < (m + 1) / 2) : bmod x m = x % m := by
|
||||
simp [bmod, hx]
|
||||
|
||||
theorem bmod_eq_neg {n : Nat} {m : Int} (hm : 0 ≤ m) (hn : n = 2 * m) : m.bmod n = -m := by
|
||||
by_cases h : m = 0
|
||||
· subst h; simp
|
||||
@@ -2863,9 +2778,6 @@ theorem bmod_natAbs_add_one (x : Int) (w : x ≠ -1) : x.bmod (x.natAbs + 1) = -
|
||||
· rw [sign_eq_one_iff_pos.2 hx]
|
||||
exact ⟨by omega, by omega, ⟨-1, by omega⟩⟩
|
||||
|
||||
@[deprecated bmod_natAbs_add_one (since := "2025-04-04")]
|
||||
abbrev bmod_natAbs_plus_one := @bmod_natAbs_add_one
|
||||
|
||||
theorem bmod_self_add_one {x : Nat} : (x : Int).bmod (x + 1) = if x = 0 then 0 else -1 := by
|
||||
have := bmod_natAbs_add_one x (by omega)
|
||||
simp only [natAbs_natCast] at this
|
||||
@@ -2876,7 +2788,7 @@ theorem one_bmod_two : Int.bmod 1 2 = -1 := by simp
|
||||
|
||||
theorem one_bmod {b : Nat} (h : 3 ≤ b) : Int.bmod 1 b = 1 := by
|
||||
have hb : 1 % (b : Int) = 1 := by rw [one_emod]; omega
|
||||
rw [bmod_pos _ _ (by omega), hb]
|
||||
rw [bmod_eq_emod_of_lt (by omega), hb]
|
||||
|
||||
theorem bmod_two_eq (x : Int) : x.bmod 2 = -1 ∨ x.bmod 2 = 0 := by
|
||||
have := le_bmod (x := x) (m := 2) (by omega)
|
||||
@@ -2986,11 +2898,6 @@ theorem bmod_eq_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m +
|
||||
n.bmod m = n :=
|
||||
(Nat.eq_zero_or_pos m).elim (by rintro rfl; simp) (fun hm => by simp_all [bmod_eq_iff])
|
||||
|
||||
@[deprecated bmod_eq_of_le (since := "2025-04-11")]
|
||||
theorem bmod_eq_self_of_le {n : Int} {m : Nat} (hn' : -(m / 2) ≤ n) (hn : n < (m + 1) / 2) :
|
||||
n.bmod m = n :=
|
||||
bmod_eq_of_le hn' hn
|
||||
|
||||
theorem bmod_bmod_of_dvd {a : Int} {n m : Nat} (hnm : n ∣ m) :
|
||||
(a.bmod m).bmod n = a.bmod n := by
|
||||
rw [← Int.sub_eq_iff_eq_add.2 (bmod_add_bdiv a m).symm]
|
||||
@@ -3001,11 +2908,6 @@ theorem bmod_eq_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x
|
||||
x.bmod y = x := by
|
||||
apply bmod_eq_of_le (by omega) (by omega)
|
||||
|
||||
@[deprecated bmod_eq_of_le_mul_two (since := "2025-04-11")]
|
||||
theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt : x * 2 < y) :
|
||||
x.bmod y = x :=
|
||||
bmod_eq_of_le_mul_two hle hlt
|
||||
|
||||
/- ### ediv -/
|
||||
|
||||
theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
|
||||
@@ -3024,7 +2926,7 @@ theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y
|
||||
obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
|
||||
obtain ⟨yn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
|
||||
rw [← Int.natCast_ediv]
|
||||
exact Int.ofNat_zero_le (xn / yn)
|
||||
exact natCast_nonneg (xn / yn)
|
||||
|
||||
/-- When both x and y are negative we need stricter bounds on x and y
|
||||
to establish the upper bound of x/y, i.e., x / y < x.natAbs.
|
||||
@@ -3061,7 +2963,7 @@ theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y
|
||||
· obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
|
||||
obtain ⟨yn, rfl⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
|
||||
rw [show xn = ofNat xn by norm_cast, Int.ofNat_ediv_negSucc (a := xn)]
|
||||
simp only [ofNat_eq_coe, natCast_ediv, Int.natCast_add, cast_ofNat_Int, Int.neg_le_neg_iff]
|
||||
simp only [ofNat_eq_natCast, natCast_ediv, Int.natCast_add, cast_ofNat_Int, Int.neg_le_neg_iff]
|
||||
norm_cast
|
||||
apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
|
||||
|
||||
|
||||
35
src/Init/Data/Int/DivMod/Pow.lean
Normal file
35
src/Init/Data/Int/DivMod/Pow.lean
Normal file
@@ -0,0 +1,35 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
public import Init.Data.Int.Pow
|
||||
|
||||
/-!
|
||||
# Lemmas about divisibility of powers
|
||||
-/
|
||||
|
||||
namespace Int
|
||||
|
||||
theorem dvd_pow {a b : Int} {n : Nat} (hab : b ∣ a) : b ^ n ∣ a ^ n := by
|
||||
rcases hab with ⟨c, rfl⟩
|
||||
rw [Int.mul_pow]
|
||||
exact Int.dvd_mul_right (b ^ n) (c ^ n)
|
||||
|
||||
theorem ediv_pow {a b : Int} {n : Nat} (hab : b ∣ a) :
|
||||
(a / b) ^ n = a ^ n / b ^ n := by
|
||||
obtain ⟨c, rfl⟩ := hab
|
||||
by_cases b = 0
|
||||
· by_cases n = 0 <;> simp [*, Int.zero_pow]
|
||||
· simp [Int.mul_pow, Int.pow_ne_zero, *]
|
||||
|
||||
theorem tdiv_pow {a b : Int} {n : Nat} (hab : b ∣ a) :
|
||||
(a.tdiv b) ^ n = (a ^ n).tdiv (b ^ n) := by
|
||||
rw [Int.tdiv_eq_ediv_of_dvd hab, ediv_pow hab, Int.tdiv_eq_ediv_of_dvd (dvd_pow hab)]
|
||||
|
||||
theorem fdiv_pow {a b : Int} {n : Nat} (hab : b ∣ a) :
|
||||
(a.fdiv b) ^ n = (a ^ n).fdiv (b ^ n) := by
|
||||
rw [Int.fdiv_eq_ediv_of_dvd hab, ediv_pow hab, Int.fdiv_eq_ediv_of_dvd (dvd_pow hab)]
|
||||
@@ -17,7 +17,7 @@ open Nat
|
||||
/-! ## Definitions of basic functions -/
|
||||
|
||||
theorem subNatNat_of_sub_eq_zero {m n : Nat} (h : n - m = 0) : subNatNat m n = ↑(m - n) := by
|
||||
rw [subNatNat, h, ofNat_eq_coe]
|
||||
rw [subNatNat, h, ofNat_eq_natCast]
|
||||
|
||||
theorem subNatNat_of_sub_eq_succ {m n k : Nat} (h : n - m = succ k) : subNatNat m n = -[k+1] := by
|
||||
rw [subNatNat, h]
|
||||
@@ -74,9 +74,6 @@ theorem negSucc_inj : negSucc m = negSucc n ↔ m = n := ⟨negSucc.inj, fun H =
|
||||
|
||||
theorem negSucc_eq (n : Nat) : -[n+1] = -((n : Int) + 1) := rfl
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_coe (n : Nat) : -[n+1] = -↑(n + 1) := rfl
|
||||
|
||||
@[simp] theorem negSucc_ne_zero (n : Nat) : -[n+1] ≠ 0 := nofun
|
||||
|
||||
@[simp] theorem zero_ne_negSucc (n : Nat) : 0 ≠ -[n+1] := nofun
|
||||
@@ -132,7 +129,7 @@ theorem subNatNat_elim (m n : Nat) (motive : Nat → Nat → Int → Prop)
|
||||
|
||||
theorem subNatNat_add_left : subNatNat (m + n) m = n := by
|
||||
unfold subNatNat
|
||||
rw [Nat.sub_eq_zero_of_le (Nat.le_add_right ..), Nat.add_sub_cancel_left, ofNat_eq_coe]
|
||||
rw [Nat.sub_eq_zero_of_le (Nat.le_add_right ..), Nat.add_sub_cancel_left, ofNat_eq_natCast]
|
||||
|
||||
theorem subNatNat_add_right : subNatNat m (m + n + 1) = negSucc n := by
|
||||
simp [subNatNat, Nat.add_assoc, Nat.add_sub_cancel_left]
|
||||
@@ -353,10 +350,6 @@ protected theorem add_sub_assoc (a b c : Int) : a + b - c = a + (b - c) := by
|
||||
change ofNat (n - succ m) = subNatNat n (succ m)
|
||||
rw [subNatNat, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_coe' (n : Nat) : -[n+1] = -↑n - 1 := by
|
||||
rw [Int.sub_eq_add_neg, ← Int.neg_add]; rfl
|
||||
|
||||
protected theorem subNatNat_eq_coe {m n : Nat} : subNatNat m n = ↑m - ↑n := by
|
||||
apply subNatNat_elim m n fun m n i => i = m - n
|
||||
· intro i n
|
||||
@@ -559,7 +552,7 @@ protected theorem mul_eq_zero {a b : Int} : a * b = 0 ↔ a = 0 ∨ b = 0 := by
|
||||
exact match a, b, h with
|
||||
| .ofNat 0, _, _ => by simp
|
||||
| _, .ofNat 0, _ => by simp
|
||||
| .ofNat (a+1), .negSucc b, h => by cases h
|
||||
| .ofNat (_+1), .negSucc _, h => by cases h
|
||||
|
||||
protected theorem mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 :=
|
||||
Or.rec a0 b0 ∘ Int.mul_eq_zero.mp
|
||||
@@ -607,6 +600,4 @@ protected theorem natCast_zero : ((0 : Nat) : Int) = (0 : Int) := rfl
|
||||
|
||||
protected theorem natCast_one : ((1 : Nat) : Int) = (1 : Int) := rfl
|
||||
|
||||
@[simp, norm_cast] theorem natAbs_cast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
end Int
|
||||
|
||||
@@ -27,28 +27,28 @@ namespace Int
|
||||
natCast_nonneg _
|
||||
|
||||
@[simp] theorem neg_natCast_le_natCast (n m : Nat) : -(n : Int) ≤ (m : Int) :=
|
||||
Int.le_trans (by simp) (ofNat_zero_le m)
|
||||
Int.le_trans (by simp) (natCast_nonneg m)
|
||||
|
||||
@[simp] theorem neg_natCast_le_ofNat (n m : Nat) : -(n : Int) ≤ (no_index (OfNat.ofNat m)) :=
|
||||
Int.le_trans (by simp) (ofNat_zero_le m)
|
||||
Int.le_trans (by simp) (natCast_nonneg m)
|
||||
|
||||
@[simp] theorem neg_ofNat_le_ofNat (n m : Nat) : -(no_index (OfNat.ofNat n)) ≤ (no_index (OfNat.ofNat m)) :=
|
||||
Int.le_trans (by simp) (ofNat_zero_le m)
|
||||
Int.le_trans (by simp) (natCast_nonneg m)
|
||||
|
||||
@[simp] theorem neg_ofNat_le_natCast (n m : Nat) : -(no_index (OfNat.ofNat n)) ≤ (m : Int) :=
|
||||
Int.le_trans (by simp) (ofNat_zero_le m)
|
||||
Int.le_trans (by simp) (natCast_nonneg m)
|
||||
|
||||
theorem neg_lt_self_iff {n : Int} : -n < n ↔ 0 < n := by
|
||||
omega
|
||||
|
||||
@[deprecated ofNat_add_ofNat (since := "2025-10-26")]
|
||||
protected theorem ofNat_add_out (m n : Nat) : ↑m + ↑n = (↑(m + n) : Int) := rfl
|
||||
|
||||
@[deprecated ofNat_mul_ofNat (since := "2025-10-26")]
|
||||
protected theorem ofNat_mul_out (m n : Nat) : ↑m * ↑n = (↑(m * n) : Int) := rfl
|
||||
|
||||
protected theorem ofNat_add_one_out (n : Nat) : ↑n + (1 : Int) = ↑(Nat.succ n) := rfl
|
||||
|
||||
@[simp] theorem ofNat_eq_natCast (n : Nat) : Int.ofNat n = n := rfl
|
||||
|
||||
@[norm_cast] theorem natCast_inj {m n : Nat} : (m : Int) = (n : Int) ↔ m = n := ofNat_inj
|
||||
|
||||
@[norm_cast]
|
||||
@@ -62,8 +62,6 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
|
||||
|
||||
@[simp high] theorem natCast_nonpos_iff {n : Nat} : (n : Int) ≤ 0 ↔ n = 0 := by omega
|
||||
|
||||
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
|
||||
|
||||
@[simp, norm_cast] theorem cast_id {n : Int} : Int.cast n = n := rfl
|
||||
|
||||
@[simp] theorem ble'_eq_true (a b : Int) : (Int.ble' a b = true) = (a ≤ b) := by
|
||||
@@ -84,7 +82,7 @@ theorem natCast_succ_pos (n : Nat) : 0 < (n.succ : Int) := natCast_pos.2 n.succ_
|
||||
symm
|
||||
simp only [Int.toNat]
|
||||
split <;> rename_i x a
|
||||
· simp only [Int.ofNat_eq_coe]
|
||||
· simp only [Int.ofNat_eq_natCast]
|
||||
split <;> rename_i y b h
|
||||
· simp at h
|
||||
omega
|
||||
@@ -118,14 +116,8 @@ theorem pos_iff_toNat_pos {n : Int} : 0 < n ↔ 0 < n.toNat := by
|
||||
|
||||
theorem natCast_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated natCast_toNat_eq_self (since := "2025-04-16")]
|
||||
theorem ofNat_toNat_eq_self {a : Int} : a.toNat = a ↔ 0 ≤ a := natCast_toNat_eq_self
|
||||
|
||||
theorem eq_natCast_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := by omega
|
||||
|
||||
@[deprecated eq_natCast_toNat (since := "2025-04-16")]
|
||||
theorem eq_ofNat_toNat {a : Int} : a = a.toNat ↔ 0 ≤ a := eq_natCast_toNat
|
||||
|
||||
theorem toNat_le_toNat {n m : Int} (h : n ≤ m) : n.toNat ≤ m.toNat := by omega
|
||||
theorem toNat_lt_toNat {n m : Int} (hn : 0 < m) : n.toNat < m.toNat ↔ n < m := by omega
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.Int.Cooper
|
||||
@@ -12,9 +11,7 @@ import all Init.Data.Int.Gcd
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
namespace Int.Linear
|
||||
|
||||
/-! Helper definitions and theorems for constructing linear arithmetic proofs. -/
|
||||
@@ -22,8 +19,7 @@ namespace Int.Linear
|
||||
abbrev Var := Nat
|
||||
abbrev Context := Lean.RArray Int
|
||||
|
||||
@[expose]
|
||||
def Var.denote (ctx : Context) (v : Var) : Int :=
|
||||
abbrev Var.denote (ctx : Context) (v : Var) : Int :=
|
||||
ctx.get v
|
||||
|
||||
inductive Expr where
|
||||
@@ -36,8 +32,7 @@ inductive Expr where
|
||||
| mulR (a : Expr) (k : Int)
|
||||
deriving Inhabited, @[expose] BEq
|
||||
|
||||
@[expose]
|
||||
def Expr.denote (ctx : Context) : Expr → Int
|
||||
abbrev Expr.denote (ctx : Context) : Expr → Int
|
||||
| .add a b => denote ctx a + denote ctx b
|
||||
| .sub a b => denote ctx a - denote ctx b
|
||||
| .neg a => - denote ctx a
|
||||
@@ -46,6 +41,9 @@ def Expr.denote (ctx : Context) : Expr → Int
|
||||
| .mulL k e => k * denote ctx e
|
||||
| .mulR e k => denote ctx e * k
|
||||
|
||||
set_option allowUnsafeReducibility true
|
||||
attribute [semireducible] Var.denote Expr.denote
|
||||
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
@@ -68,35 +66,36 @@ protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
intro _ _; subst k₁ v₁
|
||||
simp [← ih p₂, ← Bool.and'_eq_and]; rfl
|
||||
|
||||
@[expose]
|
||||
def Poly.denote (ctx : Context) (p : Poly) : Int :=
|
||||
abbrev Poly.denote (ctx : Context) (p : Poly) : Int :=
|
||||
match p with
|
||||
| .num k => k
|
||||
| .add k v p => k * v.denote ctx + denote ctx p
|
||||
|
||||
noncomputable abbrev Poly.denote'.go (ctx : Context) (p : Poly) : Int → Int :=
|
||||
Poly.rec
|
||||
(fun k r => Bool.rec
|
||||
(r + k)
|
||||
r
|
||||
(Int.beq' k 0))
|
||||
(fun k v _ ih r => Bool.rec
|
||||
(ih (r + k * v.denote ctx))
|
||||
(ih (r + v.denote ctx))
|
||||
(Int.beq' k 1))
|
||||
p
|
||||
|
||||
/--
|
||||
Similar to `Poly.denote`, but produces a denotation better for `simp +arith`.
|
||||
Remark: we used to convert `Poly` back into `Expr` to achieve that.
|
||||
-/
|
||||
@[expose] noncomputable def Poly.denote' (ctx : Context) (p : Poly) : Int :=
|
||||
noncomputable abbrev Poly.denote' (ctx : Context) (p : Poly) : Int :=
|
||||
Poly.rec (fun k => k)
|
||||
(fun k v p _ => Bool.rec
|
||||
(go p (k * v.denote ctx))
|
||||
(go p (v.denote ctx))
|
||||
(denote'.go ctx p (k * v.denote ctx))
|
||||
(denote'.go ctx p (v.denote ctx))
|
||||
(Int.beq' k 1))
|
||||
p
|
||||
where
|
||||
go (p : Poly) : Int → Int :=
|
||||
Poly.rec
|
||||
(fun k r => Bool.rec
|
||||
(r + k)
|
||||
r
|
||||
(Int.beq' k 0))
|
||||
(fun k v _ ih r => Bool.rec
|
||||
(ih (r + k * v.denote ctx))
|
||||
(ih (r + v.denote ctx))
|
||||
(Int.beq' k 1))
|
||||
p
|
||||
|
||||
attribute [semireducible] Poly.denote Poly.denote' Poly.denote'.go
|
||||
|
||||
@[simp] theorem Poly.denote'_go_eq_denote (ctx : Context) (p : Poly) (r : Int) : denote'.go ctx p r = p.denote ctx + r := by
|
||||
induction p generalizing r
|
||||
@@ -1091,7 +1090,7 @@ theorem eq_unsat_coeff (ctx : Context) (p : Poly) (k : Int) : eq_unsat_coeff_cer
|
||||
induction p
|
||||
next => rfl
|
||||
next a y p ih =>
|
||||
simp [coeff_k, coeff, cond_eq_if]; split
|
||||
simp [coeff_k, coeff, cond_eq_ite]; split
|
||||
next h => simp [h]
|
||||
next h => rw [← Nat.beq_eq, Bool.not_eq_true] at h; simp [h, ← ih]; rfl
|
||||
|
||||
|
||||
@@ -62,8 +62,6 @@ protected theorem le_total (a b : Int) : a ≤ b ∨ b ≤ a :=
|
||||
let ⟨k, (hk : m + k = n)⟩ := Nat.le.dest h
|
||||
le.intro k (by rw [← hk]; rfl)⟩
|
||||
|
||||
@[simp] theorem ofNat_zero_le (n : Nat) : 0 ≤ (↑n : Int) := ofNat_le.2 n.zero_le
|
||||
|
||||
theorem eq_ofNat_of_zero_le {a : Int} (h : 0 ≤ a) : ∃ n : Nat, a = n := by
|
||||
have t := le.dest_sub h; rwa [Int.sub_zero] at t
|
||||
|
||||
@@ -88,8 +86,12 @@ theorem lt.dest {a b : Int} (h : a < b) : ∃ n : Nat, a + Nat.succ n = b :=
|
||||
@[deprecated natCast_pos (since := "2025-05-13"), simp high]
|
||||
theorem ofNat_pos {n : Nat} : 0 < (↑n : Int) ↔ 0 < n := ofNat_lt
|
||||
|
||||
@[simp]
|
||||
theorem natCast_nonneg (n : Nat) : 0 ≤ (n : Int) := ⟨_⟩
|
||||
|
||||
@[deprecated natCast_nonneg (since := "2025-10-26")]
|
||||
theorem ofNat_zero_le (n : Nat) : 0 ≤ (↑n : Int) := ofNat_le.2 n.zero_le
|
||||
|
||||
@[deprecated natCast_nonneg (since := "2025-05-13")]
|
||||
theorem ofNat_nonneg (n : Nat) : 0 ≤ (n : Int) := ⟨_⟩
|
||||
|
||||
@@ -234,13 +236,10 @@ theorem eq_natAbs_of_nonneg {a : Int} (h : 0 ≤ a) : a = natAbs a := by
|
||||
let ⟨n, e⟩ := eq_ofNat_of_zero_le h
|
||||
rw [e]; rfl
|
||||
|
||||
@[deprecated eq_natAbs_of_nonneg (since := "2025-03-11")]
|
||||
abbrev eq_natAbs_of_zero_le := @eq_natAbs_of_nonneg
|
||||
|
||||
theorem le_natAbs {a : Int} : a ≤ natAbs a :=
|
||||
match Int.le_total 0 a with
|
||||
| .inl h => by rw [eq_natAbs_of_nonneg h]; apply Int.le_refl
|
||||
| .inr h => Int.le_trans h (ofNat_zero_le _)
|
||||
| .inr h => Int.le_trans h (natCast_nonneg _)
|
||||
|
||||
@[simp] theorem negSucc_lt_zero (n : Nat) : -[n+1] < 0 :=
|
||||
Int.not_le.1 fun h => let ⟨_, h⟩ := eq_ofNat_of_zero_le h; nomatch h
|
||||
@@ -468,10 +467,10 @@ protected theorem max_lt {a b c : Int} : max a b < c ↔ a < c ∧ b < c := by
|
||||
simpa using Int.max_le (a := a + 1) (b := b + 1) (c := c)
|
||||
|
||||
@[simp] theorem ofNat_max_zero (n : Nat) : (max (n : Int) 0) = n := by
|
||||
rw [Int.max_eq_left (ofNat_zero_le n)]
|
||||
rw [Int.max_eq_left (natCast_nonneg n)]
|
||||
|
||||
@[simp] theorem zero_max_ofNat (n : Nat) : (max 0 (n : Int)) = n := by
|
||||
rw [Int.max_eq_right (ofNat_zero_le n)]
|
||||
rw [Int.max_eq_right (natCast_nonneg n)]
|
||||
|
||||
@[simp] theorem negSucc_max_zero (n : Nat) : (max (Int.negSucc n) 0) = 0 := by
|
||||
rw [Int.max_eq_right (negSucc_le_zero _)]
|
||||
@@ -554,8 +553,8 @@ protected theorem mul_le_mul_of_nonpos_left {a b c : Int}
|
||||
|
||||
@[simp, norm_cast] theorem natAbs_natCast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
@[deprecated natAbs_natCast (since := "2025-04-16")]
|
||||
theorem natAbs_ofNat (n : Nat) : natAbs ↑n = n := natAbs_natCast n
|
||||
@[deprecated natAbs_natCast (since := "2025-10-26")]
|
||||
theorem natAbs_cast (n : Nat) : natAbs ↑n = n := rfl
|
||||
|
||||
/-
|
||||
TODO: rename `natAbs_ofNat'` to `natAbs_ofNat` once the current deprecated alias
|
||||
@@ -634,7 +633,7 @@ theorem eq_zero_of_dvd_of_natAbs_lt_natAbs {d n : Int} (h : d ∣ n) (h₁ : n.n
|
||||
/-! ### toNat -/
|
||||
|
||||
theorem toNat_eq_max : ∀ a : Int, (toNat a : Int) = max a 0
|
||||
| (n : Nat) => (Int.max_eq_left (ofNat_zero_le n)).symm
|
||||
| (n : Nat) => (Int.max_eq_left (natCast_nonneg n)).symm
|
||||
| -[n+1] => (Int.max_eq_right (Int.le_of_lt (negSucc_lt_zero n))).symm
|
||||
|
||||
@[simp] theorem toNat_zero : (0 : Int).toNat = 0 := rfl
|
||||
@@ -646,17 +645,11 @@ theorem toNat_of_nonneg {a : Int} (h : 0 ≤ a) : (toNat a : Int) = a := by
|
||||
|
||||
@[simp] theorem toNat_natCast (n : Nat) : toNat ↑n = n := rfl
|
||||
|
||||
@[deprecated toNat_natCast (since := "2025-04-16")]
|
||||
theorem toNat_ofNat (n : Nat) : toNat ↑n = n := rfl
|
||||
|
||||
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
|
||||
simp [toNat]
|
||||
|
||||
@[simp] theorem toNat_natCast_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
||||
|
||||
@[deprecated toNat_natCast_add_one (since := "2025-04-16")]
|
||||
theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := toNat_natCast_add_one
|
||||
|
||||
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
|
||||
match a with
|
||||
| (n : Nat) => simp
|
||||
@@ -717,9 +710,6 @@ theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
|
||||
| (m : Nat), n => by simp [toNat?, Int.ofNat_inj]
|
||||
| -[m+1], n => by constructor <;> nofun
|
||||
|
||||
@[deprecated mem_toNat? (since := "2025-03-11")]
|
||||
abbrev mem_toNat' := @mem_toNat?
|
||||
|
||||
/-! ## Order properties of the integers -/
|
||||
|
||||
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
||||
@@ -728,7 +718,7 @@ protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_t
|
||||
simp only [Int.not_lt, iff_false]; constructor
|
||||
|
||||
theorem eq_negSucc_of_lt_zero : ∀ {a : Int}, a < 0 → ∃ n : Nat, a = -[n+1]
|
||||
| ofNat _, h => absurd h (Int.not_lt.2 (ofNat_zero_le _))
|
||||
| ofNat _, h => absurd h (Int.not_lt.2 (natCast_nonneg _))
|
||||
| -[n+1], _ => ⟨n, rfl⟩
|
||||
|
||||
protected theorem lt_of_add_lt_add_left {a b c : Int} (h : a + b < a + c) : b < c := by
|
||||
@@ -796,10 +786,10 @@ theorem add_one_le_iff {a b : Int} : a + 1 ≤ b ↔ a < b := .rfl
|
||||
theorem lt_add_one_iff {a b : Int} : a < b + 1 ↔ a ≤ b := Int.add_le_add_iff_right _
|
||||
|
||||
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
|
||||
lt_add_one_iff.mpr (ofNat_zero_le _)
|
||||
lt_add_one_iff.mpr (natCast_nonneg _)
|
||||
|
||||
theorem not_ofNat_neg (n : Nat) : ¬((n : Int) < 0) :=
|
||||
Int.not_lt.mpr (ofNat_zero_le ..)
|
||||
Int.not_lt.mpr (natCast_nonneg ..)
|
||||
|
||||
theorem le_add_one {a b : Int} (h : a ≤ b) : a ≤ b + 1 :=
|
||||
Int.le_of_lt (Int.lt_add_one_iff.2 h)
|
||||
@@ -1250,7 +1240,11 @@ protected theorem neg_of_mul_pos_right {a b : Int}
|
||||
@[simp] theorem sign_one : sign 1 = 1 := rfl
|
||||
theorem sign_neg_one : sign (-1) = -1 := rfl
|
||||
|
||||
@[simp] theorem sign_of_add_one (x : Nat) : Int.sign (x + 1) = 1 := rfl
|
||||
@[simp] theorem sign_natCast_add_one (n : Nat) : sign (n + 1) = 1 := rfl
|
||||
|
||||
@[deprecated sign_natCast_add_one (since := "2025-10-26")]
|
||||
theorem sign_of_add_one (x : Nat) : Int.sign (x + 1) = 1 := rfl
|
||||
|
||||
@[simp] theorem sign_negSucc (x : Nat) : Int.sign (Int.negSucc x) = -1 := rfl
|
||||
|
||||
theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
|
||||
@@ -1259,17 +1253,9 @@ theorem natAbs_sign (z : Int) : z.sign.natAbs = if z = 0 then 0 else 1 :=
|
||||
theorem natAbs_sign_of_ne_zero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 := by
|
||||
rw [Int.natAbs_sign, if_neg hz]
|
||||
|
||||
@[deprecated natAbs_sign_of_ne_zero (since := "2025-04-16")]
|
||||
theorem natAbs_sign_of_nonzero {z : Int} (hz : z ≠ 0) : z.sign.natAbs = 1 :=
|
||||
natAbs_sign_of_ne_zero hz
|
||||
|
||||
theorem sign_natCast_of_ne_zero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
match n, Nat.exists_eq_succ_of_ne_zero hn with
|
||||
| _, ⟨n, rfl⟩ => Int.sign_of_add_one n
|
||||
|
||||
@[deprecated sign_natCast_of_ne_zero (since := "2025-04-16")]
|
||||
theorem sign_ofNat_of_nonzero {n : Nat} (hn : n ≠ 0) : Int.sign n = 1 :=
|
||||
sign_natCast_of_ne_zero hn
|
||||
| _, ⟨n, rfl⟩ => Int.sign_natCast_add_one n
|
||||
|
||||
@[simp] theorem sign_neg (z : Int) : Int.sign (-z) = -Int.sign z := by
|
||||
match z with | 0 | succ _ | -[_+1] => rfl
|
||||
@@ -1325,8 +1311,6 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
|
||||
exact Int.le_add_one (natCast_nonneg _)
|
||||
| .negSucc _ => simp +decide [sign]
|
||||
|
||||
@[deprecated sign_nonneg_iff (since := "2025-03-11")] abbrev sign_nonneg := @sign_nonneg_iff
|
||||
|
||||
@[simp] theorem sign_pos_iff : 0 < sign x ↔ 0 < x := by
|
||||
match x with
|
||||
| 0
|
||||
@@ -1409,9 +1393,6 @@ theorem natAbs_add_of_nonpos {a b : Int} (ha : a ≤ 0) (hb : b ≤ 0) :
|
||||
natAbs_add_of_nonneg (Int.neg_nonneg_of_nonpos ha) (Int.neg_nonneg_of_nonpos hb),
|
||||
natAbs_neg (-a), natAbs_neg (-b)]
|
||||
|
||||
@[deprecated negSucc_eq (since := "2025-03-11")]
|
||||
theorem negSucc_eq' (m : Nat) : -[m+1] = -m - 1 := by simp only [negSucc_eq, Int.neg_add]; rfl
|
||||
|
||||
theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
|
||||
(w₁ : 0 ≤ a) (w₂ : a < b) : a.natAbs < b.natAbs :=
|
||||
match a, b, eq_ofNat_of_zero_le w₁, eq_ofNat_of_zero_le (Int.le_trans w₁ (Int.le_of_lt w₂)) with
|
||||
@@ -1420,9 +1401,6 @@ theorem natAbs_lt_natAbs_of_nonneg_of_lt {a b : Int}
|
||||
theorem natAbs_eq_iff_mul_eq_zero : natAbs a = n ↔ (a - n) * (a + n) = 0 := by
|
||||
rw [natAbs_eq_iff, Int.mul_eq_zero, ← Int.sub_neg, Int.sub_eq_zero, Int.sub_eq_zero]
|
||||
|
||||
@[deprecated natAbs_eq_iff_mul_eq_zero (since := "2025-03-11")]
|
||||
abbrev eq_natAbs_iff_mul_eq_zero := @natAbs_eq_iff_mul_eq_zero
|
||||
|
||||
instance instIsLinearOrder : IsLinearOrder Int := by
|
||||
apply IsLinearOrder.of_le
|
||||
case le_antisymm => constructor; apply Int.le_antisymm
|
||||
|
||||
@@ -14,9 +14,20 @@ namespace Int
|
||||
|
||||
/-! # pow -/
|
||||
|
||||
@[simp] protected theorem pow_zero (b : Int) : b^0 = 1 := rfl
|
||||
@[simp, norm_cast]
|
||||
theorem natCast_pow (m n : Nat) : (m ^ n : Nat) = (m : Int) ^ n := rfl
|
||||
|
||||
theorem negSucc_pow (m n : Nat) : (-[m+1] : Int) ^ n = if n % 2 = 0 then Int.ofNat (m.succ ^ n) else Int.negOfNat (m.succ ^ n) := rfl
|
||||
|
||||
@[simp] protected theorem pow_zero (m : Int) : m ^ 0 = 1 := by cases m <;> simp [← natCast_pow, negSucc_pow]
|
||||
|
||||
protected theorem pow_succ (m : Int) (n : Nat) : m ^ n.succ = m ^ n * m := by
|
||||
rcases m with _ | a
|
||||
· rfl
|
||||
· simp only [negSucc_pow, Nat.succ_mod_succ_eq_zero_iff, Nat.reduceAdd, ← Nat.mod_two_ne_zero,
|
||||
Nat.pow_succ, ofNat_eq_natCast, @negOfNat_eq (_ * _), ite_not, apply_ite (· * -[a+1]),
|
||||
ofNat_mul_negSucc, negOfNat_mul_negSucc]
|
||||
|
||||
protected theorem pow_succ (b : Int) (e : Nat) : b ^ (e+1) = (b ^ e) * b := rfl
|
||||
protected theorem pow_succ' (b : Int) (e : Nat) : b ^ (e+1) = b * (b ^ e) := by
|
||||
rw [Int.mul_comm, Int.pow_succ]
|
||||
|
||||
@@ -32,33 +43,46 @@ protected theorem zero_pow {n : Nat} (h : n ≠ 0) : (0 : Int) ^ n = 0 := by
|
||||
protected theorem one_pow {n : Nat} : (1 : Int) ^ n = 1 := by
|
||||
induction n with simp_all [Int.pow_succ]
|
||||
|
||||
protected theorem mul_pow {a b : Int} {n : Nat} : (a * b) ^ n = a ^ n * b ^ n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
rw [Int.pow_succ, Int.pow_succ, Int.pow_succ, ih, Int.mul_assoc, Int.mul_assoc,
|
||||
Int.mul_left_comm (b^n)]
|
||||
|
||||
protected theorem pow_one (a : Int) : a ^ 1 = a := by
|
||||
rw [Int.pow_succ, Int.pow_zero, Int.one_mul]
|
||||
|
||||
protected theorem pow_mul {a : Int} {n m : Nat} : a ^ (n * m) = (a ^ n) ^ m := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih =>
|
||||
rw [Int.pow_succ, Nat.mul_add_one, Int.pow_add, ih]
|
||||
|
||||
protected theorem pow_pos {n : Int} {m : Nat} : 0 < n → 0 < n ^ m := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => exact fun h => Int.mul_pos (ih h) h
|
||||
| succ m ih =>
|
||||
simp only [Int.pow_succ]
|
||||
exact fun h => Int.mul_pos (ih h) h
|
||||
|
||||
protected theorem pow_nonneg {n : Int} {m : Nat} : 0 ≤ n → 0 ≤ n ^ m := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => exact fun h => Int.mul_nonneg (ih h) h
|
||||
| succ m ih =>
|
||||
simp only [Int.pow_succ]
|
||||
exact fun h => Int.mul_nonneg (ih h) h
|
||||
|
||||
protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => exact fun h => Int.mul_ne_zero (ih h) h
|
||||
| succ m ih =>
|
||||
simp only [Int.pow_succ]
|
||||
exact fun h => Int.mul_ne_zero (ih h) h
|
||||
|
||||
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := ⟨Int.pow_ne_zero (NeZero.ne _)⟩
|
||||
|
||||
-- This can't be removed until the next update-stage0
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp, norm_cast]
|
||||
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
|
||||
match n with
|
||||
| 0 => rfl
|
||||
| n + 1 =>
|
||||
simp only [Nat.pow_succ, Int.pow_succ, Int.natCast_mul, Int.natCast_pow _ n]
|
||||
instance {n : Int} : NeZero (n^0) := ⟨by simp⟩
|
||||
|
||||
@[simp]
|
||||
protected theorem two_pow_pred_sub_two_pow {w : Nat} (h : 0 < w) :
|
||||
@@ -81,7 +105,7 @@ theorem pow_lt_pow_of_lt {a : Int} {b c : Nat} (ha : 1 < a) (hbc : b < c):
|
||||
omega
|
||||
|
||||
@[simp] theorem natAbs_pow (n : Int) : (k : Nat) → (n ^ k).natAbs = n.natAbs ^ k
|
||||
| 0 => rfl
|
||||
| 0 => by simp
|
||||
| k + 1 => by rw [Int.pow_succ, natAbs_mul, natAbs_pow, Nat.pow_succ]
|
||||
|
||||
theorem toNat_pow_of_nonneg {x : Int} (h : 0 ≤ x) (k : Nat) : (x ^ k).toNat = x.toNat ^ k := by
|
||||
@@ -90,4 +114,21 @@ theorem toNat_pow_of_nonneg {x : Int} (h : 0 ≤ x) (k : Nat) : (x ^ k).toNat =
|
||||
| succ k ih =>
|
||||
rw [Int.pow_succ, Int.toNat_mul (Int.pow_nonneg h) h, ih, Nat.pow_succ]
|
||||
|
||||
protected theorem sq_nonnneg (m : Int) : 0 ≤ m ^ 2 := by
|
||||
rw [Int.pow_succ, Int.pow_one]
|
||||
cases m
|
||||
· apply Int.mul_nonneg <;> simp
|
||||
· apply Int.mul_nonneg_of_nonpos_of_nonpos <;> exact negSucc_le_zero _
|
||||
|
||||
protected theorem pow_nonneg_of_even {m : Int} {n : Nat} (h : n % 2 = 0) : 0 ≤ m ^ n := by
|
||||
rw [← Nat.mod_add_div n 2, h, Nat.zero_add, Int.pow_mul]
|
||||
apply Int.pow_nonneg
|
||||
exact Int.sq_nonnneg m
|
||||
|
||||
protected theorem neg_pow {m : Int} {n : Nat} : (-m)^n = (-1)^(n % 2) * m^n := by
|
||||
rw [Int.neg_eq_neg_one_mul, Int.mul_pow]
|
||||
rw (occs := [1]) [← Nat.mod_add_div n 2]
|
||||
rw [Int.pow_add, Int.pow_mul]
|
||||
simp [Int.one_pow]
|
||||
|
||||
end Int
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
public import Init.Data.Iterators.PostconditionMonad
|
||||
public import Init.Data.Iterators.Consumers
|
||||
public import Init.Data.Iterators.Producers
|
||||
public import Init.Data.Iterators.Combinators
|
||||
public import Init.Data.Iterators.Lemmas
|
||||
public import Init.Data.Iterators.ToIterator
|
||||
|
||||
@@ -241,6 +241,16 @@ def IterStep.successor : IterStep α β → Option α
|
||||
| .skip it => some it
|
||||
| .done => none
|
||||
|
||||
@[simp]
|
||||
theorem IterStep.successor_yield {it : α} {out : β} :
|
||||
(IterStep.yield it out).successor = some it := rfl
|
||||
|
||||
@[simp]
|
||||
theorem IterStep.successor_skip {it : α} : (IterStep.skip (β := β) it).successor = some it := rfl
|
||||
|
||||
@[simp]
|
||||
theorem IterStep.successor_done : (IterStep.done (α := α) (β := β)).successor = none := rfl
|
||||
|
||||
/--
|
||||
If present, applies `f` to the iterator of an `IterStep` and replaces the iterator
|
||||
with the result of the application of `f`.
|
||||
@@ -543,6 +553,10 @@ def Iter.IsPlausibleSuccessorOf {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it' it : Iter (α := α) β) : Prop :=
|
||||
it'.toIterM.IsPlausibleSuccessorOf it.toIterM
|
||||
|
||||
theorem Iter.isPlausibleSuccessorOf_eq_invImage {α : Type w} {β : Type w} [Iterator α Id β] :
|
||||
IsPlausibleSuccessorOf (α := α) (β := β) =
|
||||
InvImage (IterM.IsPlausibleSuccessorOf (α := α) (β := β) (m := Id)) Iter.toIterM := rfl
|
||||
|
||||
theorem Iter.isPlausibleSuccessorOf_iff_exists {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
{it' it : Iter (α := α) β} :
|
||||
it'.IsPlausibleSuccessorOf it ↔ ∃ step, step.successor = some it' ∧ it.IsPlausibleStep step := by
|
||||
@@ -555,6 +569,16 @@ theorem Iter.isPlausibleSuccessorOf_iff_exists {α : Type w} {β : Type w} [Iter
|
||||
exact ⟨step.mapIterator Iter.toIterM,
|
||||
by cases step <;> simp_all [IterStep.successor, Iter.IsPlausibleStep]⟩
|
||||
|
||||
theorem Iter.IsPlausibleStep.isPlausibleSuccessor_of_yield {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] {it' it : Iter (α := α) β} {out : β}
|
||||
(h : it.IsPlausibleStep (.yield it' out)) : it'.IsPlausibleSuccessorOf it := by
|
||||
simpa [isPlausibleSuccessorOf_iff_exists] using ⟨.yield it' out, by simp [h]⟩
|
||||
|
||||
theorem Iter.IsPlausibleStep.isPlausibleSuccessor_of_skip {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] {it' it : Iter (α := α) β} (h : it.IsPlausibleStep (.skip it')) :
|
||||
it'.IsPlausibleSuccessorOf it := by
|
||||
simpa [isPlausibleSuccessorOf_iff_exists] using ⟨.skip it', by simp [h]⟩
|
||||
|
||||
/--
|
||||
Asserts that a certain iterator `it` could plausibly yield the value `out` after an arbitrary
|
||||
number of steps.
|
||||
@@ -656,6 +680,10 @@ Given this typeclass, termination proofs for well-founded recursion over an iter
|
||||
class Finite (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] : Prop where
|
||||
wf : WellFounded (IterM.IsPlausibleSuccessorOf (α := α) (m := m))
|
||||
|
||||
theorem Finite.wf_of_id {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] :
|
||||
WellFounded (Iter.IsPlausibleSuccessorOf (α := α)) := by
|
||||
simpa [Iter.isPlausibleSuccessorOf_eq_invImage] using InvImage.wf _ Finite.wf
|
||||
|
||||
/--
|
||||
This type is a wrapper around `IterM` so that it becomes a useful termination measure for
|
||||
recursion over finite iterators. See also `IterM.finitelyManySteps` and `Iter.finitelyManySteps`.
|
||||
@@ -705,6 +733,12 @@ theorem IterM.TerminationMeasures.Finite.rel_of_skip
|
||||
Rel ⟨it'⟩ ⟨it⟩ := by
|
||||
exact .single ⟨_, rfl, h⟩
|
||||
|
||||
theorem IterM.TerminationMeasures.Finite.rel_trans
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
{it it' it'' : TerminationMeasures.Finite α m} :
|
||||
it.Rel it' → it'.Rel it'' → it.Rel it'' :=
|
||||
.trans
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
first
|
||||
| exact IterM.TerminationMeasures.Finite.rel_of_yield ‹_›
|
||||
@@ -783,6 +817,24 @@ def IterM.TerminationMeasures.Productive.Rel
|
||||
TerminationMeasures.Productive α m → TerminationMeasures.Productive α m → Prop :=
|
||||
Relation.TransGen <| InvImage IterM.IsPlausibleSkipSuccessorOf IterM.TerminationMeasures.Productive.it
|
||||
|
||||
theorem IterM.TerminationMeasures.Finite.Rel.of_productive
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] {a b : Finite α m} :
|
||||
Productive.Rel ⟨a.it⟩ ⟨b.it⟩ → Finite.Rel a b := by
|
||||
generalize ha' : Productive.mk a.it = a'
|
||||
generalize hb' : Productive.mk b.it = b'
|
||||
have ha : a = ⟨a'.it⟩ := by simp [← ha']
|
||||
have hb : b = ⟨b'.it⟩ := by simp [← hb']
|
||||
rw [ha, hb]
|
||||
clear ha hb ha' hb' a b
|
||||
rw [Productive.Rel, Finite.Rel]
|
||||
intro h
|
||||
induction h
|
||||
· rename_i ih
|
||||
exact .single ⟨_, rfl, ih⟩
|
||||
· rename_i hab ih
|
||||
refine .trans ih ?_
|
||||
exact .single ⟨_, rfl, hab⟩
|
||||
|
||||
instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Productive α m] : WellFoundedRelation (IterM.TerminationMeasures.Productive α m) where
|
||||
rel := IterM.TerminationMeasures.Productive.Rel
|
||||
|
||||
@@ -9,4 +9,5 @@ prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic
|
||||
public import Init.Data.Iterators.Combinators.FilterMap
|
||||
public import Init.Data.Iterators.Combinators.FlatMap
|
||||
public import Init.Data.Iterators.Combinators.Take
|
||||
public import Init.Data.Iterators.Combinators.ULift
|
||||
|
||||
@@ -8,4 +8,5 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic.FilterMap
|
||||
public import Init.Data.Iterators.Combinators.Monadic.FlatMap
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Take
|
||||
public import Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
|
||||
@@ -106,16 +106,6 @@ instance Attach.instIteratorLoopPartial {α β : Type w} {m : Type w → Type w'
|
||||
IteratorLoopPartial (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{P : β → Prop} [Iterator α m β] [IteratorSize α m] :
|
||||
IteratorSize (Attach α m P) m where
|
||||
size it := IteratorSize.size it.internalState.inner
|
||||
|
||||
instance {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{P : β → Prop} [Iterator α m β] [IteratorSizePartial α m] :
|
||||
IteratorSizePartial (Attach α m P) m where
|
||||
size it := IteratorSizePartial.size it.internalState.inner
|
||||
|
||||
end Types
|
||||
|
||||
/--
|
||||
|
||||
@@ -94,7 +94,7 @@ it.filterMapWithPostcondition ---a'-----c'-------⊥
|
||||
**Termination properties:**
|
||||
|
||||
* `Finite` instance: only if `it` is finite
|
||||
* `Productive` instance: only if `it` is finite`
|
||||
* `Productive` instance: only if `it` is finite
|
||||
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` never returns `none`, then
|
||||
@@ -604,30 +604,4 @@ def IterM.filter {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [M
|
||||
(f : β → Bool) (it : IterM (α := α) m β) :=
|
||||
(it.filterMap (fun b => if f b then some b else none) : IterM m β)
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} [Finite α m] :
|
||||
IteratorSize (FilterMap α m n lift f) n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} :
|
||||
IteratorSizePartial (FilterMap α m n lift f) n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} [IteratorSize α m] :
|
||||
IteratorSize (Map α m n lift f) n where
|
||||
size it := lift (IteratorSize.size it.internalState.inner)
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} [IteratorSizePartial α m] :
|
||||
IteratorSizePartial (Map α m n lift f) n where
|
||||
size it := lift (IteratorSizePartial.size it.internalState.inner)
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
223
src/Init/Data/Iterators/Combinators/Monadic/Take.lean
Normal file
223
src/Init/Data/Iterators/Combinators/Monadic/Take.lean
Normal file
@@ -0,0 +1,223 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
|
||||
@[expose] public section
|
||||
|
||||
/-!
|
||||
This module provides the iterator combinator `IterM.take`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
variable {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
|
||||
/--
|
||||
The internal state of the `IterM.take` iterator combinator.
|
||||
-/
|
||||
@[unbox]
|
||||
structure Take (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
Internal implementation detail of the iterator library.
|
||||
Caution: For `take n`, `countdown` is `n + 1`.
|
||||
If `countdown` is zero, the combinator only terminates when `inner` terminates.
|
||||
-/
|
||||
countdown : Nat
|
||||
/-- Internal implementation detail of the iterator library -/
|
||||
inner : IterM (α := α) m β
|
||||
/--
|
||||
Internal implementation detail of the iterator library.
|
||||
This proof term ensures that a `take` always produces a finite iterator from a productive one.
|
||||
-/
|
||||
finite : countdown > 0 ∨ Finite α m
|
||||
|
||||
/--
|
||||
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
|
||||
up to the first `n` of `it`'s values in order and then terminates.
|
||||
|
||||
**Marble diagram:**
|
||||
|
||||
```text
|
||||
it ---a----b---c--d-e--⊥
|
||||
it.take 3 ---a----b---c⊥
|
||||
|
||||
it ---a--⊥
|
||||
it.take 3 ---a--⊥
|
||||
```
|
||||
|
||||
**Termination properties:**
|
||||
|
||||
* `Finite` instance: only if `it` is productive
|
||||
* `Productive` instance: only if `it` is productive
|
||||
|
||||
**Performance:**
|
||||
|
||||
This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.take [Iterator α m β] (n : Nat) (it : IterM (α := α) m β) :=
|
||||
toIterM (Take.mk (n + 1) it (Or.inl <| Nat.zero_lt_succ _)) m β
|
||||
|
||||
/--
|
||||
This combinator is only useful for advanced use cases.
|
||||
|
||||
Given a finite iterator `it`, returns an iterator that behaves exactly like `it` but is of the same
|
||||
type as `it.take n`.
|
||||
|
||||
**Marble diagram:**
|
||||
|
||||
```text
|
||||
it ---a----b---c--d-e--⊥
|
||||
it.toTake ---a----b---c--d-e--⊥
|
||||
```
|
||||
|
||||
**Termination properties:**
|
||||
|
||||
* `Finite` instance: always
|
||||
* `Productive` instance: always
|
||||
|
||||
**Performance:**
|
||||
|
||||
This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.toTake [Iterator α m β] [Finite α m] (it : IterM (α := α) m β) :=
|
||||
toIterM (Take.mk 0 it (Or.inr inferInstance)) m β
|
||||
|
||||
theorem IterM.take.surjective_of_zero_lt {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (it : IterM (α := Take α m) m β) (h : 0 < it.internalState.countdown) :
|
||||
∃ (it₀ : IterM (α := α) m β) (k : Nat), it = it₀.take k := by
|
||||
refine ⟨it.internalState.inner, it.internalState.countdown - 1, ?_⟩
|
||||
simp only [take, Nat.sub_add_cancel (m := 1) (n := it.internalState.countdown) (by omega)]
|
||||
rfl
|
||||
|
||||
inductive Take.PlausibleStep [Iterator α m β] (it : IterM (α := Take α m) m β) :
|
||||
(step : IterStep (IterM (α := Take α m) m β) β) → Prop where
|
||||
| yield : ∀ {it' out}, it.internalState.inner.IsPlausibleStep (.yield it' out) →
|
||||
(h : it.internalState.countdown ≠ 1) → PlausibleStep it (.yield ⟨it.internalState.countdown - 1, it', it.internalState.finite.imp_left (by omega)⟩ out)
|
||||
| skip : ∀ {it'}, it.internalState.inner.IsPlausibleStep (.skip it') →
|
||||
it.internalState.countdown ≠ 1 → PlausibleStep it (.skip ⟨it.internalState.countdown, it', it.internalState.finite⟩)
|
||||
| done : it.internalState.inner.IsPlausibleStep .done → PlausibleStep it .done
|
||||
| depleted : it.internalState.countdown = 1 →
|
||||
PlausibleStep it .done
|
||||
|
||||
@[always_inline, inline]
|
||||
instance Take.instIterator [Monad m] [Iterator α m β] : Iterator (Take α m) m β where
|
||||
IsPlausibleStep := Take.PlausibleStep
|
||||
step it :=
|
||||
if h : it.internalState.countdown = 1 then
|
||||
pure <| .deflate <| .done (.depleted h)
|
||||
else do
|
||||
match (← it.internalState.inner.step).inflate with
|
||||
| .yield it' out h' =>
|
||||
pure <| .deflate <| .yield ⟨it.internalState.countdown - 1, it', (it.internalState.finite.imp_left (by omega))⟩ out (.yield h' h)
|
||||
| .skip it' h' => pure <| .deflate <| .skip ⟨it.internalState.countdown, it', it.internalState.finite⟩ (.skip h' h)
|
||||
| .done h' => pure <| .deflate <| .done (.done h')
|
||||
|
||||
def Take.Rel (m : Type w → Type w') [Monad m] [Iterator α m β] [Productive α m] :
|
||||
IterM (α := Take α m) m β → IterM (α := Take α m) m β → Prop :=
|
||||
open scoped Classical in
|
||||
if _ : Finite α m then
|
||||
InvImage (Prod.Lex Nat.lt_wfRel.rel IterM.TerminationMeasures.Finite.Rel)
|
||||
(fun it => (it.internalState.countdown, it.internalState.inner.finitelyManySteps))
|
||||
else
|
||||
InvImage (Prod.Lex Nat.lt_wfRel.rel IterM.TerminationMeasures.Productive.Rel)
|
||||
(fun it => (it.internalState.countdown, it.internalState.inner.finitelyManySkips))
|
||||
|
||||
theorem Take.rel_of_countdown [Monad m] [Iterator α m β] [Productive α m]
|
||||
{it it' : IterM (α := Take α m) m β}
|
||||
(h : it'.internalState.countdown < it.internalState.countdown) : Take.Rel m it' it := by
|
||||
simp only [Rel]
|
||||
split <;> exact Prod.Lex.left _ _ h
|
||||
|
||||
theorem Take.rel_of_inner [Monad m] [Iterator α m β] [Productive α m] {remaining : Nat}
|
||||
{it it' : IterM (α := α) m β}
|
||||
(h : it'.finitelyManySkips.Rel it.finitelyManySkips) :
|
||||
Take.Rel m (it'.take remaining) (it.take remaining) := by
|
||||
simp only [Rel]
|
||||
split
|
||||
· exact Prod.Lex.right _ (.of_productive h)
|
||||
· exact Prod.Lex.right _ h
|
||||
|
||||
theorem Take.rel_of_zero_of_inner [Monad m] [Iterator α m β]
|
||||
{it it' : IterM (α := Take α m) m β}
|
||||
(h : it.internalState.countdown = 0) (h' : it'.internalState.countdown = 0)
|
||||
(h'' : haveI := it.internalState.finite.resolve_left (by omega); it'.internalState.inner.finitelyManySteps.Rel it.internalState.inner.finitelyManySteps) :
|
||||
haveI := it.internalState.finite.resolve_left (by omega)
|
||||
Take.Rel m it' it := by
|
||||
haveI := it.internalState.finite.resolve_left (by omega)
|
||||
simp only [Rel, this, ↓reduceDIte, InvImage, h, h']
|
||||
exact Prod.Lex.right _ h''
|
||||
|
||||
private def Take.instFinitenessRelation [Monad m] [Iterator α m β]
|
||||
[Productive α m] :
|
||||
FinitenessRelation (Take α m) m where
|
||||
rel := Take.Rel m
|
||||
wf := by
|
||||
rw [Rel]
|
||||
split
|
||||
all_goals
|
||||
apply InvImage.wf
|
||||
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
|
||||
· exact WellFoundedRelation.wf
|
||||
· exact WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases h'
|
||||
case yield it' out k h' h'' =>
|
||||
cases h
|
||||
cases it.internalState.finite
|
||||
· apply rel_of_countdown
|
||||
simp only
|
||||
omega
|
||||
· by_cases h : it.internalState.countdown = 0
|
||||
· simp only [h, Nat.zero_le, Nat.sub_eq_zero_of_le]
|
||||
apply rel_of_zero_of_inner h rfl
|
||||
exact .single ⟨_, rfl, h'⟩
|
||||
· apply rel_of_countdown
|
||||
simp only
|
||||
omega
|
||||
case skip it' out k h' h'' =>
|
||||
cases h
|
||||
by_cases h : it.internalState.countdown = 0
|
||||
· simp only [h]
|
||||
apply Take.rel_of_zero_of_inner h rfl
|
||||
exact .single ⟨_, rfl, h'⟩
|
||||
· obtain ⟨it, k, rfl⟩ := IterM.take.surjective_of_zero_lt it (by omega)
|
||||
apply Take.rel_of_inner
|
||||
exact IterM.TerminationMeasures.Productive.rel_of_skip h'
|
||||
case done _ =>
|
||||
cases h
|
||||
case depleted _ =>
|
||||
cases h
|
||||
|
||||
instance Take.instFinite [Monad m] [Iterator α m β] [Productive α m] :
|
||||
Finite (Take α m) m :=
|
||||
by exact Finite.of_finitenessRelation instFinitenessRelation
|
||||
|
||||
instance Take.instIteratorCollect {n : Type w → Type w'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorCollect (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorCollectPartial {n : Type w → Type w'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorCollectPartial (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorLoop {n : Type x → Type x'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorLoop (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorLoopPartial [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorLoopPartial (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
end Std.Iterators
|
||||
@@ -74,7 +74,7 @@ variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
|
||||
/--
|
||||
Transforms a step of the base iterator into a step of the `uLift` iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def Types.ULiftIterator.Monadic.modifyStep (step : IterStep (IterM (α := α) m β) β) :
|
||||
IterStep (IterM (α := ULiftIterator.{v} α m n β lift) n (ULift.{v} β)) (ULift.{v} β) :=
|
||||
match step with
|
||||
@@ -140,15 +140,6 @@ instance Types.ULiftIterator.instIteratorCollectPartial {o} [Monad n] [Monad o]
|
||||
IteratorCollectPartial (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorSize [Monad n] [Iterator α m β] [IteratorSize α m]
|
||||
[Finite (ULiftIterator α m n β lift) n] :
|
||||
IteratorSize (ULiftIterator α m n β lift) n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorSizePartial [Monad n] [Iterator α m β] [IteratorSize α m] :
|
||||
IteratorSizePartial (ULiftIterator α m n β lift) n :=
|
||||
.defaultImplementation
|
||||
|
||||
/--
|
||||
Transforms an `m`-monadic iterator with values in `β` into an `n`-monadic iterator with
|
||||
values in `ULift β`. Requires a `MonadLift m (ULiftT n)` instance.
|
||||
|
||||
70
src/Init/Data/Iterators/Combinators/Take.lean
Normal file
70
src/Init/Data/Iterators/Combinators/Take.lean
Normal file
@@ -0,0 +1,70 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Take
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
/--
|
||||
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
|
||||
up to the first `n` of `it`'s values in order and then terminates.
|
||||
|
||||
**Marble diagram:**
|
||||
|
||||
```text
|
||||
it ---a----b---c--d-e--⊥
|
||||
it.take 3 ---a----b---c⊥
|
||||
|
||||
it ---a--⊥
|
||||
it.take 3 ---a--⊥
|
||||
```
|
||||
|
||||
**Termination properties:**
|
||||
|
||||
* `Finite` instance: only if `it` is productive
|
||||
* `Productive` instance: only if `it` is productive
|
||||
|
||||
**Performance:**
|
||||
|
||||
This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.take {α : Type w} {β : Type w} [Iterator α Id β] (n : Nat) (it : Iter (α := α) β) :
|
||||
Iter (α := Take α Id) β :=
|
||||
it.toIterM.take n |>.toIter
|
||||
|
||||
/--
|
||||
This combinator is only useful for advanced use cases.
|
||||
|
||||
Given a finite iterator `it`, returns an iterator that behaves exactly like `it` but is of the same
|
||||
type as `it.take n`.
|
||||
|
||||
**Marble diagram:**
|
||||
|
||||
```text
|
||||
it ---a----b---c--d-e--⊥
|
||||
it.toTake ---a----b---c--d-e--⊥
|
||||
```
|
||||
|
||||
**Termination properties:**
|
||||
|
||||
* `Finite` instance: always
|
||||
* `Productive` instance: always
|
||||
|
||||
**Performance:**
|
||||
|
||||
This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toTake {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] (it : Iter (α := α) β) :
|
||||
Iter (α := Take α Id) β :=
|
||||
it.toIterM.toTake.toIter
|
||||
|
||||
end Std.Iterators
|
||||
@@ -202,28 +202,105 @@ def Iter.all {α β : Type w}
|
||||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||||
(it.allM (fun x => pure (f := Id) (p x))).run
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc IterM.size]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSize.size it.toIterM).run.down
|
||||
@[inline]
|
||||
def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.Partial.size]
|
||||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSizePartial α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSizePartial.size it.toIterM).run.down
|
||||
@[inline]
|
||||
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β)
|
||||
(f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[inline]
|
||||
def Iter.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] (it : Iter (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
@[inline]
|
||||
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id Id] (it : Iter.Partial (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
@[inline]
|
||||
def Iter.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline]
|
||||
def Iter.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline]
|
||||
def Iter.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] (it : Iter (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
|
||||
@[inline]
|
||||
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
(it : Iter.Partial (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
|
||||
/--
|
||||
`LawfulIteratorSize α m` ensures that the `size` function of an iterator behaves as if it
|
||||
iterated over the whole iterator, counting its elements and causing all the monadic side effects
|
||||
of the iterations. This is a fairly strong condition for monadic iterators and it will be false
|
||||
for many efficient implementations of `size` that compute the size without actually iterating.
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This class is experimental and users of the iterator API should not explicitly depend on it.
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
class LawfulIteratorSize (α : Type w) {β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorSize α Id] where
|
||||
size_eq_size_toArray {it : Iter (α := α) β} : it.size =
|
||||
haveI : IteratorCollect α Id Id := .defaultImplementation
|
||||
it.toArray.size
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.toIterM.count.run.down
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.count
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.it.toIterM.allowNontermination.count.run.down
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.Partial.count (since := "2025-10-29")]
|
||||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.count
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -88,27 +88,6 @@ class IteratorLoopPartial (α : Type w) (m : Type w → Type w') {β : Type w} [
|
||||
(it : IterM (α := α) m β) → γ →
|
||||
((b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) → n γ
|
||||
|
||||
/--
|
||||
`IteratorSize α m` provides an implementation of the `IterM.size` function.
|
||||
|
||||
This class is experimental and users of the iterator API should not explicitly depend on it.
|
||||
They can, however, assume that consumers that require an instance will work for all iterators
|
||||
provided by the standard library.
|
||||
-/
|
||||
class IteratorSize (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
size : IterM (α := α) m β → m (ULift Nat)
|
||||
|
||||
/--
|
||||
`IteratorSizePartial α m` provides an implementation of the `IterM.Partial.size` function that
|
||||
can be used as `it.allowTermination.size`.
|
||||
|
||||
This class is experimental and users of the iterator API should not explicitly depend on it.
|
||||
They can, however, assume that consumers that require an instance will work for all iterators
|
||||
provided by the standard library.
|
||||
-/
|
||||
class IteratorSizePartial (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
size : IterM (α := α) m β → m (ULift Nat)
|
||||
|
||||
end Typeclasses
|
||||
|
||||
/-- Internal implementation detail of the iterator library. -/
|
||||
@@ -315,7 +294,7 @@ instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoopPartial α m n]
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForM n (IterM.Partial (α := α) m β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
@@ -579,86 +558,112 @@ def IterM.Partial.all {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
(p : β → Bool) (it : IterM.Partial (α := α) m β) : m (ULift Bool) := do
|
||||
it.allM (fun x => pure (.up (p x)))
|
||||
|
||||
section Size
|
||||
@[inline]
|
||||
def IterM.findSomeM? {α β γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) (f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[inline]
|
||||
def IterM.Partial.findSomeM? {α β γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] (it : IterM.Partial (α := α) m β) (f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[inline]
|
||||
def IterM.findSome? {α β γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) (f : β → Option γ) :
|
||||
m (Option γ) :=
|
||||
it.findSomeM? (pure <| f ·)
|
||||
|
||||
@[inline]
|
||||
def IterM.Partial.findSome? {α β γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] (it : IterM.Partial (α := α) m β) (f : β → Option γ) :
|
||||
m (Option γ) :=
|
||||
it.findSomeM? (pure <| f ·)
|
||||
|
||||
@[inline]
|
||||
def IterM.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline]
|
||||
def IterM.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] (it : IterM.Partial (α := α) m β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline]
|
||||
def IterM.find? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) (f : β → Bool) :
|
||||
m (Option β) :=
|
||||
it.findM? (pure <| .up <| f ·)
|
||||
|
||||
@[inline]
|
||||
def IterM.Partial.find? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] (it : IterM.Partial (α := α) m β) (f : β → Bool) :
|
||||
m (Option β) :=
|
||||
it.findM? (pure <| .up <| f ·)
|
||||
|
||||
section Count
|
||||
|
||||
/--
|
||||
This is the implementation of the default instance `IteratorSize.defaultImplementation`.
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.DefaultConsumers.size {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] [IteratorLoop α m m] [Finite α m] (it : IterM (α := α) m β) :
|
||||
m (ULift Nat) :=
|
||||
def IterM.count {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] [Finite α m]
|
||||
[IteratorLoop α m m]
|
||||
[Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
|
||||
it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
|
||||
|
||||
/--
|
||||
This is the implementation of the default instance `IteratorSizePartial.defaultImplementation`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.DefaultConsumers.sizePartial {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] [IteratorLoopPartial α m m] (it : IterM (α := α) m β) :
|
||||
m (ULift Nat) :=
|
||||
it.allowNontermination.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
|
||||
|
||||
/--
|
||||
This is the default implementation of the `IteratorSize` class.
|
||||
It simply iterates using `IteratorLoop` and counts the elements.
|
||||
For certain iterators, more efficient implementations are possible and should be used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorSize.defaultImplementation {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m m] :
|
||||
IteratorSize α m where
|
||||
size := IterM.DefaultConsumers.size
|
||||
|
||||
|
||||
/--
|
||||
This is the default implementation of the `IteratorSizePartial` class.
|
||||
It simply iterates using `IteratorLoopPartial` and counts the elements.
|
||||
For certain iterators, more efficient implementations are possible and should be used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
instance IteratorSizePartial.defaultImplementation {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoopPartial α m m] :
|
||||
IteratorSizePartial α m where
|
||||
size := IterM.DefaultConsumers.sizePartial
|
||||
|
||||
/--
|
||||
Computes how many elements the iterator returns. In monadic situations, it is unclear which effects
|
||||
are caused by calling `size`, and if the monad is nondeterministic, it is also unclear what the
|
||||
returned value should be. The reference implementation, `IteratorSize.defaultImplementation`,
|
||||
simply iterates over the whole iterator monadically, counting the number of emitted values.
|
||||
An `IteratorSize` instance is considered lawful if it is equal to the reference implementation.
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
Default performance is linear in the number of steps taken by the iterator.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.size {α : Type} {m : Type → Type w'} {β : Type} [Iterator α m β] [Monad m]
|
||||
(it : IterM (α := α) m β) [IteratorSize α m] : m Nat :=
|
||||
ULift.down <$> IteratorSize.size it
|
||||
@[always_inline, inline, deprecated IterM.count (since := "2025-10-29")]
|
||||
def IterM.size {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] [Finite α m]
|
||||
[IteratorLoop α m m]
|
||||
[Monad m] (it : IterM (α := α) m β) : m (ULift Nat) :=
|
||||
it.count
|
||||
|
||||
/--
|
||||
Computes how many elements the iterator emits.
|
||||
|
||||
With monadic iterators (`IterM`), it is unclear which effects
|
||||
are caused by calling `size`, and if the monad is nondeterministic, it is also unclear what the
|
||||
returned value should be. The reference implementation, `IteratorSize.defaultImplementation`,
|
||||
simply iterates over the whole iterator monadically, counting the number of emitted values.
|
||||
An `IteratorSize` instance is considered lawful if it is equal to the reference implementation.
|
||||
|
||||
This is the partial version of `size`. It does not require a proof of finiteness and might loop
|
||||
forever. It is not possible to verify the behavior in Lean because it uses `partial`.
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
Default performance is linear in the number of steps taken by the iterator.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.Partial.size {α : Type} {m : Type → Type w'} {β : Type} [Iterator α m β] [Monad m]
|
||||
(it : IterM.Partial (α := α) m β) [IteratorSizePartial α m] : m Nat :=
|
||||
ULift.down <$> IteratorSizePartial.size it.it
|
||||
def IterM.Partial.count {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
|
||||
it.fold (init := .up 0) fun acc _ => .up (acc.down + 1)
|
||||
|
||||
end Size
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
**Performance**:
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.Partial.count (since := "2025-10-29")]
|
||||
def IterM.Partial.size {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoopPartial α m m] [Monad m] (it : IterM.Partial (α := α) m β) : m (ULift Nat) :=
|
||||
it.count
|
||||
|
||||
end Count
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -55,7 +55,7 @@ theorem LawfulMonadLiftFunction.lift_map [LawfulMonad m] [LawfulMonad n]
|
||||
theorem LawfulMonadLiftFunction.lift_seq [LawfulMonad m] [LawfulMonad n]
|
||||
[LawfulMonadLiftFunction lift] (mf : m (α → β)) (ma : m α) :
|
||||
lift (mf <*> ma) = lift mf <*> (lift ma : n α) := by
|
||||
simp only [seq_eq_bind, lift_map, lift_bind]
|
||||
simp only [seq_eq_bind_map, lift_map, lift_bind]
|
||||
|
||||
theorem LawfulMonadLiftFunction.lift_seqLeft [LawfulMonad m] [LawfulMonad n]
|
||||
[LawfulMonadLiftFunction lift] (x : m α) (y : m β) :
|
||||
|
||||
@@ -8,3 +8,4 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers
|
||||
public import Init.Data.Iterators.Lemmas.Combinators
|
||||
public import Init.Data.Iterators.Lemmas.Producers
|
||||
|
||||
@@ -10,4 +10,5 @@ public import Init.Data.Iterators.Lemmas.Combinators.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.FilterMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.FlatMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Take
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.ULift
|
||||
|
||||
@@ -11,6 +11,7 @@ import all Init.Data.Iterators.Combinators.Attach
|
||||
import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Loop
|
||||
public import Init.Data.Array.Attach
|
||||
|
||||
public section
|
||||
@@ -82,4 +83,14 @@ theorem Iter.toArray_attachWith [Iterator α Id β]
|
||||
simpa only [Array.toList_inj]
|
||||
simp [Iter.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.count_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
[LawfulIteratorLoop α Id Id] :
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
rw [← Iter.length_toList_eq_count, toList_attachWith]
|
||||
simp
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -467,6 +467,17 @@ theorem Iter.fold_map {α β γ : Type w} {δ : Type x}
|
||||
|
||||
end Fold
|
||||
|
||||
section Count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.count_map {α β β' : Type w} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → β'} :
|
||||
(it.map f).count = it.count := by
|
||||
simp [map_eq_toIter_map_toIterM, count_eq_count_toIterM]
|
||||
|
||||
end Count
|
||||
|
||||
theorem Iter.anyM_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option β')} {p : β' → m (ULift Bool)} :
|
||||
|
||||
@@ -9,4 +9,5 @@ prelude
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FilterMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FlatMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Take
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.ULift
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
import all Init.Data.Iterators.Combinators.Monadic.Attach
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
@@ -59,4 +60,14 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
|
||||
rw [← toArray_toList, ← toArray_toList, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.count_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorLoop α m m] [LawfulMonad m] [LawfulIteratorLoop α m m] :
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
letI : IteratorCollect α m m := .defaultImplementation
|
||||
rw [← up_length_toList_eq_count, ← up_length_toList_eq_count,
|
||||
← map_unattach_toList_attachWith (it := it) (P := P) (hP := hP)]
|
||||
simp only [Functor.map_map, List.length_unattach]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -895,6 +895,23 @@ theorem IterM.fold_map {α β γ δ : Type w} {m : Type w → Type w'}
|
||||
|
||||
end Fold
|
||||
|
||||
section Count
|
||||
|
||||
@[simp]
|
||||
theorem IterM.count_map {α β β' : Type w} {m : Type w → Type w'} [Iterator α m β] [Monad m]
|
||||
[IteratorLoop α m m] [Finite α m] [LawfulMonad m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → β'} :
|
||||
(it.map f).count = it.count := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [count_eq_match_step, count_eq_match_step, step_map, bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Count
|
||||
|
||||
section AnyAll
|
||||
|
||||
theorem IterM.anyM_filterMapM {α β β' : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
|
||||
77
src/Init/Data/Iterators/Lemmas/Combinators/Monadic/Take.lean
Normal file
77
src/Init/Data/Iterators/Lemmas/Combinators/Monadic/Take.lean
Normal file
@@ -0,0 +1,77 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic.Take
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
theorem Take.isPlausibleStep_take_yield [Monad m] [Iterator α m β] {n : Nat}
|
||||
{it : IterM (α := α) m β} (h : it.IsPlausibleStep (.yield it' out)) :
|
||||
(it.take (n + 1)).IsPlausibleStep (.yield (it'.take n) out) :=
|
||||
(.yield h (by simp [IterM.take]))
|
||||
|
||||
theorem Take.isPlausibleStep_take_skip [Monad m] [Iterator α m β] {n : Nat}
|
||||
{it : IterM (α := α) m β} (h : it.IsPlausibleStep (.skip it')) :
|
||||
(it.take (n + 1)).IsPlausibleStep (.skip (it'.take (n + 1))) :=
|
||||
(.skip h (by simp [IterM.take]))
|
||||
|
||||
theorem IterM.step_take {α m β} [Monad m] [Iterator α m β] {n : Nat}
|
||||
{it : IterM (α := α) m β} :
|
||||
(it.take n).step = (match n with
|
||||
| 0 => pure <| .deflate <| .done (.depleted rfl)
|
||||
| k + 1 => do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' out h => pure <| .deflate <| .yield (it'.take k) out (Take.isPlausibleStep_take_yield h)
|
||||
| .skip it' h => pure <| .deflate <| .skip (it'.take (k + 1)) (Take.isPlausibleStep_take_skip h)
|
||||
| .done h => pure <| .deflate <| .done (.done h)) := by
|
||||
simp only [take, step, Iterator.step, internalState_toIterM]
|
||||
cases n
|
||||
case zero => rfl
|
||||
case succ k =>
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> rfl
|
||||
|
||||
theorem IterM.toList_take_zero {α m β} [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite (Take α m) m]
|
||||
[IteratorCollect (Take α m) m m] [LawfulIteratorCollect (Take α m) m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(it.take 0).toList = pure [] := by
|
||||
rw [toList_eq_match_step]
|
||||
simp [step_take]
|
||||
|
||||
theorem IterM.step_toTake {α m β} [Monad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toTake.step = (do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' out h => pure <| .deflate <| .yield it'.toTake out (.yield h Nat.zero_ne_one)
|
||||
| .skip it' h => pure <| .deflate <| .skip it'.toTake (.skip h Nat.zero_ne_one)
|
||||
| .done h => pure <| .deflate <| .done (.done h)) := by
|
||||
simp only [toTake, step, Iterator.step, internalState_toIterM]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> rfl
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toTake {α m β} [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toTake.toList = it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [toList_eq_match_step, toList_eq_match_step]
|
||||
simp only [step_toTake, bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
@@ -7,8 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
import all Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
@@ -20,9 +20,13 @@ variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
|
||||
theorem IterM.step_uLift [Iterator α m β] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).step = (do
|
||||
let step := (← (monadLift it.step : ULiftT n _).run).down
|
||||
return .deflate ⟨Types.ULiftIterator.Monadic.modifyStep step.inflate.val, step.inflate.val, step.inflate.property, rfl⟩) :=
|
||||
rfl
|
||||
match (← (monadLift it.step : ULiftT n _).run).down.inflate with
|
||||
| .yield it' out h => return .deflate (.yield (it'.uLift n) (.up out) ⟨_, h, rfl⟩)
|
||||
| .skip it' h => return .deflate (.skip (it'.uLift n) ⟨_, h, rfl⟩)
|
||||
| .done h => return .deflate (.done ⟨_, h, rfl⟩)) := by
|
||||
simp only [IterM.step, Iterator.step, IterM.uLift]
|
||||
apply bind_congr; intro step
|
||||
split <;> simp [Types.ULiftIterator.Monadic.modifyStep, *]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
@@ -33,14 +37,11 @@ theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
|
||||
(fun l => l.down.map ULift.up) <$> (monadLift it.toList : ULiftT n _).run := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [IterM.toList_eq_match_step, IterM.toList_eq_match_step, step_uLift]
|
||||
simp only [bind_pure_comp, bind_map_left, liftM_bind, ULiftT.run_bind, map_bind]
|
||||
apply bind_congr
|
||||
intro step
|
||||
simp [Types.ULiftIterator.Monadic.modifyStep]
|
||||
simp only [bind_assoc, map_eq_pure_bind, monadLift_bind, ULiftT.run_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.down.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [uLift] at ihy
|
||||
simp [ihy ‹_›]
|
||||
· exact ihs ‹_›
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
@@ -63,4 +64,20 @@ theorem IterM.toArray_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift, monadLift_map]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.count_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorLoop α m m]
|
||||
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorLoop α m m]
|
||||
[LawfulMonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).count =
|
||||
(.up ·.down.down) <$> (monadLift (n := ULiftT n) it.count).run := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [count_eq_match_step, count_eq_match_step, monadLift_bind, map_eq_pure_bind, step_uLift]
|
||||
simp only [bind_assoc, ULiftT.run_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.down.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -6,8 +6,8 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Data.Iterators.Combinators.Take
|
||||
public import Std.Data.Iterators.Lemmas.Combinators.Monadic.Take
|
||||
public import Init.Data.Iterators.Combinators.Take
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.Take
|
||||
public import Init.Data.Iterators.Lemmas.Consumers
|
||||
|
||||
@[expose] public section
|
||||
@@ -19,14 +19,19 @@ theorem Iter.take_eq_toIter_take_toIterM {α β} [Iterator α Id β] {n : Nat}
|
||||
it.take n = (it.toIterM.take n).toIter :=
|
||||
rfl
|
||||
|
||||
theorem Iter.toTake_eq_toIter_toTake_toIterM {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toTake = it.toIterM.toTake.toIter :=
|
||||
rfl
|
||||
|
||||
theorem Iter.step_take {α β} [Iterator α Id β] {n : Nat}
|
||||
{it : Iter (α := α) β} :
|
||||
(it.take n).step = (match n with
|
||||
| 0 => .done (.depleted rfl)
|
||||
| k + 1 =>
|
||||
match it.step with
|
||||
| .yield it' out h => .yield (it'.take k) out (.yield h rfl)
|
||||
| .skip it' h => .skip (it'.take (k + 1)) (.skip h rfl)
|
||||
| .yield it' out h => .yield (it'.take k) out (Take.isPlausibleStep_take_yield h)
|
||||
| .skip it' h => .skip (it'.take (k + 1)) (Take.isPlausibleStep_take_skip h)
|
||||
| .done h => .done (.done h)) := by
|
||||
simp only [Iter.step, Iter.step, Iter.take_eq_toIter_take_toIterM, IterM.step_take, toIterM_toIter]
|
||||
cases n
|
||||
@@ -88,11 +93,29 @@ theorem Iter.toArray_take_of_finite {α β} [Iterator α Id β] {n : Nat}
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_take_zero {α β} [Iterator α Id β]
|
||||
[Finite (Take α Id β) Id]
|
||||
[IteratorCollect (Take α Id β) Id Id] [LawfulIteratorCollect (Take α Id β) Id Id]
|
||||
[Finite (Take α Id) Id]
|
||||
[IteratorCollect (Take α Id) Id Id] [LawfulIteratorCollect (Take α Id) Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
(it.take 0).toList = [] := by
|
||||
rw [toList_eq_match_step]
|
||||
simp [step_take]
|
||||
|
||||
theorem Iter.step_toTake {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toTake.step = (
|
||||
match it.step with
|
||||
| .yield it' out h => .yield it'.toTake out (.yield h Nat.zero_ne_one)
|
||||
| .skip it' h => .skip it'.toTake (.skip h Nat.zero_ne_one)
|
||||
| .done h => .done (.done h)) := by
|
||||
simp only [toTake_eq_toIter_toTake_toIterM, Iter.step, toIterM_toIter, IterM.step_toTake,
|
||||
Id.run_bind]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toTake {α β} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toTake.toList = it.toList := by
|
||||
simp [toTake_eq_toIter_toTake_toIterM, toList_eq_toList_toIterM]
|
||||
|
||||
end Std.Iterators
|
||||
@@ -10,6 +10,7 @@ public import Init.Data.Iterators.Combinators.ULift
|
||||
import all Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.ULift
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Loop
|
||||
|
||||
public section
|
||||
|
||||
@@ -22,14 +23,16 @@ theorem Iter.uLift_eq_toIter_uLift_toIterM {it : Iter (α := α) β} :
|
||||
rfl
|
||||
|
||||
theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
|
||||
it.uLift.step =
|
||||
⟨Types.ULiftIterator.modifyStep it.step.val,
|
||||
it.step.val.mapIterator Iter.toIterM, it.step.property,
|
||||
by simp [Types.ULiftIterator.modifyStep]⟩ := by
|
||||
it.uLift.step = match it.step with
|
||||
| .yield it' out h => .yield it'.uLift (.up out) ⟨_, h, rfl⟩
|
||||
| .skip it' h => .skip it'.uLift ⟨_, h, rfl⟩
|
||||
| .done h => .done ⟨_, h, rfl⟩ := by
|
||||
rw [Subtype.ext_iff]
|
||||
simp only [uLift_eq_toIter_uLift_toIterM, step, IterM.Step.toPure, toIterM_toIter,
|
||||
IterM.step_uLift, bind_pure_comp, Id.run_map, toIter_toIterM]
|
||||
simp [Types.ULiftIterator.modifyStep, monadLift]
|
||||
IterM.step_uLift, toIter_toIterM]
|
||||
simp only [monadLift, ULiftT.run_pure, PlausibleIterStep.yield, PlausibleIterStep.skip,
|
||||
PlausibleIterStep.done, pure_bind]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
@@ -55,4 +58,12 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp [-toArray_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.count_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] :
|
||||
it.uLift.count = it.count := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, count_eq_count_toIterM, toIterM_toIter]
|
||||
rw [IterM.count_uLift]
|
||||
simp [monadLift]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -68,8 +68,7 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
rw [← h]
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
@@ -81,7 +80,7 @@ theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
|
||||
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
@@ -331,7 +330,7 @@ theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [
|
||||
|
||||
theorem Iter.foldM_eq_foldM_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ} {f : γ → β → m γ} :
|
||||
it.foldM (init := init) f = it.toIterM.foldM (init := init) f := by
|
||||
simp [foldM_eq_forIn, IterM.foldM_eq_forIn, forIn_eq_forIn_toIterM]
|
||||
@@ -396,7 +395,7 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
|
||||
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
|
||||
@@ -422,8 +421,9 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
theorem Iter.fold_hom {γ₁ : Type x₁} {γ₂ : Type x₂} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id.{x₁}] [LawfulIteratorLoop α Id Id.{x₁}]
|
||||
[IteratorLoop α Id Id.{x₂}] [LawfulIteratorLoop α Id Id.{x₂}]
|
||||
{it : Iter (α := α) β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
@@ -469,30 +469,72 @@ theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [F
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorSize α Id] [LawfulIteratorSize α]
|
||||
theorem Iter.count_eq_count_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] {it : Iter (α := α) β} :
|
||||
it.count = it.toIterM.count.run.down :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.count_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
|
||||
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray.size = it.size := by
|
||||
simp only [toArray_eq_toArray_toIterM, LawfulIteratorCollect.toArray_eq]
|
||||
simp [← toArray_eq_toArray_toIterM, LawfulIteratorSize.size_eq_size_toArray]
|
||||
it.count = it.fold (γ := Nat) (init := 0) (fun acc _ => acc + 1) := by
|
||||
rw [count_eq_count_toIterM, IterM.count_eq_fold, ← fold_eq_fold_toIterM]
|
||||
rw [← fold_hom (f := ULift.down)]
|
||||
simp
|
||||
|
||||
theorem Iter.count_eq_forIn {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id.{w}] [LawfulIteratorLoop α Id Id.{w}]
|
||||
[IteratorLoop α Id Id.{0}] [LawfulIteratorLoop α Id Id.{0}]
|
||||
{it : Iter (α := α) β} :
|
||||
it.count = (ForIn.forIn (m := Id) it 0 (fun _ acc => return .yield (acc + 1))).run := by
|
||||
rw [count_eq_fold, forIn_pure_yield_eq_fold, Id.run_pure]
|
||||
|
||||
theorem Iter.count_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.count = (match it.step.val with
|
||||
| .yield it' _ => it'.count + 1
|
||||
| .skip it' => it'.count
|
||||
| .done => 0) := by
|
||||
simp only [count_eq_count_toIterM]
|
||||
rw [IterM.count_eq_match_step]
|
||||
simp only [bind_pure_comp, id_map', Id.run_bind, Iter.step]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toList_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.size_toArray_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorSize α Id] [LawfulIteratorSize α]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList.length = it.size := by
|
||||
rw [← toList_toArray, Array.length_toList, size_toArray_eq_size]
|
||||
it.toArray.size = it.count := by
|
||||
simp only [toArray_eq_toArray_toIterM, count_eq_count_toIterM, Id.run_map,
|
||||
← IterM.up_size_toArray_eq_count]
|
||||
|
||||
@[deprecated Iter.size_toArray_eq_count (since := "2025-10-29")]
|
||||
def Iter.size_toArray_eq_size := @size_toArray_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toListRev_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.length_toList_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorSize α Id] [LawfulIteratorSize α]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev.length = it.size := by
|
||||
rw [toListRev_eq, List.length_reverse, length_toList_eq_size]
|
||||
it.toList.length = it.count := by
|
||||
rw [← toList_toArray, Array.length_toList, size_toArray_eq_count]
|
||||
|
||||
@[deprecated Iter.length_toList_eq_count (since := "2025-10-29")]
|
||||
def Iter.length_toList_eq_size := @length_toList_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toListRev_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev.length = it.count := by
|
||||
rw [toListRev_eq, List.length_reverse, length_toList_eq_count]
|
||||
|
||||
@[deprecated Iter.length_toListRev_eq_count (since := "2025-10-29")]
|
||||
def Iter.length_toListRev_eq_size := @length_toListRev_eq_count
|
||||
|
||||
theorem Iter.anyM_eq_forIn {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -726,4 +768,170 @@ theorem Iter.all_eq_not_any_not {α β : Type w} [Iterator α Id β]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.findSomeM?_eq_match_step {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option γ)} :
|
||||
it.findSomeM? f = (do
|
||||
match it.step.val with
|
||||
| .yield it' out =>
|
||||
match ← f out with
|
||||
| none => it'.findSomeM? f
|
||||
| some fx => return (some fx)
|
||||
| .skip it' => it'.findSomeM? f
|
||||
| .done => return none) := by
|
||||
rw [findSomeM?, forIn_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr; intro fx
|
||||
split <;> simp [findSomeM?]
|
||||
· simp [findSomeM?]
|
||||
· simp
|
||||
|
||||
theorem Iter.findSomeM?_toList {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → m (Option γ)} :
|
||||
it.toList.findSomeM? f = it.findSomeM? f := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [it.findSomeM?_eq_match_step, it.toList_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp only [List.findSomeM?_cons]
|
||||
apply bind_congr; intro fx
|
||||
split <;> simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.findSome?_eq_findSomeM? {α β : Type w} {γ : Type x}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.findSome? f = Id.run (it.findSomeM? (pure <| f ·)) :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.findSome?_eq_findSome?_toIterM {α β γ : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id.{w}] [Finite α Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.findSome? f = (it.toIterM.findSome? f).run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.findSome?_eq_match_step {α β : Type w} {γ : Type x}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
[LawfulIteratorLoop α Id Id] {it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.findSome? f = (match it.step.val with
|
||||
| .yield it' out =>
|
||||
match f out with
|
||||
| none => it'.findSome? f
|
||||
| some fx => some fx
|
||||
| .skip it' => it'.findSome? f
|
||||
| .done => none) := by
|
||||
rw [findSome?_eq_findSomeM?, findSomeM?_eq_match_step]
|
||||
split
|
||||
· simp only [pure_bind, findSome?_eq_findSomeM?]
|
||||
split <;> simp
|
||||
· simp [findSome?_eq_findSomeM?]
|
||||
· simp
|
||||
|
||||
theorem Iter.findSome?_toList {α β : Type w} {γ : Type x}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [IteratorCollect α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.toList.findSome? f = it.findSome? f := by
|
||||
simp [findSome?_eq_findSomeM?, List.findSome?_eq_findSomeM?, findSomeM?_toList]
|
||||
|
||||
theorem Iter.findSomeM?_pure {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorLoop α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.findSomeM? (pure <| f ·) = pure (f := m) (it.findSome? f) := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
simp [← findSomeM?_toList, ← findSome?_toList, List.findSomeM?_pure]
|
||||
|
||||
theorem Iter.findM?_eq_findSomeM? {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = it.findSomeM? (fun x => return if (← f x).down then some x else none) :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.findM?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = (do
|
||||
match it.step.val with
|
||||
| .yield it' out =>
|
||||
if (← f out).down then return (some out) else it'.findM? f
|
||||
| .skip it' => it'.findM? f
|
||||
| .done => return none) := by
|
||||
rw [findM?_eq_findSomeM?, findSomeM?_eq_match_step]
|
||||
split
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr; intro fx
|
||||
split <;> simp [findM?_eq_findSomeM?]
|
||||
· simp [findM?_eq_findSomeM?]
|
||||
· simp
|
||||
|
||||
theorem Iter.findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → m Bool} :
|
||||
it.toList.findM? f = it.findM? (.up <$> f ·) := by
|
||||
simp [findM?_eq_findSomeM?, List.findM?_eq_findSomeM?, findSomeM?_toList]
|
||||
|
||||
theorem Iter.findM?_eq_findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = it.toList.findM? (ULift.down <$> f ·) := by
|
||||
simp [findM?_toList]
|
||||
|
||||
theorem Iter.find?_eq_findM? {α β : Type w} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.find? f = Id.run (it.findM? (pure <| .up <| f ·)) :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.find?_eq_find?_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.find? f = (it.toIterM.find? f).run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.find?_eq_findSome? {α β : Type w} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] {it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.find? f = it.findSome? (fun x => if f x then some x else none) := by
|
||||
simp [find?_eq_findM?, findSome?_eq_findSomeM?, findM?_eq_findSomeM?]
|
||||
|
||||
theorem Iter.find?_eq_match_step {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.find? f = (match it.step.val with
|
||||
| .yield it' out =>
|
||||
if f out then some out else it'.find? f
|
||||
| .skip it' => it'.find? f
|
||||
| .done => none) := by
|
||||
rw [find?_eq_findM?, findM?_eq_match_step]
|
||||
split
|
||||
· simp only [pure_bind]
|
||||
split <;> simp [find?_eq_findM?]
|
||||
· simp [find?_eq_findM?]
|
||||
· simp
|
||||
|
||||
theorem Iter.find?_toList {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [IteratorCollect α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.toList.find? f = it.find? f := by
|
||||
simp [find?_eq_findSome?, List.find?_eq_findSome?_guard, findSome?_toList, Option.guard_def]
|
||||
|
||||
theorem Iter.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorLoop α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → ULift Bool} :
|
||||
it.findM? (pure (f := m) <| f ·) = pure (f := m) (it.find? (ULift.down <| f ·)) := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
rw [findM?_eq_match_step, find?_eq_match_step]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp only [pure_bind]
|
||||
split
|
||||
· simp
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -335,6 +335,73 @@ theorem IterM.drain_eq_map_toArray {α β : Type w} {m : Type w → Type w'} [It
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
simp [IterM.drain_eq_map_toList]
|
||||
|
||||
theorem IterM.count_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.count = it.fold (init := .up 0) (fun acc _ => .up <| acc.down + 1) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.count_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.count = ForIn.forIn it (.up 0) (fun _ acc => return .yield (.up (acc.down + 1))) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.count_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.count = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' _ => return .up ((← it'.count).down + 1)
|
||||
| .skip it' => return .up (← it'.count).down
|
||||
| .done => return .up 0) := by
|
||||
simp only [count_eq_fold]
|
||||
have (acc : Nat) (it' : IterM (α := α) m β) :
|
||||
it'.fold (init := ULift.up acc) (fun acc _ => .up (acc.down + 1)) =
|
||||
(ULift.up <| ·.down + acc) <$>
|
||||
it'.fold (init := ULift.up 0) (fun acc _ => .up (acc.down + 1)) := by
|
||||
rw [← fold_hom]
|
||||
· simp only [Nat.zero_add]; rfl
|
||||
· simp only [ULift.up.injEq]; omega
|
||||
rw [fold_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [Nat.zero_add, bind_pure_comp]
|
||||
rw [this 1]
|
||||
· simp
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_size_toArray_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.size) <$> it.toArray = it.count := by
|
||||
rw [toArray_eq_fold, count_eq_fold, ← fold_hom]
|
||||
· simp only [List.size_toArray, List.length_nil]; rfl
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_length_toList_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toList = it.count := by
|
||||
rw [toList_eq_fold, count_eq_fold, ← fold_hom]
|
||||
· simp only [List.length_nil]; rfl
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.up_length_toListRev_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toListRev = it.count := by
|
||||
simp only [toListRev_eq, Functor.map_map, List.length_reverse, up_length_toList_eq_count]
|
||||
|
||||
theorem IterM.anyM_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {p : β → m (ULift Bool)} :
|
||||
@@ -514,4 +581,126 @@ theorem IterM.all_eq_not_any_not {α β : Type w} {m : Type w → Type w'} [Iter
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.findSomeM?_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → m (Option γ)} :
|
||||
it.findSomeM? f = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out =>
|
||||
match ← f out with
|
||||
| none => it'.findSomeM? f
|
||||
| some fx => return (some fx)
|
||||
| .skip it' => it'.findSomeM? f
|
||||
| .done => return none) := by
|
||||
rw [findSomeM?, forIn_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr; intro fx
|
||||
split <;> simp [findSomeM?]
|
||||
· simp [findSomeM?]
|
||||
· simp
|
||||
|
||||
theorem IterM.findSome?_eq_findSomeM? {α β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [Finite α m]
|
||||
{it : IterM (α := α) m β} {f : β → Option γ} :
|
||||
it.findSome? f = it.findSomeM? (pure <| f ·) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.findSome?_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → Option γ} :
|
||||
it.findSome? f = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out =>
|
||||
match f out with
|
||||
| none => it'.findSome? f
|
||||
| some fx => return (some fx)
|
||||
| .skip it' => it'.findSome? f
|
||||
| .done => return none) := by
|
||||
rw [findSome?_eq_findSomeM?, findSomeM?_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
split <;> simp [findSome?_eq_findSomeM?]
|
||||
|
||||
theorem IterM.findSomeM?_pure {α β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m]
|
||||
[LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → Option γ} :
|
||||
it.findSomeM? (pure <| f ·) = it.findSome? f := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [findSomeM?_eq_match_step, findSome?_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [pure_bind]
|
||||
split <;> simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.findM?_eq_findSomeM? {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [Finite α m]
|
||||
{it : IterM (α := α) m β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = it.findSomeM? (fun x => return if (← f x).down then some x else none) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.findM?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out =>
|
||||
if (← f out).down then return (some out) else it'.findM? f
|
||||
| .skip it' => it'.findM? f
|
||||
| .done => return none) := by
|
||||
rw [findM?_eq_findSomeM?, findSomeM?_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
split
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr; intro fx
|
||||
split <;> simp [findM?_eq_findSomeM?]
|
||||
· simp [findM?_eq_findSomeM?]
|
||||
· simp
|
||||
|
||||
theorem IterM.find?_eq_findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [Finite α m] {it : IterM (α := α) m β} {f : β → Bool} :
|
||||
it.find? f = it.findM? (pure <| .up <| f ·) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.find?_eq_findSome? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorLoop α m m] [LawfulMonad m] [Finite α m] {it : IterM (α := α) m β} {f : β → Bool} :
|
||||
it.find? f = it.findSome? (fun x => if f x then some x else none) := by
|
||||
simp [find?_eq_findM?, findSome?_eq_findSomeM?, findM?_eq_findSomeM?]
|
||||
|
||||
theorem IterM.find?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m] [LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → Bool} :
|
||||
it.find? f = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out =>
|
||||
if f out then return (some out) else it'.find? f
|
||||
| .skip it' => it'.find? f
|
||||
| .done => return none) := by
|
||||
rw [find?_eq_findM?, findM?_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
split
|
||||
· simp only [pure_bind]
|
||||
split <;> simp [find?_eq_findM?]
|
||||
· simp [find?_eq_findM?]
|
||||
· simp
|
||||
|
||||
theorem IterM.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [IteratorLoop α m m]
|
||||
[LawfulMonad m] [Finite α m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : β → ULift Bool} :
|
||||
it.findM? (pure (f := m) <| f ·) = it.find? (ULift.down <| f ·) := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [findM?_eq_match_step, find?_eq_match_step]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [pure_bind]
|
||||
split
|
||||
· simp
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
10
src/Init/Data/Iterators/Lemmas/Producers.lean
Normal file
10
src/Init/Data/Iterators/Lemmas/Producers.lean
Normal file
@@ -0,0 +1,10 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Producers.Monadic
|
||||
public import Init.Data.Iterators.Lemmas.Producers.List
|
||||
@@ -7,8 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Std.Data.Iterators.Producers.List
|
||||
public import Std.Data.Iterators.Lemmas.Producers.Monadic.List
|
||||
public import Init.Data.Iterators.Producers.List
|
||||
public import Init.Data.Iterators.Lemmas.Producers.Monadic.List
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Lean.PremiseSelection.Basic
|
||||
import Lean.PremiseSelection.MePo
|
||||
public import Init.Data.Iterators.Lemmas.Producers.Monadic.List
|
||||
71
src/Init/Data/Iterators/Lemmas/Producers/Monadic/List.lean
Normal file
71
src/Init/Data/Iterators/Lemmas/Producers/Monadic/List.lean
Normal file
@@ -0,0 +1,71 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
public import Init.Data.Iterators.Producers.Monadic.List
|
||||
|
||||
@[expose] public section
|
||||
|
||||
/-!
|
||||
# Lemmas about list iterators
|
||||
|
||||
This module provides lemmas about the interactions of `List.iterM` with `IterM.step` and various
|
||||
collectors.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
|
||||
variable {m : Type w → Type w'} {n : Type w → Type w''} [Monad m] {β : Type w}
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iterM_nil :
|
||||
(([] : List β).iterM m).step = pure (.deflate ⟨.done, rfl⟩) := by
|
||||
simp only [IterM.step, Iterator.step]; rfl
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iterM_cons {x : β} {xs : List β} :
|
||||
((x :: xs).iterM m).step = pure (.deflate ⟨.yield (xs.iterM m) x, rfl⟩) := by
|
||||
simp only [List.iterM, IterM.step, Iterator.step]; rfl
|
||||
|
||||
theorem _root_.List.step_iterM {l : List β} :
|
||||
(l.iterM m).step = match l with
|
||||
| [] => pure (.deflate ⟨.done, rfl⟩)
|
||||
| x :: xs => pure (.deflate ⟨.yield (xs.iterM m) x, rfl⟩) := by
|
||||
cases l <;> simp [List.step_iterM_cons, List.step_iterM_nil]
|
||||
|
||||
theorem ListIterator.toArrayMapped_iterM [Monad n] [LawfulMonad n]
|
||||
{β : Type w} {γ : Type w} {lift : ⦃δ : Type w⦄ → m δ → n δ}
|
||||
[LawfulMonadLiftFunction lift] {f : β → n γ} {l : List β} :
|
||||
IteratorCollect.toArrayMapped lift f (l.iterM m) (m := m) = List.toArray <$> l.mapM f := by
|
||||
rw [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
induction l with
|
||||
| nil =>
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [List.step_iterM_nil, LawfulMonadLiftFunction.lift_pure]
|
||||
| cons x xs ih =>
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [List.step_iterM_cons, List.mapM_cons, pure_bind, ih, LawfulMonadLiftFunction.lift_pure]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toArray_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toArray = pure l.toArray := by
|
||||
simp only [IterM.toArray, ListIterator.toArrayMapped_iterM]
|
||||
rw [List.mapM_pure, map_pure, List.map_id']
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toList_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toList = pure l := by
|
||||
rw [← IterM.toList_toArray, List.toArray_iterM, map_pure, List.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toListRev_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toListRev = pure l.reverse := by
|
||||
simp [IterM.toListRev_eq, List.toList_iterM]
|
||||
|
||||
end Std.Iterators
|
||||
10
src/Init/Data/Iterators/Producers.lean
Normal file
10
src/Init/Data/Iterators/Producers.lean
Normal file
@@ -0,0 +1,10 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Producers.Monadic
|
||||
public import Init.Data.Iterators.Producers.List
|
||||
@@ -6,7 +6,7 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Std.Data.Iterators.Producers.Monadic.List
|
||||
public import Init.Data.Iterators.Producers.Monadic.List
|
||||
|
||||
@[expose] public section
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user