mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-18 02:44:12 +00:00
Compare commits
305 Commits
grind_arra
...
IntModule_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26268136dc | ||
|
|
98c220ea8d | ||
|
|
b277f3a402 | ||
|
|
7563199ccc | ||
|
|
42882ce465 | ||
|
|
f20d0e4532 | ||
|
|
9ece4e463a | ||
|
|
c38c0898a3 | ||
|
|
070e622f05 | ||
|
|
12a8f1b5f8 | ||
|
|
7050dc6d38 | ||
|
|
376ae32c7c | ||
|
|
0c44aab811 | ||
|
|
a5eeed4f2c | ||
|
|
be80a23281 | ||
|
|
92ac564f3c | ||
|
|
0fcb6495d6 | ||
|
|
e7c8baaef5 | ||
|
|
8d8c73416a | ||
|
|
cf527e05bd | ||
|
|
61ee83f73b | ||
|
|
26b7e49c05 | ||
|
|
466c9b56ba | ||
|
|
00474e17ff | ||
|
|
891a2c6590 | ||
|
|
d489c6196c | ||
|
|
6703af1ea0 | ||
|
|
7f8ccd8425 | ||
|
|
a8d5982fce | ||
|
|
50cfe354be | ||
|
|
a750da5a7f | ||
|
|
588df4612a | ||
|
|
4ce18249d3 | ||
|
|
dd78012ddd | ||
|
|
1e69d88d6f | ||
|
|
db499e96aa | ||
|
|
c5ca9aa87c | ||
|
|
28f89c0567 | ||
|
|
f416143fbc | ||
|
|
743c60224a | ||
|
|
e6b5c45e04 | ||
|
|
8af3b89203 | ||
|
|
3710e4f176 | ||
|
|
da9a536ffd | ||
|
|
ec9865dbd5 | ||
|
|
a2b03b3efd | ||
|
|
0077dd3d55 | ||
|
|
63cfe908c5 | ||
|
|
c796609159 | ||
|
|
827c69e46e | ||
|
|
19d9f6c450 | ||
|
|
42eb3bb4b5 | ||
|
|
f3f932ae8c | ||
|
|
6c6a058beb | ||
|
|
04113f2be5 | ||
|
|
2b393a3b88 | ||
|
|
bec538cc57 | ||
|
|
e74d3a2f1c | ||
|
|
1b5a9be785 | ||
|
|
aea8e11d4b | ||
|
|
935aa38603 | ||
|
|
e5c6fe1dac | ||
|
|
62f3ee2887 | ||
|
|
e8c82610cd | ||
|
|
86eded35db | ||
|
|
f0fdab86bb | ||
|
|
d58e253671 | ||
|
|
e1ecc150e3 | ||
|
|
76fcd276c6 | ||
|
|
d0c1053903 | ||
|
|
48a0e742d8 | ||
|
|
d131cf39c1 | ||
|
|
c16204615d | ||
|
|
e83b768140 | ||
|
|
705769f466 | ||
|
|
cd346a360e | ||
|
|
6240cd5aa9 | ||
|
|
cfa38b055b | ||
|
|
e9086533ed | ||
|
|
cf47e5f6a7 | ||
|
|
16e67dc738 | ||
|
|
5810f8907d | ||
|
|
22e8b476ba | ||
|
|
3a8258b2d5 | ||
|
|
aa9f966aee | ||
|
|
e129e75e66 | ||
|
|
04c273dbc6 | ||
|
|
2b39b453e7 | ||
|
|
43aaae7348 | ||
|
|
92dec7e864 | ||
|
|
b3a53d5d01 | ||
|
|
3b2990b381 | ||
|
|
17b133369d | ||
|
|
259e2ec3e8 | ||
|
|
c9d0af1d7e | ||
|
|
471553102c | ||
|
|
18caad9756 | ||
|
|
f557bf6024 | ||
|
|
548cc4e555 | ||
|
|
38fb9c5328 | ||
|
|
ba39fd3ca8 | ||
|
|
fcb3b2ec66 | ||
|
|
e1408d29bc | ||
|
|
9e913a29de | ||
|
|
46c3eaece9 | ||
|
|
47c294b3a9 | ||
|
|
5568e06160 | ||
|
|
ed4195778d | ||
|
|
997892d49a | ||
|
|
e07ed1ae5c | ||
|
|
d247297214 | ||
|
|
242429a262 | ||
|
|
d9b2a5e9f7 | ||
|
|
4e96a4ff45 | ||
|
|
7b67727067 | ||
|
|
8ed6824b75 | ||
|
|
fdf6d2ea3b | ||
|
|
dc531a1740 | ||
|
|
ddff851294 | ||
|
|
db414957a0 | ||
|
|
114fa440f0 | ||
|
|
aa988bb892 | ||
|
|
e2a947c2e6 | ||
|
|
26946ddc7f | ||
|
|
0bfd95dd20 | ||
|
|
957b904ef9 | ||
|
|
1835f190c7 | ||
|
|
f86560d134 | ||
|
|
cc3dafe67a | ||
|
|
5bc5d31fd9 | ||
|
|
ac0c59caae | ||
|
|
2a8cd373ca | ||
|
|
ef6386b8a9 | ||
|
|
021c21a273 | ||
|
|
286ddf5e28 | ||
|
|
97bc609e77 | ||
|
|
cdc923167e | ||
|
|
1d971c8735 | ||
|
|
82c2c4cd51 | ||
|
|
019ea2a74b | ||
|
|
ec9ff12fc6 | ||
|
|
444595878b | ||
|
|
3d3aa98c83 | ||
|
|
27080dca35 | ||
|
|
aef4a29148 | ||
|
|
5d50433e6a | ||
|
|
812bab6910 | ||
|
|
ff6eb56f5c | ||
|
|
4b7ea26d91 | ||
|
|
32eedc2c22 | ||
|
|
95e532a536 | ||
|
|
cceabbbe7e | ||
|
|
8019c6cc32 | ||
|
|
5390cdbee1 | ||
|
|
e713232623 | ||
|
|
0d0da768d8 | ||
|
|
3feb63231e | ||
|
|
121ce56506 | ||
|
|
300c22a4e6 | ||
|
|
f247f2bdd0 | ||
|
|
db5bd5a205 | ||
|
|
140a633589 | ||
|
|
3aa479fd8c | ||
|
|
b280b83c98 | ||
|
|
84f15ac93a | ||
|
|
d4b17b9fd2 | ||
|
|
4694aaad02 | ||
|
|
e450a02621 | ||
|
|
deda28e6e3 | ||
|
|
8aa003bdfc | ||
|
|
6a698c1c22 | ||
|
|
b4660c96a9 | ||
|
|
2cddf2394b | ||
|
|
75fe50a33e | ||
|
|
c2876a1a6a | ||
|
|
9f6846a343 | ||
|
|
64e105c121 | ||
|
|
d10a85539a | ||
|
|
f0347ee719 | ||
|
|
faffe86334 | ||
|
|
c168d06edf | ||
|
|
abfc49d0f7 | ||
|
|
34e98c2efc | ||
|
|
e7549b5651 | ||
|
|
9f65d0251a | ||
|
|
a7af9f7d5f | ||
|
|
39cbe04946 | ||
|
|
77fd1ba6b9 | ||
|
|
0002ea8a37 | ||
|
|
7bd82b103a | ||
|
|
2c9c58b1f7 | ||
|
|
54c12df950 | ||
|
|
01a0524749 | ||
|
|
551e755d23 | ||
|
|
082ca94d3b | ||
|
|
ee5b652136 | ||
|
|
91b5e19833 | ||
|
|
cf8315ed96 | ||
|
|
44e36dec6f | ||
|
|
a92890ec84 | ||
|
|
eccc472e8d | ||
|
|
d8c54fb93d | ||
|
|
aab65f595d | ||
|
|
0a9c246497 | ||
|
|
2a63b392dd | ||
|
|
0b2884bfa3 | ||
|
|
c53ab2835c | ||
|
|
54dd7aae8c | ||
|
|
52e0742108 | ||
|
|
614e6122f7 | ||
|
|
1a9de502f2 | ||
|
|
085c4ed3f9 | ||
|
|
be4ebb8ac3 | ||
|
|
2344e3f254 | ||
|
|
48f394b1d4 | ||
|
|
2629921c01 | ||
|
|
e123b327a5 | ||
|
|
e904314742 | ||
|
|
0ebd320940 | ||
|
|
b1980ef871 | ||
|
|
8fce30e7cb | ||
|
|
308a383079 | ||
|
|
2d67524e42 | ||
|
|
41c41e455a | ||
|
|
f61a412801 | ||
|
|
00f6b1e70a | ||
|
|
8422d936cf | ||
|
|
dd1d3e6a3a | ||
|
|
e38b8a0a7a | ||
|
|
3e0168df58 | ||
|
|
fcaae1dc58 | ||
|
|
8cc6a4a028 | ||
|
|
4ec5dad05f | ||
|
|
7e1d0cc125 | ||
|
|
2ae066fdc0 | ||
|
|
c9c794ee8a | ||
|
|
106708ee78 | ||
|
|
666fb5c571 | ||
|
|
8d8fd0715f | ||
|
|
4abc4430dc | ||
|
|
d46188de54 | ||
|
|
de57b77feb | ||
|
|
f0eae3b879 | ||
|
|
1abf6fe1f5 | ||
|
|
f917951745 | ||
|
|
8904e5c070 | ||
|
|
ef9094d7f8 | ||
|
|
d50292d31b | ||
|
|
24cb133eb2 | ||
|
|
eddbe08118 | ||
|
|
d16c4052c2 | ||
|
|
febad6a380 | ||
|
|
257cd15a00 | ||
|
|
5963bc8b8a | ||
|
|
ec9b00996f | ||
|
|
50474fef78 | ||
|
|
a5567618ac | ||
|
|
a3caf60f6a | ||
|
|
c3d31cf24b | ||
|
|
f7ecf06234 | ||
|
|
b97d35d879 | ||
|
|
ebf5fbd294 | ||
|
|
74d8746356 | ||
|
|
1d9dd33bec | ||
|
|
9b9dd8546a | ||
|
|
de7d43865e | ||
|
|
3ce7dd318d | ||
|
|
b1709d1fc1 | ||
|
|
6ebf39d0fc | ||
|
|
a6e2df6250 | ||
|
|
e08b2a1f62 | ||
|
|
2f4e56b5d2 | ||
|
|
a487bb8d63 | ||
|
|
8457342d33 | ||
|
|
596e65d7df | ||
|
|
7c76dbf6be | ||
|
|
6b102c91e3 | ||
|
|
b9243e19be | ||
|
|
d6478e15c7 | ||
|
|
1629440cb8 | ||
|
|
4500a7f02b | ||
|
|
c12159b519 | ||
|
|
1260059a59 | ||
|
|
8165ecc1db | ||
|
|
344b52f999 | ||
|
|
5e952598dc | ||
|
|
b9aefb4a50 | ||
|
|
9afe5ccae3 | ||
|
|
cb0284f98e | ||
|
|
35e83066e6 | ||
|
|
ba847d41f1 | ||
|
|
f5e72d0962 | ||
|
|
536c87d73c | ||
|
|
c95e058e3c | ||
|
|
4746e38414 | ||
|
|
f718f26200 | ||
|
|
184dbae130 | ||
|
|
bc47aa180b | ||
|
|
f7b6e155d4 | ||
|
|
f4e86e310c | ||
|
|
5f0bdfcada | ||
|
|
0f4459b42c | ||
|
|
55b89aaf38 | ||
|
|
9fc8713946 | ||
|
|
106411420b |
21
.github/workflows/build-template.yml
vendored
21
.github/workflows/build-template.yml
vendored
@@ -82,7 +82,7 @@ jobs:
|
||||
- name: CI Merge Checkout
|
||||
run: |
|
||||
git fetch --depth=1 origin ${{ github.sha }}
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-*
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-* tests/lean/run/importStructure.lean
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
# NOTE: must be in sync with `save` below
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
${{ matrix.name == 'Linux Lake' && false && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.c
|
||||
@@ -127,9 +127,12 @@ jobs:
|
||||
[ -d build ] || mkdir build
|
||||
cd build
|
||||
# arguments passed to `cmake`
|
||||
# this also enables githash embedding into stage 1 library
|
||||
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
|
||||
OPTIONS+=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
|
||||
OPTIONS=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
|
||||
if [[ -n '${{ matrix.release }}' ]]; then
|
||||
# this also enables githash embedding into stage 1 library, which prohibits reusing
|
||||
# `.olean`s across commits, so we don't do it in the fast non-release CI
|
||||
OPTIONS+=(-DCHECK_OLEAN_VERSION=ON)
|
||||
fi
|
||||
if [[ -n '${{ matrix.cross_target }}' ]]; then
|
||||
# used by `prepare-llvm`
|
||||
export EXTRA_FLAGS=--target=${{ matrix.cross_target }}
|
||||
@@ -193,7 +196,7 @@ jobs:
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.name == 'Linux release')
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
with:
|
||||
@@ -210,7 +213,7 @@ jobs:
|
||||
- name: Check Stage 3
|
||||
run: |
|
||||
make -C build -j$NPROC check-stage3
|
||||
if: matrix.test-speedcenter
|
||||
if: matrix.check-stage3
|
||||
- name: Test Speedcenter Benchmarks
|
||||
run: |
|
||||
# Necessary for some timing metrics but does not work on Namespace runners
|
||||
@@ -224,7 +227,7 @@ jobs:
|
||||
run: |
|
||||
# clean rebuild in case of Makefile changes
|
||||
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
|
||||
if: matrix.name == 'Linux' && inputs.check-level >= 1
|
||||
if: matrix.check-rebootstrap
|
||||
- name: CCache stats
|
||||
if: always()
|
||||
run: ccache -s
|
||||
@@ -242,7 +245,7 @@ jobs:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
${{ matrix.name == 'Linux Lake' && false && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.c
|
||||
|
||||
44
.github/workflows/ci.yml
vendored
44
.github/workflows/ci.yml
vendored
@@ -164,9 +164,15 @@ jobs:
|
||||
{
|
||||
// portable release build: use channel with older glibc (2.26)
|
||||
"name": "Linux release",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"os": large && level < 2 ? "nscloud-ubuntu-22.04-amd64-4x16" : "ubuntu-latest",
|
||||
"release": true,
|
||||
"check-level": 0,
|
||||
// Special handling for release jobs. We want:
|
||||
// 1. To run it in PRs so developrs get PR toolchains (so secondary is sufficient)
|
||||
// 2. To skip it in merge queues as it takes longer than the
|
||||
// Linux lake build and adds little value in the merge queue
|
||||
// 3. To run it in release (obviously)
|
||||
"check-level": isPr ? 0 : 2,
|
||||
"secondary": isPr,
|
||||
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-linux-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||
@@ -176,21 +182,14 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux Lake",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16" : "ubuntu-latest",
|
||||
"check-level": 0,
|
||||
// just a secondary build job for now until false positives can be excluded
|
||||
"secondary": true,
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
// TODO: importStructure is not compatible with .olean caching
|
||||
// TODO: why does scopedMacros fail?
|
||||
"CTEST_OPTIONS": "-E 'scopedMacros|importStructure'"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"test": true,
|
||||
"check-rebootstrap": level >= 1,
|
||||
"check-stage3": level >= 2,
|
||||
"test-speedcenter": level >= 2,
|
||||
"check-level": 1,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
},
|
||||
{
|
||||
"name": "Linux Reldebug",
|
||||
@@ -223,7 +222,8 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
"os": "macos-14",
|
||||
// standard GH runner only comes with 7GB so use large runner if possible
|
||||
"os": large ? "nscloud-macos-sonoma-arm64-6x14" : "macos-14",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
|
||||
"release": true,
|
||||
"shell": "bash -euxo pipefail {0}",
|
||||
@@ -231,11 +231,7 @@ jobs:
|
||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||
"binary-check": "otool -L",
|
||||
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
|
||||
// Special handling for MacOS aarch64, we want:
|
||||
// 1. To run it in PRs so Mac devs get PR toolchains (so secondary is sufficient)
|
||||
// 2. To skip it in merge queues as it takes longer than the Linux build and adds
|
||||
// little value in the merge queue
|
||||
// 3. To run it in release (obviously)
|
||||
// See above for release job levels
|
||||
"check-level": isPr ? 0 : 2,
|
||||
"secondary": isPr,
|
||||
},
|
||||
@@ -254,7 +250,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux aarch64",
|
||||
"os": "nscloud-ubuntu-22.04-arm64-4x8",
|
||||
"os": "nscloud-ubuntu-22.04-arm64-4x16",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
@@ -364,7 +360,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -408,7 +404,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@v2
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
64
.github/workflows/pr-release.yml
vendored
64
.github/workflows/pr-release.yml
vendored
@@ -48,19 +48,30 @@ 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}"
|
||||
- name: Delete existing release if present
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
# Try to delete any existing release for the current PR.
|
||||
# Try to delete any existing release for the current PR (just the version without the SHA suffix).
|
||||
gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} -y || true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release
|
||||
- name: Release (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -73,7 +84,22 @@ jobs:
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Report release status
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
draft: false
|
||||
tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}
|
||||
repository: ${{ github.repository_owner }}/lean4-pr-releases
|
||||
env:
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Report release status (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
@@ -87,6 +113,20 @@ jobs:
|
||||
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}",
|
||||
});
|
||||
|
||||
- name: Report release status (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: "${{ steps.workflow-info.outputs.sourceHeadSha }}",
|
||||
state: "success",
|
||||
context: "PR toolchain (SHA-suffixed)",
|
||||
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}",
|
||||
});
|
||||
|
||||
- name: Add label
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
@@ -282,16 +322,18 @@ jobs:
|
||||
if [ "$EXISTS" = "0" ]; then
|
||||
echo "Branch does not exist, creating it."
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
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 }}"
|
||||
else
|
||||
echo "Branch already exists, pushing an empty commit."
|
||||
echo "Branch already exists, updating lean-toolchain."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The Batteries `nightly-testing` or `nightly-testing-YYYY-MM-DD` branch may have moved since this branch was created, so merge their changes.
|
||||
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
|
||||
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
|
||||
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
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 }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
@@ -346,21 +388,23 @@ jobs:
|
||||
if [ "$EXISTS" = "0" ]; then
|
||||
echo "Branch does not exist, creating it."
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
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 }}"
|
||||
else
|
||||
echo "Branch already exists, merging $BASE and bumping Batteries."
|
||||
echo "Branch already exists, updating lean-toolchain and bumping Batteries."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The Mathlib `nightly-testing` branch or `nightly-testing-YYYY-MM-DD` tag may have moved since this branch was created, so merge their changes.
|
||||
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
|
||||
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
|
||||
lake update batteries
|
||||
git add lake-manifest.json
|
||||
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,7 +6,6 @@
|
||||
lake-manifest.json
|
||||
/build
|
||||
/src/lakefile.toml
|
||||
/tests/lakefile.toml
|
||||
/lakefile.toml
|
||||
GPATH
|
||||
GRTAGS
|
||||
|
||||
@@ -50,7 +50,7 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- Re-running `script/release_checklist.py` will then create the tag `v4.6.0` from `master`/`main` and push it (unless `toolchain-tag: false` in the `release_repos.yml` file)
|
||||
- `script/release_checklist.py` will then merge the tag `v4.6.0` into the `stable` branch and push it (unless `stable-branch: false` in the `release_repos.yml` file).
|
||||
- Special notes on repositories with exceptional requirements:
|
||||
- `doc-gen4` has addition dependencies which we do not update at each toolchain release, although occasionally these break and need to be updated manually.
|
||||
- `doc-gen4` has additional dependencies which we do not update at each toolchain release, although occasionally these break and need to be updated manually.
|
||||
- `verso`:
|
||||
- The `subverso` dependency is unusual in that it needs to be compatible with _every_ Lean release simultaneously.
|
||||
Usually you don't need to do anything.
|
||||
@@ -94,6 +94,8 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
|
||||
This checklist walks you through creating the first release candidate for a version of Lean.
|
||||
|
||||
For subsequent release candidates, the process is essentially the same, but we start out with the `releases/v4.7.0` branch already created.
|
||||
|
||||
We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
|
||||
- Decide which nightly release you want to turn into a release candidate.
|
||||
@@ -112,7 +114,7 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
git fetch nightly tag nightly-2024-02-29
|
||||
git checkout nightly-2024-02-29
|
||||
git checkout -b releases/v4.7.0
|
||||
git push --set-upstream origin releases/v4.18.0
|
||||
git push --set-upstream origin releases/v4.7.0
|
||||
```
|
||||
- In `src/CMakeLists.txt`,
|
||||
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
|
||||
|
||||
9
script/bench.sh
Executable file
9
script/bench.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# We benchmark against stage 2 to test new optimizations.
|
||||
timeout -s KILL 1h time bash -c 'mkdir -p build/release; cd build/release; cmake ../.. && make -j$(nproc) stage2' 1>&2
|
||||
export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
cd tests/bench
|
||||
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
|
||||
temci report run_output.yaml --reporter codespeed2
|
||||
@@ -50,5 +50,4 @@ echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -Wl,-Bstatic
|
||||
# when not using the above flags, link GMP dynamically/as usual. Always link ICU dynamically.
|
||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp $(pkg-config --libs libuv) -lucrtbase'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"
|
||||
echo -n " -DLEAN_TEST_VARS=''"
|
||||
|
||||
@@ -53,6 +53,23 @@ def tag_exists(repo_url, tag_name, github_token):
|
||||
matching_tags = response.json()
|
||||
return any(tag["ref"] == f"refs/tags/{tag_name}" for tag in matching_tags)
|
||||
|
||||
def commit_hash_for_tag(repo_url, tag_name, github_token):
|
||||
# Use /git/matching-refs/tags/ to get all matching tags
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/git/matching-refs/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
# Check if any of the returned refs exactly match our tag
|
||||
matching_tags = response.json()
|
||||
matching_commits = [tag["object"]["sha"] for tag in matching_tags if tag["ref"] == f"refs/tags/{tag_name}"]
|
||||
if len(matching_commits) != 1:
|
||||
return None
|
||||
else:
|
||||
return matching_commits[0]
|
||||
|
||||
def release_page_exists(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/releases/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
@@ -286,6 +303,14 @@ def main():
|
||||
lean4_success = False
|
||||
else:
|
||||
print(f" ✅ Tag {toolchain} exists")
|
||||
commit_hash = commit_hash_for_tag(lean_repo_url, toolchain, github_token)
|
||||
SHORT_HASH_LENGTH = 7 # Lake abbreviates the Lean commit to 7 characters.
|
||||
if commit_hash is None:
|
||||
print(f" ❌ Could not resolve tag {toolchain} to a commit.")
|
||||
lean4_success = False
|
||||
elif commit_hash[0] == '0' and commit_hash[:SHORT_HASH_LENGTH].isnumeric():
|
||||
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")
|
||||
|
||||
@@ -94,6 +94,7 @@ def generate_script(repo, version, config):
|
||||
"echo 'This repo has nightly-testing infrastructure'",
|
||||
f"git merge origin/bump/{version.split('-rc')[0]}",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
"grep nightly-testing lakefile.* && echo 'Please ensure the lakefile does not include nightly-testing versions.'",
|
||||
""
|
||||
])
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 21)
|
||||
set(LEAN_VERSION_MINOR 22)
|
||||
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'")
|
||||
@@ -58,9 +58,6 @@ option(USE_GITHASH "GIT_HASH" ON)
|
||||
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
|
||||
# When ON we install a copy of cadical
|
||||
option(INSTALL_CADICAL "Install a copy of cadical" ON)
|
||||
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
|
||||
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
|
||||
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
|
||||
|
||||
# FLAGS for disabling optimizations and debugging
|
||||
option(FREE_VAR_RANGE_OPT "FREE_VAR_RANGE_OPT" ON)
|
||||
@@ -182,10 +179,6 @@ else()
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_MULTI_THREAD")
|
||||
endif()
|
||||
|
||||
if(AUTO_THREAD_FINALIZATION AND NOT MSVC)
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_AUTO_THREAD_FINALIZATION")
|
||||
endif()
|
||||
|
||||
# Set Module Path
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import Init.Ext
|
||||
import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.GrindInstances
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
import Init.Internal
|
||||
|
||||
@@ -45,7 +45,7 @@ theorem em (p : Prop) : p ∨ ¬p :=
|
||||
| Or.inr h, _ => Or.inr h
|
||||
| _, Or.inr h => Or.inr h
|
||||
| Or.inl hut, Or.inl hvf =>
|
||||
have hne : u ≠ v := by simp [hvf, hut, true_ne_false]
|
||||
have hne : u ≠ v := by simp [hvf, hut]
|
||||
Or.inl hne
|
||||
have p_implies_uv : p → u = v :=
|
||||
fun hp =>
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Prelude
|
||||
meta import Init.Prelude
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
/-!
|
||||
|
||||
@@ -50,7 +50,7 @@ attribute [simp] id_map
|
||||
(comp_map _ _ _).symm
|
||||
|
||||
theorem Functor.map_unit [Functor f] [LawfulFunctor f] {a : f PUnit} : (fun _ => PUnit.unit) <$> a = a := by
|
||||
simp [map]
|
||||
simp
|
||||
|
||||
/--
|
||||
An applicative functor satisfies the laws of an applicative functor.
|
||||
@@ -148,7 +148,7 @@ attribute [simp] pure_bind bind_assoc bind_pure_comp
|
||||
attribute [grind] pure_bind
|
||||
|
||||
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
|
||||
show x >>= (fun a => pure (id a)) = x
|
||||
change x >>= (fun a => pure (id a)) = x
|
||||
rw [bind_pure_comp, id_map]
|
||||
|
||||
/--
|
||||
|
||||
@@ -58,7 +58,7 @@ protected theorem bind_pure_comp [Monad m] (f : α → β) (x : ExceptT ε m α)
|
||||
intros; rfl
|
||||
|
||||
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
|
||||
show (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
|
||||
change (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
|
||||
rw [← ExceptT.bind_pure_comp]
|
||||
apply ext
|
||||
simp [run_bind]
|
||||
@@ -67,10 +67,10 @@ protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad
|
||||
| Except.error _ => simp
|
||||
| Except.ok _ =>
|
||||
simp [←bind_pure_comp]; apply bind_congr; intro b;
|
||||
cases b <;> simp [comp, Except.map, const]
|
||||
cases b <;> simp [Except.map, const]
|
||||
|
||||
protected theorem seqRight_eq [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x *> y = const α id <$> x <*> y := by
|
||||
show (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
|
||||
change (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
|
||||
rw [← ExceptT.bind_pure_comp]
|
||||
apply ext
|
||||
simp [run_bind]
|
||||
@@ -206,15 +206,15 @@ theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f :
|
||||
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||
show (f >>= fun g => g <$> x).run s = _
|
||||
change (f >>= fun g => g <$> x).run s = _
|
||||
simp
|
||||
|
||||
@[simp] theorem run_seqRight [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
|
||||
show (x >>= fun _ => y).run s = _
|
||||
change (x >>= fun _ => y).run s = _
|
||||
simp
|
||||
|
||||
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
|
||||
show (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||
change (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||
simp
|
||||
|
||||
theorem seqRight_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x *> y = const α id <$> x <*> y := by
|
||||
|
||||
@@ -9,7 +9,7 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Tactics
|
||||
import Init.Meta
|
||||
meta import Init.Meta
|
||||
|
||||
namespace Lean.Parser.Tactic.Conv
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ notation, basic datatypes and type classes
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Prelude
|
||||
meta import Init.Prelude
|
||||
import Init.SizeOf
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
@@ -2252,7 +2252,7 @@ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
|
||||
Quot.liftOn f
|
||||
(fun (f : ∀ (x : α), β x) => f x)
|
||||
(fun _ _ h => h x)
|
||||
show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
|
||||
change extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
|
||||
exact congrArg extfunApp (Quot.sound h)
|
||||
|
||||
/--
|
||||
|
||||
@@ -46,3 +46,4 @@ import Init.Data.NeZero
|
||||
import Init.Data.Function
|
||||
import Init.Data.RArray
|
||||
import Init.Data.Vector
|
||||
import Init.Data.Iterators
|
||||
|
||||
@@ -209,7 +209,7 @@ theorem Context.evalList_sort_congr
|
||||
induction c generalizing a b with
|
||||
| nil => simp [sort.loop, h₂]
|
||||
| cons c _ ih =>
|
||||
simp [sort.loop]; apply ih; simp [evalList_insert ctx h, evalList]
|
||||
simp [sort.loop]; apply ih; simp [evalList_insert ctx h]
|
||||
cases a with
|
||||
| nil => apply absurd h₃; simp
|
||||
| cons a as =>
|
||||
@@ -282,7 +282,7 @@ theorem Context.toList_nonEmpty (e : Expr) : e.toList ≠ [] := by
|
||||
simp [Expr.toList]
|
||||
cases h : l.toList with
|
||||
| nil => contradiction
|
||||
| cons => simp [List.append]
|
||||
| cons => simp
|
||||
|
||||
theorem Context.unwrap_isNeutral
|
||||
{ctx : Context α}
|
||||
@@ -328,13 +328,13 @@ theorem Context.eval_toList (ctx : Context α) (e : Expr) : evalList α ctx e.to
|
||||
induction e with
|
||||
| var x => rfl
|
||||
| op l r ih₁ ih₂ =>
|
||||
simp [evalList, Expr.toList, eval, ←ih₁, ←ih₂]
|
||||
simp [Expr.toList, eval, ←ih₁, ←ih₂]
|
||||
apply evalList_append <;> apply toList_nonEmpty
|
||||
|
||||
theorem Context.eval_norm (ctx : Context α) (e : Expr) : evalList α ctx (norm ctx e) = eval α ctx e := by
|
||||
simp [norm]
|
||||
cases h₁ : ContextInformation.isIdem ctx <;> cases h₂ : ContextInformation.isComm ctx <;>
|
||||
simp_all [evalList_removeNeutrals, eval_toList, toList_nonEmpty, evalList_mergeIdem, evalList_sort]
|
||||
simp_all [evalList_removeNeutrals, eval_toList, evalList_mergeIdem, evalList_sort]
|
||||
|
||||
theorem Context.eq_of_norm (ctx : Context α) (a b : Expr) (h : norm ctx a == norm ctx b) : eval α ctx a = eval α ctx b := by
|
||||
have h := congrArg (evalList α ctx) (eq_of_beq h)
|
||||
|
||||
@@ -68,15 +68,15 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toList_attachWith {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs, P x} :
|
||||
@[simp, grind =] theorem toList_attachWith {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs, P x} :
|
||||
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList_iff] using H) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem toList_attach {xs : Array α} :
|
||||
@[simp, grind =] theorem toList_attach {xs : Array α} :
|
||||
xs.attach.toList = xs.toList.attachWith (· ∈ xs) (by simp [mem_toList_iff]) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toList_pmap {xs : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ xs, P a} :
|
||||
@[simp, grind =] theorem toList_pmap {xs : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.pmap f H).toList = xs.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
|
||||
simp [pmap]
|
||||
|
||||
@@ -92,16 +92,16 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
intro a m h₁ h₂
|
||||
congr
|
||||
|
||||
@[simp] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
@[simp, grind =] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
|
||||
@[simp] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (xs : Array α) (h : ∀ b ∈ xs.push a, P b) :
|
||||
@[simp, grind =] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (xs : Array α) (h : ∀ b ∈ xs.push a, P b) :
|
||||
pmap f (xs.push a) h =
|
||||
(pmap f xs (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
@[simp, grind =] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
|
||||
@[simp] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #[], P x) : (#[] : Array α).attachWith P H = #[] := rfl
|
||||
@[simp, grind =] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #[], P x) : (#[] : Array α).attachWith P H = #[] := rfl
|
||||
|
||||
@[simp] theorem _root_.List.attachWith_mem_toArray {l : List α} :
|
||||
l.attachWith (fun x => x ∈ l.toArray) (fun x h => by simpa using h) =
|
||||
@@ -122,11 +122,13 @@ theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a,
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
@[grind =]
|
||||
theorem map_pmap {p : α → Prop} {g : β → γ} {f : ∀ a, p a → β} {xs : Array α} (H) :
|
||||
map g (pmap f xs H) = pmap (fun a h => g (f a h)) xs H := by
|
||||
cases xs
|
||||
simp [List.map_pmap]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_map {p : β → Prop} {g : ∀ b, p b → γ} {f : α → β} {xs : Array α} (H) :
|
||||
pmap g (map f xs) H = pmap (fun a h => g (f a) h) xs fun _ h => H _ (mem_map_of_mem h) := by
|
||||
cases xs
|
||||
@@ -142,18 +144,18 @@ theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α → Prop} {H :
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_push {a : α} {xs : Array α} :
|
||||
@[simp, grind =] theorem attach_push {a : α} {xs : Array α} :
|
||||
(xs.push a).attach =
|
||||
(xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_push_of_mem a h⟩)).push ⟨a, by simp⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr (List.push_toArray _ _)]
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs.push a, P x} :
|
||||
@[simp, grind =] theorem attachWith_push {a : α} {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs.push a, P x} :
|
||||
(xs.push a).attachWith P H =
|
||||
(xs.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push ⟨a, H a (by simp)⟩ := by
|
||||
cases xs
|
||||
simp [attachWith_congr (List.push_toArray _ _)]
|
||||
simp
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} {f : ∀ a, p a → β} {xs : Array α} (H) :
|
||||
pmap f xs H = xs.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
@@ -189,38 +191,39 @@ theorem attachWith_map_subtype_val {p : α → Prop} {xs : Array α} (H : ∀ a
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem mem_attachWith {xs : Array α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem size_attach {xs : Array α} : xs.attach.size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem size_attachWith {p : α → Prop} {xs : Array α} {H} : (xs.attachWith p H).size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@@ -252,13 +255,13 @@ theorem attachWith_ne_empty_iff {xs : Array α} {P : α → Prop} {H : ∀ a ∈
|
||||
xs.attachWith P H ≠ #[] ↔ xs ≠ #[] := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Array α} (h : ∀ a ∈ xs, p a) (i : Nat) :
|
||||
(pmap f xs h)[i]? = Option.pmap f xs[i]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases xs; simp
|
||||
|
||||
-- The argument `f` is explicit to allow rewriting from right to left.
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {xs : Array α} (h : ∀ a ∈ xs, p a) {i : Nat}
|
||||
(hi : i < (pmap f xs h).size) :
|
||||
(pmap f xs h)[i] =
|
||||
@@ -266,57 +269,59 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {xs : Array α} (
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f xs h ▸ hi))) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attach {xs : Array α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap _ _ h
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem pmap_attach {xs : Array α} {p : {x // x ∈ xs} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
@[simp, grind =] theorem pmap_attach {xs : Array α} {p : {x // x ∈ xs} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
pmap f xs.attach H =
|
||||
xs.pmap (P := fun a => ∃ h : a ∈ xs, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem pmap_attachWith {xs : Array α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
@[simp, grind =] theorem pmap_attachWith {xs : Array α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
pmap f (xs.attachWith q H₁) H₂ =
|
||||
xs.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem foldl_pmap {xs : Array α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (g : γ → β → γ) (x : γ) :
|
||||
(xs.pmap f H).foldl g x = xs.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind =]
|
||||
theorem foldr_pmap {xs : Array α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (g : β → γ → γ) (x : γ) :
|
||||
(xs.pmap f H).foldr g x = xs.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
@[simp] theorem foldl_attachWith
|
||||
@[simp, grind =] theorem foldl_attachWith
|
||||
{xs : Array α} {q : α → Prop} (H : ∀ a, a ∈ xs → q a) {f : β → { x // q x} → β} {b} (w : stop = xs.size) :
|
||||
(xs.attachWith q H).foldl f b 0 stop = xs.attach.foldl (fun b ⟨a, h⟩ => f b ⟨a, H _ h⟩) b := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_attachWith, List.foldl_map]
|
||||
|
||||
@[simp] theorem foldr_attachWith
|
||||
@[simp, grind =] theorem foldr_attachWith
|
||||
{xs : Array α} {q : α → Prop} (H : ∀ a, a ∈ xs → q a) {f : { x // q x} → β → β} {b} (w : start = xs.size) :
|
||||
(xs.attachWith q H).foldr f b start 0 = xs.attach.foldr (fun a acc => f ⟨a.1, H _ a.2⟩ acc) b := by
|
||||
subst w
|
||||
@@ -337,7 +342,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
|
||||
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -356,23 +361,25 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
|
||||
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
@[grind =]
|
||||
theorem attach_map {xs : Array α} {f : α → β} :
|
||||
(xs.map f).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem h⟩) := by
|
||||
cases xs
|
||||
ext <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem attachWith_map {xs : Array α} {f : α → β} {P : β → Prop} (H : ∀ (b : β), b ∈ xs.map f → P b) :
|
||||
(xs.map f).attachWith P H = (xs.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases xs
|
||||
simp [List.attachWith_map]
|
||||
|
||||
@[simp] theorem map_attachWith {xs : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ xs → P a}
|
||||
@[simp, grind =] theorem map_attachWith {xs : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ xs → P a}
|
||||
{f : { x // P x } → β} :
|
||||
(xs.attachWith P H).map f = xs.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
cases xs <;> simp_all
|
||||
@@ -393,6 +400,7 @@ theorem map_attach_eq_pmap {xs : Array α} {f : { x // x ∈ xs } → β} :
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
(xs.filterMap f).attach = xs.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
@@ -400,6 +408,7 @@ theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
rw [attach_congr List.filterMap_toArray]
|
||||
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filter {xs : Array α} (p : α → Bool) :
|
||||
(xs.filter p).attach = xs.attach.filterMap
|
||||
fun x => if w : p x.1 then some ⟨x.1, mem_filter.mpr ⟨x.2, w⟩⟩ else none := by
|
||||
@@ -409,7 +418,7 @@ theorem attach_filter {xs : Array α} (p : α → Bool) :
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem filterMap_attachWith {q : α → Prop} {xs : Array α} {f : {x // q x} → Option β} (H)
|
||||
(w : stop = (xs.attachWith q H).size) :
|
||||
(xs.attachWith q H).filterMap f 0 stop = xs.attach.filterMap (fun ⟨x, h⟩ => f ⟨x, H _ h⟩) := by
|
||||
@@ -417,7 +426,7 @@ theorem filterMap_attachWith {q : α → Prop} {xs : Array α} {f : {x // q x}
|
||||
cases xs
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem filter_attachWith {q : α → Prop} {xs : Array α} {p : {x // q x} → Bool} (H)
|
||||
(w : stop = (xs.attachWith q H).size) :
|
||||
(xs.attachWith q H).filter p 0 stop =
|
||||
@@ -426,6 +435,7 @@ theorem filter_attachWith {q : α → Prop} {xs : Array α} {p : {x // q x} →
|
||||
cases xs
|
||||
simp [Function.comp_def, List.filter_map]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f : ∀ b, q b → γ} {xs} (H₁ H₂) :
|
||||
pmap f (pmap g xs H₁) H₂ =
|
||||
pmap (α := { x // x ∈ xs }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) xs.attach
|
||||
@@ -433,7 +443,7 @@ theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f
|
||||
cases xs
|
||||
simp [List.pmap_pmap, List.pmap_map]
|
||||
|
||||
@[simp] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {xs ys : Array ι}
|
||||
@[simp, grind =] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {xs ys : Array ι}
|
||||
(h : ∀ a ∈ xs ++ ys, p a) :
|
||||
(xs ++ ys).pmap f h =
|
||||
(xs.pmap f fun a ha => h a (mem_append_left ys ha)) ++
|
||||
@@ -448,7 +458,7 @@ theorem pmap_append' {p : α → Prop} {f : ∀ a : α, p a → β} {xs ys : Arr
|
||||
xs.pmap f h₁ ++ ys.pmap f h₂ :=
|
||||
pmap_append _
|
||||
|
||||
@[simp] theorem attach_append {xs ys : Array α} :
|
||||
@[simp, grind =] theorem attach_append {xs ys : Array α} :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
cases xs
|
||||
@@ -456,59 +466,62 @@ theorem pmap_append' {p : α → Prop} {f : ∀ a : α, p a → β} {xs ys : Arr
|
||||
rw [attach_congr (List.append_toArray _ _)]
|
||||
simp [List.attach_append, Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : Array α}
|
||||
@[simp, grind =] theorem attachWith_append {P : α → Prop} {xs ys : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp [attachWith, attach_append, map_pmap, pmap_append]
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
@[simp, grind =] theorem pmap_reverse {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
induction xs <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : Array α}
|
||||
@[simp, grind =] theorem attachWith_reverse {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_reverse {xs : Array α} :
|
||||
@[simp, grind =] theorem attach_reverse {xs : Array α} :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr List.reverse_toArray]
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attach {xs : Array α} :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
@[simp, grind =] theorem back?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).back? = xs.attach.back?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
@[simp, grind =] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back? h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem back?_attach {xs : Array α} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back? h⟩ := by
|
||||
cases xs
|
||||
@@ -526,7 +539,7 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Array α} {H
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem count_attach [BEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
xs.attach.count a = xs.count ↑a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -535,13 +548,13 @@ theorem count_attach [BEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
simp only [Subtype.beq_iff]
|
||||
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem count_attachWith [BEq α] {p : α → Prop} {xs : Array α} (H : ∀ a ∈ xs, p a) {a : {x // p x}} :
|
||||
(xs.attachWith p H).count a = xs.count ↑a := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {xs : Array α} (H₁) :
|
||||
@[simp, grind =] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {xs : Array α} (H₁) :
|
||||
(xs.pmap g H₁).countP f =
|
||||
xs.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
|
||||
@@ -690,7 +703,7 @@ and simplifies these to the function directly taking the value.
|
||||
{f : { x // p x } → Array β} {g : α → Array β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(xs.flatMap f) = xs.unattach.flatMap g := by
|
||||
cases xs
|
||||
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
mk.injEq]
|
||||
rw [List.flatMap_subtype]
|
||||
simp [hf]
|
||||
|
||||
@@ -246,7 +246,7 @@ def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic)
|
||||
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
|
||||
show ((xs.set i xs[j]).set j xs[i]
|
||||
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]
|
||||
|
||||
@@ -1788,7 +1788,7 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
induction xs, i, h using Array.eraseIdx.induct with
|
||||
| @case1 xs i h h' xs' ih =>
|
||||
unfold eraseIdx
|
||||
simp +zetaDelta [h', xs', ih]
|
||||
simp +zetaDelta [h', ih]
|
||||
| case2 xs i h h' =>
|
||||
unfold eraseIdx
|
||||
simp [h']
|
||||
|
||||
@@ -119,13 +119,13 @@ abbrev pop_toList := @Array.toList_pop
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp, grind =] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
apply ext'; simp only [toList_append, List.append_nil]
|
||||
|
||||
@[deprecated append_empty (since := "2025-01-13")]
|
||||
abbrev append_nil := @append_empty
|
||||
|
||||
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
apply ext'; simp only [toList_append, List.nil_append]
|
||||
|
||||
@[deprecated empty_append (since := "2025-01-13")]
|
||||
abbrev nil_append := @empty_append
|
||||
|
||||
@@ -52,6 +52,7 @@ theorem countP_push {a : α} {xs : Array α} : countP p (xs.push a) = countP p x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem countP_singleton {a : α} : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp
|
||||
|
||||
@@ -59,10 +60,12 @@ theorem size_eq_countP_add_countP {xs : Array α} : xs.size = countP p xs + coun
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.length_eq_countP_add_countP (p := p)]
|
||||
|
||||
@[grind _=_]
|
||||
theorem countP_eq_size_filter {xs : Array α} : countP p xs = (filter p xs).size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_eq_length_filter]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_eq_size_filter' : countP p = size ∘ filter p := by
|
||||
funext xs
|
||||
apply countP_eq_size_filter
|
||||
@@ -71,7 +74,7 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
|
||||
simp only [countP_eq_size_filter]
|
||||
apply size_filter_le
|
||||
|
||||
@[simp] theorem countP_append {xs ys : Array α} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
@[simp, grind =] theorem countP_append {xs ys : Array α} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp
|
||||
@@ -102,6 +105,7 @@ theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.boole_getElem_le_countP]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_set {xs : Array α} {i : Nat} {a : α} (h : i < xs.size) :
|
||||
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -146,7 +150,7 @@ theorem countP_flatMap {p : β → Bool} {xs : Array α} {f : α → Array β} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_flatMap, Function.comp_def]
|
||||
|
||||
@[simp] theorem countP_reverse {xs : Array α} : countP p xs.reverse = countP p xs := by
|
||||
@[simp, grind =] theorem countP_reverse {xs : Array α} : countP p xs.reverse = countP p xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_reverse]
|
||||
|
||||
@@ -173,7 +177,7 @@ variable [BEq α]
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem count_empty {a : α} : count a #[] = 0 := rfl
|
||||
@[simp, grind =] theorem count_empty {a : α} : count a #[] = 0 := rfl
|
||||
|
||||
theorem count_push {a b : α} {xs : Array α} :
|
||||
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
|
||||
@@ -186,21 +190,28 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
|
||||
theorem count_le_size {a : α} {xs : Array α} : count a xs ≤ xs.size := countP_le_size
|
||||
|
||||
grind_pattern count_le_size => count a xs
|
||||
|
||||
@[grind =]
|
||||
theorem count_eq_size_filter {a : α} {xs : Array α} : count a xs = (filter (· == a) xs).size := by
|
||||
simp [count, countP_eq_size_filter]
|
||||
|
||||
theorem count_le_count_push {a b : α} {xs : Array α} : count a xs ≤ count a (xs.push b) := by
|
||||
simp [count_push]
|
||||
|
||||
@[grind =]
|
||||
theorem count_singleton {a b : α} : count a #[b] = if b == a then 1 else 0 := by
|
||||
simp [count_eq_countP]
|
||||
|
||||
@[simp] theorem count_append {a : α} {xs ys : Array α} : count a (xs ++ ys) = count a xs + count a ys :=
|
||||
@[simp, grind =] theorem count_append {a : α} {xs ys : Array α} : count a (xs ++ ys) = count a xs + count a ys :=
|
||||
countP_append
|
||||
|
||||
@[simp] theorem count_flatten {a : α} {xss : Array (Array α)} :
|
||||
@[simp, grind =] theorem count_flatten {a : α} {xss : Array (Array α)} :
|
||||
count a xss.flatten = (xss.map (count a)).sum := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.count_flatten, Function.comp_def]
|
||||
|
||||
@[simp] theorem count_reverse {a : α} {xs : Array α} : count a xs.reverse = count a xs := by
|
||||
@[simp, grind =] theorem count_reverse {a : α} {xs : Array α} : count a xs.reverse = count a xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@@ -209,9 +220,10 @@ theorem boole_getElem_le_count {xs : Array α} {i : Nat} {a : α} (h : i < xs.si
|
||||
rw [count_eq_countP]
|
||||
apply boole_getElem_le_countP (p := (· == a))
|
||||
|
||||
@[grind =]
|
||||
theorem count_set {xs : Array α} {i : Nat} {a b : α} (h : i < xs.size) :
|
||||
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
simp [count_eq_countP, countP_set, h]
|
||||
simp [count_eq_countP, countP_set]
|
||||
|
||||
variable [LawfulBEq α]
|
||||
|
||||
@@ -219,7 +231,7 @@ variable [LawfulBEq α]
|
||||
simp [count_push]
|
||||
|
||||
@[simp] theorem count_push_of_ne {xs : Array α} (h : b ≠ a) : count a (xs.push b) = count a xs := by
|
||||
simp_all [count_push, h]
|
||||
simp_all [count_push]
|
||||
|
||||
theorem count_singleton_self {a : α} : count a #[a] = 1 := by simp
|
||||
|
||||
@@ -280,17 +292,17 @@ abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
|
||||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Array α} {f : α → β} {x : α} :
|
||||
count x xs ≤ count (f x) (map f xs) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_le_count_map, countP_map]
|
||||
simp [List.count_le_count_map]
|
||||
|
||||
theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {xs : Array α} :
|
||||
count b (filterMap f xs) = countP (fun a => f a == some b) xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_filterMap, countP_filterMap]
|
||||
simp [List.count_filterMap]
|
||||
|
||||
theorem count_flatMap {α} [BEq β] {xs : Array α} {f : α → Array β} {x : β} :
|
||||
count x (xs.flatMap f) = sum (map (count x ∘ f) xs) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
|
||||
simp [List.count_flatMap, Function.comp_def]
|
||||
|
||||
theorem countP_replace {a b : α} {xs : Array α} {p : α → Bool} :
|
||||
(xs.replace a b).countP p =
|
||||
|
||||
@@ -23,7 +23,7 @@ private theorem rel_of_isEqvAux
|
||||
induction i with
|
||||
| zero => contradiction
|
||||
| succ i ih =>
|
||||
simp only [Array.isEqvAux, Bool.and_eq_true, decide_eq_true_eq] at heqv
|
||||
simp only [Array.isEqvAux, Bool.and_eq_true] at heqv
|
||||
by_cases hj' : j < i
|
||||
next =>
|
||||
exact ih _ heqv.right hj'
|
||||
|
||||
@@ -24,6 +24,7 @@ open Nat
|
||||
|
||||
/-! ### eraseP -/
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_empty : #[].eraseP p = #[] := by simp
|
||||
|
||||
theorem eraseP_of_forall_mem_not {xs : Array α} (h : ∀ a, a ∈ xs → ¬p a) : xs.eraseP p = xs := by
|
||||
@@ -64,6 +65,7 @@ theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
|
||||
let ⟨_, ys, zs, _, _, e₁, e₂⟩ := exists_of_eraseP al pa
|
||||
rw [e₂]; simp [size_append, e₁]
|
||||
|
||||
@[grind =]
|
||||
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
|
||||
split <;> rename_i h
|
||||
· simp only [any_eq_true] at h
|
||||
@@ -81,11 +83,12 @@ theorem le_size_eraseP {xs : Array α} : xs.size - 1 ≤ (xs.eraseP p).size := b
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.le_length_eraseP
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseP
|
||||
|
||||
@[simp] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_eraseP_of_neg pa
|
||||
|
||||
@@ -93,15 +96,18 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem eraseP_map {f : β → α} {xs : Array β} : (xs.map f).eraseP p = (xs.eraseP (p ∘ f)).map f := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.eraseP_map
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filterMap {f : α → Option β} {xs : Array α} :
|
||||
(filterMap f xs).eraseP p = filterMap f (xs.eraseP (fun x => match f x with | some y => p y | none => false)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.eraseP_filterMap
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filter {f : α → Bool} {xs : Array α} :
|
||||
(filter f xs).eraseP p = filter f (xs.eraseP (fun x => p x && f x)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -119,6 +125,7 @@ theorem eraseP_append_right {xs : Array α} ys (h : ∀ b ∈ xs, ¬p b) :
|
||||
rcases ys with ⟨ys⟩
|
||||
simpa using List.eraseP_append_right ys (by simpa using h)
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_append {xs : Array α} {ys : Array α} :
|
||||
(xs ++ ys).eraseP p = if xs.any p then xs.eraseP p ++ ys else xs ++ ys.eraseP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -126,6 +133,7 @@ theorem eraseP_append {xs : Array α} {ys : Array α} :
|
||||
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append, List.any_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).eraseP p = if p a then replicate (n - 1) a else replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
|
||||
@@ -165,6 +173,7 @@ theorem eraseP_eq_iff {p} {xs : Array α} :
|
||||
· exact Or.inl h
|
||||
· exact Or.inr ⟨a, l₁, by simpa using h₁, h₂, ⟨l, by simp⟩⟩
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {xs : Array α} (h : ∀ a ∈ xs, ¬ p a ∨ ¬ q a) :
|
||||
(xs.eraseP p).eraseP q = (xs.eraseP q).eraseP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -197,7 +206,7 @@ theorem erase_eq_eraseP [LawfulBEq α] (a : α) (xs : Array α) : xs.erase a = x
|
||||
theorem erase_ne_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.erase a ≠ #[] ↔ xs ≠ #[] ∧ xs ≠ #[a] := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.erase_ne_nil_iff]
|
||||
simp
|
||||
|
||||
theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a ∈ xs) :
|
||||
∃ ys zs, a ∉ ys ∧ xs = ys.push a ++ zs ∧ xs.erase a = ys ++ zs := by
|
||||
@@ -208,6 +217,7 @@ theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a ∈ xs) :
|
||||
(xs.erase a).size = xs.size - 1 := by
|
||||
rw [erase_eq_eraseP]; exact size_eraseP_of_mem h (beq_self_eq_true a)
|
||||
|
||||
@[grind =]
|
||||
theorem size_erase [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
(xs.erase a).size = if a ∈ xs then xs.size - 1 else xs.size := by
|
||||
rw [erase_eq_eraseP, size_eraseP]
|
||||
@@ -222,11 +232,12 @@ theorem le_size_erase [LawfulBEq α] {a : α} {xs : Array α} : xs.size - 1 ≤
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.le_length_erase
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_erase (by simpa using h)
|
||||
|
||||
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
a ∈ xs.erase b ↔ a ∈ xs :=
|
||||
erase_eq_eraseP b xs ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -234,6 +245,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
|
||||
rw [erase_eq_eraseP', eraseP_eq_self_iff]
|
||||
simp [forall_mem_ne']
|
||||
|
||||
@[grind _=_]
|
||||
theorem erase_filter [LawfulBEq α] {f : α → Bool} {xs : Array α} :
|
||||
(filter f xs).erase a = filter f (xs.erase a) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -251,6 +263,7 @@ theorem erase_append_right [LawfulBEq α] {a : α} {xs : Array α} (ys : Array
|
||||
rcases ys with ⟨ys⟩
|
||||
simpa using List.erase_append_right ys (by simpa using h)
|
||||
|
||||
@[grind =]
|
||||
theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
(xs ++ ys).erase a = if a ∈ xs then xs.erase a ++ ys else xs ++ ys.erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -258,6 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
(replicate n a).erase b = if b == a then replicate (n - 1) a else replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
@@ -269,6 +283,7 @@ abbrev erase_mkArray := @erase_replicate
|
||||
|
||||
-- The arguments `a b` are explicit,
|
||||
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
|
||||
@[grind =]
|
||||
theorem erase_comm [LawfulBEq α] (a b : α) {xs : Array α} :
|
||||
(xs.erase a).erase b = (xs.erase b).erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -291,7 +306,7 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
@[simp] theorem erase_replicate_self [LawfulBEq α] {a : α} :
|
||||
(replicate n a).erase a = replicate (n - 1) a := by
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
simp [List.erase_replicate]
|
||||
simp
|
||||
|
||||
@[deprecated erase_replicate_self (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_self := @erase_replicate_self
|
||||
@@ -312,6 +327,7 @@ theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.siz
|
||||
xs.eraseIdx i h = xs.eraseIdxIfInBounds i := by
|
||||
simp [eraseIdxIfInBounds, h]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_eq_take_drop_succ {xs : Array α} {i : Nat} (h) :
|
||||
xs.eraseIdx i h = xs.take i ++ xs.drop (i + 1) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -322,6 +338,7 @@ theorem eraseIdx_eq_take_drop_succ {xs : Array α} {i : Nat} (h) :
|
||||
rw [List.take_of_length_le]
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_eraseIdx {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} :
|
||||
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -335,10 +352,11 @@ theorem getElem?_eraseIdx_of_lt {xs : Array α} {i : Nat} (h : i < xs.size) {j :
|
||||
theorem getElem?_eraseIdx_of_ge {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} (h' : i ≤ j) :
|
||||
(xs.eraseIdx i)[j]? = xs[j + 1]? := by
|
||||
rw [getElem?_eraseIdx]
|
||||
simp only [dite_eq_ite, ite_eq_right_iff]
|
||||
simp only [ite_eq_right_iff]
|
||||
intro h'
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_eraseIdx {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} (h' : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i)[j] = if h'' : j < i then
|
||||
xs[j]
|
||||
@@ -362,6 +380,7 @@ theorem eraseIdx_ne_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i ≠
|
||||
simp [h]
|
||||
· simp
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseIdx {xs : Array α} {i : Nat} {h} {a : α} (h : a ∈ xs.eraseIdx i) : a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseIdx (by simpa using h)
|
||||
@@ -373,13 +392,29 @@ theorem eraseIdx_append_of_lt_size {xs : Array α} {k : Nat} (hk : k < xs.size)
|
||||
simp at hk
|
||||
simp [List.eraseIdx_append_of_lt_length, *]
|
||||
|
||||
theorem eraseIdx_append_of_length_le {xs : Array α} {k : Nat} (hk : xs.size ≤ k) (ys : Array α) (h) :
|
||||
theorem eraseIdx_append_of_size_le {xs : Array α} {k : Nat} (hk : xs.size ≤ k) (ys : Array α) (h) :
|
||||
eraseIdx (xs ++ ys) k = xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
|
||||
rcases xs with ⟨l⟩
|
||||
rcases ys with ⟨l'⟩
|
||||
simp at hk
|
||||
simp [List.eraseIdx_append_of_length_le, *]
|
||||
|
||||
@[deprecated eraseIdx_append_of_size_le (since := "2025-06-11")]
|
||||
abbrev eraseIdx_append_of_length_le := @eraseIdx_append_of_size_le
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_append {xs ys : Array α} (h : k < (xs ++ ys).size) :
|
||||
eraseIdx (xs ++ ys) k =
|
||||
if h' : k < xs.size then
|
||||
eraseIdx xs k ++ ys
|
||||
else
|
||||
xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
|
||||
split <;> rename_i h
|
||||
· simp [eraseIdx_append_of_lt_size h]
|
||||
· rw [eraseIdx_append_of_size_le]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
(replicate n a).eraseIdx k = replicate (n - 1) a := by
|
||||
simp at h
|
||||
@@ -428,6 +463,48 @@ theorem eraseIdx_set_gt {xs : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.eraseIdx_set_gt, *]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_set {xs : Array α} {i : Nat} {a : α} {hi : i < xs.size} {j : Nat} {hj : j < (xs.set i a).size} :
|
||||
(xs.set i a).eraseIdx j =
|
||||
if h' : j < i then
|
||||
(xs.eraseIdx j).set (i - 1) a (by simp; omega)
|
||||
else if h'' : j = i then
|
||||
xs.eraseIdx i
|
||||
else
|
||||
(xs.eraseIdx j (by simp at hj; omega)).set i a (by simp at hj ⊢; omega) := by
|
||||
split <;> rename_i h'
|
||||
· rw [eraseIdx_set_lt]
|
||||
omega
|
||||
· split <;> rename_i h''
|
||||
· subst h''
|
||||
rw [eraseIdx_set_eq]
|
||||
· rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
theorem set_eraseIdx_le {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : i ≤ j) (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a = (xs.set (j + 1) a (by simp at hj; omega)).eraseIdx i (by simp at ⊢; omega) := by
|
||||
rw [eraseIdx_set_lt]
|
||||
· simp
|
||||
· omega
|
||||
|
||||
theorem set_eraseIdx_gt {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : j < i) (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a = (xs.set j a).eraseIdx i (by simp at ⊢; omega) := by
|
||||
rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_eraseIdx {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a =
|
||||
if h' : i ≤ j then
|
||||
(xs.set (j + 1) a (by simp at hj; omega)).eraseIdx i (by simp at ⊢; omega)
|
||||
else
|
||||
(xs.set j a).eraseIdx i (by simp at ⊢; omega) := by
|
||||
split <;> rename_i h'
|
||||
· rw [set_eraseIdx_le]
|
||||
omega
|
||||
· rw [set_eraseIdx_gt]
|
||||
omega
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{xs : Array α} {i : Nat} (h : i + 1 < xs.size) :
|
||||
(xs.eraseIdx (i + 1)).set i xs[i + 1] (by simp; omega) = xs.eraseIdx i := by
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Array
|
||||
· simp
|
||||
omega
|
||||
· simp only [size_extract] at h₁ h₂
|
||||
simp [h]
|
||||
simp
|
||||
|
||||
theorem size_extract_le {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).size ≤ j - i := by
|
||||
@@ -46,7 +46,7 @@ theorem size_extract_of_le {as : Array α} {i j : Nat} (h : j ≤ as.size) :
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop ≤ as.size) :
|
||||
(as.push b).extract start stop = as.extract start stop := by
|
||||
ext i h₁ h₂
|
||||
@@ -56,7 +56,7 @@ theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop ≤ a
|
||||
simp only [getElem_extract, getElem_push]
|
||||
rw [dif_pos (by omega)]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
|
||||
as.extract 0 stop = as.pop := by
|
||||
ext i h₁ h₂
|
||||
@@ -65,7 +65,7 @@ theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
|
||||
· simp only [size_extract, size_pop] at h₁ h₂
|
||||
simp [getElem_extract, getElem_pop]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind _=_]
|
||||
theorem extract_append_extract {as : Array α} {i j k : Nat} :
|
||||
as.extract i j ++ as.extract j k = as.extract (min i j) (max j k) := by
|
||||
ext l h₁ h₂
|
||||
@@ -162,14 +162,14 @@ theorem extract_sub_one {as : Array α} {i j : Nat} (h : j < as.size) :
|
||||
@[simp]
|
||||
theorem getElem?_extract_of_lt {as : Array α} {i j k : Nat} (h : k < min j as.size - i) :
|
||||
(as.extract i j)[k]? = some (as[i + k]'(by omega)) := by
|
||||
simp [getElem?_extract, h]
|
||||
simp [h]
|
||||
|
||||
theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
|
||||
(as.extract 0 (j + 1))[j]? = as[j]? := by
|
||||
simp [getElem?_extract]
|
||||
omega
|
||||
|
||||
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
|
||||
@[simp, grind =] 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
|
||||
@@ -185,6 +185,7 @@ theorem ne_empty_of_extract_ne_empty {as : Array α} {i j : Nat} (h : as.extract
|
||||
as ≠ #[] :=
|
||||
mt extract_eq_empty_of_eq_empty h
|
||||
|
||||
@[grind =]
|
||||
theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
|
||||
(as.set k a).extract i j =
|
||||
if _ : k < i then
|
||||
@@ -211,13 +212,14 @@ theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
|
||||
simp [getElem_set]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_extract {as : Array α} {i j k : Nat} (h : k < (as.extract i j).size) {a : α} :
|
||||
(as.extract i j).set k a = (as.set (i + k) a (by simp at h; omega)).extract i j := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
· simp_all [getElem_set]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_append {as bs : Array α} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext l h₁ h₂
|
||||
@@ -242,14 +244,14 @@ theorem extract_append_right {as bs : Array α} :
|
||||
(as ++ bs).extract as.size (as.size + i) = bs.extract 0 i := by
|
||||
simp
|
||||
|
||||
@[simp] theorem map_extract {as : Array α} {i j : Nat} :
|
||||
@[simp, grind =] theorem map_extract {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).map f = (as.map f).extract i j := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
· simp only [size_map, size_extract] at h₁ h₂
|
||||
simp only [getElem_map, getElem_extract]
|
||||
|
||||
@[simp] theorem extract_replicate {a : α} {n i j : Nat} :
|
||||
@[simp, grind =] theorem extract_replicate {a : α} {n i j : Nat} :
|
||||
(replicate n a).extract i j = replicate (min j n - i) a := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
@@ -297,6 +299,7 @@ theorem set_eq_push_extract_append_extract {as : Array α} {i : Nat} (h : i < as
|
||||
simp at h
|
||||
simp [List.set_eq_take_append_cons_drop, h, List.take_of_length_le]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_reverse {as : Array α} {i j : Nat} :
|
||||
as.reverse.extract i j = (as.extract (as.size - j) (as.size - i)).reverse := by
|
||||
ext l h₁ h₂
|
||||
@@ -307,6 +310,7 @@ theorem extract_reverse {as : Array α} {i j : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_extract {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).reverse = as.reverse.extract (as.size - j) (as.size - i) := by
|
||||
rw [extract_reverse]
|
||||
|
||||
@@ -23,10 +23,10 @@ Examples:
|
||||
-/
|
||||
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp] theorem size_finRange {n} : (Array.finRange n).size = n := by
|
||||
@[simp, grind =] theorem size_finRange {n} : (Array.finRange n).size = n := by
|
||||
simp [Array.finRange]
|
||||
|
||||
@[simp] theorem getElem_finRange {i : Nat} (h : i < (Array.finRange n).size) :
|
||||
@[simp, grind =] theorem getElem_finRange {i : Nat} (h : i < (Array.finRange n).size) :
|
||||
(Array.finRange n)[i] = Fin.cast size_finRange ⟨i, h⟩ := by
|
||||
simp [Array.finRange]
|
||||
|
||||
@@ -49,6 +49,7 @@ theorem finRange_succ_last {n} :
|
||||
· simp_all
|
||||
omega
|
||||
|
||||
@[grind _=_]
|
||||
theorem finRange_reverse {n} : (Array.finRange n).reverse = (Array.finRange n).map Fin.rev := by
|
||||
ext i h
|
||||
· simp
|
||||
|
||||
@@ -38,11 +38,22 @@ theorem findSome?_singleton {a : α} {f : α → Option β} : #[a].findSome? f =
|
||||
@[simp] theorem findSomeRev?_push_of_isNone {xs : Array α} (h : (f a).isNone) : (xs.push a).findSomeRev? f = xs.findSomeRev? f := by
|
||||
cases xs; simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem findSomeRev?_push {xs : Array α} {a : α} {f : α → Option β} :
|
||||
(xs.push a).findSomeRev? f = (f a).or (xs.findSomeRev? f) := by
|
||||
match h : f a with
|
||||
| some b =>
|
||||
rw [findSomeRev?_push_of_isSome]
|
||||
all_goals simp_all
|
||||
| none =>
|
||||
rw [findSomeRev?_push_of_isNone]
|
||||
all_goals simp_all
|
||||
|
||||
theorem exists_of_findSome?_eq_some {f : α → Option β} {xs : Array α} (w : xs.findSome? f = some b) :
|
||||
∃ a, a ∈ xs ∧ f a = some b := by
|
||||
cases xs; simp_all [List.exists_of_findSome?_eq_some]
|
||||
|
||||
@[simp] theorem findSome?_eq_none_iff : findSome? p xs = none ↔ ∀ x ∈ xs, p x = none := by
|
||||
@[simp, grind =] theorem findSome?_eq_none_iff : findSome? p xs = none ↔ ∀ x ∈ xs, p x = none := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem findSome?_isSome_iff {f : α → Option β} {xs : Array α} :
|
||||
@@ -59,36 +70,39 @@ theorem findSome?_eq_some_iff {f : α → Option β} {xs : Array α} {b : β} :
|
||||
· rintro ⟨xs, a, ys, h₀, h₁, h₂⟩
|
||||
exact ⟨xs.toList, a, ys.toList, by simpa using congrArg toList h₀, h₁, by simpa⟩
|
||||
|
||||
@[simp] theorem findSome?_guard {xs : Array α} : findSome? (Option.guard fun x => p x) xs = find? p xs := by
|
||||
@[simp, grind =] theorem findSome?_guard {xs : Array α} : findSome? (Option.guard p) xs = find? p xs := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_eq_findSome?_guard {xs : Array α} : find? p xs = findSome? (Option.guard fun x => p x) xs :=
|
||||
theorem find?_eq_findSome?_guard {xs : Array α} : find? p xs = findSome? (Option.guard p) xs :=
|
||||
findSome?_guard.symm
|
||||
|
||||
@[simp] theorem getElem?_zero_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f)[0]? = xs.findSome? f := by
|
||||
@[simp, grind =] theorem getElem?_zero_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f)[0]? = xs.findSome? f := by
|
||||
cases xs; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filterMap {f : α → Option β} {xs : Array α} (h) :
|
||||
@[simp, grind =] theorem getElem_zero_filterMap {f : α → Option β} {xs : Array α} (h) :
|
||||
(xs.filterMap f)[0] = (xs.findSome? f).get (by cases xs; simpa [List.length_filterMap_eq_countP] using h) := by
|
||||
cases xs; simp [← List.head_eq_getElem, ← getElem?_zero_filterMap]
|
||||
cases xs; simp [← getElem?_zero_filterMap]
|
||||
|
||||
@[simp] theorem back?_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f).back? = xs.findSomeRev? f := by
|
||||
@[simp, grind =] theorem back?_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f).back? = xs.findSomeRev? f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem back!_filterMap [Inhabited β] {f : α → Option β} {xs : Array α} :
|
||||
@[simp, grind =] theorem back!_filterMap [Inhabited β] {f : α → Option β} {xs : Array α} :
|
||||
(xs.filterMap f).back! = (xs.findSomeRev? f).getD default := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
@[simp, grind _=_] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
(xs.findSome? f).map g = xs.findSome? (Option.map g ∘ f) := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem findSome?_map {f : β → γ} {xs : Array β} : findSome? p (xs.map f) = xs.findSome? (p ∘ f) := by
|
||||
cases xs; simp [List.findSome?_map]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_append {xs ys : Array α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
|
||||
cases xs; cases ys; simp [List.findSome?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_zero_flatten (xss : Array (Array α)) :
|
||||
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
|
||||
cases xss using array₂_induction
|
||||
@@ -104,12 +118,14 @@ theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
exact ⟨xs, m, by simpa using h⟩
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
|
||||
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
|
||||
have t := getElem?_zero_flatten xss
|
||||
simp [getElem?_eq_getElem, h] at t
|
||||
simp at t
|
||||
simp [← t]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [← List.toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@@ -140,8 +156,9 @@ abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp] theorem find?_empty : find? p #[] = none := rfl
|
||||
@[simp, grind =] theorem find?_empty : find? p #[] = none := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].find? p = if p a then some a else none := by
|
||||
simp
|
||||
@@ -150,11 +167,26 @@ theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
findRev? p (xs.push a) = some a := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[simp] theorem findRev?_cons_of_neg {xs : Array α} (h : ¬p a) :
|
||||
@[simp] theorem findRev?_push_of_neg {xs : Array α} (h : ¬p a) :
|
||||
findRev? p (xs.push a) = findRev? p xs := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[simp] theorem find?_eq_none : find? p xs = none ↔ ∀ x ∈ xs, ¬ p x := by
|
||||
@[deprecated findRev?_push_of_neg (since := "2025-06-12")]
|
||||
abbrev findRev?_cons_of_neg := @findRev?_push_of_neg
|
||||
|
||||
@[grind =]
|
||||
theorem finRev?_push {xs : Array α} :
|
||||
findRev? p (xs.push a) = (Option.guard p a).or (xs.findRev? p) := by
|
||||
cases h : p a
|
||||
· rw [findRev?_push_of_neg, Option.guard_eq_none_iff.mpr h]
|
||||
all_goals simp [h]
|
||||
· rw [findRev?_push_of_pos, Option.guard_eq_some_iff.mpr ⟨rfl, h⟩]
|
||||
all_goals simp [h]
|
||||
|
||||
@[deprecated finRev?_push (since := "2025-06-12")]
|
||||
abbrev findRev?_cons := @finRev?_push
|
||||
|
||||
@[simp, grind =] theorem find?_eq_none : find? p xs = none ↔ ∀ x ∈ xs, ¬ p x := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_eq_some_iff_append {xs : Array α} :
|
||||
@@ -178,60 +210,63 @@ theorem find?_push_eq_some {xs : Array α} :
|
||||
(xs.push a).find? p = some b ↔ xs.find? p = some b ∨ (xs.find? p = none ∧ (p a ∧ a = b)) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
@[simp, grind =] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind →]
|
||||
theorem find?_some {xs : Array α} (h : find? p xs = some a) : p a := by
|
||||
cases xs
|
||||
simp at h
|
||||
exact List.find?_some h
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ xs := by
|
||||
cases xs
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
@[simp] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem getElem?_zero_filter {p : α → Bool} {xs : Array α} :
|
||||
@[simp, grind =] theorem getElem?_zero_filter {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p)[0]? = xs.find? p := by
|
||||
cases xs; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filter {p : α → Bool} {xs : Array α} (h) :
|
||||
@[simp, grind =] theorem getElem_zero_filter {p : α → Bool} {xs : Array α} (h) :
|
||||
(xs.filter p)[0] =
|
||||
(xs.find? p).get (by cases xs; simpa [← List.countP_eq_length_filter] using h) := by
|
||||
cases xs
|
||||
simp [List.getElem_zero_eq_head]
|
||||
|
||||
@[simp] theorem back?_filter {p : α → Bool} {xs : Array α} : (xs.filter p).back? = xs.findRev? p := by
|
||||
@[simp, grind =] theorem back?_filter {p : α → Bool} {xs : Array α} : (xs.filter p).back? = xs.findRev? p := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem back!_filter [Inhabited α] {p : α → Bool} {xs : Array α} :
|
||||
@[simp, grind =] theorem back!_filter [Inhabited α] {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p).back! = (xs.findRev? p).get! := by
|
||||
cases xs; simp [Option.get!_eq_getD]
|
||||
|
||||
@[simp] theorem find?_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
@[simp, grind =] theorem find?_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_map {f : β → α} {xs : Array β} :
|
||||
@[simp, grind =] theorem find?_map {f : β → α} {xs : Array β} :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_append {xs ys : Array α} :
|
||||
@[simp, grind =] theorem find?_append {xs ys : Array α} :
|
||||
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (·.find? p) := by
|
||||
@[simp, grind _=_] theorem find?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (find? p) := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.findSome?_map, Function.comp_def]
|
||||
|
||||
@@ -270,10 +305,10 @@ theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α → Bool} {a
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp] theorem find?_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[simp, grind =] theorem find?_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
simp [List.find?_flatMap, Array.flatMap_toArray]
|
||||
simp [List.find?_flatMap]
|
||||
|
||||
theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
@@ -282,6 +317,7 @@ theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β
|
||||
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
|
||||
|
||||
@[grind =]
|
||||
theorem find?_replicate :
|
||||
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [← List.toArray_replicate, List.find?_replicate]
|
||||
@@ -312,7 +348,7 @@ abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [← List.toArray_replicate, List.find?_replicate_eq_none_iff, Classical.or_iff_not_imp_left]
|
||||
simp [← List.toArray_replicate, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
|
||||
@@ -334,6 +370,7 @@ abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkArray := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
(xs.pmap f H).find? p = (xs.attach.find? (fun ⟨a, m⟩ => p (f a (H a m)))).map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
@@ -347,12 +384,15 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
@@ -361,6 +401,8 @@ theorem findIdx_getElem {xs : Array α} {w : xs.findIdx p < xs.size} :
|
||||
p xs[xs.findIdx p] :=
|
||||
xs.findIdx_of_getElem?_eq_some (getElem?_eq_getElem w)
|
||||
|
||||
grind_pattern findIdx_getElem => xs[xs.findIdx p]
|
||||
|
||||
theorem findIdx_lt_size_of_exists {xs : Array α} (h : ∃ x ∈ xs, p x) :
|
||||
xs.findIdx p < xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -387,18 +429,24 @@ theorem findIdx_le_size {p : α → Bool} {xs : Array α} : xs.findIdx p ≤ xs.
|
||||
· simp at e
|
||||
exact Nat.le_of_eq (findIdx_eq_size.mpr e)
|
||||
|
||||
grind_pattern findIdx_le_size => xs.findIdx p, xs.size
|
||||
|
||||
@[simp]
|
||||
theorem findIdx_lt_size {p : α → Bool} {xs : Array α} :
|
||||
xs.findIdx p < xs.size ↔ ∃ x ∈ xs, p x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
grind_pattern findIdx_lt_size => xs.findIdx p, xs.size
|
||||
|
||||
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
|
||||
theorem not_of_lt_findIdx {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.findIdx p) :
|
||||
p (xs[i]'(Nat.le_trans h findIdx_le_size)) = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.not_of_lt_findIdx (by simpa using h)
|
||||
|
||||
grind_pattern not_of_lt_findIdx => xs.findIdx p, xs[i]
|
||||
|
||||
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
|
||||
theorem le_findIdx_of_not {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
|
||||
(h2 : ∀ j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i ≤ xs.findIdx p := by
|
||||
@@ -426,6 +474,7 @@ theorem findIdx_eq {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
|
||||
simp at h3
|
||||
simp_all [not_of_lt_findIdx h3]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_append {p : α → Bool} {xs ys : Array α} :
|
||||
(xs ++ ys).findIdx p =
|
||||
if xs.findIdx p < xs.size then xs.findIdx p else ys.findIdx p + xs.size := by
|
||||
@@ -433,12 +482,13 @@ theorem findIdx_append {p : α → Bool} {xs ys : Array α} :
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.findIdx_append]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findIdx p = if xs.findIdx p < xs.size then xs.findIdx p else xs.size + if p a then 0 else 1 := by
|
||||
simp only [push_eq_append, findIdx_append]
|
||||
split <;> rename_i h
|
||||
· rfl
|
||||
· simp [findIdx_singleton, Nat.add_comm]
|
||||
· simp [Nat.add_comm]
|
||||
|
||||
theorem findIdx_le_findIdx {xs : Array α} {p q : α → Bool} (h : ∀ x ∈ xs, p x → q x) : xs.findIdx q ≤ xs.findIdx p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -455,7 +505,7 @@ theorem false_of_mem_extract_findIdx {xs : Array α} {p : α → Bool} (h : x
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.false_of_mem_take_findIdx (by simpa using h)
|
||||
|
||||
@[simp] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
(xs.extract 0 i).findIdx p = min i (xs.findIdx p) := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -467,24 +517,24 @@ theorem false_of_mem_extract_findIdx {xs : Array α} {p : α → Bool} (h : x
|
||||
|
||||
/-! ### findIdx? -/
|
||||
|
||||
@[simp] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := by simp
|
||||
theorem findIdx?_singleton {a : α} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := by simp
|
||||
@[grind =] theorem findIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx? p = if p a then some 0 else none := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ ∀ x, x ∈ xs → p x = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_isSome {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_isSome]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_isNone {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -503,7 +553,7 @@ theorem findIdx?_eq_some_of_exists {xs : Array α} {p : α → Bool} (h : ∃ x,
|
||||
theorem findIdx?_eq_none_iff_findIdx_eq {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ xs.findIdx p = xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_eq_none_iff_findIdx_eq]
|
||||
simp
|
||||
|
||||
theorem findIdx?_eq_guard_findIdx_lt {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = Option.guard (fun i => i < xs.size) (xs.findIdx p) := by
|
||||
@@ -526,18 +576,19 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.of_findIdx?_eq_none (by simpa using w)
|
||||
|
||||
@[simp] theorem findIdx?_map {f : β → α} {xs : Array β} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findIdx?_map {f : β → α} {xs : Array β} {p : α → Bool} :
|
||||
findIdx? p (xs.map f) = xs.findIdx? (p ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_map]
|
||||
|
||||
@[simp] theorem findIdx?_append :
|
||||
@[simp, grind =] theorem findIdx?_append :
|
||||
(xs ++ ys : Array α).findIdx? p =
|
||||
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.size) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.findIdx?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx?_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findIdx? p = (xs.findIdx? p).or (if p a then some xs.size else none) := by
|
||||
simp only [push_eq_append, findIdx?_append]
|
||||
@@ -553,7 +604,7 @@ theorem findIdx?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
cases xss using array₂_induction
|
||||
simp [List.findIdx?_flatten, Function.comp_def]
|
||||
|
||||
@[simp] theorem findIdx?_replicate :
|
||||
@[simp, grind =] theorem findIdx?_replicate :
|
||||
(replicate n a).findIdx? p = if 0 < n ∧ p a then some 0 else none := by
|
||||
rw [← List.toArray_replicate]
|
||||
simp only [List.findIdx?_toArray]
|
||||
@@ -578,6 +629,7 @@ theorem findIdx?_eq_none_of_findIdx?_eq_none {xs : Array α} {p q : α → Bool}
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.findIdx?_eq_none_of_findIdx?_eq_none (by simpa using w)
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_eq_getD_findIdx? {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx p = (xs.findIdx? p).getD xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -594,15 +646,17 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
|
||||
cases xs
|
||||
simp [hf]
|
||||
|
||||
@[simp] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
(xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p #[] = none := by simp
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findFinIdx? p = if p a then some ⟨0, by simp⟩ else none := by
|
||||
simp
|
||||
@@ -620,7 +674,7 @@ theorem findFinIdx?_eq_pmap_findIdx? {xs : Array α} {p : α → Bool} :
|
||||
(fun i h => h) := by
|
||||
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
|
||||
|
||||
@[simp] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
xs.findFinIdx? p = none ↔ ∀ x, x ∈ xs → ¬ p x := by
|
||||
simp [findFinIdx?_eq_pmap_findIdx?]
|
||||
|
||||
@@ -636,12 +690,14 @@ theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α → Bool} {i : Fin xs.si
|
||||
· rintro ⟨h, w⟩
|
||||
exact ⟨i, ⟨i.2, h, fun j hji => w ⟨j, by omega⟩ hji⟩, rfl⟩
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or (if p a then some ⟨xs.size, by simp⟩ else none) := by
|
||||
simp only [findFinIdx?_eq_pmap_findIdx?, findIdx?_push, Option.pmap_or]
|
||||
split <;> rename_i h _ <;> split <;> simp [h]
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_append {xs ys : Array α} {p : α → Bool} :
|
||||
(xs ++ ys).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or
|
||||
@@ -651,13 +707,13 @@ theorem findFinIdx?_append {xs ys : Array α} {p : α → Bool} :
|
||||
· simp [h, Option.pmap_map, Option.map_pmap, Nat.add_comm]
|
||||
· simp [h]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isSome_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -678,6 +734,7 @@ The verification API for `idxOf` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
|
||||
-/
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
|
||||
(xs ++ ys).idxOf a = if a ∈ xs then xs.idxOf a else ys.idxOf a + xs.size := by
|
||||
rw [idxOf, findIdx_append]
|
||||
@@ -691,10 +748,23 @@ theorem idxOf_eq_size [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∉ xs) : x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_eq_length (by simpa using h)]
|
||||
|
||||
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∈ xs) : xs.idxOf a < xs.size := by
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∈ xs) : xs.idxOf a < xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_lt_length (by simpa using h)]
|
||||
simp [List.idxOf_lt_length_of_mem (by simpa using h)]
|
||||
|
||||
theorem idxOf_le_size [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf a ≤ xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_le_length]
|
||||
|
||||
grind_pattern idxOf_le_size => xs.idxOf a, xs.size
|
||||
|
||||
theorem idxOf_lt_size_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf a < xs.size ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_lt_length_iff]
|
||||
|
||||
grind_pattern idxOf_lt_size_iff => xs.idxOf a, xs.size
|
||||
|
||||
/-! ### idxOf?
|
||||
|
||||
@@ -702,19 +772,20 @@ The verification API for `idxOf?` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
|
||||
-/
|
||||
|
||||
theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
@[grind =] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
|
||||
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
@[simp, grind =] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = none ↔ a ∉ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf?_eq_none_iff]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isSome ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isNone = ¬ a ∈ xs := by
|
||||
simp
|
||||
@@ -727,11 +798,11 @@ The lemmas below should be made consistent with those for `findFinIdx?` (and pro
|
||||
|
||||
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
|
||||
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
|
||||
simp [idxOf?, finIdxOf?]
|
||||
|
||||
theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
@[grind =] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
|
||||
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
@[simp, grind =] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.finIdxOf? a = none ↔ a ∉ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.finIdxOf?_eq_none_iff, Array.size]
|
||||
@@ -742,14 +813,16 @@ theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by sim
|
||||
unfold Array.size at i ⊢
|
||||
simp [List.finIdxOf?_eq_some_iff]
|
||||
|
||||
@[simp]
|
||||
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isSome ↔ a ∈ xs := by
|
||||
@[simp, grind =]
|
||||
theorem isSome_finIdxOf? [BEq α] [PartialEquivBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isSome = xs.contains a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = ¬ a ∈ xs := by
|
||||
simp
|
||||
@[simp, grind =]
|
||||
theorem isNone_finIdxOf? [BEq α] [PartialEquivBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = !xs.contains a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -47,11 +47,16 @@ theorem insertIdx_zero {xs : Array α} {x : α} : xs.insertIdx 0 x = #[x] ++ xs
|
||||
simp at h
|
||||
simp [List.length_insertIdx, h]
|
||||
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
theorem eraseIdx_insertIdx_self {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-15")]
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
|
||||
simp [eraseIdx_insertIdx_self]
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge {as : Array α}
|
||||
(w₁ : i < as.size) (w₂ : j ≤ (as.eraseIdx i).size) (h : i ≤ j) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
@@ -66,6 +71,18 @@ theorem insertIdx_eraseIdx_of_le {as : Array α}
|
||||
cases as
|
||||
simpa using List.insertIdx_eraseIdx_of_le (by simpa) (by simpa)
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_eraseIdx {as : Array α} (h₁ : i < as.size) (h₂ : j ≤ (as.eraseIdx i).size) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
if h : i ≤ j then
|
||||
(as.insertIdx (j + 1) a (by simp_all; omega)).eraseIdx i (by simp_all; omega)
|
||||
else
|
||||
(as.insertIdx j a).eraseIdx (i + 1) (by simp_all) := by
|
||||
split <;> rename_i h'
|
||||
· rw [insertIdx_eraseIdx_of_ge] <;> omega
|
||||
· rw [insertIdx_eraseIdx_of_le] <;> omega
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_comm (a b : α) {i j : Nat} {xs : Array α} (_ : i ≤ j) (_ : j ≤ xs.size) :
|
||||
(xs.insertIdx i a).insertIdx (j + 1) b (by simpa) =
|
||||
(xs.insertIdx j b).insertIdx i a (by simp; omega) := by
|
||||
@@ -81,6 +98,7 @@ theorem insertIdx_size_self {xs : Array α} {x : α} : xs.insertIdx xs.size x =
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < (xs.insertIdx i x).size) :
|
||||
(xs.insertIdx i x)[k] =
|
||||
if h₁ : k < i then
|
||||
@@ -91,21 +109,22 @@ theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.siz
|
||||
else
|
||||
xs[k-1]'(by simp [size_insertIdx] at h; omega) := by
|
||||
cases xs
|
||||
simp [List.getElem_insertIdx, w]
|
||||
simp [List.getElem_insertIdx]
|
||||
|
||||
theorem getElem_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < i) :
|
||||
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k] := by
|
||||
simp [getElem_insertIdx, w, h]
|
||||
simp [getElem_insertIdx, h]
|
||||
|
||||
theorem getElem_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i ≤ xs.size) :
|
||||
(xs.insertIdx i x)[i]'(by simp; omega) = x := by
|
||||
simp [getElem_insertIdx, w]
|
||||
simp [getElem_insertIdx]
|
||||
|
||||
theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k ≤ xs.size) (h : k > i) :
|
||||
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k - 1]'(by omega) := by
|
||||
simp [getElem_insertIdx, w, h]
|
||||
simp [getElem_insertIdx]
|
||||
rw [dif_neg (by omega), dif_neg (by omega)]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i x)[k]? =
|
||||
if k < i then
|
||||
@@ -116,7 +135,7 @@ theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i ≤ xs.si
|
||||
else
|
||||
xs[k-1]? := by
|
||||
cases xs
|
||||
simp [List.getElem?_insertIdx, h]
|
||||
simp [List.getElem?_insertIdx]
|
||||
|
||||
theorem getElem?_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < i) :
|
||||
(xs.insertIdx i x)[k]? = xs[k]? := by
|
||||
|
||||
@@ -89,6 +89,8 @@ theorem size_pos_of_mem {a : α} {xs : Array α} (h : a ∈ xs) : 0 < xs.size :=
|
||||
simp only [mem_toArray] at h
|
||||
simpa using List.length_pos_of_mem h
|
||||
|
||||
grind_pattern size_pos_of_mem => a ∈ xs, xs.size
|
||||
|
||||
theorem exists_mem_of_size_pos {xs : Array α} (h : 0 < xs.size) : ∃ a, a ∈ xs := by
|
||||
cases xs
|
||||
simpa using List.exists_mem_of_length_pos h
|
||||
@@ -123,7 +125,7 @@ theorem none_eq_getElem?_iff {xs : Array α} {i : Nat} : none = xs[i]? ↔ xs.si
|
||||
simp
|
||||
|
||||
theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [getElem?_eq_none_iff, h]
|
||||
simp [h]
|
||||
|
||||
grind_pattern Array.getElem?_eq_none => xs.size ≤ i, xs[i]?
|
||||
|
||||
@@ -133,7 +135,6 @@ grind_pattern Array.getElem?_eq_none => xs.size ≤ i, xs[i]?
|
||||
theorem getElem?_eq_some_iff {xs : Array α} : xs[i]? = some b ↔ ∃ h : i < xs.size, xs[i] = b :=
|
||||
_root_.getElem?_eq_some_iff
|
||||
|
||||
@[grind →]
|
||||
theorem getElem_of_getElem? {xs : Array α} : xs[i]? = some a → ∃ h : i < xs.size, xs[i] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
@@ -153,16 +154,16 @@ theorem getElem_eq_iff {xs : Array α} {i : Nat} {h : i < xs.size} : xs[i] = x
|
||||
exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
|
||||
|
||||
theorem getElem_eq_getElem?_get {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
xs[i] = xs[i]?.get (by simp [getElem?_eq_getElem, h]) := by
|
||||
simp [getElem_eq_iff]
|
||||
xs[i] = xs[i]?.get (by simp [h]) := by
|
||||
simp
|
||||
|
||||
theorem getD_getElem? {xs : Array α} {i : Nat} {d : α} :
|
||||
xs[i]?.getD d = if p : i < xs.size then xs[i]'p else d := by
|
||||
if h : i < xs.size then
|
||||
simp [h, getElem?_def]
|
||||
simp [h]
|
||||
else
|
||||
have p : i ≥ xs.size := Nat.le_of_not_gt h
|
||||
simp [getElem?_eq_none p, h]
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem?_empty {i : Nat} : (#[] : Array α)[i]? = none := rfl
|
||||
|
||||
@@ -174,14 +175,14 @@ theorem getElem_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
|
||||
|
||||
@[simp] theorem getElem_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size] = x := by
|
||||
simp only [push, ← getElem_toList, List.concat_eq_append]
|
||||
rw [List.getElem_append_right] <;> simp [← getElem_toList, Nat.zero_lt_one]
|
||||
rw [List.getElem_append_right] <;> simp
|
||||
|
||||
theorem getElem_push {xs : Array α} {x : α} {i : Nat} (h : i < (xs.push x).size) :
|
||||
@[grind =] theorem getElem_push {xs : Array α} {x : α} {i : Nat} (h : i < (xs.push x).size) :
|
||||
(xs.push x)[i] = if h : i < xs.size then xs[i] else x := by
|
||||
by_cases h' : i < xs.size
|
||||
· simp [getElem_push_lt, h']
|
||||
· simp at h
|
||||
simp [getElem_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
|
||||
simp [Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
|
||||
|
||||
@[grind =] theorem getElem?_push {xs : Array α} {x} : (xs.push x)[i]? = if i = xs.size then some x else xs[i]? := by
|
||||
simp [getElem?_def, getElem_push]
|
||||
@@ -905,7 +906,7 @@ theorem all_push [BEq α] {xs : Array α} {a : α} {p : α → Bool} :
|
||||
abbrev getElem_set_eq := @getElem_set_self
|
||||
|
||||
@[simp] theorem getElem?_set_self {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} :
|
||||
(xs.set i v)[i]? = some v := by simp [getElem?_eq_getElem, h]
|
||||
(xs.set i v)[i]? = some v := by simp [h]
|
||||
|
||||
@[deprecated getElem?_set_self (since := "2024-12-11")]
|
||||
abbrev getElem?_set_eq := @getElem?_set_self
|
||||
@@ -917,7 +918,7 @@ abbrev getElem?_set_eq := @getElem?_set_self
|
||||
|
||||
@[simp] theorem getElem?_set_ne {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat}
|
||||
(ne : i ≠ j) : (xs.set i v)[j]? = xs[j]? := by
|
||||
by_cases h : j < xs.size <;> simp [getElem?_eq_getElem, getElem?_eq_none, Nat.ge_of_not_lt, ne, h]
|
||||
by_cases h : j < xs.size <;> simp [ne, h]
|
||||
|
||||
@[grind] theorem getElem_set {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(h : j < (xs.set i v).size) :
|
||||
@@ -954,6 +955,13 @@ theorem set_push {xs : Array α} {x y : α} {h} :
|
||||
· simp at h
|
||||
omega
|
||||
|
||||
@[grind _=_]
|
||||
theorem set_pop {xs : Array α} {x : α} {i : Nat} (h : i < xs.pop.size) :
|
||||
xs.pop.set i x h = (xs.set i x (by simp at h; omega)).pop := by
|
||||
ext i h₁ h₂
|
||||
· simp
|
||||
· simp [getElem_set]
|
||||
|
||||
@[simp] theorem set_eq_empty_iff {xs : Array α} {i : Nat} {a : α} {h : i < xs.size} :
|
||||
xs.set i a = #[] ↔ xs = #[] := by
|
||||
cases xs <;> cases i <;> simp [set]
|
||||
@@ -986,7 +994,11 @@ theorem mem_or_eq_of_mem_set
|
||||
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
|
||||
#[].setIfInBounds i a = #[] := rfl
|
||||
|
||||
@[simp] theorem set!_eq_setIfInBounds : @set! = @setIfInBounds := rfl
|
||||
@[simp, grind =] theorem set!_eq_setIfInBounds : set! xs i v = setIfInBounds xs i v := rfl
|
||||
|
||||
@[grind]
|
||||
theorem setIfInBounds_def (xs : Array α) (i : Nat) (a : α) :
|
||||
xs.setIfInBounds i a = if h : i < xs.size then xs.set i a else xs := rfl
|
||||
|
||||
@[deprecated set!_eq_setIfInBounds (since := "2024-12-12")]
|
||||
abbrev set!_is_setIfInBounds := @set!_eq_setIfInBounds
|
||||
@@ -1032,7 +1044,7 @@ theorem getElem?_setIfInBounds_self {xs : Array α} {i : Nat} {a : α} :
|
||||
@[simp]
|
||||
theorem getElem?_setIfInBounds_self_of_lt {xs : Array α} {i : Nat} {a : α} (h : i < xs.size) :
|
||||
(xs.setIfInBounds i a)[i]? = some a := by
|
||||
simp [getElem?_setIfInBounds, h]
|
||||
simp [h]
|
||||
|
||||
@[deprecated getElem?_setIfInBounds_self (since := "2024-12-11")]
|
||||
abbrev getElem?_setIfInBounds_eq := @getElem?_setIfInBounds_self
|
||||
@@ -1076,9 +1088,9 @@ theorem mem_or_eq_of_mem_setIfInBounds
|
||||
@[simp] theorem getD_getElem?_setIfInBounds {xs : Array α} {i : Nat} {v d : α} :
|
||||
(xs.setIfInBounds i v)[i]?.getD d = if i < xs.size then v else d := by
|
||||
by_cases h : i < xs.size <;>
|
||||
simp [setIfInBounds, Nat.not_lt_of_le, h, getD_getElem?]
|
||||
simp [setIfInBounds, h, ]
|
||||
|
||||
@[simp] theorem toList_setIfInBounds {xs : Array α} {i : Nat} {x : α} :
|
||||
@[simp, grind =] theorem toList_setIfInBounds {xs : Array α} {i : Nat} {x : α} :
|
||||
(xs.setIfInBounds i x).toList = xs.toList.set i x := by
|
||||
simp only [setIfInBounds]
|
||||
split <;> rename_i h
|
||||
@@ -1188,7 +1200,7 @@ where
|
||||
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 ‹_›]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, length_toList, List.foldlM_cons, bind_assoc,
|
||||
simp only [aux (i + 1), map_eq_pure_bind, List.foldlM_cons, bind_assoc,
|
||||
pure_bind]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
@@ -1488,6 +1500,19 @@ theorem forall_mem_filter {p : α → Bool} {xs : Array α} {P : α → Prop} :
|
||||
(∀ (i) (_ : i ∈ xs.filter p), P i) ↔ ∀ (j) (_ : j ∈ xs), p j → P j := by
|
||||
simp
|
||||
|
||||
@[grind] theorem getElem_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size) :
|
||||
p (xs.filter p)[i] :=
|
||||
(mem_filter.mp (getElem_mem h)).2
|
||||
|
||||
theorem getElem?_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
|
||||
grind_pattern getElem?_filter => (xs.filter p)[i]?, some a
|
||||
|
||||
@[simp] theorem filter_filter {p q : α → Bool} {xs : Array α} :
|
||||
filter p (filter q xs) = filter (fun a => p a && q a) xs := by
|
||||
apply ext'
|
||||
@@ -1730,7 +1755,7 @@ theorem forall_mem_filterMap {f : α → Option β} {xs : Array α} {P : β →
|
||||
|
||||
theorem map_filterMap_of_inv {f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {xs : Array α} :
|
||||
map g (filterMap f xs) = xs := by
|
||||
simp only [map_filterMap, H, filterMap_some, id]
|
||||
simp only [map_filterMap, H, filterMap_some]
|
||||
|
||||
@[grind →]
|
||||
theorem forall_none_of_filterMap_eq_empty (h : filterMap f xs = #[]) : ∀ x ∈ xs, f x = none := by
|
||||
@@ -1869,7 +1894,7 @@ theorem getElem?_append_left {xs ys : Array α} {i : Nat} (hn : i < xs.size) :
|
||||
(xs ++ ys)[i]? = xs[i]? := by
|
||||
have hn' : i < (xs ++ ys).size := Nat.lt_of_lt_of_le hn <|
|
||||
size_append .. ▸ Nat.le_add_right ..
|
||||
simp_all [getElem?_eq_getElem, getElem_append]
|
||||
simp_all
|
||||
|
||||
theorem getElem?_append_right {xs ys : Array α} {i : Nat} (h : xs.size ≤ i) :
|
||||
(xs ++ ys)[i]? = ys[i - xs.size]? := by
|
||||
@@ -2000,7 +2025,7 @@ theorem append_eq_singleton_iff {xs ys : Array α} {x : α} :
|
||||
xs ++ ys = #[x] ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[]) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, mk.injEq, List.append_eq_singleton_iff, toArray_eq_append_iff]
|
||||
simp only [List.append_toArray, mk.injEq, List.append_eq_singleton_iff]
|
||||
|
||||
theorem singleton_eq_append_iff {xs ys : Array α} {x : α} :
|
||||
#[x] = xs ++ ys ↔ (xs = #[] ∧ ys = #[x]) ∨ (xs = #[x] ∧ ys = #[]) := by
|
||||
@@ -2326,7 +2351,7 @@ theorem flatMap_toArray {β} {f : α → Array β} {as : List α} :
|
||||
theorem size_flatMap {xs : Array α} {f : α → Array β} :
|
||||
(xs.flatMap f).size = sum (map (fun a => (f a).size) xs) := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [Function.comp_def]
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem mem_flatMap {f : α → Array β} {b} {xs : Array α} : b ∈ xs.flatMap f ↔ ∃ a, a ∈ xs ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
@@ -2544,7 +2569,7 @@ 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, toList_filter', toList_replicate, List.filter_replicate]
|
||||
simp only [w]
|
||||
split <;> simp_all
|
||||
|
||||
@[deprecated filter_replicate (since := "2025-03-18")]
|
||||
@@ -2584,7 +2609,7 @@ 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, h, w]
|
||||
| some b, _ => simp [filterMap_replicate, w]
|
||||
|
||||
@[deprecated filterMap_replicate_of_isSome (since := "2025-03-18")]
|
||||
abbrev filterMap_mkArray_of_isSome := @filterMap_replicate_of_isSome
|
||||
@@ -2619,7 +2644,7 @@ 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 [flatMap_toList, List.flatMap_replicate]
|
||||
simp [List.flatMap_replicate]
|
||||
|
||||
@[deprecated flatMap_replicate (since := "2025-03-18")]
|
||||
abbrev flatMap_mkArray := @flatMap_replicate
|
||||
@@ -2997,6 +3022,10 @@ theorem extract_empty_of_size_le_start {xs : Array α} {start stop : Nat} (h : x
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
theorem _root_.List.toArray_drop {l : List α} {k : Nat} :
|
||||
(l.drop k).toArray = l.toArray.extract k := by
|
||||
rw [List.drop_eq_extract, List.extract_toArray, List.size_toArray]
|
||||
|
||||
@[deprecated extract_size (since := "2025-02-27")]
|
||||
theorem take_size {xs : Array α} : xs.take xs.size = xs := by
|
||||
cases xs
|
||||
@@ -3607,8 +3636,8 @@ We can prove that two folds over the same array are related (by some arbitrary r
|
||||
if we know that the initial elements are related and the folding function, for each element of the array,
|
||||
preserves the relation.
|
||||
-/
|
||||
theorem foldl_rel {xs : Array α} {f g : β → α → β} {a b : β} {r : β → β → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) :
|
||||
theorem foldl_rel {xs : Array α} {f : β → α → β} {g : γ → α → γ} {a : β} {b : γ} {r : β → γ → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c : β) (c' : γ), r c c' → r (f c a) (g c' a)) :
|
||||
r (xs.foldl (fun acc a => f acc a) a) (xs.foldl (fun acc a => g acc a) b) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.foldl_rel h (by simpa using h')
|
||||
@@ -3618,8 +3647,8 @@ We can prove that two folds over the same array are related (by some arbitrary r
|
||||
if we know that the initial elements are related and the folding function, for each element of the array,
|
||||
preserves the relation.
|
||||
-/
|
||||
theorem foldr_rel {xs : Array α} {f g : α → β → β} {a b : β} {r : β → β → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c c' : β), r c c' → r (f a c) (g a c')) :
|
||||
theorem foldr_rel {xs : Array α} {f : α → β → β} {g : α → γ → γ} {a : β} {b : γ} {r : β → γ → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ xs → ∀ (c : β) (c' : γ), r c c' → r (f a c) (g a c')) :
|
||||
r (xs.foldr (fun a acc => f a acc) a) (xs.foldr (fun a acc => g a acc) b) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.foldr_rel h (by simpa using h')
|
||||
@@ -4113,7 +4142,7 @@ theorem getElem_modify_of_ne {xs : Array α} {i : Nat} (h : i ≠ j)
|
||||
|
||||
@[simp] theorem getElem_swap_right {xs : Array α} {i j : Nat} {hi hj} :
|
||||
(xs.swap i j hi hj)[j]'(by simpa using hj) = xs[i] := by
|
||||
simp [swap_def, getElem_set]
|
||||
simp [swap_def]
|
||||
|
||||
@[simp] theorem getElem_swap_left {xs : Array α} {i j : Nat} {hi hj} :
|
||||
(xs.swap i j hi hj)[i]'(by simpa using hi) = xs[j] := by
|
||||
@@ -4410,7 +4439,7 @@ theorem size_uset {xs : Array α} {v : α} {i : USize} (h : i.toNat < xs.size) :
|
||||
|
||||
@[simp] theorem getD_eq_getD_getElem? {xs : Array α} {i : Nat} {d : α} :
|
||||
xs.getD i d = xs[i]?.getD d := by
|
||||
simp only [getD]; split <;> simp [getD_getElem?, *]
|
||||
simp only [getD]; split <;> simp [*]
|
||||
|
||||
theorem getElem!_eq_getD [Inhabited α] {xs : Array α} {i} : xs[i]! = xs.getD i default := by
|
||||
rfl
|
||||
@@ -4438,13 +4467,13 @@ theorem getElem?_size_le {xs : Array α} {i : Nat} (h : xs.size ≤ i) : xs[i]?
|
||||
simp [getElem?_neg, h]
|
||||
|
||||
theorem getElem_mem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs.toList := by
|
||||
simp only [← getElem_toList, List.getElem_mem, ugetElem_eq_getElem]
|
||||
simp only [← getElem_toList, List.getElem_mem]
|
||||
|
||||
theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD default := by
|
||||
simp [back!, back?, getElem!_def, Option.getD]; rfl
|
||||
|
||||
@[simp, grind] theorem back?_push {xs : Array α} {x : α} : (xs.push x).back? = some x := by
|
||||
simp [back?, ← getElem?_toList]
|
||||
simp [back?]
|
||||
|
||||
@[simp] theorem back!_push [Inhabited α] {xs : Array α} {x : α} : (xs.push x).back! = x := by
|
||||
simp [back!_eq_back?]
|
||||
@@ -4512,7 +4541,7 @@ abbrev contains_def [DecidableEq α] {a : α} {xs : Array α} : xs.contains a
|
||||
(zip xs ys).size = min xs.size ys.size :=
|
||||
size_zipWith
|
||||
|
||||
@[simp] theorem getElem_zipWith {xs : Array α} {ys : Array β} {f : α → β → γ} {i : Nat}
|
||||
@[simp, grind =] theorem getElem_zipWith {xs : Array α} {ys : Array β} {f : α → β → γ} {i : Nat}
|
||||
(hi : i < (zipWith f xs ys).size) :
|
||||
(zipWith f xs ys)[i] = f (xs[i]'(by simp at hi; omega)) (ys[i]'(by simp at hi; omega)) := by
|
||||
cases xs
|
||||
@@ -4593,7 +4622,7 @@ theorem uset_toArray {l : List α} {i : USize} {a : α} {h : i.toNat < l.toArray
|
||||
@[simp, grind =] theorem flatten_toArray {L : List (List α)} :
|
||||
(L.toArray.map List.toArray).flatten = L.flatten.toArray := by
|
||||
apply ext'
|
||||
simp [Function.comp_def]
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -4685,7 +4714,7 @@ namespace List
|
||||
intro h'
|
||||
specialize ih (by omega)
|
||||
have : as.length - (i + 1) + 1 = as.length - i := by omega
|
||||
simp_all [ih]
|
||||
simp_all
|
||||
· simp only [size_toArray, Nat.not_lt] at h
|
||||
have : as.length = 0 := by omega
|
||||
simp_all
|
||||
@@ -4696,7 +4725,7 @@ end List
|
||||
namespace Array
|
||||
|
||||
@[deprecated size_toArray (since := "2024-12-11")]
|
||||
theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
|
||||
theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp
|
||||
|
||||
@[deprecated getElem?_eq_getElem (since := "2024-12-11")]
|
||||
theorem getElem?_lt
|
||||
@@ -4712,7 +4741,7 @@ theorem get?_eq_getElem? (xs : Array α) (i : Nat) : xs.get? i = xs[i]? := rfl
|
||||
|
||||
@[deprecated getElem?_eq_none (since := "2024-12-11")]
|
||||
theorem getElem?_len_le (xs : Array α) {i : Nat} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [getElem?_eq_none, h]
|
||||
simp [h]
|
||||
|
||||
@[deprecated getD_getElem? (since := "2024-12-11")] abbrev getD_get? := @getD_getElem?
|
||||
|
||||
@@ -4727,7 +4756,7 @@ set_option linter.deprecated false in
|
||||
theorem get!_eq_getD_getElem? [Inhabited α] (xs : Array α) (i : Nat) :
|
||||
xs.get! i = xs[i]?.getD default := by
|
||||
by_cases p : i < xs.size <;>
|
||||
simp [get!, getElem!_eq_getD, getD_eq_getD_getElem?, getD_getElem?, p]
|
||||
simp [get!, getD_eq_getD_getElem?, p]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated get!_eq_getD_getElem? (since := "2025-02-12")] abbrev get!_eq_getElem? := @get!_eq_getD_getElem?
|
||||
|
||||
@@ -162,7 +162,7 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Array α} : lex xs ys = false ↔ ys ≤ xs := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp [List.not_lt_iff_ge]
|
||||
simp
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
|
||||
fun xs ys => decidable_of_iff (lex xs ys = true) lex_eq_true_iff_lt
|
||||
|
||||
@@ -51,27 +51,27 @@ theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.siz
|
||||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h :=
|
||||
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp, grind =] theorem size_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
(xs.mapFinIdx f).size = xs.size :=
|
||||
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
|
||||
@[simp] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
@[simp, grind =] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
Array.size_mapFinIdx
|
||||
|
||||
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
(h : i < (xs.mapFinIdx f).size) :
|
||||
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
|
||||
(mapFinIdx_spec (p := fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat} :
|
||||
(xs.mapFinIdx f)[i]? =
|
||||
xs[i]?.pbind fun b h => some <| f i b (getElem?_eq_some_iff.1 h).1 := by
|
||||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp, grind =] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@@ -91,20 +91,20 @@ theorem mapIdx_spec {f : Nat → α → β} {xs : Array α}
|
||||
∀ i h, p i ((xs.mapIdx f)[i]) h :=
|
||||
(mapIdx_induction (motive := fun _ => True) trivial fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx {f : Nat → α → β} {xs : Array α} : (xs.mapIdx f).size = xs.size :=
|
||||
@[simp, grind =] theorem size_mapIdx {f : Nat → α → β} {xs : Array α} : (xs.mapIdx f).size = xs.size :=
|
||||
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
|
||||
@[simp] theorem getElem_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat}
|
||||
@[simp, grind =] theorem getElem_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat}
|
||||
(h : i < (xs.mapIdx f).size) :
|
||||
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
|
||||
(mapIdx_spec (p := fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
|
||||
|
||||
@[simp] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat} :
|
||||
(xs.mapIdx f)[i]? =
|
||||
xs[i]?.map (f i) := by
|
||||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
|
||||
@[simp] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||||
@[simp, grind =] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||||
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Array
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp] theorem getElem_zipIdx {xs : Array α} {k : Nat} {i : Nat} (h : i < (xs.zipIdx k).size) :
|
||||
@[simp, grind =] theorem getElem_zipIdx {xs : Array α} {k : Nat} {i : Nat} (h : i < (xs.zipIdx k).size) :
|
||||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||||
simp [zipIdx]
|
||||
|
||||
@@ -135,12 +135,12 @@ abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
|
||||
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||||
ext i hi₁ hi₂ <;> simp [Nat.add_comm]
|
||||
ext i hi₁ hi₂ <;> simp
|
||||
|
||||
@[deprecated zipIdx_toArray (since := "2025-01-21")]
|
||||
abbrev zipWithIndex_toArray := @zipIdx_toArray
|
||||
|
||||
@[simp] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
@[simp, grind =] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -185,7 +185,7 @@ abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapFinIdx_empty {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx #[] f = #[] :=
|
||||
rfl
|
||||
|
||||
@@ -195,6 +195,7 @@ theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) → α → (h : i < xs.
|
||||
simp only [List.mapFinIdx_toArray, List.mapFinIdx_eq_ofFn, Fin.getElem_fin, List.getElem_toArray]
|
||||
simp [Array.size]
|
||||
|
||||
@[grind =]
|
||||
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) → α → (h : i < (xs ++ ys).size) → β} :
|
||||
(xs ++ ys).mapFinIdx f =
|
||||
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||||
@@ -203,7 +204,7 @@ theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) → α → (h : i < (
|
||||
cases ys
|
||||
simp [List.mapFinIdx_append, Array.size]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) → α → (h : i < (xs.push a).size) → β} :
|
||||
mapFinIdx (xs.push a) f =
|
||||
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
|
||||
@@ -237,7 +238,7 @@ theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp, grind =] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
b ∈ xs.mapFinIdx f ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -290,7 +291,7 @@ theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) → α → (
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {xs : Array α}
|
||||
@[simp, grind =] theorem mapFinIdx_mapFinIdx {xs : Array α}
|
||||
{f : (i : Nat) → α → (h : i < xs.size) → β}
|
||||
{g : (i : Nat) → β → (h : i < (xs.mapFinIdx f).size) → γ} :
|
||||
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
|
||||
@@ -305,14 +306,14 @@ theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||||
@[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⟩
|
||||
simp [List.mapFinIdx_reverse, Array.size]
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #[] = #[] :=
|
||||
rfl
|
||||
|
||||
@@ -332,13 +333,14 @@ theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat → α → β} :
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs ys : Array α} :
|
||||
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.mapIdx_append]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_push {xs : Array α} {a : α} :
|
||||
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
|
||||
simp [← append_singleton, mapIdx_append]
|
||||
@@ -360,7 +362,7 @@ theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {xs : Array α} :
|
||||
@[simp, grind =] theorem mem_mapIdx {b : β} {xs : Array α} :
|
||||
b ∈ mapIdx f xs ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -414,7 +416,7 @@ theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_eq_mapIdx_iff]
|
||||
|
||||
@[simp] theorem mapIdx_set {f : Nat → α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
|
||||
@[simp, grind =] theorem mapIdx_set {f : Nat → α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
|
||||
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_set]
|
||||
@@ -424,17 +426,17 @@ theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_set]
|
||||
|
||||
@[simp] theorem back?_mapIdx {xs : Array α} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem back?_mapIdx {xs : Array α} {f : Nat → α → β} :
|
||||
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getLast?_mapIdx]
|
||||
|
||||
@[simp] theorem back_mapIdx {xs : Array α} {f : Nat → α → β} (h) :
|
||||
@[simp, grind =] theorem back_mapIdx {xs : Array α} {f : Nat → α → β} (h) :
|
||||
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getLast_mapIdx]
|
||||
|
||||
@[simp] theorem mapIdx_mapIdx {xs : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
@[simp, grind =] theorem mapIdx_mapIdx {xs : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
@@ -447,7 +449,7 @@ theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β}
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||||
@[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⟩
|
||||
simp [List.mapIdx_reverse]
|
||||
@@ -456,7 +458,7 @@ end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[grind] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
@[grind =] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
{f : (i : Nat) → α → (h : i < l.length) → m β} :
|
||||
l.toArray.mapFinIdxM f = toArray <$> l.mapFinIdxM f := by
|
||||
let rec go (i : Nat) (acc : Array β) (inv : i + acc.size = l.length) :
|
||||
@@ -477,7 +479,7 @@ namespace List
|
||||
simp only [Array.mapFinIdxM, mapFinIdxM]
|
||||
exact go _ #[] _
|
||||
|
||||
@[grind] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
@[grind =] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
{f : Nat → α → m β} :
|
||||
l.toArray.mapIdxM f = toArray <$> l.mapIdxM f := by
|
||||
let rec go (bs : List α) (acc : Array β) (inv : bs.length + acc.size = l.length) :
|
||||
|
||||
@@ -36,19 +36,19 @@ theorem map_toList_inj [Monad m] [LawfulMonad m]
|
||||
xs.mapM (m := m) (pure <| f ·) = pure (xs.map f) := by
|
||||
induction xs; simp_all
|
||||
|
||||
@[simp] theorem idRun_mapM {xs : Array α} {f : α → Id β} : (xs.mapM f).run = xs.map (f · |>.run) :=
|
||||
@[simp, grind =] theorem idRun_mapM {xs : Array α} {f : α → Id β} : (xs.mapM f).run = xs.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
mapM_pure
|
||||
|
||||
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
|
||||
@[simp, grind =] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
|
||||
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
|
||||
@[simp, grind =] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
|
||||
(xs ++ ys).mapM f = (return (← xs.mapM f) ++ (← ys.mapM f)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
@@ -59,7 +59,7 @@ theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] {f : α → m β} {xs : Ar
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
|
||||
rw [List.mapM_eq_reverse_foldlM_cons]
|
||||
simp only [bind_pure_comp, Functor.map_map]
|
||||
simp only [Functor.map_map]
|
||||
suffices ∀ (l), (fun l' => l'.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) l xs =
|
||||
List.foldlM (fun acc a => acc.push <$> f a) l.reverse.toArray xs by
|
||||
exact this []
|
||||
@@ -143,13 +143,13 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
cases as <;> cases bs
|
||||
simp_all
|
||||
|
||||
@[simp] theorem forM_append [Monad m] [LawfulMonad m] {xs ys : Array α} {f : α → m PUnit} :
|
||||
@[simp, grind =] theorem forM_append [Monad m] [LawfulMonad m] {xs ys : Array α} {f : α → m PUnit} :
|
||||
forM (xs ++ ys) f = (do forM xs f; forM ys f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] {xs : Array α} {g : α → β} {f : β → m PUnit} :
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] {xs : Array α} {g : α → β} {f : β → m PUnit} :
|
||||
forM (xs.map g) f = forM xs (fun a => f (g a)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -208,7 +208,7 @@ theorem forIn'_yield_eq_foldl
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (g : α → β) (f : (b : β) → b ∈ xs.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem h) y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -234,14 +234,14 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
forIn xs init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
xs.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldlM_map]
|
||||
simp
|
||||
|
||||
@[simp] theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (f : α → β → β) (init : β) :
|
||||
forIn xs init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (xs.foldl (fun b a => f a b) init) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||||
simp [List.forIn_pure_yield_eq_foldl]
|
||||
|
||||
theorem idRun_forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → Id β) (init : β) :
|
||||
@@ -256,7 +256,7 @@ theorem forIn_yield_eq_foldl
|
||||
xs.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Array
|
||||
|
||||
/-! ### ofFn -/
|
||||
|
||||
@[simp] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
|
||||
@[simp, grind =] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
|
||||
simp [ofFn, ofFn.go]
|
||||
|
||||
theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
@@ -42,10 +42,10 @@ theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
| zero => simp
|
||||
| succ m ih => simp [ofFn_succ, ih]
|
||||
|
||||
@[simp] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
|
||||
@[simp, grind =] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
|
||||
@[simp, grind =] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
theorem ofFn_succ' {f : Fin (n+1) → α} :
|
||||
@@ -58,7 +58,7 @@ theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
|
||||
rw [← Array.toList_inj]
|
||||
simp
|
||||
|
||||
@[simp 500]
|
||||
@[simp 500, grind =]
|
||||
theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
@@ -73,7 +73,7 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Array α) :=
|
||||
Fin.foldlM n (fun xs i => xs.push <$> f i) (Array.emptyWithCapacity n)
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : ofFnM f = pure #[] := by
|
||||
simp [ofFnM]
|
||||
|
||||
@@ -109,7 +109,7 @@ theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
funext x
|
||||
simp
|
||||
|
||||
@[simp] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
@[simp, grind =] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toList <$> ofFnM f = List.ofFnM f := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
|
||||
@@ -91,17 +91,26 @@ theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a ∈ xs ↔ a
|
||||
simp only [perm_iff_toList_perm] at p
|
||||
simpa using p.mem_iff
|
||||
|
||||
grind_pattern Perm.mem_iff => xs ~ ys, a ∈ xs
|
||||
grind_pattern Perm.mem_iff => xs ~ ys, a ∈ ys
|
||||
|
||||
theorem Perm.append {xs ys as bs : Array α} (p₁ : xs ~ ys) (p₂ : as ~ bs) :
|
||||
xs ++ as ~ ys ++ bs := by
|
||||
cases xs; cases ys; cases as; cases bs
|
||||
simp only [append_toArray, perm_iff_toList_perm] at p₁ p₂ ⊢
|
||||
exact p₁.append p₂
|
||||
|
||||
grind_pattern Perm.append => xs ~ ys, as ~ bs, xs ++ as
|
||||
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]
|
||||
exact p.append .rfl
|
||||
|
||||
grind_pattern Perm.push => xs ~ ys, xs.push x
|
||||
grind_pattern Perm.push => xs ~ ys, ys.push x
|
||||
|
||||
theorem Perm.push_comm (x y : α) {xs ys : Array α} (p : xs ~ ys) :
|
||||
(xs.push x).push y ~ (ys.push y).push x := by
|
||||
cases xs; cases ys
|
||||
|
||||
@@ -128,6 +128,16 @@ theorem erase_range' :
|
||||
simp only [← List.toArray_range', List.erase_toArray]
|
||||
simp [List.erase_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range' {a s n step} (h : 0 < step := by simp) :
|
||||
count a (range' s n step) = if ∃ i, i < n ∧ a = s + step * i then 1 else 0 := by
|
||||
rw [← List.toArray_range', List.count_toArray, ← List.count_range' h]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range_1' {a s n} :
|
||||
count a (range' s n) = if s ≤ a ∧ a < s + n then 1 else 0 := by
|
||||
rw [← List.toArray_range', List.count_toArray, ← List.count_range_1']
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@[grind _=_]
|
||||
@@ -179,11 +189,11 @@ theorem self_mem_range_succ {n : Nat} : n ∈ range (n + 1) := by simp
|
||||
@[simp, grind =] theorem take_range {i n : Nat} : take (range n) i = range (min i n) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind =] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[simp] theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind =] theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp only [← List.toArray_range, List.find?_toArray, List.find?_range_eq_none]
|
||||
|
||||
@@ -191,6 +201,10 @@ theorem self_mem_range_succ {n : Nat} : n ∈ range (n + 1) := by simp
|
||||
theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n - (i + 1)) := by
|
||||
simp [range_eq_range', erase_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range {a n} :
|
||||
count a (range n) = if a < n then 1 else 0 := by
|
||||
rw [← List.toArray_range, List.count_toArray, ← List.count_range]
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@@ -199,13 +213,13 @@ theorem zipIdx_eq_empty_iff {xs : Array α} {i : Nat} : xs.zipIdx i = #[] ↔ xs
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_zipIdx {xs : Array α} {i j} : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
|
||||
simp [getElem?_def]
|
||||
|
||||
theorem map_snd_add_zipIdx_eq_zipIdx {xs : Array α} {n k : Nat} :
|
||||
map (Prod.map id (· + n)) (zipIdx xs k) = zipIdx xs (n + k) :=
|
||||
ext_getElem? fun i ↦ by simp [(· ∘ ·), Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
ext_getElem? fun i ↦ by simp [Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
-- Arguments are explicit for parity with `zipIdx_map_fst`.
|
||||
@[simp]
|
||||
@@ -242,7 +256,7 @@ theorem zipIdx_eq_map_add {xs : Array α} {i : Nat} :
|
||||
simp only [zipIdx_toArray, List.map_toArray, mk.injEq]
|
||||
rw [List.zipIdx_eq_map_add]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx #[x] k = #[(x, k)] :=
|
||||
rfl
|
||||
|
||||
@@ -290,6 +304,7 @@ theorem zipIdx_map {xs : Array α} {k : Nat} {f : α → β} :
|
||||
cases xs
|
||||
simp [List.zipIdx_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipIdx_append {xs ys : Array α} {k : Nat} :
|
||||
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + xs.size) := by
|
||||
cases xs
|
||||
|
||||
@@ -45,6 +45,7 @@ theorem zipWith_self {f : α → α → δ} {xs : Array α} : zipWith f xs xs =
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
using `Option.map` and `Option.bind` rather than a `match`.
|
||||
-/
|
||||
@[grind =]
|
||||
theorem getElem?_zipWith {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
@@ -76,31 +77,35 @@ theorem getElem?_zip_eq_some {as : Array α} {bs : Array β} {z : α × β} {i :
|
||||
· rintro ⟨h₀, h₁⟩
|
||||
exact ⟨_, _, h₀, h₁, rfl⟩
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipWith_map {μ} {f : γ → δ → μ} {g : α → γ} {h : β → δ} {as : Array α} {bs : Array β} :
|
||||
zipWith f (as.map g) (bs.map h) = zipWith (fun a b => f (g a) (h b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_left {as : Array α} {bs : Array β} {f : α → α'} {g : α' → β → γ} :
|
||||
zipWith g (as.map f) bs = zipWith (fun a b => g (f a) b) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map_left]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_right {as : Array α} {bs : Array β} {f : β → β'} {g : α → β' → γ} :
|
||||
zipWith g as (bs.map f) = zipWith (fun a b => g a (f b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map_right]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} {i : δ} :
|
||||
(zipWith f as bs).foldr g i = (zip as bs).foldr (fun p r => g (f p.1 p.2) r) i := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_foldr_eq_zip_foldr]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} :
|
||||
(zipWith f as bs).foldl g i = (zip as bs).foldl (fun r p => g r (f p.1 p.2)) i := by
|
||||
cases as
|
||||
@@ -111,22 +116,26 @@ theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} :
|
||||
theorem zipWith_eq_empty_iff {f : α → β → γ} {as : Array α} {bs : Array β} : zipWith f as bs = #[] ↔ as = #[] ∨ bs = #[] := by
|
||||
cases as <;> cases bs <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {cs : Array γ} {ds : Array δ} :
|
||||
map f (zipWith g cs ds) = zipWith (fun x y => f (g x y)) cs ds := by
|
||||
cases cs
|
||||
cases ds
|
||||
simp [List.map_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem take_zipWith : (zipWith f as bs).take i = zipWith f (as.take i) (bs.take i) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.take_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_zipWith : (zipWith f as bs).extract i j = zipWith f (as.extract i j) (bs.extract i j) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.drop_zipWith, List.take_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_append {f : α → β → γ} {as as' : Array α} {bs bs' : Array β}
|
||||
(h : as.size = bs.size) :
|
||||
zipWith f (as ++ as') (bs ++ bs') = zipWith f as bs ++ zipWith f as' bs' := by
|
||||
@@ -152,7 +161,7 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Array α} {bs : Array
|
||||
· rintro ⟨⟨ws⟩, ⟨xs⟩, ⟨ys⟩, ⟨zs⟩, h, rfl, rfl, h₁, h₂⟩
|
||||
exact ⟨ws, xs, ys, zs, by simp_all⟩
|
||||
|
||||
@[simp] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||||
@[simp, grind =] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -184,6 +193,7 @@ theorem zipWith_eq_zipWith_take_min (as : Array α) (bs : Array β) :
|
||||
simp
|
||||
rw [List.zipWith_eq_zipWith_take_min]
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_zipWith (h : as.size = bs.size) :
|
||||
(zipWith f as bs).reverse = zipWith f as.reverse bs.reverse := by
|
||||
cases as
|
||||
@@ -200,7 +210,7 @@ theorem lt_size_right_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i <
|
||||
i < bs.size :=
|
||||
lt_size_right_of_zipWith h
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_zip {as : Array α} {bs : Array β} {i : Nat} {h : i < (zip as bs).size} :
|
||||
(zip as bs)[i] =
|
||||
(as[i]'(lt_size_left_of_zip h), bs[i]'(lt_size_right_of_zip h)) :=
|
||||
@@ -211,18 +221,22 @@ theorem zip_eq_zipWith {as : Array α} {bs : Array β} : zip as bs = zipWith Pro
|
||||
cases bs
|
||||
simp [List.zip_eq_zipWith]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map {f : α → γ} {g : β → δ} {as : Array α} {bs : Array β} :
|
||||
zip (as.map f) (bs.map g) = (zip as bs).map (Prod.map f g) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zip_map]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {as : Array α} {bs : Array β} :
|
||||
zip (as.map f) bs = (zip as bs).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_right {f : β → γ} {as : Array α} {bs : Array β} :
|
||||
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size) :
|
||||
zip (as ++ bs) (cs ++ ds) = zip as cs ++ zip bs ds := by
|
||||
cases as
|
||||
@@ -231,6 +245,7 @@ theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size
|
||||
cases ds
|
||||
simp_all [List.zip_append]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_map' {f : α → β} {g : α → γ} {xs : Array α} :
|
||||
zip (xs.map f) (xs.map g) = xs.map fun a => (f a, g a) := by
|
||||
cases xs
|
||||
@@ -276,7 +291,7 @@ theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
|
||||
∃ as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size ∧ as = as₁ ++ as₂ ∧ bs = bs₁ ++ bs₂ ∧ xs = zip as₁ bs₁ ∧ ys = zip as₂ bs₂ := by
|
||||
simp [zip_eq_zipWith, zipWith_eq_append_iff]
|
||||
|
||||
@[simp] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||||
@[simp, grind =] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -293,6 +308,7 @@ theorem zip_eq_zip_take_min {as : Array α} {bs : Array β} :
|
||||
|
||||
/-! ### zipWithAll -/
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
(zipWithAll f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
@@ -301,31 +317,35 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
simp [List.getElem?_zipWithAll]
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map {μ} {f : Option γ → Option δ → μ} {g : α → γ} {h : β → δ} {as : Array α} {bs : Array β} :
|
||||
zipWithAll f (as.map g) (bs.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_left {as : Array α} {bs : Array β} {f : α → α'} {g : Option α' → Option β → γ} :
|
||||
zipWithAll g (as.map f) bs = zipWithAll (fun a b => g (f <$> a) b) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map_left]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_right {as : Array α} {bs : Array β} {f : β → β'} {g : Option α → Option β' → γ} :
|
||||
zipWithAll g as (bs.map f) = zipWithAll (fun a b => g a (f <$> b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map_right]
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option δ → α} {cs : Array γ} {ds : Array δ} :
|
||||
map f (zipWithAll g cs ds) = zipWithAll (fun x y => f (g x y)) cs ds := by
|
||||
cases cs
|
||||
cases ds
|
||||
simp [List.map_zipWithAll]
|
||||
|
||||
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
@[simp, grind =] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
zipWithAll f (replicate n a) (replicate n b) = replicate n (f (some a) (some b)) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -342,6 +362,7 @@ theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem unzip_eq_map {xs : Array (α × β)} : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
|
||||
cases xs
|
||||
simp [List.unzip_eq_map]
|
||||
@@ -375,9 +396,11 @@ theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl
|
||||
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← fst_unzip, ← snd_unzip, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
@[simp, grind =] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
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
|
||||
|
||||
@@ -6,7 +6,10 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.BasicAux
|
||||
import Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
import Init.Data.BitVec.Bitblast
|
||||
import Init.Data.BitVec.Folds
|
||||
import Init.Data.BitVec.Decidable
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Folds
|
||||
|
||||
@@ -74,25 +74,27 @@ section getXsb
|
||||
|
||||
/--
|
||||
Returns the `i`th least significant bit.
|
||||
|
||||
This will be renamed `getLsb` after the existing deprecated alias is removed.
|
||||
-/
|
||||
@[inline, expose] def getLsb' (x : BitVec w) (i : Fin w) : Bool := x.toNat.testBit i
|
||||
@[inline, expose] def getLsb (x : BitVec w) (i : Fin w) : Bool := x.toNat.testBit i
|
||||
|
||||
@[deprecated getLsb (since := "2025-06-17"), inherit_doc getLsb]
|
||||
abbrev getLsb' := @getLsb
|
||||
|
||||
/-- Returns the `i`th least significant bit, or `none` if `i ≥ w`. -/
|
||||
@[inline, expose] def getLsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getLsb' x ⟨i, h⟩) else none
|
||||
if h : i < w then some (getLsb x ⟨i, h⟩) else none
|
||||
|
||||
/--
|
||||
Returns the `i`th most significant bit.
|
||||
|
||||
This will be renamed `BitVec.getMsb` after the existing deprecated alias is removed.
|
||||
-/
|
||||
@[inline] def getMsb' (x : BitVec w) (i : Fin w) : Bool := x.getLsb' ⟨w-1-i, by omega⟩
|
||||
@[inline] def getMsb (x : BitVec w) (i : Fin w) : Bool := x.getLsb ⟨w-1-i, by omega⟩
|
||||
|
||||
@[deprecated getMsb (since := "2025-06-17"), inherit_doc getMsb]
|
||||
abbrev getMsb' := @getMsb
|
||||
|
||||
/-- Returns the `i`th most significant bit or `none` if `i ≥ w`. -/
|
||||
@[inline] def getMsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getMsb' x ⟨i, h⟩) else none
|
||||
if h : i < w then some (getMsb x ⟨i, h⟩) else none
|
||||
|
||||
/-- Returns the `i`th least significant bit or `false` if `i ≥ w`. -/
|
||||
@[inline, expose] def getLsbD (x : BitVec w) (i : Nat) : Bool :=
|
||||
@@ -110,11 +112,11 @@ end getXsb
|
||||
section getElem
|
||||
|
||||
instance : GetElem (BitVec w) Nat Bool fun _ i => i < w where
|
||||
getElem xs i h := xs.getLsb' ⟨i, h⟩
|
||||
getElem xs i h := xs.getLsb ⟨i, h⟩
|
||||
|
||||
/-- We prefer `x[i]` as the simp normal form for `getLsb'` -/
|
||||
@[simp] theorem getLsb'_eq_getElem (x : BitVec w) (i : Fin w) :
|
||||
x.getLsb' i = x[i] := rfl
|
||||
@[simp] theorem getLsb_eq_getElem (x : BitVec w) (i : Fin w) :
|
||||
x.getLsb i = x[i] := rfl
|
||||
|
||||
/-- We prefer `x[i]?` as the simp normal form for `getLsb?` -/
|
||||
@[simp] theorem getLsb?_eq_getElem? (x : BitVec w) (i : Nat) :
|
||||
@@ -174,7 +176,7 @@ recommended_spelling "zero" for "0#n" in [BitVec.ofNat, «term__#__»]
|
||||
recommended_spelling "one" for "1#n" in [BitVec.ofNat, «term__#__»]
|
||||
|
||||
/-- Unexpander for bitvector literals. -/
|
||||
@[app_unexpander BitVec.ofNat] def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
||||
@[app_unexpander BitVec.ofNat] meta def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $n $i:num) => `($i:num#$n)
|
||||
| _ => throw ()
|
||||
|
||||
@@ -183,7 +185,7 @@ scoped syntax:max term:max noWs "#'" noWs term:max : term
|
||||
macro_rules | `($i#'$p) => `(BitVec.ofNatLT $i $p)
|
||||
|
||||
/-- Unexpander for bitvector literals without truncation. -/
|
||||
@[app_unexpander BitVec.ofNatLT] def unexpandBitVecOfNatLt : Lean.PrettyPrinter.Unexpander
|
||||
@[app_unexpander BitVec.ofNatLT] meta def unexpandBitVecOfNatLt : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $i $p) => `($i#'$p)
|
||||
| _ => throw ()
|
||||
|
||||
@@ -723,6 +725,12 @@ def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
|
||||
|
||||
end bitwise
|
||||
|
||||
/-- The bitvector of width `w` that has the smallest value when interpreted as an integer. -/
|
||||
def intMin (w : Nat) := twoPow w (w - 1)
|
||||
|
||||
/-- The bitvector of width `w` that has the largest value when interpreted as an integer. -/
|
||||
def intMax (w : Nat) := (twoPow w (w - 1)) - 1
|
||||
|
||||
/--
|
||||
Computes a hash of a bitvector, combining 64-bit words using `mixHash`.
|
||||
-/
|
||||
@@ -842,4 +850,15 @@ treating `x` and `y` as 2's complement signed bitvectors.
|
||||
def smulOverflow {w : Nat} (x y : BitVec w) : Bool :=
|
||||
(x.toInt * y.toInt ≥ 2 ^ (w - 1)) || (x.toInt * y.toInt < - 2 ^ (w - 1))
|
||||
|
||||
/-- Count the number of leading zeros downward from the `n`-th bit to the `0`-th bit for the bitblaster.
|
||||
This builds a tree of `if-then-else` lookups whose length is linear in the bitwidth,
|
||||
and an efficient circuit for bitblasting `clz`. -/
|
||||
def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
match n with
|
||||
| 0 => if x.getLsbD 0 then BitVec.ofNat w (w - 1) else BitVec.ofNat w w
|
||||
| n' + 1 => if x.getLsbD n then BitVec.ofNat w (w - 1 - n) else clzAuxRec x n'
|
||||
|
||||
/-- Count the number of leading zeros. -/
|
||||
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -6,12 +6,14 @@ Authors: Harun Khan, Abdalrhman M Mohamed, Joe Hendrix, Siddharth Bhat
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.Folds
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
import Init.Data.Nat.Mod
|
||||
import all Init.Data.Int.DivMod
|
||||
import Init.Data.Int.LemmasAux
|
||||
import all Init.Data.BitVec.Lemmas
|
||||
import all Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Decidable
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Folds
|
||||
|
||||
/-!
|
||||
# Bit blasting of bitvectors
|
||||
@@ -238,7 +240,7 @@ theorem toNat_add_of_and_eq_zero {x y : BitVec w} (h : x &&& y = 0#w) :
|
||||
simp only [decide_eq_true_eq] at this
|
||||
omega
|
||||
rw [← carry_width]
|
||||
simp [not_eq_true, carry_of_and_eq_zero h]
|
||||
simp [carry_of_and_eq_zero h]
|
||||
|
||||
/-- Carry function for bitwise addition. -/
|
||||
def adcb (x y c : Bool) : Bool × Bool := (atLeastTwo x y c, x ^^ (y ^^ c))
|
||||
@@ -252,7 +254,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
|
||||
(getLsbD x i ^^ (getLsbD y i ^^ carry i x y c)) := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
let ⟨y, y_lt⟩ := y
|
||||
simp only [getLsbD, toNat_add, toNat_setWidth, i_lt, toNat_ofFin, toNat_ofBool,
|
||||
simp only [getLsbD, toNat_add, toNat_setWidth, toNat_ofFin, toNat_ofBool,
|
||||
Nat.mod_add_mod, Nat.add_mod_mod]
|
||||
apply Eq.trans
|
||||
rw [← Nat.div_add_mod x (2^i), ← Nat.div_add_mod y (2^i)]
|
||||
@@ -295,7 +297,7 @@ theorem adc_spec (x y : BitVec w) (c : Bool) :
|
||||
simp [carry, Nat.mod_one]
|
||||
cases c <;> rfl
|
||||
case step =>
|
||||
simp [adcb, Prod.mk.injEq, carry_succ, getElem_add_add_bool]
|
||||
simp [adcb, carry_succ, getElem_add_add_bool]
|
||||
|
||||
theorem add_eq_adc (w : Nat) (x y : BitVec w) : x + y = (adc x y false).snd := by
|
||||
simp [adc_spec]
|
||||
@@ -312,7 +314,7 @@ theorem msb_add {w : Nat} {x y: BitVec w} :
|
||||
Bool.xor x.msb (Bool.xor y.msb (carry (w - 1) x y false)) := by
|
||||
simp only [BitVec.msb, BitVec.getMsbD]
|
||||
by_cases h : w ≤ 0
|
||||
· simp [h, show w = 0 by omega]
|
||||
· simp [show w = 0 by omega]
|
||||
· rw [getLsbD_add (x := x)]
|
||||
simp [show w > 0 by omega]
|
||||
omega
|
||||
@@ -332,15 +334,15 @@ theorem add_eq_or_of_and_eq_zero {w : Nat} (x y : BitVec w)
|
||||
(h : x &&& y = 0#w) : x + y = x ||| y := by
|
||||
rw [add_eq_adc, adc, iunfoldr_replace (fun _ => false) (x ||| y)]
|
||||
· rfl
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false, getLsbD_or,
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false,
|
||||
Prod.mk.injEq, and_eq_false_imp]
|
||||
intros i
|
||||
replace h : (x &&& y).getLsbD i = (0#w).getLsbD i := by rw [h]
|
||||
simp only [getLsbD_and, getLsbD_zero, and_eq_false_imp] at h
|
||||
constructor
|
||||
· intros hx
|
||||
simp_all [hx]
|
||||
· by_cases hx : x.getLsbD i <;> simp_all [hx]
|
||||
simp_all
|
||||
· by_cases hx : x.getLsbD i <;> simp_all
|
||||
|
||||
/-! ### Sub-/
|
||||
|
||||
@@ -377,7 +379,7 @@ theorem bit_not_add_self (x : BitVec w) :
|
||||
simp only [add_eq_adc]
|
||||
apply iunfoldr_replace_snd (fun _ => false) (-1) false rfl
|
||||
intro i; simp only [adcb, Fin.is_lt, getLsbD_eq_getElem, atLeastTwo_false_right, bne_false,
|
||||
ofNat_eq_ofNat, Fin.getElem_fin, Prod.mk.injEq, and_eq_false_imp]
|
||||
ofNat_eq_ofNat, Prod.mk.injEq, and_eq_false_imp]
|
||||
rw [iunfoldr_replace_snd (fun _ => ()) (((iunfoldr (fun i c => (c, !(x[i.val])))) ()).snd)]
|
||||
<;> simp [bit_not_testBit, neg_one_eq_allOnes, getElem_allOnes]
|
||||
|
||||
@@ -409,7 +411,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
· rw [getLsbD_add hi]
|
||||
have : 0 < w := by omega
|
||||
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
_root_.true_and, not_eq_eq_eq_not]
|
||||
not_eq_eq_eq_not]
|
||||
cases i with
|
||||
| zero =>
|
||||
have carry_zero : carry 0 ?x ?y false = false := by
|
||||
@@ -424,7 +426,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
· rintro h j hj; exact And.right <| h j (by omega)
|
||||
· rintro h j hj; exact ⟨by omega, h j (by omega)⟩
|
||||
· have h_ge : w ≤ i := by omega
|
||||
simp [getLsbD_of_ge _ _ h_ge, h_ge, hi]
|
||||
simp [h_ge, hi]
|
||||
|
||||
theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
(-x)[i] = (x[i] ^^ decide (∃ j < i, x.getLsbD j = true)) := by
|
||||
@@ -433,7 +435,7 @@ theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
getMsbD (-x) i =
|
||||
(getMsbD x i ^^ decide (∃ j < w, i < j ∧ getMsbD x j = true)) := by
|
||||
simp only [getMsbD, getLsbD_neg, Bool.decide_and, Bool.and_eq_true, decide_eq_true_eq]
|
||||
simp only [getMsbD, getLsbD_neg, Bool.and_eq_true, decide_eq_true_eq]
|
||||
by_cases hi : i < w
|
||||
case neg =>
|
||||
simp [hi]; omega
|
||||
@@ -518,14 +520,11 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
rw [(show w = w - 1 + 1 by omega), Int.pow_succ] at this
|
||||
omega
|
||||
|
||||
@[simp] theorem setWidth_neg_of_le {x : BitVec v} (h : w ≤ v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
|
||||
simp [← BitVec.signExtend_eq_setWidth_of_le _ h, BitVec.signExtend_neg_of_le h]
|
||||
|
||||
/-! ### abs -/
|
||||
|
||||
theorem msb_abs {w : Nat} {x : BitVec w} :
|
||||
x.abs.msb = (decide (x = intMin w) && decide (0 < w)) := by
|
||||
simp only [BitVec.abs, getMsbD_neg, ne_eq, decide_not, Bool.not_bne]
|
||||
simp only [BitVec.abs]
|
||||
by_cases h₀ : 0 < w
|
||||
· by_cases h₁ : x = intMin w
|
||||
· simp [h₁, msb_intMin]
|
||||
@@ -548,54 +547,14 @@ theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true :=
|
||||
rw [Nat.mod_eq_of_lt (by omega)]
|
||||
omega
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
simp [BitVec.ule, BitVec.ult, ← decide_not]
|
||||
|
||||
theorem ule_eq_carry (x y : BitVec w) : x.ule y = carry w y (~~~x) true := by
|
||||
simp [ule_eq_not_ult, ult_eq_not_carry]
|
||||
|
||||
/-- If two bitvectors have the same `msb`, then signed and unsigned comparisons coincide -/
|
||||
theorem slt_eq_ult_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) :
|
||||
x.slt y = x.ult y := by
|
||||
simp only [BitVec.slt, toInt_eq_msb_cond, BitVec.ult, decide_eq_decide, h]
|
||||
cases y.msb <;> simp
|
||||
|
||||
/-- If two bitvectors have different `msb`s, then unsigned comparison is determined by this bit -/
|
||||
theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
x.ult y = y.msb := by
|
||||
simp only [BitVec.ult, msb_eq_decide, ne_eq, decide_eq_decide] at *
|
||||
omega
|
||||
|
||||
/-- If two bitvectors have different `msb`s, then signed and unsigned comparisons are opposites -/
|
||||
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
x.slt y = !x.ult y := by
|
||||
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
|
||||
cases y.msb <;> (simp [-Int.natCast_pow]; omega)
|
||||
|
||||
theorem slt_eq_ult {x y : BitVec w} :
|
||||
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
|
||||
by_cases h : x.msb = y.msb
|
||||
· simp [h, slt_eq_ult_of_msb_eq]
|
||||
· have h' : x.msb != y.msb := by simp_all
|
||||
simp [slt_eq_not_ult_of_msb_neq h, h']
|
||||
|
||||
theorem slt_eq_not_carry {x y : BitVec w} :
|
||||
x.slt y = (x.msb == y.msb).xor (carry w x (~~~y) true) := by
|
||||
simp only [slt_eq_ult, bne, ult_eq_not_carry]
|
||||
cases x.msb == y.msb <;> simp
|
||||
|
||||
theorem sle_eq_not_slt {x y : BitVec w} : x.sle y = !y.slt x := by
|
||||
simp only [BitVec.sle, BitVec.slt, ← decide_not, decide_eq_decide]; omega
|
||||
|
||||
theorem zero_sle_eq_not_msb {w : Nat} {x : BitVec w} : BitVec.sle 0#w x = !x.msb := by
|
||||
rw [sle_eq_not_slt, BitVec.slt_zero_eq_msb]
|
||||
|
||||
theorem zero_sle_iff_msb_eq_false {w : Nat} {x : BitVec w} : BitVec.sle 0#w x ↔ x.msb = false := by
|
||||
simp [zero_sle_eq_not_msb]
|
||||
|
||||
theorem toNat_toInt_of_sle {w : Nat} {x : BitVec w} (hx : BitVec.sle 0#w x) : x.toInt.toNat = x.toNat :=
|
||||
toNat_toInt_of_msb x (zero_sle_iff_msb_eq_false.1 hx)
|
||||
|
||||
theorem sle_eq_carry {x y : BitVec w} :
|
||||
x.sle y = !((x.msb == y.msb).xor (carry w y (~~~x) true)) := by
|
||||
rw [sle_eq_not_slt, slt_eq_not_carry, beq_comm]
|
||||
@@ -618,12 +577,6 @@ theorem neg_sle_zero (h : 0 < w) {x : BitVec w} :
|
||||
rw [sle_eq_slt_or_eq, neg_slt_zero h, sle_eq_slt_or_eq]
|
||||
simp [Bool.beq_eq_decide_eq (-x), Bool.beq_eq_decide_eq _ x, Eq.comm (a := x), Bool.or_assoc]
|
||||
|
||||
theorem sle_eq_ule {x y : BitVec w} : x.sle y = (x.msb != y.msb ^^ x.ule y) := by
|
||||
rw [sle_eq_not_slt, slt_eq_ult, ← Bool.xor_not, ← ule_eq_not_ult, bne_comm]
|
||||
|
||||
theorem sle_eq_ule_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) : x.sle y = x.ule y := by
|
||||
simp [BitVec.sle_eq_ule, h]
|
||||
|
||||
/-! ### mul recurrence for bit blasting -/
|
||||
|
||||
/--
|
||||
@@ -658,7 +611,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
getElem_twoPow]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [h]
|
||||
simp
|
||||
· by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
@@ -667,8 +620,8 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
simp [hik', hik'']
|
||||
omega
|
||||
· ext k
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and,
|
||||
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
|
||||
simp only [and_twoPow,
|
||||
]
|
||||
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
|
||||
|
||||
/--
|
||||
@@ -825,7 +778,7 @@ private theorem Nat.div_add_eq_left_of_lt {x y z : Nat} (hx : z ∣ x) (hy : y <
|
||||
· apply Nat.le_trans
|
||||
· exact div_mul_le_self x z
|
||||
· omega
|
||||
· simp only [succ_eq_add_one, Nat.add_mul, Nat.one_mul]
|
||||
· simp only [Nat.add_mul, Nat.one_mul]
|
||||
apply Nat.add_lt_add_of_le_of_lt
|
||||
· apply Nat.le_of_eq
|
||||
exact (Nat.div_eq_iff_eq_mul_left hz hx).mp rfl
|
||||
@@ -938,10 +891,10 @@ def DivModState.lawful_init {w : Nat} (args : DivModArgs w) (hd : 0#w < args.d)
|
||||
hwrn := by simp only; omega,
|
||||
hdPos := by assumption
|
||||
hrLtDivisor := by simp [BitVec.lt_def] at hd ⊢; assumption
|
||||
hrWidth := by simp [DivModState.init],
|
||||
hqWidth := by simp [DivModState.init],
|
||||
hrWidth := by simp,
|
||||
hqWidth := by simp,
|
||||
hdiv := by
|
||||
simp only [DivModState.init, toNat_ofNat, zero_mod, Nat.mul_zero, Nat.add_zero];
|
||||
simp only [toNat_ofNat, zero_mod, Nat.mul_zero, Nat.add_zero];
|
||||
rw [Nat.shiftRight_eq_div_pow]
|
||||
apply Nat.div_eq_of_lt args.n.isLt
|
||||
}
|
||||
@@ -969,7 +922,7 @@ theorem DivModState.umod_eq_of_lawful {qr : DivModState w}
|
||||
n % d = qr.r := by
|
||||
apply umod_eq_of_mul_add_toNat h.hrLtDivisor
|
||||
have hdiv := h.hdiv
|
||||
simp only [shiftRight_zero] at hdiv
|
||||
simp only at hdiv
|
||||
simp only [h_final] at *
|
||||
exact hdiv.symm
|
||||
|
||||
@@ -1023,7 +976,7 @@ theorem DivModState.toNat_shiftRight_sub_one_eq
|
||||
{args : DivModArgs w} {qr : DivModState w} (h : qr.Poised args) :
|
||||
args.n.toNat >>> (qr.wn - 1)
|
||||
= (args.n.toNat >>> qr.wn) * 2 + (args.n.getLsbD (qr.wn - 1)).toNat := by
|
||||
show BitVec.toNat (args.n >>> (qr.wn - 1)) = _
|
||||
change BitVec.toNat (args.n >>> (qr.wn - 1)) = _
|
||||
have {..} := h -- break the structure down for `omega`
|
||||
rw [shiftRight_sub_one_eq_shiftConcat args.n h.hwn_lt]
|
||||
rw [toNat_shiftConcat_eq_of_lt (k := w - qr.wn)]
|
||||
@@ -1047,7 +1000,7 @@ obeys the division equation. -/
|
||||
theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
|
||||
DivModState.Lawful args (divSubtractShift args qr) := by
|
||||
rcases args with ⟨n, d⟩
|
||||
simp only [divSubtractShift, decide_eq_true_eq]
|
||||
simp only [divSubtractShift]
|
||||
-- We add these hypotheses for `omega` to find them later.
|
||||
have ⟨⟨hrwn, hd, hrd, hr, hn, hrnd⟩, hwn_lt⟩ := h
|
||||
have : d.toNat * (qr.q.toNat * 2) = d.toNat * qr.q.toNat * 2 := by rw [Nat.mul_assoc]
|
||||
@@ -1184,7 +1137,7 @@ theorem getLsbD_udiv (n d : BitVec w) (hy : 0#w < d) (i : Nat) :
|
||||
|
||||
theorem getMsbD_udiv (n d : BitVec w) (hd : 0#w < d) (i : Nat) :
|
||||
(n / d).getMsbD i = (decide (i < w) && (divRec w {n, d} (DivModState.init w)).q.getMsbD i) := by
|
||||
simp [getMsbD_eq_getLsbD, getLsbD_udiv, udiv_eq_divRec (by assumption)]
|
||||
simp [getMsbD_eq_getLsbD, udiv_eq_divRec (by assumption)]
|
||||
|
||||
/- ### Arithmetic shift right (sshiftRight) recurrence -/
|
||||
|
||||
@@ -1351,7 +1304,7 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
|
||||
(negOverflow x) = (decide (0 < w) && (x == intMin w)) := by
|
||||
simp only [negOverflow]
|
||||
rcases w with _|w
|
||||
· simp [toInt_of_zero_length, Int.min_eq_right]
|
||||
· simp [toInt_of_zero_length]
|
||||
· suffices - 2 ^ w = (intMin (w + 1)).toInt by simp [beq_eq_decide_eq, ← toInt_inj, this]
|
||||
simp only [toInt_intMin, Nat.add_one_sub_one, Int.natCast_emod, Int.neg_inj]
|
||||
rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
|
||||
@@ -1393,7 +1346,7 @@ theorem umulOverflow_eq {w : Nat} (x y : BitVec w) :
|
||||
(0 < w && BitVec.twoPow (w * 2) w ≤ x.zeroExtend (w * 2) * y.zeroExtend (w * 2)) := by
|
||||
simp only [umulOverflow, toNat_twoPow, le_def, toNat_mul, toNat_setWidth, mod_mul_mod]
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero, toInt_zero, mul_mod_mod]
|
||||
· simp [of_length_zero]
|
||||
· simp only [ge_iff_le, show 0 < w + 1 by omega, decide_true, mul_mod_mod, Bool.true_and,
|
||||
decide_eq_decide]
|
||||
rw [Nat.mod_eq_of_lt BitVec.toNat_mul_toNat_lt, Nat.mod_eq_of_lt]
|
||||
@@ -1629,11 +1582,11 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w ∨ b ≠ -1
|
||||
have := Nat.two_pow_pos (w - 1)
|
||||
|
||||
by_cases hbintMin : b = intMin w
|
||||
· simp only [ne_eq, Decidable.not_not] at hbintMin
|
||||
· simp only at hbintMin
|
||||
subst hbintMin
|
||||
have toIntA_lt := @BitVec.toInt_lt w a; norm_cast at toIntA_lt
|
||||
have le_toIntA := @BitVec.le_toInt w a; norm_cast at le_toIntA
|
||||
simp only [sdiv_intMin, h, ↓reduceIte, toInt_zero, toInt_intMin, wpos,
|
||||
simp only [sdiv_intMin, toInt_intMin, wpos,
|
||||
Nat.two_pow_pred_mod_two_pow, Int.tdiv_neg]
|
||||
· by_cases ha_intMin : a = intMin w
|
||||
· simp only [ha_intMin, ↓reduceIte, show 1 < w by omega, toInt_one, toInt_intMin, wpos,
|
||||
@@ -1709,6 +1662,88 @@ theorem toInt_sdiv (a b : BitVec w) : (a.sdiv b).toInt = (a.toInt.tdiv b.toInt).
|
||||
· rw [← toInt_bmod_cancel]
|
||||
rw [BitVec.toInt_sdiv_of_ne_or_ne _ _ (by simpa only [Decidable.not_and_iff_not_or_not] using h)]
|
||||
|
||||
private theorem neg_udiv_eq_intMin_iff_eq_intMin_eq_one_of_msb_eq_true
|
||||
{x y : BitVec w} (hx : x.msb = true) (hy : y.msb = false) :
|
||||
-x / y = intMin w ↔ (x = intMin w ∧ y = 1#w) := by
|
||||
constructor
|
||||
· intros h
|
||||
rcases w with _ | w; decide +revert
|
||||
have : (-x / y).msb = true := by simp [h, msb_intMin]
|
||||
rw [msb_udiv] at this
|
||||
simp only [bool_to_prop] at this
|
||||
obtain ⟨hx, hy⟩ := this
|
||||
simp only [beq_iff_eq] at hy
|
||||
subst hy
|
||||
simp only [udiv_one, zero_lt_succ, neg_eq_intMin] at h
|
||||
simp [h]
|
||||
· rintro ⟨hx, hy⟩
|
||||
subst hx hy
|
||||
simp
|
||||
|
||||
/--
|
||||
the most significant bit of the signed division `x.sdiv y` can be computed
|
||||
by the following cases:
|
||||
(1) x nonneg, y nonneg: never neg.
|
||||
(2) x nonneg, y neg: neg when result nonzero.
|
||||
We know that y is nonzero since it is negative, so we only check `|x| ≥ |y|`.
|
||||
(3) x neg, y nonneg: neg when result nonzero.
|
||||
We check that `y ≠ 0` and `|x| ≥ |y|`.
|
||||
(4) x neg, y neg: neg when `x = intMin, `y = -1`, since `intMin / -1 = intMin`.
|
||||
|
||||
The proof strategy is to perform a case analysis on the sign of `x` and `y`,
|
||||
followed by unfolding the `sdiv` into `udiv`.
|
||||
-/
|
||||
theorem msb_sdiv_eq_decide {x y : BitVec w} :
|
||||
(x.sdiv y).msb = (decide (0 < w) &&
|
||||
(!x.msb && y.msb && decide (-y ≤ x)) ||
|
||||
(x.msb && !y.msb && decide (y ≤ -x) && !decide (y = 0#w)) ||
|
||||
(x.msb && y.msb && decide (x = intMin w) && decide (y = -1#w)))
|
||||
:= by
|
||||
rcases w; decide +revert
|
||||
case succ w =>
|
||||
simp only [decide_true, ne_eq, decide_and, decide_not, Bool.true_and,
|
||||
sdiv_eq, udiv_eq]
|
||||
rcases hxmsb : x.msb <;> rcases hymsb : y.msb
|
||||
· simp [hxmsb, hymsb, msb_udiv_eq_false_of, Bool.not_false, Bool.and_false, Bool.false_and,
|
||||
Bool.and_true, Bool.or_self, Bool.and_self]
|
||||
· simp only [hxmsb, hymsb, msb_neg, msb_udiv_eq_false_of, bne_false, Bool.not_false,
|
||||
Bool.and_self, ne_zero_of_msb_true, decide_false, Bool.and_true, Bool.true_and, Bool.not_true,
|
||||
Bool.false_and, Bool.or_false, bool_to_prop]
|
||||
have : x / -y ≠ intMin (w + 1) := by
|
||||
intros h
|
||||
have : (x / -y).msb = (intMin (w + 1)).msb := by simp only [h]
|
||||
simp only [msb_udiv, msb_intMin, show 0 < w + 1 by omega, decide_true, and_eq_true, beq_iff_eq] at this
|
||||
obtain ⟨hcontra, _⟩ := this
|
||||
simp only [hcontra, true_eq_false] at hxmsb
|
||||
simp [this, hymsb, udiv_ne_zero_iff_ne_zero_and_le]
|
||||
· simp only [hxmsb, hymsb, Bool.not_true, Bool.and_self, Bool.false_and, Bool.not_false,
|
||||
Bool.true_and, Bool.false_or, Bool.and_false, Bool.or_false]
|
||||
by_cases hx₁ : x = 0#(w + 1)
|
||||
· simp [hx₁, neg_zero, zero_udiv, msb_zero, le_zero_iff, Bool.and_not_self]
|
||||
· by_cases hy₁ : y = 0#(w + 1)
|
||||
· simp [hy₁, udiv_zero, neg_zero, msb_zero, decide_true, Bool.not_true, Bool.and_false]
|
||||
· simp only [hy₁, decide_false, Bool.not_false, Bool.and_true]
|
||||
by_cases hxy₁ : (- x / y) = 0#(w + 1)
|
||||
· simp only [hxy₁, neg_zero, msb_zero, false_eq_decide_iff, BitVec.not_le,
|
||||
decide_eq_true_eq, BitVec.not_le]
|
||||
simp only [udiv_eq_zero_iff_eq_zero_or_lt, hy₁, _root_.false_or] at hxy₁
|
||||
bv_omega
|
||||
· simp only [udiv_eq_zero_iff_eq_zero_or_lt, _root_.not_or, BitVec.not_lt,
|
||||
hy₁, not_false_eq_true, _root_.true_and] at hxy₁
|
||||
simp only [hxy₁, decide_true, msb_neg, bne_iff_ne, ne_eq,
|
||||
bool_to_prop,
|
||||
bne_iff_ne, ne_eq, udiv_eq_zero_iff_eq_zero_or_lt, hy₁, _root_.false_or,
|
||||
BitVec.not_lt, hxy₁, _root_.true_and, decide_not, not_eq_eq_eq_not, not_eq_not,
|
||||
msb_udiv, msb_neg]
|
||||
simp only [hx₁, not_false_eq_true, _root_.true_and, decide_not, hxmsb, not_eq_eq_eq_not,
|
||||
Bool.not_true, decide_eq_false_iff_not, Decidable.not_not, beq_iff_eq]
|
||||
rw [neg_udiv_eq_intMin_iff_eq_intMin_eq_one_of_msb_eq_true hxmsb hymsb]
|
||||
· simp only [msb_udiv, msb_neg, hxmsb, bne_true, Bool.not_and, Bool.not_true, Bool.and_true,
|
||||
Bool.false_and, Bool.and_false, hymsb, ne_zero_of_msb_true, decide_false, Bool.not_false,
|
||||
Bool.or_self, Bool.and_self, Bool.true_and, Bool.false_or]
|
||||
simp only [bool_to_prop]
|
||||
simp [BitVec.ne_zero_of_msb_true (x := x) hxmsb, neg_eq_iff_eq_neg]
|
||||
|
||||
theorem msb_umod_eq_false_of_left {x : BitVec w} (hx : x.msb = false) (y : BitVec w) : (x % y).msb = false := by
|
||||
rw [msb_eq_false_iff_two_mul_lt] at hx ⊢
|
||||
rw [toNat_umod]
|
||||
@@ -1728,7 +1763,7 @@ theorem msb_umod_of_le_of_ne_zero_of_le {x y : BitVec w}
|
||||
theorem toInt_srem (x y : BitVec w) : (x.srem y).toInt = x.toInt.tmod y.toInt := by
|
||||
rw [srem_eq]
|
||||
by_cases hyz : y = 0#w
|
||||
· simp only [hyz, ofNat_eq_ofNat, msb_zero, umod_zero, neg_zero, neg_neg, toInt_zero, Int.tmod_zero]
|
||||
· simp only [hyz, msb_zero, umod_zero, neg_zero, neg_neg, toInt_zero, Int.tmod_zero]
|
||||
cases x.msb <;> rfl
|
||||
cases h : x.msb
|
||||
· cases h' : y.msb
|
||||
@@ -1807,7 +1842,7 @@ theorem toInt_umod_neg_add {x y : BitVec w} (hymsb : y.msb = true) (hxmsb : x.ms
|
||||
have hylt : (-y).toNat ≤ 2 ^ (w) := toNat_neg_lt_of_msb y hymsb
|
||||
have hmodlt := Nat.mod_lt x.toNat (y := (-y).toNat)
|
||||
(by rw [toNat_neg, Nat.mod_eq_of_lt (by omega)]; omega)
|
||||
simp only [hdvd, reduceIte, toInt_add, hxnonneg, show ¬0 ≤ y.toInt by omega]
|
||||
simp only [toInt_add]
|
||||
rw [toInt_umod, toInt_eq_neg_toNat_neg_of_msb_true hymsb, Int.bmod_add_bmod,
|
||||
Int.bmod_eq_of_le (by omega) (by omega),
|
||||
toInt_eq_toNat_of_msb hxmsb, Int.emod_neg]
|
||||
@@ -1822,7 +1857,7 @@ theorem toInt_sub_neg_umod {x y : BitVec w} (hxmsb : x.msb = true) (hymsb : y.ms
|
||||
· subst hyzero; simp
|
||||
· simp only [toNat_eq, toNat_ofNat, zero_mod] at hyzero
|
||||
have hypos : 0 < y.toNat := by omega
|
||||
simp only [reduceIte, toInt_sub, toInt_eq_toNat_of_msb hymsb, toInt_umod,
|
||||
simp only [toInt_sub, toInt_eq_toNat_of_msb hymsb, toInt_umod,
|
||||
Int.sub_bmod_bmod, toInt_eq_neg_toNat_neg_of_msb_true hxmsb, Int.neg_emod]
|
||||
have hmodlt := Nat.mod_lt (x := (-x).toNat) (y := y.toNat) hypos
|
||||
rw [Int.bmod_eq_of_le (by omega) (by omega)]
|
||||
@@ -1860,7 +1895,7 @@ theorem toInt_smod {x y : BitVec w} :
|
||||
· simp [show ¬-x % y = 0#(w + 1) by simp_all, toInt_sub_neg_umod hxmsb hymsb hx_dvd_y]
|
||||
· rw [←Int.neg_inj, neg_toInt_neg_umod_eq_of_msb_true_msb_true hxmsb hymsb]
|
||||
simp [BitVec.toInt_eq_neg_toNat_neg_of_msb_true, hxmsb, hymsb,
|
||||
Int.fmod_eq_emod_of_nonneg _, show 0 ≤ (-y).toNat by omega]
|
||||
Int.fmod_eq_emod_of_nonneg _]
|
||||
|
||||
/-! ### Lemmas that use bit blasting circuits -/
|
||||
|
||||
@@ -1894,7 +1929,7 @@ theorem carry_extractLsb'_eq_carry {w i len : Nat} (hi : i < len)
|
||||
{x y : BitVec w} {b : Bool}:
|
||||
(carry i (extractLsb' 0 len x) (extractLsb' 0 len y) b)
|
||||
= (carry i x y b) := by
|
||||
simp only [carry, extractLsb'_toNat, shiftRight_zero, toNat_false, Nat.add_zero, ge_iff_le,
|
||||
simp only [carry, extractLsb'_toNat, shiftRight_zero, ge_iff_le,
|
||||
decide_eq_decide]
|
||||
have : 2 ^ i ∣ 2^len := by
|
||||
apply Nat.pow_dvd_pow
|
||||
|
||||
146
src/Init/Data/BitVec/Bootstrap.lean
Normal file
146
src/Init/Data/BitVec/Bootstrap.lean
Normal file
@@ -0,0 +1,146 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth Bhat
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import all Init.Data.BitVec.Basic
|
||||
|
||||
namespace BitVec
|
||||
|
||||
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
|
||||
@[simp] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
simp only [getLsbD_ofFin]
|
||||
apply Nat.testBit_lt_two_pow
|
||||
have p : 2^w ≤ 2^i := Nat.pow_le_pow_right (by omega) ge
|
||||
omega
|
||||
|
||||
/-- Prove equality of bitvectors in terms of nat operations. -/
|
||||
theorem eq_of_toNat_eq {n} : ∀ {x y : BitVec n}, x.toNat = y.toNat → x = y
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
theorem eq_of_getLsbD_eq {x y : BitVec w}
|
||||
(pred : ∀ i, i < w → x.getLsbD i = y.getLsbD i) : x = y := by
|
||||
apply eq_of_toNat_eq
|
||||
apply Nat.eq_of_testBit_eq
|
||||
intro i
|
||||
if i_lt : i < w then
|
||||
exact pred i i_lt
|
||||
else
|
||||
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
||||
simp [testBit_toNat, getLsbD_of_ge _ _ p]
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_ofNat (x w : Nat) : (BitVec.ofNat w x).toNat = x % 2^w := by
|
||||
simp [BitVec.toNat, BitVec.ofNat, Fin.ofNat]
|
||||
|
||||
@[ext] theorem eq_of_getElem_eq {x y : BitVec n} :
|
||||
(∀ i (hi : i < n), x[i] = y[i]) → x = y :=
|
||||
fun h => BitVec.eq_of_getLsbD_eq (h ↑·)
|
||||
|
||||
@[simp] theorem toNat_append (x : BitVec m) (y : BitVec n) :
|
||||
(x ++ y).toNat = x.toNat <<< n ||| y.toNat :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_cast (h : w = v) (x : BitVec w) : (x.cast h).toNat = x.toNat := rfl
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_ofFin (x : Fin (2^n)) : (BitVec.ofFin x).toNat = x.val := rfl
|
||||
|
||||
@[simp] theorem toNat_ofNatLT (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||||
|
||||
@[simp] theorem toNat_cons (b : Bool) (x : BitVec w) :
|
||||
(cons b x).toNat = (b.toNat <<< w) ||| x.toNat := by
|
||||
let ⟨x, _⟩ := x
|
||||
simp only [cons, toNat_cast, toNat_append, toNat_ofBool, toNat_ofFin]
|
||||
|
||||
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||||
(cons b x)[i] = if h : i = n then b else x[i] := by
|
||||
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or]
|
||||
rw [Nat.testBit_shiftLeft]
|
||||
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
|
||||
· have p1 : ¬(n ≤ i) := by omega
|
||||
have p2 : i ≠ n := by omega
|
||||
simp [p1, p2]
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
|
||||
Bool.true_and, testBit_toNat, getLsbD_of_ge, Bool.or_false]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
have p2 : i - n ≠ 0 := by omega
|
||||
simp [p1, p2, Nat.testBit_bool_to_nat]
|
||||
|
||||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_right (by trivial : 0 < 2) le)
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
(setWidth' p x).toNat = x.toNat := by
|
||||
simp only [setWidth', toNat_ofNatLT]
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_setWidth (i : Nat) (x : BitVec n) :
|
||||
BitVec.toNat (setWidth i x) = x.toNat % 2^i := by
|
||||
let ⟨x, lt_n⟩ := x
|
||||
simp only [setWidth]
|
||||
if n_le_i : n ≤ i then
|
||||
have x_lt_two_i : x < 2 ^ i := lt_two_pow_of_le lt_n n_le_i
|
||||
simp [n_le_i, Nat.mod_eq_of_lt, x_lt_two_i]
|
||||
else
|
||||
simp [n_le_i, toNat_ofNat]
|
||||
|
||||
@[simp] theorem ofNat_toNat (m : Nat) (x : BitVec n) : BitVec.ofNat m x.toNat = setWidth m x := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_ofNat, toNat_setWidth]
|
||||
|
||||
theorem getElem_setWidth' (x : BitVec w) (i : Nat) (h : w ≤ v) (hi : i < v) :
|
||||
(setWidth' h x)[i] = x.getLsbD i := by
|
||||
rw [getElem_eq_testBit_toNat, toNat_setWidth', getLsbD]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_setWidth (m : Nat) (x : BitVec n) (i : Nat) (h : i < m) :
|
||||
(setWidth m x)[i] = x.getLsbD i := by
|
||||
rw [setWidth]
|
||||
split
|
||||
· rw [getElem_setWidth']
|
||||
· simp only [ofNat_toNat, getElem_eq_testBit_toNat, toNat_setWidth, Nat.testBit_mod_two_pow,
|
||||
getLsbD, Bool.and_eq_right_iff_imp, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
||||
ext i
|
||||
simp only [getElem_cons]
|
||||
split <;> rename_i h
|
||||
· simp [BitVec.msb, getMsbD, h]
|
||||
· by_cases h' : i < w
|
||||
· simp_all only [getElem_setWidth, getLsbD_eq_getElem]
|
||||
· omega
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_neg (x : BitVec n) : (- x).toNat = (2^n - x.toNat) % 2^n := by
|
||||
simp [Neg.neg, BitVec.neg]
|
||||
|
||||
@[simp] theorem setWidth_neg_of_le {x : BitVec v} (h : w ≤ v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
simp only [toNat_setWidth, toNat_neg]
|
||||
rw [Nat.mod_mod_of_dvd _ (Nat.pow_dvd_pow 2 h)]
|
||||
rw [Nat.mod_eq_mod_iff]
|
||||
rw [Nat.mod_def]
|
||||
refine ⟨1 + x.toNat / 2^w, 2^(v-w), ?_⟩
|
||||
rw [← Nat.pow_add]
|
||||
have : v - w + w = v := by omega
|
||||
rw [this]
|
||||
rw [Nat.add_mul, Nat.one_mul, Nat.mul_comm (2^w)]
|
||||
have sub_sub : ∀ (a : Nat) {b c : Nat} (h : c ≤ b), a - (b - c) = a + c - b := by omega
|
||||
rw [sub_sub _ (Nat.div_mul_le_self x.toNat (2 ^ w))]
|
||||
have : x.toNat / 2 ^ w * 2 ^ w ≤ x.toNat := Nat.div_mul_le_self x.toNat (2 ^ w)
|
||||
have : x.toNat < 2 ^w ∨ x.toNat - 2 ^ w < x.toNat / 2 ^ w * 2 ^ w := by
|
||||
have := Nat.lt_div_mul_add (a := x.toNat) (b := 2 ^ w) (Nat.two_pow_pos w)
|
||||
omega
|
||||
omega
|
||||
|
||||
end BitVec
|
||||
79
src/Init/Data/BitVec/Decidable.lean
Normal file
79
src/Init/Data/BitVec/Decidable.lean
Normal file
@@ -0,0 +1,79 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth Bhat
|
||||
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace BitVec
|
||||
|
||||
/-! ### Decidable quantifiers -/
|
||||
|
||||
theorem forall_zero_iff {P : BitVec 0 → Prop} :
|
||||
(∀ v, P v) ↔ P 0#0 := by
|
||||
constructor
|
||||
· intro h
|
||||
apply h
|
||||
· intro h v
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
apply h
|
||||
|
||||
theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
||||
(∀ v : BitVec (n + 1), P v) ↔ (∀ (x : Bool) (v : BitVec n), P (v.cons x)) := by
|
||||
constructor
|
||||
· intro h _ _
|
||||
apply h
|
||||
· intro h v
|
||||
have w : v = (v.setWidth n).cons v.msb := by simp only [cons_msb_setWidth]
|
||||
rw [w]
|
||||
apply h
|
||||
|
||||
instance instDecidableForallBitVecZero (P : BitVec 0 → Prop) :
|
||||
∀ [Decidable (P 0#0)], Decidable (∀ v, P v)
|
||||
| .isTrue h => .isTrue fun v => by
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
exact h
|
||||
| .isFalse h => .isFalse (fun w => h (w _))
|
||||
|
||||
instance instDecidableForallBitVecSucc (P : BitVec (n+1) → Prop) [DecidablePred P]
|
||||
[Decidable (∀ (x : Bool) (v : BitVec n), P (v.cons x))] : Decidable (∀ v, P v) :=
|
||||
decidable_of_iff' (∀ x (v : BitVec n), P (v.cons x)) forall_cons_iff
|
||||
|
||||
instance instDecidableExistsBitVecZero (P : BitVec 0 → Prop) [Decidable (P 0#0)] :
|
||||
Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
|
||||
instance instDecidableExistsBitVecSucc (P : BitVec (n+1) → Prop) [DecidablePred P]
|
||||
[Decidable (∀ (x : Bool) (v : BitVec n), ¬ P (v.cons x))] : Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
|
||||
/--
|
||||
For small numerals this isn't necessary (as typeclass search can use the above two instances),
|
||||
but for large numerals this provides a shortcut.
|
||||
Note, however, that for large numerals the decision procedure may be very slow,
|
||||
and you should use `bv_decide` if possible.
|
||||
-/
|
||||
instance instDecidableForallBitVec :
|
||||
∀ (n : Nat) (P : BitVec n → Prop) [DecidablePred P], Decidable (∀ v, P v)
|
||||
| 0, _, _ => inferInstance
|
||||
| n + 1, _, _ =>
|
||||
have := instDecidableForallBitVec n
|
||||
inferInstance
|
||||
|
||||
/--
|
||||
For small numerals this isn't necessary (as typeclass search can use the above two instances),
|
||||
but for large numerals this provides a shortcut.
|
||||
Note, however, that for large numerals the decision procedure may be very slow.
|
||||
-/
|
||||
instance instDecidableExistsBitVec :
|
||||
∀ (n : Nat) (P : BitVec n → Prop) [DecidablePred P], Decidable (∃ v, P v)
|
||||
| 0, _, _ => inferInstance
|
||||
| _ + 1, _, _ => inferInstance
|
||||
|
||||
end BitVec
|
||||
@@ -82,9 +82,9 @@ theorem iunfoldr_getLsbD' {f : Fin w → α → α × Bool} (state : Nat → α)
|
||||
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
|
||||
| inl h3 => simp [if_neg, (Nat.ne_of_lt h3)]
|
||||
| inl h3 => simp [(Nat.ne_of_lt h3)]
|
||||
exact (ih hj2).1 ⟨i.val, h3⟩
|
||||
| inr h3 => simp [h3, if_pos]
|
||||
| inr h3 => simp [h3]
|
||||
cases (Nat.eq_zero_or_pos j.val) with
|
||||
| inl hj3 => congr
|
||||
rw [← (ih hj2).2]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -488,7 +488,7 @@ Converts `true` to `1` and `false` to `0`.
|
||||
|
||||
@[simp] theorem ite_eq_true_else_eq_false {q : Prop} :
|
||||
(if b = true then q else b = false) ↔ (b = true → q) := by
|
||||
cases b <;> simp [not_eq_self]
|
||||
cases b <;> simp
|
||||
|
||||
/-
|
||||
`not_ite_eq_true_eq_true` and related theorems below are added for
|
||||
|
||||
@@ -183,10 +183,7 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
|
||||
| zero =>
|
||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
congr
|
||||
try -- TODO: block can be deleted after bootstrapping
|
||||
funext
|
||||
simp [foldrM_loop_zero]
|
||||
rfl
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
@@ -255,7 +252,7 @@ theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) :
|
||||
foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by
|
||||
rw [foldl_succ]
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldl_succ, Fin.last]
|
||||
| zero => simp [Fin.last]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp
|
||||
|
||||
theorem foldl_add (f : α → Fin (n + m) → α) (x) :
|
||||
|
||||
@@ -102,9 +102,30 @@ theorem dite_val {n : Nat} {c : Prop} [Decidable c] {x y : Fin n} :
|
||||
(if c then x else y).val = if c then x.val else y.val := by
|
||||
by_cases c <;> simp [*]
|
||||
|
||||
instance (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
namespace NatCast
|
||||
|
||||
/--
|
||||
This is not a global instance, but may be activated locally via `open Fin.NatCast in ...`.
|
||||
|
||||
This is not an instance because the `binop%` elaborator assumes that
|
||||
there are no non-trivial coercion loops,
|
||||
but this introduces a coercion from `Nat` to `Fin n` and back.
|
||||
|
||||
Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
|
||||
For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
|
||||
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
|
||||
-/
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
natCast a := Fin.ofNat n a
|
||||
|
||||
attribute [scoped instance] instNatCast
|
||||
|
||||
end NatCast
|
||||
|
||||
@[expose]
|
||||
def intCast [NeZero n] (a : Int) : Fin n :=
|
||||
if 0 ≤ a then
|
||||
@@ -112,9 +133,22 @@ def intCast [NeZero n] (a : Int) : Fin n :=
|
||||
else
|
||||
- Fin.ofNat n a.natAbs
|
||||
|
||||
instance (n : Nat) [NeZero n] : IntCast (Fin n) where
|
||||
namespace IntCast
|
||||
|
||||
/--
|
||||
This is not a global instance, but may be activated locally via `open Fin.IntCast in ...`.
|
||||
|
||||
See the doc-string for `Fin.NatCast.instNatCast` for more details.
|
||||
-/
|
||||
@[expose]
|
||||
def instIntCast (n : Nat) [NeZero n] : IntCast (Fin n) where
|
||||
intCast := Fin.intCast
|
||||
|
||||
attribute [scoped instance] instIntCast
|
||||
|
||||
end IntCast
|
||||
|
||||
open IntCast in
|
||||
theorem intCast_def {n : Nat} [NeZero n] (x : Int) :
|
||||
(x : Fin n) = if 0 ≤ x then Fin.ofNat n x.natAbs else -Fin.ofNat n x.natAbs := rfl
|
||||
|
||||
@@ -347,7 +381,7 @@ theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt one_pos
|
||||
@[simp] theorem val_succ (j : Fin n) : (j.succ : Nat) = j + 1 := rfl
|
||||
|
||||
@[simp] theorem succ_pos (a : Fin n) : (0 : Fin (n + 1)) < a.succ := by
|
||||
simp [Fin.lt_def, Nat.succ_pos]
|
||||
simp [Fin.lt_def]
|
||||
|
||||
@[simp] theorem succ_le_succ_iff {a b : Fin n} : a.succ ≤ b.succ ↔ a ≤ b := Nat.succ_le_succ_iff
|
||||
|
||||
@@ -380,7 +414,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
||||
simp only [lt_def, val_add, val_last, Fin.ext_iff]
|
||||
let ⟨k, hk⟩ := k
|
||||
match Nat.eq_or_lt_of_le (Nat.le_of_lt_succ hk) with
|
||||
| .inl h => cases h; simp [Nat.succ_pos]
|
||||
| .inl h => cases h; simp
|
||||
| .inr hk' => simp [Nat.ne_of_lt hk', Nat.mod_eq_of_lt (Nat.succ_lt_succ hk'), Nat.le_succ]
|
||||
|
||||
@[simp] theorem add_one_le_iff {n : Nat} : ∀ {k : Fin (n + 1)}, k + 1 ≤ k ↔ k = last _ := by
|
||||
@@ -392,7 +426,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
||||
intro (k : Fin (n+2))
|
||||
rw [← add_one_lt_iff, lt_def, le_def, Nat.lt_iff_le_and_ne, and_iff_left]
|
||||
rw [val_add_one]
|
||||
split <;> simp [*, (Nat.succ_ne_zero _).symm, Nat.ne_of_gt (Nat.lt_succ_self _)]
|
||||
split <;> simp [*, Nat.ne_of_gt (Nat.lt_succ_self _)]
|
||||
|
||||
@[simp] theorem last_le_iff {n : Nat} {k : Fin (n + 1)} : last n ≤ k ↔ k = last n := by
|
||||
rw [Fin.ext_iff, Nat.le_antisymm_iff, le_def, and_iff_right (by apply le_last)]
|
||||
@@ -704,7 +738,7 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
||||
∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
|
||||
| ⟨0, _⟩, _, ha, _ => by simp only [mk_zero, ne_eq, not_true] at ha
|
||||
| ⟨i + 1, _⟩, ⟨0, _⟩, _, hb => by simp only [mk_zero, ne_eq, not_true] at hb
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [Fin.ext_iff, Nat.succ.injEq]
|
||||
| ⟨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
|
||||
@@ -1045,6 +1079,17 @@ theorem val_neg {n : Nat} [NeZero n] (x : Fin n) :
|
||||
have := Fin.val_ne_zero_iff.mpr h
|
||||
omega
|
||||
|
||||
protected theorem sub_eq_add_neg {n : Nat} (x y : Fin n) : x - y = x + -y := by
|
||||
by_cases h : n = 0
|
||||
· subst h
|
||||
apply elim0 x
|
||||
· replace h : NeZero n := ⟨h⟩
|
||||
ext
|
||||
rw [Fin.coe_sub, Fin.val_add, val_neg]
|
||||
split
|
||||
· simp_all
|
||||
· simp [Nat.add_comm]
|
||||
|
||||
/-! ### mul -/
|
||||
|
||||
theorem ofNat_mul [NeZero n] (x : Nat) (y : Fin n) :
|
||||
@@ -1072,7 +1117,7 @@ protected theorem mul_one [i : NeZero n] (k : Fin n) : k * 1 = k := by
|
||||
| n + 1, _ =>
|
||||
match n with
|
||||
| 0 => exact Subsingleton.elim (α := Fin 1) ..
|
||||
| n+1 => simp [Fin.ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
||||
| n+1 => simp [mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
||||
|
||||
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
|
||||
Fin.ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
||||
|
||||
@@ -31,19 +31,19 @@ Examples:
|
||||
@[inline, expose]
|
||||
def uncurry : (α → β → φ) → α × β → φ := fun f a => f a.1 a.2
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem curry_uncurry (f : α → β → φ) : curry (uncurry f) = f :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem uncurry_curry (f : α × β → φ) : uncurry (curry f) = f :=
|
||||
funext fun ⟨_a, _b⟩ => rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem uncurry_apply_pair {α β γ} (f : α → β → γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f x y = f (x, y) :=
|
||||
rfl
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ theorem compare_eq_ite_le (a b : Int) :
|
||||
· next hlt => simp [Int.le_of_lt hlt, Int.not_le.2 hlt]
|
||||
· next hge =>
|
||||
split
|
||||
· next hgt => simp [Int.le_of_lt hgt, Int.not_le.2 hgt]
|
||||
· next hgt => simp [Int.not_le.2 hgt]
|
||||
· next hle => simp [Int.not_lt.1 hge, Int.not_lt.1 hle]
|
||||
|
||||
protected theorem compare_swap (a b : Int) : (compare a b).swap = compare b a := by
|
||||
|
||||
@@ -3,7 +3,6 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Jeremy Avigad, Mario Carneiro
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
@@ -57,7 +56,7 @@ protected theorem dvd_trans : ∀ {a b c : Int}, a ∣ b → b ∣ c → a ∣ c
|
||||
|
||||
@[simp] protected theorem dvd_neg {a b : Int} : a ∣ -b ↔ a ∣ b := by
|
||||
constructor <;> exact fun ⟨k, e⟩ =>
|
||||
⟨-k, by simp [← e, Int.neg_mul, Int.mul_neg, Int.neg_neg]⟩
|
||||
⟨-k, by simp [← e, Int.mul_neg, Int.neg_neg]⟩
|
||||
|
||||
@[simp] theorem natAbs_dvd_natAbs {a b : Int} : natAbs a ∣ natAbs b ↔ a ∣ b := by
|
||||
refine ⟨fun ⟨k, hk⟩ => ?_, fun ⟨k, hk⟩ => ⟨natAbs k, hk.symm ▸ natAbs_mul a k⟩⟩
|
||||
@@ -99,7 +98,7 @@ theorem ofNat_emod (m n : Nat) : (↑(m % n) : Int) = m % n := natCast_emod m n
|
||||
theorem emod_add_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| ofNat m, -[n+1] => by
|
||||
show (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
rw [Int.neg_mul_neg]; exact congrArg ofNat <| Nat.mod_add_div ..
|
||||
| -[_+1], 0 => by rw [emod_zero]; rfl
|
||||
| -[m+1], succ n => aux m n.succ
|
||||
@@ -149,7 +148,7 @@ theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c
|
||||
fun {k n} => @fun
|
||||
| ofNat _ => congrArg ofNat <| Nat.add_mul_div_right _ _ k.succ_pos
|
||||
| -[m+1] => by
|
||||
show ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
|
||||
change ((n * k.succ : Nat) - m.succ : Int).ediv k.succ = n - (m / k.succ + 1 : Nat)
|
||||
by_cases h : m < n * k.succ
|
||||
· rw [← Int.ofNat_sub h, ← Int.ofNat_sub ((Nat.div_lt_iff_lt_mul k.succ_pos).2 h)]
|
||||
apply congrArg ofNat
|
||||
@@ -158,7 +157,7 @@ theorem add_mul_ediv_right (a b : Int) {c : Int} (H : c ≠ 0) : (a + b * c) / c
|
||||
have H {a b : Nat} (h : a ≤ b) : (a : Int) + -((b : Int) + 1) = -[b - a +1] := by
|
||||
rw [negSucc_eq, Int.ofNat_sub h]
|
||||
simp only [Int.sub_eq_add_neg, Int.neg_add, Int.neg_neg, Int.add_left_comm, Int.add_assoc]
|
||||
show ediv (↑(n * succ k) + -((m : Int) + 1)) (succ k) = n + -(↑(m / succ k) + 1 : Int)
|
||||
change ediv (↑(n * succ k) + -((m : Int) + 1)) (succ k) = n + -(↑(m / succ k) + 1 : Int)
|
||||
rw [H h, H ((Nat.le_div_iff_mul_le k.succ_pos).2 h)]
|
||||
apply congrArg negSucc
|
||||
rw [Nat.mul_comm, Nat.sub_mul_div_of_le]; rwa [Nat.mul_comm]
|
||||
|
||||
@@ -3,7 +3,6 @@ Copyright (c) 2016 Jeremy Avigad. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Jeremy Avigad, Mario Carneiro, Kim Morrison, Markus Himmel
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
@@ -203,6 +202,9 @@ theorem tdiv_eq_ediv_of_nonneg : ∀ {a b : Int}, 0 ≤ a → a.tdiv b = a / b
|
||||
| succ _, succ _, _ => rfl
|
||||
| succ _, -[_+1], _ => rfl
|
||||
|
||||
@[simp] theorem natCast_tdiv_eq_ediv {a : Nat} {b : Int} : (a : Int).tdiv b = a / b :=
|
||||
tdiv_eq_ediv_of_nonneg (by simp)
|
||||
|
||||
theorem tdiv_eq_ediv {a b : Int} :
|
||||
a.tdiv b = a / b + if 0 ≤ a ∨ b ∣ a then 0 else sign b := by
|
||||
simp only [dvd_iff_emod_eq_zero]
|
||||
@@ -215,7 +217,7 @@ theorem tdiv_eq_ediv {a b : Int} :
|
||||
negSucc_not_nonneg, sign_of_add_one]
|
||||
simp only [negSucc_emod_ofNat_succ_eq_zero_iff]
|
||||
norm_cast
|
||||
simp only [subNat_eq_zero_iff, Nat.succ_eq_add_one, sign_negSucc, Int.sub_neg, false_or]
|
||||
simp only [Nat.succ_eq_add_one, false_or]
|
||||
split <;> rename_i h
|
||||
· rw [Int.add_zero, neg_ofNat_eq_negSucc_iff]
|
||||
exact Nat.succ_div_of_mod_eq_zero h
|
||||
@@ -329,17 +331,17 @@ theorem fdiv_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.fdiv b = a / b := by
|
||||
theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
show (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
rw [Int.neg_mul_neg]; exact congrArg ofNat (Nat.mod_add_div ..)
|
||||
| -[m+1], 0 => by
|
||||
show -(↑((succ m) % 0) : Int) + 0 * -↑(succ m / 0) = -↑(succ m)
|
||||
change -(↑((succ m) % 0) : Int) + 0 * -↑(succ m / 0) = -↑(succ m)
|
||||
rw [Nat.mod_zero, Int.zero_mul, Int.add_zero]
|
||||
| -[m+1], ofNat n => by
|
||||
show -(↑((succ m) % n) : Int) + ↑n * -↑(succ m / n) = -↑(succ m)
|
||||
change -(↑((succ m) % n) : Int) + ↑n * -↑(succ m / n) = -↑(succ m)
|
||||
rw [Int.mul_neg, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n) * ↑(succ m / succ n) = -↑(succ m)
|
||||
change -(↑(succ m % succ n) : Int) + -↑(succ n) * ↑(succ m / succ n) = -↑(succ m)
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
@@ -361,17 +363,17 @@ theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
show subNatNat (m % succ n) n + (↑(succ n * (m / succ n)) + n + 1) = (m + 1)
|
||||
change subNatNat (m % succ n) n + (↑(succ n * (m / succ n)) + n + 1) = (m + 1)
|
||||
rw [Int.add_comm _ n, ← Int.add_assoc, ← Int.add_assoc,
|
||||
Int.subNatNat_eq_coe, Int.sub_add_cancel]
|
||||
exact congrArg (ofNat · + 1) <| Nat.mod_add_div ..
|
||||
| -[_+1], 0 => by rw [fmod_zero]; rfl
|
||||
| -[m+1], succ n => by
|
||||
show subNatNat .. - (↑(succ n * (m / succ n)) + ↑(succ n)) = -↑(succ m)
|
||||
change subNatNat .. - (↑(succ n * (m / succ n)) + ↑(succ n)) = -↑(succ m)
|
||||
rw [Int.subNatNat_eq_coe, ← Int.sub_sub, ← Int.neg_sub, Int.sub_sub, Int.sub_sub_self]
|
||||
exact congrArg (-ofNat ·) <| Nat.succ_add .. ▸ Nat.mod_add_div .. ▸ rfl
|
||||
| -[m+1], -[n+1] => by
|
||||
show -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
change -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
/-- Variant of `fmod_add_fdiv` with the multiplication written the other way around. -/
|
||||
@@ -572,7 +574,7 @@ theorem neg_one_ediv (b : Int) : -1 / b = -b.sign :=
|
||||
· refine Nat.le_trans ?_ (Nat.le_add_right _ _)
|
||||
rw [← Nat.mul_div_mul_left _ _ m.succ_pos]
|
||||
apply Nat.div_mul_le_self
|
||||
· show m.succ * n.succ ≤ _
|
||||
· change m.succ * n.succ ≤ _
|
||||
rw [Nat.mul_left_comm]
|
||||
apply Nat.mul_le_mul_left
|
||||
apply (Nat.div_lt_iff_lt_mul k.succ_pos).1
|
||||
@@ -1315,7 +1317,7 @@ protected theorem eq_tdiv_of_mul_eq_left {a b c : Int}
|
||||
| 0, n => by simp [Int.neg_zero]
|
||||
| succ _, (n:Nat) => by simp [tdiv, ← Int.negSucc_eq]
|
||||
| -[_+1], 0 | -[_+1], -[_+1] => by
|
||||
simp only [tdiv, neg_negSucc, ← Int.natCast_succ, Int.neg_neg]
|
||||
simp only [tdiv, neg_negSucc, Int.neg_neg]
|
||||
| succ _, -[_+1] | -[_+1], succ _ => (Int.neg_neg _).symm
|
||||
|
||||
protected theorem neg_tdiv_neg (a b : Int) : (-a).tdiv (-b) = a.tdiv b := by
|
||||
@@ -1406,7 +1408,7 @@ theorem mul_tmod (a b n : Int) : (a * b).tmod n = (a.tmod n * b.tmod n).tmod n :
|
||||
case inv => simp [Int.dvd_neg]
|
||||
induction m using wlog_sign
|
||||
case inv => simp
|
||||
simp only [← Int.natCast_mul, ← ofNat_tmod]
|
||||
simp only [← ofNat_tmod]
|
||||
norm_cast at h
|
||||
rw [Nat.mod_mod_of_dvd _ h]
|
||||
|
||||
@@ -1574,7 +1576,7 @@ theorem neg_mul_tmod_left (a b : Int) : (-(a * b)).tmod b = 0 := by
|
||||
|
||||
@[simp] protected theorem tdiv_one : ∀ a : Int, a.tdiv 1 = a
|
||||
| (n:Nat) => congrArg ofNat (Nat.div_one _)
|
||||
| -[n+1] => by simp [Int.tdiv, neg_ofNat_succ]; rfl
|
||||
| -[n+1] => by simp [Int.tdiv]; rfl
|
||||
|
||||
@[simp] theorem tmod_one (a : Int) : tmod a 1 = 0 := by
|
||||
simp [tmod_def, Int.tdiv_one, Int.one_mul, Int.sub_self]
|
||||
@@ -1696,7 +1698,7 @@ theorem lt_ediv_iff_of_dvd_of_neg {a b c : Int} (hc : c < 0) (hcb : c ∣ b) :
|
||||
theorem ediv_le_ediv_iff_of_dvd_of_pos_of_pos {a b c d : Int} (hb : 0 < b) (hd : 0 < d)
|
||||
(hba : b ∣ a) (hdc : d ∣ c) : a / b ≤ c / d ↔ d * a ≤ c * b := by
|
||||
obtain ⟨⟨x, rfl⟩, y, rfl⟩ := hba, hdc
|
||||
simp [*, Int.ne_of_lt, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
simp [*, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
|
||||
theorem ediv_le_ediv_iff_of_dvd_of_pos_of_neg {a b c d : Int} (hb : 0 < b) (hd : d < 0)
|
||||
(hba : b ∣ a) (hdc : d ∣ c) : a / b ≤ c / d ↔ c * b ≤ d * a := by
|
||||
@@ -1711,12 +1713,12 @@ theorem ediv_le_ediv_iff_of_dvd_of_neg_of_pos {a b c d : Int} (hb : b < 0) (hd :
|
||||
theorem ediv_le_ediv_iff_of_dvd_of_neg_of_neg {a b c d : Int} (hb : b < 0) (hd : d < 0)
|
||||
(hba : b ∣ a) (hdc : d ∣ c) : a / b ≤ c / d ↔ d * a ≤ c * b := by
|
||||
obtain ⟨⟨x, rfl⟩, y, rfl⟩ := hba, hdc
|
||||
simp [*, Int.ne_of_lt, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
simp [*, Int.ne_of_lt, d.mul_assoc, b.mul_comm]
|
||||
|
||||
theorem ediv_lt_ediv_iff_of_dvd_of_pos {a b c d : Int} (hb : 0 < b) (hd : 0 < d) (hba : b ∣ a)
|
||||
(hdc : d ∣ c) : a / b < c / d ↔ d * a < c * b := by
|
||||
obtain ⟨⟨x, rfl⟩, y, rfl⟩ := hba, hdc
|
||||
simp [*, Int.ne_of_lt, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
simp [*, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
|
||||
theorem ediv_lt_ediv_iff_of_dvd_of_pos_of_neg {a b c d : Int} (hb : 0 < b) (hd : d < 0)
|
||||
(hba : b ∣ a) (hdc : d ∣ c) : a / b < c / d ↔ c * b < d * a := by
|
||||
@@ -1731,7 +1733,7 @@ theorem ediv_lt_ediv_iff_of_dvd_of_neg_of_pos {a b c d : Int} (hb : b < 0) (hd :
|
||||
theorem ediv_lt_ediv_iff_of_dvd_of_neg_of_neg {a b c d : Int} (hb : b < 0) (hd : d < 0)
|
||||
(hba : b ∣ a) (hdc : d ∣ c) : a / b < c / d ↔ d * a < c * b := by
|
||||
obtain ⟨⟨x, rfl⟩, y, rfl⟩ := hba, hdc
|
||||
simp [*, Int.ne_of_lt, Int.ne_of_gt, d.mul_assoc, b.mul_comm]
|
||||
simp [*, Int.ne_of_lt, d.mul_assoc, b.mul_comm]
|
||||
|
||||
/-! ### `tdiv` and ordering -/
|
||||
|
||||
@@ -2444,7 +2446,7 @@ theorem lt_mul_fdiv_self_add {x k : Int} (h : 0 < k) : x < k * (x.fdiv k) + k :=
|
||||
|
||||
@[simp]
|
||||
theorem emod_bmod (x : Int) (n : Nat) : Int.bmod (x%n) n = Int.bmod x n := by
|
||||
simp [bmod, Int.emod_emod]
|
||||
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 :=
|
||||
@@ -2745,7 +2747,7 @@ theorem bmod_lt {x : Int} {m : Nat} (h : 0 < m) : bmod x m < (m + 1) / 2 := by
|
||||
split
|
||||
· assumption
|
||||
· apply Int.lt_of_lt_of_le
|
||||
· show _ < 0
|
||||
· change _ < 0
|
||||
have : x % m < m := emod_lt_of_pos x (natCast_pos.mpr h)
|
||||
exact Int.sub_neg_of_lt this
|
||||
· exact Int.le.intro_sub _ rfl
|
||||
@@ -2985,7 +2987,7 @@ theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤
|
||||
· simp [hx', zero_ediv]
|
||||
· by_cases hy : y = 0
|
||||
· simp [hy]; omega
|
||||
· simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
|
||||
· simp only [Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
|
||||
show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
|
||||
apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c := (1 : Int)) (by omega) (by omega)
|
||||
|
||||
|
||||
@@ -631,7 +631,7 @@ theorem lcm_mul_left_dvd_mul_lcm (k m n : Nat) : lcm (m * n) k ∣ lcm m k * lcm
|
||||
simpa [lcm_comm, Nat.mul_comm] using lcm_mul_right_dvd_mul_lcm _ _ _
|
||||
|
||||
theorem lcm_dvd_mul_self_left_iff_dvd_mul {k n m : Nat} : lcm k n ∣ k * m ↔ n ∣ k * m := by
|
||||
simp [← natAbs_dvd_natAbs, natAbs_mul, Nat.lcm_dvd_mul_self_left_iff_dvd_mul,
|
||||
simp [Nat.lcm_dvd_mul_self_left_iff_dvd_mul,
|
||||
lcm_eq_natAbs_lcm_natAbs]
|
||||
|
||||
theorem lcm_dvd_mul_self_right_iff_dvd_mul {k m n : Nat} : lcm n k ∣ m * k ↔ n ∣ m * k := by
|
||||
|
||||
@@ -339,7 +339,7 @@ protected theorem add_sub_assoc (a b c : Int) : a + b - c = a + (b - c) := by
|
||||
match m with
|
||||
| 0 => rfl
|
||||
| succ m =>
|
||||
show ofNat (n - succ m) = subNatNat n (succ m)
|
||||
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")]
|
||||
@@ -454,7 +454,7 @@ theorem negOfNat_eq_subNatNat_zero (n) : negOfNat n = subNatNat 0 n := by cases
|
||||
theorem ofNat_mul_subNatNat (m n k : Nat) :
|
||||
m * subNatNat n k = subNatNat (m * n) (m * k) := by
|
||||
cases m with
|
||||
| zero => simp [ofNat_zero, Int.zero_mul, Nat.zero_mul, subNatNat_self]
|
||||
| zero => simp [Int.zero_mul, Nat.zero_mul, subNatNat_self]
|
||||
| succ m => cases n.lt_or_ge k with
|
||||
| inl h =>
|
||||
have h' : succ m * n < succ m * k := Nat.mul_lt_mul_of_pos_left h (Nat.succ_pos m)
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Int.Linear
|
||||
abbrev Var := Nat
|
||||
abbrev Context := Lean.RArray Int
|
||||
|
||||
@[expose]
|
||||
def Var.denote (ctx : Context) (v : Var) : Int :=
|
||||
ctx.get v
|
||||
|
||||
@@ -36,6 +37,7 @@ inductive Expr where
|
||||
| mulR (a : Expr) (k : Int)
|
||||
deriving Inhabited, BEq
|
||||
|
||||
@[expose]
|
||||
def Expr.denote (ctx : Context) : Expr → Int
|
||||
| .add a b => Int.add (denote ctx a) (denote ctx b)
|
||||
| .sub a b => Int.sub (denote ctx a) (denote ctx b)
|
||||
@@ -50,6 +52,7 @@ inductive Poly where
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving BEq
|
||||
|
||||
@[expose]
|
||||
def Poly.denote (ctx : Context) (p : Poly) : Int :=
|
||||
match p with
|
||||
| .num k => k
|
||||
@@ -59,6 +62,7 @@ def Poly.denote (ctx : Context) (p : Poly) : Int :=
|
||||
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]
|
||||
def Poly.denote' (ctx : Context) (p : Poly) : Int :=
|
||||
match p with
|
||||
| .num k => k
|
||||
@@ -75,8 +79,8 @@ where
|
||||
theorem Poly.denote'_go_eq_denote (ctx : Context) (p : Poly) (r : Int) : denote'.go ctx r p = p.denote ctx + r := by
|
||||
induction r, p using denote'.go.induct ctx <;> simp [denote'.go, denote]
|
||||
next => rw [Int.add_comm]
|
||||
next ih => simp [denote'.go] at ih; rw [ih]; ac_rfl
|
||||
next ih => simp [denote'.go] at ih; rw [ih]; ac_rfl
|
||||
next ih => simp at ih; rw [ih]; ac_rfl
|
||||
next ih => simp at ih; rw [ih]; ac_rfl
|
||||
|
||||
theorem Poly.denote'_eq_denote (ctx : Context) (p : Poly) : p.denote' ctx = p.denote ctx := by
|
||||
unfold denote' <;> split <;> simp [denote, denote'_go_eq_denote] <;> ac_rfl
|
||||
@@ -84,11 +88,13 @@ theorem Poly.denote'_eq_denote (ctx : Context) (p : Poly) : p.denote' ctx = p.de
|
||||
theorem Poly.denote'_add (ctx : Context) (a : Int) (x : Var) (p : Poly) : (Poly.add a x p).denote' ctx = a * x.denote ctx + p.denote ctx := by
|
||||
simp [Poly.denote'_eq_denote, denote]
|
||||
|
||||
@[expose]
|
||||
def Poly.addConst (p : Poly) (k : Int) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num (k+k')
|
||||
| .add k' v' p => .add k' v' (addConst p k)
|
||||
|
||||
@[expose]
|
||||
def Poly.insert (k : Int) (v : Var) (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => .add k v (.num k')
|
||||
@@ -104,16 +110,19 @@ def Poly.insert (k : Int) (v : Var) (p : Poly) : Poly :=
|
||||
.add k' v' (insert k v p)
|
||||
|
||||
/-- Normalizes the given polynomial by fusing monomial and constants. -/
|
||||
@[expose]
|
||||
def Poly.norm (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k => .num k
|
||||
| .add k v p => (norm p).insert k v
|
||||
|
||||
@[expose]
|
||||
def Poly.append (p₁ p₂ : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k₁ => p₂.addConst k₁
|
||||
| .add k x p₁ => .add k x (append p₁ p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.combine' (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
|
||||
match fuel with
|
||||
| 0 => p₁.append p₂
|
||||
@@ -133,10 +142,12 @@ def Poly.combine' (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
|
||||
else
|
||||
.add a₂ x₂ (combine' fuel (.add a₁ x₁ p₁) p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
combine' 100000000 p₁ p₂
|
||||
|
||||
/-- Converts the given expression into a polynomial. -/
|
||||
@[expose]
|
||||
def Expr.toPoly' (e : Expr) : Poly :=
|
||||
go 1 e (.num 0)
|
||||
where
|
||||
@@ -150,6 +161,7 @@ where
|
||||
| .neg a => go (-coeff) a
|
||||
|
||||
/-- Converts the given expression into a polynomial, and then normalizes it. -/
|
||||
@[expose]
|
||||
def Expr.norm (e : Expr) : Poly :=
|
||||
e.toPoly'.norm
|
||||
|
||||
@@ -159,6 +171,7 @@ Examples:
|
||||
- `cdiv 7 3` returns `3`
|
||||
- `cdiv (-7) 3` returns `-2`.
|
||||
-/
|
||||
@[expose]
|
||||
def cdiv (a b : Int) : Int :=
|
||||
-((-a)/b)
|
||||
|
||||
@@ -173,6 +186,7 @@ See theorem `cdiv_add_cmod`. We also have
|
||||
-b < cmod a b ≤ 0
|
||||
```
|
||||
-/
|
||||
@[expose]
|
||||
def cmod (a b : Int) : Int :=
|
||||
-((-a)%b)
|
||||
|
||||
@@ -219,6 +233,7 @@ theorem cdiv_eq_div_of_divides {a b : Int} (h : a % b = 0) : a/b = cdiv a b := b
|
||||
next => rw [Int.mul_eq_mul_right_iff h] at this; assumption
|
||||
|
||||
/-- Returns the constant of the given linear polynomial. -/
|
||||
@[expose]
|
||||
def Poly.getConst : Poly → Int
|
||||
| .num k => k
|
||||
| .add _ _ p => getConst p
|
||||
@@ -230,6 +245,7 @@ Notes:
|
||||
- We only use this function with `k`s that divides all coefficients.
|
||||
- We use `cdiv` for the constant to implement the inequality tightening rule.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.div (k : Int) : Poly → Poly
|
||||
| .num k' => .num (cdiv k' k)
|
||||
| .add k' x p => .add (k'/k) x (div k p)
|
||||
@@ -238,6 +254,7 @@ def Poly.div (k : Int) : Poly → Poly
|
||||
Returns `true` if `k` divides all coefficients and the constant of the given
|
||||
linear polynomial.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.divAll (k : Int) : Poly → Bool
|
||||
| .num k' => k' % k == 0
|
||||
| .add k' _ p => k' % k == 0 && divAll k p
|
||||
@@ -245,6 +262,7 @@ def Poly.divAll (k : Int) : Poly → Bool
|
||||
/--
|
||||
Returns `true` if `k` divides all coefficients of the given linear polynomial.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.divCoeffs (k : Int) : Poly → Bool
|
||||
| .num _ => true
|
||||
| .add k' _ p => k' % k == 0 && divCoeffs k p
|
||||
@@ -252,11 +270,13 @@ def Poly.divCoeffs (k : Int) : Poly → Bool
|
||||
/--
|
||||
`p.mul k` multiplies all coefficients and constant of the polynomial `p` by `k`.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.mul' (p : Poly) (k : Int) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num (k*k')
|
||||
| .add k' v p => .add (k*k') v (mul' p k)
|
||||
|
||||
@[expose]
|
||||
def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
if k == 0 then
|
||||
.num 0
|
||||
@@ -343,7 +363,7 @@ theorem Expr.denote_toPoly'_go (ctx : Context) (e : Expr) :
|
||||
simp [eq_of_beq h]
|
||||
| case2 k k' h =>
|
||||
simp only [toPoly'.go, h, cond_false]
|
||||
simp [Var.denote]
|
||||
simp
|
||||
| case3 k i => simp [toPoly'.go]
|
||||
| case4 k a b iha ihb => simp [toPoly'.go, iha, ihb]
|
||||
| case5 k a b iha ihb =>
|
||||
@@ -351,7 +371,7 @@ theorem Expr.denote_toPoly'_go (ctx : Context) (e : Expr) :
|
||||
rw [Int.sub_eq_add_neg, ←Int.neg_mul, Int.add_assoc]
|
||||
| case6 k k' a h
|
||||
| case8 k a k' h =>
|
||||
simp only [toPoly'.go, h, cond_false]
|
||||
simp only [toPoly'.go, h]
|
||||
simp [eq_of_beq h]
|
||||
| case7 k a k' h ih =>
|
||||
simp only [toPoly'.go, h, cond_false]
|
||||
@@ -383,9 +403,10 @@ attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm == p) : e.denote ctx = p.denote' ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [Poly.norm] at h
|
||||
simp at h
|
||||
simp [*]
|
||||
|
||||
@[expose]
|
||||
def norm_eq_cert (lhs rhs : Expr) (p : Poly) : Bool :=
|
||||
p == (lhs.sub rhs).norm
|
||||
|
||||
@@ -401,6 +422,7 @@ theorem norm_le (ctx : Context) (lhs rhs : Expr) (p : Poly) (h : norm_eq_cert lh
|
||||
· exact Int.sub_nonpos_of_le
|
||||
· exact Int.le_of_sub_nonpos
|
||||
|
||||
@[expose]
|
||||
def norm_eq_var_cert (lhs rhs : Expr) (x y : Var) : Bool :=
|
||||
(lhs.sub rhs).norm == .add 1 x (.add (-1) y (.num 0))
|
||||
|
||||
@@ -411,6 +433,7 @@ theorem norm_eq_var (ctx : Context) (lhs rhs : Expr) (x y : Var) (h : norm_eq_va
|
||||
simp at h
|
||||
rw [←Int.sub_eq_zero, h, ← @Int.sub_eq_zero (Var.denote ctx x), Int.sub_eq_add_neg]
|
||||
|
||||
@[expose]
|
||||
def norm_eq_var_const_cert (lhs rhs : Expr) (x : Var) (k : Int) : Bool :=
|
||||
(lhs.sub rhs).norm == .add 1 x (.num (-k))
|
||||
|
||||
@@ -429,6 +452,7 @@ private theorem mul_eq_zero_iff (a k : Int) (h₁ : k > 0) : k * a = 0 ↔ a = 0
|
||||
theorem norm_eq_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k → k > 0 → (p.denote ctx = 0 ↔ p'.denote ctx = 0) := by
|
||||
intro; subst p; intro h; simp [mul_eq_zero_iff, *]
|
||||
|
||||
@[expose]
|
||||
def norm_eq_coeff_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
|
||||
(lhs.sub rhs).norm == p.mul k && k > 0
|
||||
|
||||
@@ -448,7 +472,7 @@ private theorem mul_le_zero_iff (a k : Int) (h₁ : k > 0) : k * a ≤ 0 ↔ a
|
||||
simp at h; assumption
|
||||
|
||||
private theorem norm_le_coeff' (ctx : Context) (p p' : Poly) (k : Int) : p = p'.mul k → k > 0 → (p.denote ctx ≤ 0 ↔ p'.denote ctx ≤ 0) := by
|
||||
simp [norm_eq_coeff_cert]
|
||||
simp
|
||||
intro; subst p; intro h; simp [mul_le_zero_iff, *]
|
||||
|
||||
theorem norm_le_coeff (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int)
|
||||
@@ -492,6 +516,7 @@ private theorem eq_of_norm_eq_of_divCoeffs {ctx : Context} {p₁ p₂ : Poly} {k
|
||||
apply mul_add_cmod_le_iff
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def norm_le_coeff_tight_cert (lhs rhs : Expr) (p : Poly) (k : Int) : Bool :=
|
||||
let p' := lhs.sub rhs |>.norm
|
||||
k > 0 && (p'.divCoeffs k && p == p'.div k)
|
||||
@@ -502,11 +527,13 @@ theorem norm_le_coeff_tight (ctx : Context) (lhs rhs : Expr) (p : Poly) (k : Int
|
||||
rw [norm_le ctx lhs rhs (lhs.sub rhs).norm BEq.rfl, Poly.denote'_eq_denote]
|
||||
apply eq_of_norm_eq_of_divCoeffs
|
||||
|
||||
@[expose]
|
||||
def Poly.isUnsatEq (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num k => k != 0
|
||||
| _ => false
|
||||
|
||||
@[expose]
|
||||
def Poly.isValidEq (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num k => k == 0
|
||||
@@ -530,11 +557,13 @@ theorem eq_eq_true (ctx : Context) (lhs rhs : Expr) : (lhs.sub rhs).norm.isValid
|
||||
rw [← Int.sub_eq_zero, h]
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def Poly.isUnsatLe (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num k => k > 0
|
||||
| _ => false
|
||||
|
||||
@[expose]
|
||||
def Poly.isValidLe (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num k => k ≤ 0
|
||||
@@ -595,6 +624,7 @@ private theorem poly_eq_zero_eq_false (ctx : Context) {p : Poly} {k : Int} : p.d
|
||||
have high := h₃
|
||||
exact contra h₂ low high this
|
||||
|
||||
@[expose]
|
||||
def unsatEqDivCoeffCert (lhs rhs : Expr) (k : Int) : Bool :=
|
||||
let p := (lhs.sub rhs).norm
|
||||
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
|
||||
@@ -621,6 +651,7 @@ private theorem gcd_dvd_step {k a b x : Int} (h : k ∣ a*x + b) : gcd a k ∣ b
|
||||
have h₂ : gcd a k ∣ a*x := Int.dvd_trans (gcd_dvd_left a k) (Int.dvd_mul_right a x)
|
||||
exact Int.dvd_iff_dvd_of_dvd_add h₁ |>.mp h₂
|
||||
|
||||
@[expose]
|
||||
def Poly.gcdCoeffs : Poly → Int → Int
|
||||
| .num _, k => k
|
||||
| .add k' _ p, k => gcdCoeffs p (gcd k' k)
|
||||
@@ -631,6 +662,7 @@ theorem Poly.gcd_dvd_const {ctx : Context} {p : Poly} {k : Int} (h : k ∣ p.den
|
||||
rw [Int.add_comm] at h
|
||||
exact ih (gcd_dvd_step h)
|
||||
|
||||
@[expose]
|
||||
def Poly.isUnsatDvd (k : Int) (p : Poly) : Bool :=
|
||||
p.getConst % p.gcdCoeffs k != 0
|
||||
|
||||
@@ -668,9 +700,11 @@ theorem dvd_eq_false (ctx : Context) (k : Int) (e : Expr) (h : e.norm.isUnsatDvd
|
||||
rw [norm_dvd ctx k e e.norm BEq.rfl]
|
||||
apply dvd_eq_false' ctx k e.norm h
|
||||
|
||||
@[expose]
|
||||
def dvd_coeff_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
|
||||
k != 0 && (k₁ == k*k₂ && p₁ == p₂.mul k)
|
||||
|
||||
@[expose]
|
||||
def norm_dvd_gcd_cert (k₁ : Int) (e₁ : Expr) (k₂ : Int) (p₂ : Poly) (k : Int) : Bool :=
|
||||
dvd_coeff_cert k₁ e₁.norm k₂ p₂ k
|
||||
|
||||
@@ -702,6 +736,7 @@ private theorem dvd_gcd_of_dvd (d a x p : Int) (h : d ∣ a * x + p) : gcd d a
|
||||
rw [Int.mul_assoc, Int.mul_assoc, ← Int.mul_sub] at h
|
||||
exists k₁ * k - k₂ * x
|
||||
|
||||
@[expose]
|
||||
def dvd_elim_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (p₂ : Poly) : Bool :=
|
||||
match p₁ with
|
||||
| .add a _ p => k₂ == gcd k₁ a && p₂ == p
|
||||
@@ -764,6 +799,7 @@ private theorem dvd_solve_elim' {x : Int} {d₁ a₁ p₁ : Int} {d₂ a₂ p₂
|
||||
rw [h₃, h₄, Int.mul_assoc, Int.mul_assoc, ←Int.mul_sub] at this
|
||||
exact ⟨k₄ * k₁ - k₃ * k₂, this⟩
|
||||
|
||||
@[expose]
|
||||
def dvd_solve_combine_cert (d₁ : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) (g α β : Int) : Bool :=
|
||||
match p₁, p₂ with
|
||||
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
|
||||
@@ -779,12 +815,13 @@ theorem dvd_solve_combine (ctx : Context) (d₁ : Int) (p₁ : Poly) (d₂ : Int
|
||||
split <;> simp
|
||||
next a₁ x₁ p₁ a₂ x₂ p₂ =>
|
||||
intro _ hg hd hp; subst x₁ p
|
||||
simp [Poly.denote'_add]
|
||||
simp
|
||||
intro h₁ h₂
|
||||
rw [Int.add_comm] at h₁ h₂
|
||||
rw [Int.add_comm _ (g * x₂.denote ctx), Int.add_left_comm, ← Int.add_assoc, hd]
|
||||
exact dvd_solve_combine' hg.symm h₁ h₂
|
||||
|
||||
@[expose]
|
||||
def dvd_solve_elim_cert (d₁ : Int) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d : Int) (p : Poly) : Bool :=
|
||||
match p₁, p₂ with
|
||||
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
|
||||
@@ -816,6 +853,7 @@ theorem le_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p₂) : p
|
||||
simp at h
|
||||
simp [*]
|
||||
|
||||
@[expose]
|
||||
def le_coeff_cert (p₁ p₂ : Poly) (k : Int) : Bool :=
|
||||
k > 0 && (p₁.divCoeffs k && p₂ == p₁.div k)
|
||||
|
||||
@@ -824,6 +862,7 @@ theorem le_coeff (ctx : Context) (p₁ p₂ : Poly) (k : Int) : le_coeff_cert p
|
||||
intro h₁ h₂ h₃
|
||||
exact eq_of_norm_eq_of_divCoeffs h₁ h₂ h₃ |>.mp
|
||||
|
||||
@[expose]
|
||||
def le_neg_cert (p₁ p₂ : Poly) : Bool :=
|
||||
p₂ == (p₁.mul (-1) |>.addConst 1)
|
||||
|
||||
@@ -834,11 +873,13 @@ theorem le_neg (ctx : Context) (p₁ p₂ : Poly) : le_neg_cert p₁ p₂ → ¬
|
||||
simp at h
|
||||
exact h
|
||||
|
||||
@[expose]
|
||||
def Poly.leadCoeff (p : Poly) : Int :=
|
||||
match p with
|
||||
| .add a _ _ => a
|
||||
| _ => 1
|
||||
|
||||
@[expose]
|
||||
def le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let a₁ := p₁.leadCoeff.natAbs
|
||||
let a₂ := p₂.leadCoeff.natAbs
|
||||
@@ -854,6 +895,7 @@ theorem le_combine (ctx : Context) (p₁ p₂ p₃ : Poly)
|
||||
· rw [← Int.zero_mul (Poly.denote ctx p₂)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
|
||||
· rw [← Int.zero_mul (Poly.denote ctx p₁)]; apply Int.mul_le_mul_of_nonpos_right <;> simp [*]
|
||||
|
||||
@[expose]
|
||||
def le_combine_coeff_cert (p₁ p₂ p₃ : Poly) (k : Int) : Bool :=
|
||||
let a₁ := p₁.leadCoeff.natAbs
|
||||
let a₂ := p₂.leadCoeff.natAbs
|
||||
@@ -883,6 +925,7 @@ theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : p₁.norm == p₂) : p
|
||||
simp at h
|
||||
simp [*]
|
||||
|
||||
@[expose]
|
||||
def eq_coeff_cert (p p' : Poly) (k : Int) : Bool :=
|
||||
p == p'.mul k && k > 0
|
||||
|
||||
@@ -893,6 +936,7 @@ theorem eq_coeff (ctx : Context) (p p' : Poly) (k : Int) : eq_coeff_cert p p' k
|
||||
theorem eq_unsat (ctx : Context) (p : Poly) : p.isUnsatEq → p.denote' ctx = 0 → False := by
|
||||
simp [Poly.isUnsatEq] <;> split <;> simp
|
||||
|
||||
@[expose]
|
||||
def eq_unsat_coeff_cert (p : Poly) (k : Int) : Bool :=
|
||||
p.divCoeffs k && k > 0 && cmod p.getConst k < 0
|
||||
|
||||
@@ -902,6 +946,7 @@ theorem eq_unsat_coeff (ctx : Context) (p : Poly) (k : Int) : eq_unsat_coeff_cer
|
||||
have h := poly_eq_zero_eq_false ctx h₁ h₂ h₃; clear h₁ h₂ h₃
|
||||
simp [h]
|
||||
|
||||
@[expose]
|
||||
def Poly.coeff (p : Poly) (x : Var) : Int :=
|
||||
match p with
|
||||
| .add a y p => bif x == y then a else coeff p x
|
||||
@@ -916,7 +961,8 @@ private theorem dvd_of_eq' {a x p : Int} : a*x + p = 0 → a ∣ p := by
|
||||
rw [Int.mul_comm, ← Int.neg_mul, Eq.comm, Int.mul_comm] at h
|
||||
exact ⟨-x, h⟩
|
||||
|
||||
private def abs (x : Int) : Int :=
|
||||
@[expose]
|
||||
def abs (x : Int) : Int :=
|
||||
Int.ofNat x.natAbs
|
||||
|
||||
private theorem abs_dvd {a p : Int} (h : a ∣ p) : abs a ∣ p := by
|
||||
@@ -924,6 +970,7 @@ private theorem abs_dvd {a p : Int} (h : a ∣ p) : abs a ∣ p := by
|
||||
· simp at h; assumption
|
||||
· simp [Int.negSucc_eq] at h; assumption
|
||||
|
||||
@[expose]
|
||||
def dvd_of_eq_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
d₂ == abs a && p₂ == p₁.insert (-a) x
|
||||
@@ -950,6 +997,7 @@ private theorem eq_dvd_subst' {a x p d b q : Int} : a*x + p = 0 → d ∣ b*x +
|
||||
rw [← Int.mul_assoc] at h
|
||||
exact ⟨z, h⟩
|
||||
|
||||
@[expose]
|
||||
def eq_dvd_subst_cert (x : Var) (p₁ : Poly) (d₂ : Int) (p₂ : Poly) (d₃ : Int) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
@@ -979,6 +1027,7 @@ theorem eq_dvd_subst (ctx : Context) (x : Var) (p₁ : Poly) (d₂ : Int) (p₂
|
||||
apply abs_dvd
|
||||
simp [this, Int.neg_mul]
|
||||
|
||||
@[expose]
|
||||
def eq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
@@ -991,6 +1040,7 @@ theorem eq_eq_subst (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃
|
||||
intro h₁ h₂
|
||||
simp [*]
|
||||
|
||||
@[expose]
|
||||
def eq_le_subst_nonneg_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
@@ -1006,6 +1056,7 @@ theorem eq_le_subst_nonneg (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly)
|
||||
simp at h₂
|
||||
simp [*]
|
||||
|
||||
@[expose]
|
||||
def eq_le_subst_nonpos_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
@@ -1022,6 +1073,7 @@ theorem eq_le_subst_nonpos (ctx : Context) (x : Var) (p₁ : Poly) (p₂ : Poly)
|
||||
rw [Int.mul_comm]
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def eq_of_core_cert (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
p₃ == p₁.combine (p₂.mul (-1))
|
||||
|
||||
@@ -1031,6 +1083,7 @@ theorem eq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
intro; subst p₃; simp
|
||||
intro h; rw [h, Int.add_neg_eq_sub, Int.sub_self]
|
||||
|
||||
@[expose]
|
||||
def Poly.isUnsatDiseq (p : Poly) : Bool :=
|
||||
match p with
|
||||
| .num 0 => true
|
||||
@@ -1047,11 +1100,12 @@ theorem diseq_coeff (ctx : Context) (p p' : Poly) (k : Int) : eq_coeff_cert p p'
|
||||
intro _ _; simp [mul_eq_zero_iff, *]
|
||||
|
||||
theorem diseq_neg (ctx : Context) (p p' : Poly) : p' == p.mul (-1) → p.denote' ctx ≠ 0 → p'.denote' ctx ≠ 0 := by
|
||||
simp; intro _ _; simp [mul_eq_zero_iff, *]
|
||||
simp; intro _ _; simp [*]
|
||||
|
||||
theorem diseq_unsat (ctx : Context) (p : Poly) : p.isUnsatDiseq → p.denote' ctx ≠ 0 → False := by
|
||||
simp [Poly.isUnsatDiseq] <;> split <;> simp
|
||||
|
||||
@[expose]
|
||||
def diseq_eq_subst_cert (x : Var) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
@@ -1071,6 +1125,7 @@ theorem diseq_of_core (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
intro h; rw [← Int.sub_eq_zero] at h
|
||||
rw [Int.add_neg_eq_sub]; assumption
|
||||
|
||||
@[expose]
|
||||
def eq_of_le_ge_cert (p₁ p₂ : Poly) : Bool :=
|
||||
p₂ == p₁.mul (-1)
|
||||
|
||||
@@ -1081,6 +1136,7 @@ theorem eq_of_le_ge (ctx : Context) (p₁ : Poly) (p₂ : Poly)
|
||||
intro h₁ h₂
|
||||
simp [Int.eq_iff_le_and_ge, *]
|
||||
|
||||
@[expose]
|
||||
def le_of_le_diseq_cert (p₁ : Poly) (p₂ : Poly) (p₃ : Poly) : Bool :=
|
||||
-- Remark: we can generate two different certificates in the future, and avoid the `||` in the certificate.
|
||||
(p₂ == p₁ || p₂ == p₁.mul (-1)) &&
|
||||
@@ -1095,6 +1151,7 @@ theorem le_of_le_diseq (ctx : Context) (p₁ : Poly) (p₂ : Poly) (p₃ : Poly)
|
||||
next h => have := Int.lt_of_le_of_lt h₁ h; simp at this
|
||||
intro h; cases h <;> intro <;> subst p₂ p₃ <;> simp <;> apply this
|
||||
|
||||
@[expose]
|
||||
def diseq_split_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
p₂ == p₁.addConst 1 &&
|
||||
p₃ == (p₁.mul (-1)).addConst 1
|
||||
@@ -1113,6 +1170,7 @@ theorem diseq_split_resolve (ctx : Context) (p₁ p₂ p₃ : Poly)
|
||||
intro h₁ h₂ h₃
|
||||
exact (diseq_split ctx p₁ p₂ p₃ h₁ h₂).resolve_left h₃
|
||||
|
||||
@[expose]
|
||||
def OrOver (n : Nat) (p : Nat → Prop) : Prop :=
|
||||
match n with
|
||||
| 0 => False
|
||||
@@ -1127,6 +1185,7 @@ theorem orOver_resolve {n p} : OrOver (n+1) p → ¬ p n → OrOver n p := by
|
||||
· contradiction
|
||||
· assumption
|
||||
|
||||
@[expose]
|
||||
def OrOver_cases_type (n : Nat) (p : Nat → Prop) : Prop :=
|
||||
match n with
|
||||
| 0 => p 0
|
||||
@@ -1186,6 +1245,7 @@ private theorem cooper_dvd_left_core
|
||||
rw [this] at h₃
|
||||
exists k.toNat
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_left_cert (p₁ p₂ p₃ : Poly) (d : Int) (n : Nat) : Bool :=
|
||||
p₁.casesOn (fun _ => false) fun a x _ =>
|
||||
p₂.casesOn (fun _ => false) fun b y _ =>
|
||||
@@ -1194,11 +1254,13 @@ def cooper_dvd_left_cert (p₁ p₂ p₃ : Poly) (d : Int) (n : Nat) : Bool :=
|
||||
.and (a < 0) <| .and (b > 0) <|
|
||||
.and (d > 0) <| n == Int.lcm a (a * d / Int.gcd (a * d) c)
|
||||
|
||||
@[expose]
|
||||
def Poly.tail (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .add _ _ p => p
|
||||
| _ => p
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_left_split (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) : Prop :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1238,6 +1300,7 @@ theorem cooper_dvd_left (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (n : N
|
||||
simp only [denote'_addConst_eq]
|
||||
exact cooper_dvd_left_core ha hb hd h₁ h₂ h₃
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_left_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (b : Int) (p' : Poly) : Bool :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1248,8 +1311,9 @@ def cooper_dvd_left_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (b : Int) (p' :
|
||||
theorem cooper_dvd_left_split_ineq (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) (b : Int) (p' : Poly)
|
||||
: cooper_dvd_left_split ctx p₁ p₂ p₃ d k → cooper_dvd_left_split_ineq_cert p₁ p₂ k b p' → p'.denote' ctx ≤ 0 := by
|
||||
simp [cooper_dvd_left_split_ineq_cert, cooper_dvd_left_split]
|
||||
intros; subst p' b; simp [denote'_mul_combine_mul_addConst_eq]; assumption
|
||||
intros; subst p' b; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_left_split_dvd1_cert (p₁ p' : Poly) (a : Int) (k : Int) : Bool :=
|
||||
a == p₁.leadCoeff && p' == p₁.tail.addConst k
|
||||
|
||||
@@ -1258,6 +1322,7 @@ theorem cooper_dvd_left_split_dvd1 (ctx : Context) (p₁ p₂ p₃ : Poly) (d :
|
||||
simp [cooper_dvd_left_split_dvd1_cert, cooper_dvd_left_split]
|
||||
intros; subst a p'; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_left_split_dvd2_cert (p₁ p₃ : Poly) (d : Int) (k : Nat) (d' : Int) (p' : Poly): Bool :=
|
||||
let p := p₁.tail
|
||||
let s := p₃.tail
|
||||
@@ -1283,16 +1348,18 @@ private theorem cooper_left_core
|
||||
have h := cooper_dvd_left_core a_neg b_pos d_pos h₁ h₂ h₃
|
||||
simp only [Int.mul_one, gcd_zero, ofNat_natAbs_of_nonpos (Int.le_of_lt a_neg), Int.ediv_neg,
|
||||
Int.ediv_self (Int.ne_of_lt a_neg), Int.reduceNeg, lcm_neg_right, lcm_one,
|
||||
Int.add_left_comm, Int.zero_mul, Int.mul_zero, Int.add_zero, Int.dvd_zero,
|
||||
Int.zero_mul, Int.mul_zero, Int.add_zero, Int.dvd_zero,
|
||||
and_true] at h
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_left_cert (p₁ p₂ : Poly) (n : Nat) : Bool :=
|
||||
p₁.casesOn (fun _ => false) fun a x _ =>
|
||||
p₂.casesOn (fun _ => false) fun b y _ =>
|
||||
.and (x == y) <| .and (a < 0) <| .and (b > 0) <|
|
||||
n == a.natAbs
|
||||
|
||||
@[expose]
|
||||
def cooper_left_split (ctx : Context) (p₁ p₂ : Poly) (k : Nat) : Prop :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1320,6 +1387,7 @@ theorem cooper_left (ctx : Context) (p₁ p₂ : Poly) (n : Nat)
|
||||
simp only [denote'_addConst_eq]
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_left_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (b : Int) (p' : Poly) : Bool :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1330,8 +1398,9 @@ def cooper_left_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (b : Int) (p' : Pol
|
||||
theorem cooper_left_split_ineq (ctx : Context) (p₁ p₂ : Poly) (k : Nat) (b : Int) (p' : Poly)
|
||||
: cooper_left_split ctx p₁ p₂ k → cooper_left_split_ineq_cert p₁ p₂ k b p' → p'.denote' ctx ≤ 0 := by
|
||||
simp [cooper_left_split_ineq_cert, cooper_left_split]
|
||||
intros; subst p' b; simp [denote'_mul_combine_mul_addConst_eq]; assumption
|
||||
intros; subst p' b; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_left_split_dvd_cert (p₁ p' : Poly) (a : Int) (k : Int) : Bool :=
|
||||
a == p₁.leadCoeff && p' == p₁.tail.addConst k
|
||||
|
||||
@@ -1353,7 +1422,7 @@ private theorem cooper_dvd_right_core
|
||||
have h₁' : p ≤ (-a)*x := by rw [Int.neg_mul, ← Lean.Omega.Int.add_le_zero_iff_le_neg']; assumption
|
||||
have h₂' : b * x ≤ -q := by rw [← Lean.Omega.Int.add_le_zero_iff_le_neg', Int.add_comm]; assumption
|
||||
have ⟨k, h₁, h₂, h₃, h₄, h₅⟩ := Int.cooper_resolution_dvd_right a_pos' b_pos d_pos |>.mp ⟨x, h₁', h₂', h₃⟩
|
||||
simp only [Int.neg_mul, neg_gcd, lcm_neg_left, Int.mul_neg, Int.neg_neg, Int.neg_dvd] at *
|
||||
simp only [Int.neg_mul, Int.mul_neg, Int.neg_neg] at *
|
||||
apply orOver_of_exists
|
||||
have hlt := ofNat_lt h₁ h₂
|
||||
replace h₃ := Int.add_le_add_right h₃ (-(a*q)); rw [Int.add_right_neg] at h₃
|
||||
@@ -1363,8 +1432,9 @@ private theorem cooper_dvd_right_core
|
||||
have : -(c * k) + -(c * q) + b * s = -(c * q) + b * s + -(c * k) := by ac_rfl
|
||||
rw [this] at h₅; clear this
|
||||
exists k.toNat
|
||||
simp only [hlt, true_and, and_true, cast_toNat h₁, h₃, h₄, h₅]
|
||||
simp only [hlt, and_true, cast_toNat h₁, h₃, h₄, h₅]
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_right_cert (p₁ p₂ p₃ : Poly) (d : Int) (n : Nat) : Bool :=
|
||||
p₁.casesOn (fun _ => false) fun a x _ =>
|
||||
p₂.casesOn (fun _ => false) fun b y _ =>
|
||||
@@ -1373,6 +1443,7 @@ def cooper_dvd_right_cert (p₁ p₂ p₃ : Poly) (d : Int) (n : Nat) : Bool :=
|
||||
.and (a < 0) <| .and (b > 0) <|
|
||||
.and (d > 0) <| n == Int.lcm b (b * d / Int.gcd (b * d) c)
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_right_split (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) : Prop :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1402,9 +1473,10 @@ theorem cooper_dvd_right (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (n :
|
||||
intro h₁ h₂ h₃
|
||||
have := cooper_dvd_right_core ha hb hd h₁ h₂ h₃
|
||||
simp only [denote'_mul_combine_mul_addConst_eq]
|
||||
simp only [denote'_addConst_eq, ←Int.neg_mul]
|
||||
simp only [denote'_addConst_eq]
|
||||
exact cooper_dvd_right_core ha hb hd h₁ h₂ h₃
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_right_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (a : Int) (p' : Poly) : Bool :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1415,8 +1487,9 @@ def cooper_dvd_right_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (a : Int) (p'
|
||||
theorem cooper_dvd_right_split_ineq (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (k : Nat) (a : Int) (p' : Poly)
|
||||
: cooper_dvd_right_split ctx p₁ p₂ p₃ d k → cooper_dvd_right_split_ineq_cert p₁ p₂ k a p' → p'.denote' ctx ≤ 0 := by
|
||||
simp [cooper_dvd_right_split_ineq_cert, cooper_dvd_right_split]
|
||||
intros; subst a p'; simp [denote'_mul_combine_mul_addConst_eq]; assumption
|
||||
intros; subst a p'; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_right_split_dvd1_cert (p₂ p' : Poly) (b : Int) (k : Int) : Bool :=
|
||||
b == p₂.leadCoeff && p' == p₂.tail.addConst k
|
||||
|
||||
@@ -1425,6 +1498,7 @@ theorem cooper_dvd_right_split_dvd1 (ctx : Context) (p₁ p₂ p₃ : Poly) (d :
|
||||
simp [cooper_dvd_right_split_dvd1_cert, cooper_dvd_right_split]
|
||||
intros; subst b p'; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_dvd_right_split_dvd2_cert (p₂ p₃ : Poly) (d : Int) (k : Nat) (d' : Int) (p' : Poly): Bool :=
|
||||
let q := p₂.tail
|
||||
let s := p₃.tail
|
||||
@@ -1448,17 +1522,19 @@ private theorem cooper_right_core
|
||||
have d_pos : (0 : Int) < 1 := by decide
|
||||
have h₃ : 1 ∣ 0*x + 0 := Int.one_dvd _
|
||||
have h := cooper_dvd_right_core a_neg b_pos d_pos h₁ h₂ h₃
|
||||
simp only [Int.mul_one, gcd_zero, Int.natAbs_of_nonneg (Int.le_of_lt b_pos), Int.ediv_neg,
|
||||
Int.ediv_self (Int.ne_of_gt b_pos), Int.reduceNeg, lcm_neg_right, lcm_one,
|
||||
Int.add_left_comm, Int.zero_mul, Int.mul_zero, Int.add_zero, Int.dvd_zero,
|
||||
simp only [Int.mul_one, gcd_zero, Int.natAbs_of_nonneg (Int.le_of_lt b_pos),
|
||||
Int.ediv_self (Int.ne_of_gt b_pos), lcm_one,
|
||||
Int.zero_mul, Int.mul_zero, Int.add_zero, Int.dvd_zero,
|
||||
and_true, Int.neg_zero] at h
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_right_cert (p₁ p₂ : Poly) (n : Nat) : Bool :=
|
||||
p₁.casesOn (fun _ => false) fun a x _ =>
|
||||
p₂.casesOn (fun _ => false) fun b y _ =>
|
||||
.and (x == y) <| .and (a < 0) <| .and (b > 0) <| n == b.natAbs
|
||||
|
||||
@[expose]
|
||||
def cooper_right_split (ctx : Context) (p₁ p₂ : Poly) (k : Nat) : Prop :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1483,9 +1559,10 @@ theorem cooper_right (ctx : Context) (p₁ p₂ : Poly) (n : Nat)
|
||||
intro h₁ h₂
|
||||
have := cooper_right_core ha hb h₁ h₂
|
||||
simp only [denote'_mul_combine_mul_addConst_eq]
|
||||
simp only [denote'_addConst_eq, ←Int.neg_mul]
|
||||
simp only [denote'_addConst_eq]
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_right_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (a : Int) (p' : Poly) : Bool :=
|
||||
let p := p₁.tail
|
||||
let q := p₂.tail
|
||||
@@ -1496,8 +1573,9 @@ def cooper_right_split_ineq_cert (p₁ p₂ : Poly) (k : Int) (a : Int) (p' : Po
|
||||
theorem cooper_right_split_ineq (ctx : Context) (p₁ p₂ : Poly) (k : Nat) (a : Int) (p' : Poly)
|
||||
: cooper_right_split ctx p₁ p₂ k → cooper_right_split_ineq_cert p₁ p₂ k a p' → p'.denote' ctx ≤ 0 := by
|
||||
simp [cooper_right_split_ineq_cert, cooper_right_split]
|
||||
intros; subst a p'; simp [denote'_mul_combine_mul_addConst_eq]; assumption
|
||||
intros; subst a p'; simp; assumption
|
||||
|
||||
@[expose]
|
||||
def cooper_right_split_dvd_cert (p₂ p' : Poly) (b : Int) (k : Int) : Bool :=
|
||||
b == p₂.leadCoeff && p' == p₂.tail.addConst k
|
||||
|
||||
@@ -1587,6 +1665,7 @@ abbrev Poly.casesOnAdd (p : Poly) (k : Int → Var → Poly → Bool) : Bool :=
|
||||
abbrev Poly.casesOnNum (p : Poly) (k : Int → Bool) : Bool :=
|
||||
p.casesOn k (fun _ _ _ => false)
|
||||
|
||||
@[expose]
|
||||
def cooper_unsat_cert (p₁ p₂ p₃ : Poly) (d : Int) (α β : Int) : Bool :=
|
||||
p₁.casesOnAdd fun k₁ x p₁ =>
|
||||
p₂.casesOnAdd fun k₂ y p₂ =>
|
||||
@@ -1603,7 +1682,7 @@ theorem cooper_unsat (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (α β :
|
||||
: cooper_unsat_cert p₁ p₂ p₃ d α β →
|
||||
p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → d ∣ p₃.denote' ctx → False := by
|
||||
unfold cooper_unsat_cert <;> cases p₁ <;> cases p₂ <;> cases p₃ <;> simp only [Poly.casesOnAdd,
|
||||
Bool.false_eq_true, Poly.denote'_add, mul_def, add_def, false_implies]
|
||||
Bool.false_eq_true, Poly.denote'_add, false_implies]
|
||||
next k₁ x p₁ k₂ y p₂ c z p₃ =>
|
||||
cases p₁ <;> cases p₂ <;> cases p₃ <;> simp only [Poly.casesOnNum, Int.reduceNeg,
|
||||
Bool.and_eq_true, beq_iff_eq, decide_eq_true_eq, and_imp, Bool.false_eq_true,
|
||||
@@ -1626,6 +1705,7 @@ theorem emod_nonneg (x y : Int) : y != 0 → -1 * (x % y) ≤ 0 := by
|
||||
simp at this
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def emod_le_cert (y n : Int) : Bool :=
|
||||
y != 0 && n == 1 - y.natAbs
|
||||
|
||||
@@ -1665,7 +1745,7 @@ theorem natCast_sub (x y : Nat)
|
||||
(NatCast.natCast x : Int) + -1*NatCast.natCast y
|
||||
else
|
||||
(0 : Int) := by
|
||||
show (↑(x - y) : Int) = if (↑y : Int) + (-1)*↑x ≤ 0 then ↑x + (-1)*↑y else 0
|
||||
change (↑(x - y) : Int) = if (↑y : Int) + (-1)*↑x ≤ 0 then (↑x : Int) + (-1)*↑y else 0
|
||||
rw [Int.neg_mul, ← Int.sub_eq_add_neg, Int.one_mul]
|
||||
rw [Int.neg_mul, ← Int.sub_eq_add_neg, Int.one_mul]
|
||||
split
|
||||
@@ -1708,6 +1788,7 @@ private theorem eq_neg_addConst_add (ctx : Context) (p : Poly)
|
||||
rw [Int.add_right_neg]
|
||||
simp
|
||||
|
||||
@[expose]
|
||||
def dvd_le_tight_cert (d : Int) (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let b₁ := p₁.getConst
|
||||
let b₂ := p₂.getConst
|
||||
@@ -1728,6 +1809,7 @@ theorem dvd_le_tight (ctx : Context) (d : Int) (p₁ p₂ p₃ : Poly)
|
||||
simp only [Poly.denote'_eq_denote]
|
||||
exact dvd_le_tight' hd
|
||||
|
||||
@[expose]
|
||||
def dvd_neg_le_tight_cert (d : Int) (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let b₁ := p₁.getConst
|
||||
let b₂ := p₂.getConst
|
||||
@@ -1737,7 +1819,7 @@ def dvd_neg_le_tight_cert (d : Int) (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
d > 0 && (p₂ == p.addConst b₂ && p₃ == p.addConst (b₁ - d*((b₁ - b₂)/d)))
|
||||
|
||||
theorem Poly.mul_minus_one_getConst_eq (p : Poly) : (p.mul (-1)).getConst = -p.getConst := by
|
||||
simp [Poly.mul, Poly.getConst]
|
||||
simp [Poly.mul]
|
||||
induction p <;> simp [Poly.mul', Poly.getConst, *]
|
||||
|
||||
theorem dvd_neg_le_tight (ctx : Context) (d : Int) (p₁ p₂ p₃ : Poly)
|
||||
@@ -1764,6 +1846,7 @@ theorem le_norm_expr (ctx : Context) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_eq_cert lhs rhs p → lhs.denote ctx ≤ rhs.denote ctx → p.denote' ctx ≤ 0 := by
|
||||
intro h₁ h₂; rwa [norm_le ctx lhs rhs p h₁] at h₂
|
||||
|
||||
@[expose]
|
||||
def not_le_norm_expr_cert (lhs rhs : Expr) (p : Poly) : Bool :=
|
||||
p == (((lhs.sub rhs).norm).mul (-1)).addConst 1
|
||||
|
||||
@@ -1796,6 +1879,7 @@ theorem of_not_dvd (a b : Int) : a != 0 → ¬ (a ∣ b) → b % a > 0 := by
|
||||
simp [h₁] at h₂
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
def le_of_le_cert (p q : Poly) (k : Nat) : Bool :=
|
||||
q == p.addConst (- k)
|
||||
|
||||
@@ -1806,6 +1890,7 @@ theorem le_of_le (ctx : Context) (p q : Poly) (k : Nat)
|
||||
simp [Lean.Omega.Int.add_le_zero_iff_le_neg']
|
||||
exact Int.le_trans h (Int.ofNat_zero_le _)
|
||||
|
||||
@[expose]
|
||||
def not_le_of_le_cert (p q : Poly) (k : Nat) : Bool :=
|
||||
q == (p.mul (-1)).addConst (1 + k)
|
||||
|
||||
@@ -1815,10 +1900,11 @@ theorem not_le_of_le (ctx : Context) (p q : Poly) (k : Nat)
|
||||
intro h
|
||||
apply Int.pos_of_neg_neg
|
||||
apply Int.lt_of_add_one_le
|
||||
simp [Int.neg_add, Int.neg_sub]
|
||||
simp [Int.neg_add]
|
||||
rw [← Int.add_assoc, ← Int.add_assoc, Int.add_neg_cancel_right, Lean.Omega.Int.add_le_zero_iff_le_neg']
|
||||
simp; exact Int.le_trans h (Int.ofNat_zero_le _)
|
||||
|
||||
@[expose]
|
||||
def eq_def_cert (x : Var) (xPoly : Poly) (p : Poly) : Bool :=
|
||||
p == .add (-1) x xPoly
|
||||
|
||||
@@ -1827,6 +1913,7 @@ theorem eq_def (ctx : Context) (x : Var) (xPoly : Poly) (p : Poly)
|
||||
simp [eq_def_cert]; intro _ h; subst p; simp [h]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
@[expose]
|
||||
def eq_def'_cert (x : Var) (e : Expr) (p : Poly) : Bool :=
|
||||
p == .add (-1) x e.norm
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ We use them to implement the arithmetic theories in `grind`
|
||||
|
||||
abbrev Var := Nat
|
||||
abbrev Context := Lean.RArray Nat
|
||||
@[expose]
|
||||
def Var.denote (ctx : Context) (v : Var) : Nat :=
|
||||
ctx.get v
|
||||
|
||||
@@ -31,6 +32,7 @@ inductive Expr where
|
||||
| mod (a b : Expr)
|
||||
deriving BEq
|
||||
|
||||
@[expose]
|
||||
def Expr.denote (ctx : Context) : Expr → Nat
|
||||
| .num k => k
|
||||
| .var v => v.denote ctx
|
||||
@@ -39,6 +41,7 @@ def Expr.denote (ctx : Context) : Expr → Nat
|
||||
| .div a b => Nat.div (denote ctx a) (denote ctx b)
|
||||
| .mod a b => Nat.mod (denote ctx a) (denote ctx b)
|
||||
|
||||
@[expose]
|
||||
def Expr.denoteAsInt (ctx : Context) : Expr → Int
|
||||
| .num k => Int.ofNat k
|
||||
| .var v => Int.ofNat (v.denote ctx)
|
||||
@@ -48,7 +51,7 @@ def Expr.denoteAsInt (ctx : Context) : Expr → Int
|
||||
| .mod a b => Int.emod (denoteAsInt ctx a) (denoteAsInt ctx b)
|
||||
|
||||
theorem Expr.denoteAsInt_eq (ctx : Context) (e : Expr) : e.denoteAsInt ctx = e.denote ctx := by
|
||||
induction e <;> simp [denote, denoteAsInt, Int.natCast_ediv, *] <;> rfl
|
||||
induction e <;> simp [denote, denoteAsInt, *] <;> rfl
|
||||
|
||||
theorem Expr.eq_denoteAsInt (ctx : Context) (e : Expr) : e.denote ctx = e.denoteAsInt ctx := by
|
||||
apply Eq.symm; apply denoteAsInt_eq
|
||||
|
||||
@@ -448,7 +448,7 @@ protected theorem le_max_left (a b : Int) : a ≤ max a b := by rw [Int.max_def]
|
||||
protected theorem le_max_right (a b : Int) : b ≤ max a b := Int.max_comm .. ▸ Int.le_max_left ..
|
||||
|
||||
protected theorem max_eq_right {a b : Int} (h : a ≤ b) : max a b = b := by
|
||||
simp [Int.max_def, h, Int.not_lt.2 h]
|
||||
simp [Int.max_def, h]
|
||||
|
||||
protected theorem max_eq_left {a b : Int} (h : b ≤ a) : max a b = a := by
|
||||
rw [← Int.max_comm b a]; exact Int.max_eq_right h
|
||||
|
||||
@@ -19,6 +19,13 @@ 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]
|
||||
|
||||
protected theorem zero_pow {n : Nat} (h : n ≠ 0) : (0 : Int) ^ n = 0 := by
|
||||
match n, h with
|
||||
| n + 1, _ => simp [Int.pow_succ]
|
||||
|
||||
protected theorem one_pow {n : Nat} : (1 : Int) ^ n = 1 := by
|
||||
induction n with simp_all [Int.pow_succ]
|
||||
|
||||
protected theorem pow_pos {n : Int} {m : Nat} : 0 < n → 0 < n ^ m := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
|
||||
19
src/Init/Data/Iterators.lean
Normal file
19
src/Init/Data/Iterators.lean
Normal file
@@ -0,0 +1,19 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.PostconditionMonad
|
||||
import Init.Data.Iterators.Consumers
|
||||
import Init.Data.Iterators.Lemmas
|
||||
import Init.Data.Iterators.Internal
|
||||
|
||||
/-!
|
||||
# Iterators
|
||||
|
||||
See `Std.Data.Iterators` for an overview over the iterator API.
|
||||
-/
|
||||
@@ -3,9 +3,12 @@ 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
|
||||
import Init.Core
|
||||
import Init.Classical
|
||||
import Init.Ext
|
||||
import Init.NotationExtra
|
||||
import Init.TacticsExtra
|
||||
|
||||
@@ -30,7 +33,7 @@ See `Std.Data.Iterators.Producers` for ways to iterate over common data structur
|
||||
By convention, the monadic iterator associated with an object can be obtained via dot notation.
|
||||
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
|
||||
|
||||
See `Std.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
|
||||
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
|
||||
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
@@ -58,6 +61,7 @@ def x := [1, 2, 3].iterM IO
|
||||
def x := ([1, 2, 3].iterM IO : IterM IO Nat)
|
||||
```
|
||||
-/
|
||||
@[ext]
|
||||
structure IterM {α : Type w} (m : Type w → Type w') (β : Type w) where
|
||||
/-- Internal implementation detail of the iterator. -/
|
||||
internalState : α
|
||||
@@ -73,7 +77,7 @@ See `Std.Data.Iterators.Producers` for ways to iterate over common data structur
|
||||
By convention, the monadic iterator associated with an object can be obtained via dot notation.
|
||||
For example, `List.iterM IO` creates an iterator over a list in the monad `IO`.
|
||||
|
||||
See `Std.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
See `Init.Data.Iterators.Consumers` for ways to use an iterator. For example, `it.toList` will
|
||||
convert a provably finite iterator `it` into a list and `it.allowNontermination.toList` will
|
||||
do so even if finiteness cannot be proved. It is also always possible to manually iterate using
|
||||
`it.step`, relying on the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
@@ -109,12 +113,14 @@ structure Iter {α : Type w} (β : Type w) where
|
||||
Converts a pure iterator (`Iter β`) into a monadic iterator (`IterM Id β`) in the
|
||||
identity monad `Id`.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.toIterM {α : Type w} {β : Type w} (it : Iter (α := α) β) : IterM (α := α) Id β :=
|
||||
⟨it.internalState⟩
|
||||
|
||||
/--
|
||||
Converts a monadic iterator (`IterM Id β`) over `Id` into a pure iterator (`Iter β`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.toIter {α : Type w} {β : Type w} (it : IterM (α := α) Id β) : Iter (α := α) β :=
|
||||
⟨it.internalState⟩
|
||||
|
||||
@@ -168,6 +174,7 @@ inductive IterStep (α β) where
|
||||
Returns the succeeding iterator stored in an iterator step or `none` if the step is `.done`
|
||||
and the iterator has finished.
|
||||
-/
|
||||
@[expose]
|
||||
def IterStep.successor : IterStep α β → Option α
|
||||
| .yield it _ => some it
|
||||
| .skip it => some it
|
||||
@@ -177,7 +184,7 @@ def IterStep.successor : IterStep α β → Option α
|
||||
If present, applies `f` to the iterator of an `IterStep` and replaces the iterator
|
||||
with the result of the application of `f`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def IterStep.mapIterator {α' : Type u'} (f : α → α') : IterStep α β → IterStep α' β
|
||||
| .yield it out => .yield (f it) out
|
||||
| .skip it => .skip (f it)
|
||||
@@ -204,6 +211,12 @@ theorem IterStep.mapIterator_mapIterator {α' : Type u'} {α'' : Type u''}
|
||||
(step.mapIterator f).mapIterator g = step.mapIterator (g ∘ f) := by
|
||||
cases step <;> rfl
|
||||
|
||||
theorem IterStep.mapIterator_comp {α' : Type u'} {α'' : Type u''}
|
||||
{f : α → α'} {g : α' → α''} :
|
||||
IterStep.mapIterator (β := β) (g ∘ f) = mapIterator g ∘ mapIterator f := by
|
||||
apply funext
|
||||
exact fun _ => mapIterator_mapIterator.symm
|
||||
|
||||
@[simp]
|
||||
theorem IterStep.mapIterator_id {step : IterStep α β} :
|
||||
step.mapIterator id = step := by
|
||||
@@ -216,12 +229,13 @@ of another state. Having this proof bundled up with the step is important for te
|
||||
|
||||
See `IterM.Step` and `Iter.Step` for the concrete choice of the plausibility predicate.
|
||||
-/
|
||||
@[expose]
|
||||
def PlausibleIterStep (IsPlausibleStep : IterStep α β → Prop) := Subtype IsPlausibleStep
|
||||
|
||||
/--
|
||||
Match pattern for the `yield` case. See also `IterStep.yield`.
|
||||
-/
|
||||
@[match_pattern, simp]
|
||||
@[match_pattern, simp, expose]
|
||||
def PlausibleIterStep.yield {IsPlausibleStep : IterStep α β → Prop}
|
||||
(it' : α) (out : β) (h : IsPlausibleStep (.yield it' out)) :
|
||||
PlausibleIterStep IsPlausibleStep :=
|
||||
@@ -230,7 +244,7 @@ def PlausibleIterStep.yield {IsPlausibleStep : IterStep α β → Prop}
|
||||
/--
|
||||
Match pattern for the `skip` case. See also `IterStep.skip`.
|
||||
-/
|
||||
@[match_pattern, simp]
|
||||
@[match_pattern, simp, expose]
|
||||
def PlausibleIterStep.skip {IsPlausibleStep : IterStep α β → Prop}
|
||||
(it' : α) (h : IsPlausibleStep (.skip it')) : PlausibleIterStep IsPlausibleStep :=
|
||||
⟨.skip it', h⟩
|
||||
@@ -238,7 +252,7 @@ def PlausibleIterStep.skip {IsPlausibleStep : IterStep α β → Prop}
|
||||
/--
|
||||
Match pattern for the `done` case. See also `IterStep.done`.
|
||||
-/
|
||||
@[match_pattern, simp]
|
||||
@[match_pattern, simp, expose]
|
||||
def PlausibleIterStep.done {IsPlausibleStep : IterStep α β → Prop}
|
||||
(h : IsPlausibleStep .done) : PlausibleIterStep IsPlausibleStep :=
|
||||
⟨.done, h⟩
|
||||
@@ -275,7 +289,7 @@ section Monadic
|
||||
/--
|
||||
Converts wraps the state of an iterator into an `IterM` object.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def toIterM {α : Type w} (it : α) (m : Type w → Type w') (β : Type w) :
|
||||
IterM (α := α) m β :=
|
||||
⟨it⟩
|
||||
@@ -294,6 +308,7 @@ theorem internalState_toIterM {α m β} (it : α) :
|
||||
Asserts that certain step is plausibly the successor of a given iterator. What "plausible" means
|
||||
is up to the `Iterator` instance but it should be strong enough to allow termination proofs.
|
||||
-/
|
||||
@[expose]
|
||||
abbrev IterM.IsPlausibleStep {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] :
|
||||
IterM (α := α) m β → IterStep (IterM (α := α) m β) β → Prop :=
|
||||
Iterator.IsPlausibleStep (α := α) (m := m)
|
||||
@@ -302,6 +317,7 @@ abbrev IterM.IsPlausibleStep {α : Type w} {m : Type w → Type w'} {β : Type w
|
||||
The type of the step object returned by `IterM.step`, containing an `IterStep`
|
||||
and a proof that this is a plausible step for the given iterator.
|
||||
-/
|
||||
@[expose]
|
||||
abbrev IterM.Step {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) :=
|
||||
PlausibleIterStep it.IsPlausibleStep
|
||||
@@ -310,6 +326,7 @@ abbrev IterM.Step {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator
|
||||
Asserts that a certain output value could plausibly be emitted by the given iterator in its next
|
||||
step.
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.IsPlausibleOutput {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) (out : β) : Prop :=
|
||||
∃ it', it.IsPlausibleStep (.yield it' out)
|
||||
@@ -318,6 +335,7 @@ def IterM.IsPlausibleOutput {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
Asserts that a certain iterator `it'` could plausibly be the directly succeeding iterator of another
|
||||
given iterator `it`.
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.IsPlausibleSuccessorOf {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it' it : IterM (α := α) m β) : Prop :=
|
||||
∃ step, step.successor = some it' ∧ it.IsPlausibleStep step
|
||||
@@ -326,6 +344,7 @@ def IterM.IsPlausibleSuccessorOf {α : Type w} {m : Type w → Type w'} {β : Ty
|
||||
Asserts that a certain iterator `it'` could plausibly be the directly succeeding iterator of another
|
||||
given iterator `it` while no value is emitted (see `IterStep.skip`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.IsPlausibleSkipSuccessorOf {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (it' it : IterM (α := α) m β) : Prop :=
|
||||
it.IsPlausibleStep (.skip it')
|
||||
@@ -348,14 +367,27 @@ section Pure
|
||||
Asserts that certain step is plausibly the successor of a given iterator. What "plausible" means
|
||||
is up to the `Iterator` instance but it should be strong enough to allow termination proofs.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.IsPlausibleStep {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it : Iter (α := α) β) (step : IterStep (Iter (α := α) β) β) : Prop :=
|
||||
it.toIterM.IsPlausibleStep (step.mapIterator Iter.toIterM)
|
||||
|
||||
/--
|
||||
Asserts that a certain iterator `it` could plausibly yield the value `out` after an arbitrary
|
||||
number of steps.
|
||||
-/
|
||||
inductive IterM.IsPlausibleIndirectOutput {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
: IterM (α := α) m β → β → Prop where
|
||||
| direct {it : IterM (α := α) m β} {out : β} : it.IsPlausibleOutput out →
|
||||
it.IsPlausibleIndirectOutput out
|
||||
| indirect {it it' : IterM (α := α) m β} {out : β} : it'.IsPlausibleSuccessorOf it →
|
||||
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
|
||||
|
||||
/--
|
||||
The type of the step object returned by `Iter.step`, containing an `IterStep`
|
||||
and a proof that this is a plausible step for the given iterator.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.Step {α : Type w} {β : Type w} [Iterator α Id β] (it : Iter (α := α) β) :=
|
||||
PlausibleIterStep (Iter.IsPlausibleStep it)
|
||||
|
||||
@@ -370,7 +402,7 @@ def Iter.Step.toMonadic {α : Type w} {β : Type w} [Iterator α Id β] {it : It
|
||||
/--
|
||||
Converts an `IterM.Step` into an `Iter.Step`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.Step.toPure {α : Type w} {β : Type w} [Iterator α Id β] {it : IterM (α := α) Id β}
|
||||
(step : it.Step) : it.toIter.Step :=
|
||||
⟨step.val.mapIterator IterM.toIter, (by simp [Iter.IsPlausibleStep, step.property])⟩
|
||||
@@ -394,6 +426,7 @@ theorem IterM.Step.toPure_done {α β : Type w} [Iterator α Id β] {it : IterM
|
||||
Asserts that a certain output value could plausibly be emitted by the given iterator in its next
|
||||
step.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.IsPlausibleOutput {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it : Iter (α := α) β) (out : β) : Prop :=
|
||||
it.toIterM.IsPlausibleOutput out
|
||||
@@ -402,10 +435,43 @@ def Iter.IsPlausibleOutput {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
Asserts that a certain iterator `it'` could plausibly be the directly succeeding iterator of another
|
||||
given iterator `it`.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.IsPlausibleSuccessorOf {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it' it : Iter (α := α) β) : Prop :=
|
||||
it'.toIterM.IsPlausibleSuccessorOf it.toIterM
|
||||
|
||||
/--
|
||||
Asserts that a certain iterator `it` could plausibly yield the value `out` after an arbitrary
|
||||
number of steps.
|
||||
-/
|
||||
inductive Iter.IsPlausibleIndirectOutput {α β : Type w} [Iterator α Id β] :
|
||||
Iter (α := α) β → β → Prop where
|
||||
| direct {it : Iter (α := α) β} {out : β} : it.IsPlausibleOutput out →
|
||||
it.IsPlausibleIndirectOutput out
|
||||
| indirect {it it' : Iter (α := α) β} {out : β} : it'.IsPlausibleSuccessorOf it →
|
||||
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
|
||||
|
||||
theorem Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM {α β : Type w}
|
||||
[Iterator α Id β] {it : Iter (α := α) β} {out : β} :
|
||||
it.IsPlausibleIndirectOutput out ↔ it.toIterM.IsPlausibleIndirectOutput out := by
|
||||
constructor
|
||||
· intro h
|
||||
induction h with
|
||||
| direct h =>
|
||||
exact .direct h
|
||||
| indirect h _ ih =>
|
||||
exact .indirect h ih
|
||||
· intro h
|
||||
rw [← Iter.toIter_toIterM (it := it)]
|
||||
generalize it.toIterM = it at ⊢ h
|
||||
induction h with
|
||||
| direct h =>
|
||||
exact .direct h
|
||||
| indirect h h' ih =>
|
||||
rename_i it it' out
|
||||
replace h : it'.toIter.IsPlausibleSuccessorOf it.toIter := h
|
||||
exact .indirect (α := α) h ih
|
||||
|
||||
/--
|
||||
Asserts that a certain iterator `it'` could plausibly be the directly succeeding iterator of another
|
||||
given iterator `it` while no value is emitted (see `IterStep.skip`).
|
||||
@@ -419,7 +485,7 @@ Makes a single step with the given iterator `it`, potentially emitting a value a
|
||||
succeeding iterator. If this function is used recursively, termination can sometimes be proved with
|
||||
the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.step {α β : Type w} [Iterator α Id β] (it : Iter (α := α) β) : it.Step :=
|
||||
it.toIterM.step.run.toPure
|
||||
|
||||
@@ -448,6 +514,7 @@ structure IterM.TerminationMeasures.Finite
|
||||
The relation of plausible successors on `IterM.TerminationMeasures.Finite`. It is well-founded
|
||||
if there is a `Finite` instance.
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.TerminationMeasures.Finite.Rel
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] :
|
||||
TerminationMeasures.Finite α m → TerminationMeasures.Finite α m → Prop :=
|
||||
@@ -456,12 +523,13 @@ def IterM.TerminationMeasures.Finite.Rel
|
||||
instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Finite α m] : WellFoundedRelation (IterM.TerminationMeasures.Finite α m) where
|
||||
rel := IterM.TerminationMeasures.Finite.Rel
|
||||
wf := (InvImage.wf _ Finite.wf).transGen
|
||||
wf := by exact (InvImage.wf _ Finite.wf).transGen
|
||||
|
||||
/--
|
||||
Termination measure to be used in well-founded recursive functions recursing over a finite iterator
|
||||
(see also `Finite`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySteps {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Finite α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Finite α m :=
|
||||
⟨it⟩
|
||||
@@ -486,9 +554,10 @@ theorem IterM.TerminationMeasures.Finite.rel_of_skip
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
first
|
||||
| exact IterM.TerminationMeasures.Finite.rel_of_yield ‹_›
|
||||
| exact IterM.TerminationMeasures.Finite.rel_of_skip ‹_›)
|
||||
| exact IterM.TerminationMeasures.Finite.rel_of_skip ‹_›
|
||||
| fail)
|
||||
|
||||
@[inherit_doc IterM.finitelyManySteps]
|
||||
@[inherit_doc IterM.finitelyManySteps, expose]
|
||||
def Iter.finitelyManySteps {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
|
||||
it.toIterM.finitelyManySteps
|
||||
@@ -513,7 +582,8 @@ theorem Iter.TerminationMeasures.Finite.rel_of_skip
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
first
|
||||
| exact Iter.TerminationMeasures.Finite.rel_of_yield ‹_›
|
||||
| exact Iter.TerminationMeasures.Finite.rel_of_skip ‹_›)
|
||||
| exact Iter.TerminationMeasures.Finite.rel_of_skip ‹_›
|
||||
| fail)
|
||||
|
||||
theorem IterM.isPlausibleSuccessorOf_of_yield
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
@@ -553,6 +623,7 @@ structure IterM.TerminationMeasures.Productive
|
||||
The relation of plausible successors while skipping on `IterM.TerminationMeasures.Productive`.
|
||||
It is well-founded if there is a `Productive` instance.
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.TerminationMeasures.Productive.Rel
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] :
|
||||
TerminationMeasures.Productive α m → TerminationMeasures.Productive α m → Prop :=
|
||||
@@ -561,12 +632,13 @@ def IterM.TerminationMeasures.Productive.Rel
|
||||
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
|
||||
wf := (InvImage.wf _ Productive.wf).transGen
|
||||
wf := by exact (InvImage.wf _ Productive.wf).transGen
|
||||
|
||||
/--
|
||||
Termination measure to be used in well-founded recursive functions recursing over a productive
|
||||
iterator (see also `Productive`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySkips {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Productive α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
|
||||
⟨it⟩
|
||||
@@ -582,9 +654,11 @@ theorem IterM.TerminationMeasures.Productive.rel_of_skip
|
||||
.single h
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
exact IterM.TerminationMeasures.Productive.rel_of_skip ‹_›)
|
||||
first
|
||||
| exact IterM.TerminationMeasures.Productive.rel_of_skip ‹_›
|
||||
| fail)
|
||||
|
||||
@[inherit_doc IterM.finitelyManySkips]
|
||||
@[inherit_doc IterM.finitelyManySkips, expose]
|
||||
def Iter.finitelyManySkips {α : Type w} {β : Type w} [Iterator α Id β] [Productive α Id]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
|
||||
it.toIterM.finitelyManySkips
|
||||
@@ -600,7 +674,9 @@ theorem Iter.TerminationMeasures.Productive.rel_of_skip
|
||||
IterM.TerminationMeasures.Productive.rel_of_skip h
|
||||
|
||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
exact Iter.TerminationMeasures.Productive.rel_of_skip ‹_›)
|
||||
first
|
||||
| exact Iter.TerminationMeasures.Productive.rel_of_skip ‹_›
|
||||
| fail)
|
||||
|
||||
instance [Iterator α m β] [Finite α m] : Productive α m where
|
||||
wf := by
|
||||
13
src/Init/Data/Iterators/Consumers.lean
Normal file
13
src/Init/Data/Iterators/Consumers.lean
Normal file
@@ -0,0 +1,13 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Consumers.Monadic
|
||||
import Init.Data.Iterators.Consumers.Access
|
||||
import Init.Data.Iterators.Consumers.Collect
|
||||
import Init.Data.Iterators.Consumers.Loop
|
||||
import Init.Data.Iterators.Consumers.Partial
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Consumers.Partial
|
||||
import Init.Data.Iterators.Consumers.Partial
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
@@ -3,10 +3,12 @@ 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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Std.Data.Iterators.Consumers.Partial
|
||||
import Std.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Init.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Consumers.Partial
|
||||
import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
/-!
|
||||
# Collectors
|
||||
@@ -54,4 +56,18 @@ def Iter.Partial.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollectPartial α Id Id] (it : Iter.Partial (α := α) β) : List β :=
|
||||
it.it.toIterM.allowNontermination.toList.run
|
||||
|
||||
/--
|
||||
This class charaterizes how the plausibility behavior (`IsPlausibleStep`) and the actual iteration
|
||||
behavior (`it.step`) should relate to each other for pure iterators. Intuitively, a step should
|
||||
only be plausible if it is possible. For simplicity's sake, the actual definition is weaker but
|
||||
presupposes that the iterator is finite.
|
||||
|
||||
This is an experimental instance and it should not be explicitly used downstream of the standard
|
||||
library.
|
||||
-/
|
||||
class LawfulPureIterator (α : Type w) [Iterator α Id β]
|
||||
[Finite α Id] [IteratorCollect α Id Id] where
|
||||
mem_toList_iff_isPlausibleIndirectOutput {it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toList ↔ it.IsPlausibleIndirectOutput out
|
||||
|
||||
end Std.Iterators
|
||||
@@ -3,9 +3,11 @@ 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
|
||||
import Std.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Std.Data.Iterators.Consumers.Partial
|
||||
import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Init.Data.Iterators.Consumers.Partial
|
||||
|
||||
/-!
|
||||
# Loop consumers
|
||||
@@ -22,11 +24,24 @@ These operations are implemented using the `IteratorLoop` and `IteratorLoopParti
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
/--
|
||||
A `ForIn'` instance for iterators. Its generic membership relation is not easy to use,
|
||||
so this is not marked as `instance`. This way, more convenient instances can be built on top of it
|
||||
or future library improvements will make it more comfortable.
|
||||
-/
|
||||
def Iter.instForIn' {α : Type w} {β : Type w} {n : Type w → Type w'} [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
ForIn' n (Iter (α := α) β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoop.finiteForIn' (fun δ (c : Id δ) => pure c.run) |>.forIn' it.toIterM init
|
||||
fun out h acc =>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
ForIn n (Iter (α := α) β) β where
|
||||
forIn it init f :=
|
||||
IteratorLoop.finiteForIn (fun δ (c : Id δ) => pure c.run) |>.forIn it.toIterM init f
|
||||
ForIn n (Iter (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
@@ -111,4 +126,14 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.size]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSize.size it.toIterM).run.down
|
||||
|
||||
@[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
|
||||
|
||||
end Std.Iterators
|
||||
11
src/Init/Data/Iterators/Consumers/Monadic.lean
Normal file
11
src/Init/Data/Iterators/Consumers/Monadic.lean
Normal file
@@ -0,0 +1,11 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Init.Data.Iterators.Consumers.Monadic.Partial
|
||||
@@ -3,9 +3,11 @@ 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
|
||||
import Std.Data.Iterators.Consumers.Monadic.Partial
|
||||
import Std.Data.Internal.LawfulMonadLiftFunction
|
||||
import Init.Data.Iterators.Consumers.Monadic.Partial
|
||||
import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
|
||||
/-!
|
||||
# Collectors
|
||||
@@ -3,10 +3,12 @@ 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
|
||||
import Init.RCases
|
||||
import Std.Data.Iterators.Basic
|
||||
import Std.Data.Iterators.Consumers.Monadic.Partial
|
||||
import Init.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Consumers.Monadic.Partial
|
||||
|
||||
/-!
|
||||
# Loop-based consumers
|
||||
@@ -62,8 +64,9 @@ class IteratorLoop (α : Type w) (m : Type w → Type w') {β : Type w} [Iterato
|
||||
forIn : ∀ (_lift : (γ : Type w) → m γ → n γ) (γ : Type w),
|
||||
(plausible_forInStep : β → γ → ForInStep γ → Prop) →
|
||||
IteratorLoop.WellFounded α m plausible_forInStep →
|
||||
IterM (α := α) m β → γ →
|
||||
((b : β) → (c : γ) → n (Subtype (plausible_forInStep b c))) → n γ
|
||||
(it : IterM (α := α) m β) → γ →
|
||||
((b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))) →
|
||||
n γ
|
||||
|
||||
/--
|
||||
`IteratorLoopPartial α m` provides efficient implementations of loop-based consumers for `α`-based
|
||||
@@ -76,7 +79,29 @@ provided by the standard library.
|
||||
class IteratorLoopPartial (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
|
||||
(n : Type w → Type w'') where
|
||||
forInPartial : ∀ (_lift : (γ : Type w) → m γ → n γ) {γ : Type w},
|
||||
IterM (α := α) m β → γ → ((b : β) → (c : γ) → n (ForInStep γ)) → n γ
|
||||
(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
|
||||
|
||||
@@ -91,7 +116,7 @@ private def IteratorLoop.WFRel.mk {α : Type w} {m : Type w → Type w'} {β : T
|
||||
IteratorLoop.WFRel wf :=
|
||||
(it, c)
|
||||
|
||||
instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
private instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
{γ : Type x} {plausible_forInStep : β → γ → ForInStep γ → Prop}
|
||||
(wf : IteratorLoop.WellFounded α m plausible_forInStep) :
|
||||
WellFoundedRelation (IteratorLoop.WFRel wf) where
|
||||
@@ -102,23 +127,27 @@ instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
This is the loop implementation of the default instance `IteratorLoop.defaultImplementation`.
|
||||
-/
|
||||
@[specialize]
|
||||
def IterM.DefaultConsumers.forIn {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
def IterM.DefaultConsumers.forIn' {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
(lift : ∀ γ, m γ → n γ) (γ : Type w)
|
||||
(plausible_forInStep : β → γ → ForInStep γ → Prop)
|
||||
(wf : IteratorLoop.WellFounded α m plausible_forInStep)
|
||||
(it : IterM (α := α) m β) (init : γ)
|
||||
(f : (b : β) → (c : γ) → n (Subtype (plausible_forInStep b c))) : n γ :=
|
||||
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))) : n γ :=
|
||||
haveI : WellFounded _ := wf
|
||||
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
|
||||
do
|
||||
match ← it.step with
|
||||
| .yield it' out _ =>
|
||||
match ← f out init with
|
||||
| ⟨.yield c, _⟩ => IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' c f
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c
|
||||
(fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc)
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' _ => IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' init f
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init
|
||||
(fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc)
|
||||
| .done _ => return init
|
||||
termination_by IteratorLoop.WFRel.mk wf it init
|
||||
decreasing_by
|
||||
@@ -134,7 +163,7 @@ implementations are possible and should be used instead.
|
||||
def IteratorLoop.defaultImplementation {α : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[Monad n] [Iterator α m β] :
|
||||
IteratorLoop α m n where
|
||||
forIn lift := IterM.DefaultConsumers.forIn lift
|
||||
forIn lift := IterM.DefaultConsumers.forIn' lift
|
||||
|
||||
/--
|
||||
Asserts that a given `IteratorLoop` instance is equal to `IteratorLoop.defaultImplementation`.
|
||||
@@ -153,15 +182,19 @@ partial def IterM.DefaultConsumers.forInPartial {m : Type w → Type w'} {α : T
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
(lift : ∀ γ, m γ → n γ) (γ : Type w)
|
||||
(it : IterM (α := α) m β) (init : γ)
|
||||
(f : (b : β) → (c : γ) → n (ForInStep γ)) : n γ :=
|
||||
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) : n γ :=
|
||||
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
|
||||
do
|
||||
match ← it.step with
|
||||
| .yield it' out _ =>
|
||||
match ← f out init with
|
||||
| .yield c => IterM.DefaultConsumers.forInPartial lift _ it' c f
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| .yield c =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' c
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done c => return c
|
||||
| .skip it' _ => IterM.DefaultConsumers.forInPartial lift _ it' init f
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init
|
||||
|
||||
/--
|
||||
@@ -175,7 +208,7 @@ def IteratorLoopPartial.defaultImplementation {α : Type w} {m : Type w → Type
|
||||
IteratorLoopPartial α m n where
|
||||
forInPartial lift := IterM.DefaultConsumers.forInPartial lift _
|
||||
|
||||
instance (α : Type w) (m : Type w → Type w') (n : Type w → Type w')
|
||||
instance (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
|
||||
[Monad m] [Monad n] [Iterator α m β] [Finite α m] :
|
||||
letI : IteratorLoop α m n := .defaultImplementation
|
||||
LawfulIteratorLoop α m n :=
|
||||
@@ -196,27 +229,40 @@ theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
|
||||
exact WellFoundedRelation.wf
|
||||
|
||||
/--
|
||||
This `ForIn`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
|
||||
This `ForIn'`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorLoop.finiteForIn {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
def IteratorLoop.finiteForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
(lift : ∀ γ, m γ → n γ) :
|
||||
ForIn n (IterM (α := α) m β) β where
|
||||
forIn {γ} [Monad n] it init f :=
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' {γ} [Monad n] it init f :=
|
||||
IteratorLoop.forIn (α := α) (m := m) lift γ (fun _ _ _ => True)
|
||||
wellFounded_of_finite
|
||||
it init ((⟨·, .intro⟩) <$> f · ·)
|
||||
it init (fun out h acc => (⟨·, .intro⟩) <$> f out h acc)
|
||||
|
||||
/--
|
||||
A `ForIn'` instance for iterators. Its generic membership relation is not easy to use,
|
||||
so this is not marked as `instance`. This way, more convenient instances can be built on top of it
|
||||
or future library improvements will make it more comfortable.
|
||||
-/
|
||||
def IterM.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ :=
|
||||
IteratorLoop.finiteForIn' (fun _ => monadLift)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForIn n (IterM (α := α) m β) β := IteratorLoop.finiteForIn (fun _ => monadLift)
|
||||
ForIn n (IterM (α := α) m β) β :=
|
||||
haveI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [MonadLiftT m n] :
|
||||
ForIn n (IterM.Partial (α := α) m β) β where
|
||||
forIn it init f :=
|
||||
ForIn' n (IterM.Partial (α := α) m β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoopPartial.forInPartial (α := α) (m := m) (fun _ => monadLift) it.it init f
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
@@ -327,4 +373,86 @@ def IterM.Partial.drain {α : Type w} {m : Type w → Type w'} [Monad m] {β : T
|
||||
m PUnit :=
|
||||
it.fold (γ := PUnit) (fun _ _ => .unit) .unit
|
||||
|
||||
section Size
|
||||
|
||||
/--
|
||||
This is the implementation of the default instance `IteratorSize.defaultImplementation`.
|
||||
-/
|
||||
@[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) :=
|
||||
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.
|
||||
|
||||
**Performance**:
|
||||
|
||||
Default performance 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
|
||||
|
||||
/--
|
||||
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`.
|
||||
|
||||
**Performance**:
|
||||
|
||||
Default performance 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
|
||||
|
||||
end Size
|
||||
|
||||
end Std.Iterators
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Basic
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Basic
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
10
src/Init/Data/Iterators/Internal.lean
Normal file
10
src/Init/Data/Iterators/Internal.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
|
||||
import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
import Init.Data.Iterators.Internal.Termination
|
||||
@@ -3,6 +3,8 @@ 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
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Lawful.Basic
|
||||
@@ -10,7 +12,7 @@ import Init.NotationExtra
|
||||
import Init.Control.Lawful.MonadLift
|
||||
|
||||
/-!
|
||||
# Typeclass for lawfule monad lifting functions
|
||||
# Typeclass for lawful monad lifting functions
|
||||
|
||||
This module provides a typeclass `LawfulMonadLiftFunction f` that asserts that a function `f`
|
||||
mapping values from one monad to another monad commutes with `pure` and `bind`. This equivalent to
|
||||
@@ -60,9 +62,13 @@ theorem LawfulMonadLiftFunction.lift_seqRight [LawfulMonad m] [LawfulMonad n]
|
||||
lift (x *> y) = (lift x : n α) *> (lift y : n β) := by
|
||||
simp only [seqRight_eq, lift_map, lift_seq]
|
||||
|
||||
def instMonadLiftOfFunction {lift : ⦃α : Type u⦄ -> m α → n α} :
|
||||
MonadLift m n where
|
||||
monadLift := lift (α := _)
|
||||
abbrev idToMonad [Monad m] ⦃α : Type u⦄ (x : Id α) : m α :=
|
||||
pure x.run
|
||||
|
||||
def LawfulMonadLiftFunction.idToMonad [Monad m] [LawfulMonad m] :
|
||||
LawfulMonadLiftFunction (m := Id) (n := m) idToMonad where
|
||||
lift_pure := by simp [Internal.idToMonad]
|
||||
lift_bind := by simp [Internal.idToMonad]
|
||||
|
||||
instance [LawfulMonadLiftFunction lift] :
|
||||
letI : MonadLift m n := ⟨lift (α := _)⟩
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Basic
|
||||
|
||||
/-!
|
||||
This is an internal module used by iterator implementations.
|
||||
@@ -3,5 +3,7 @@ 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
|
||||
import Std.Data.Iterators.Internal.Termination
|
||||
import Init.Data.Iterators.Lemmas.Consumers
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Basic
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
11
src/Init/Data/Iterators/Lemmas/Consumers.lean
Normal file
11
src/Init/Data/Iterators/Lemmas/Consumers.lean
Normal file
@@ -0,0 +1,11 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Loop
|
||||
114
src/Init/Data/Iterators/Lemmas/Consumers/Collect.lean
Normal file
114
src/Init/Data/Iterators/Lemmas/Consumers/Collect.lean
Normal file
@@ -0,0 +1,114 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Lemmas.Basic
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Access
|
||||
import all Init.Data.Iterators.Consumers.Collect
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
theorem Iter.toArray_eq_toArray_toIterM {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray = it.toIterM.toArray.run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.toList_eq_toList_toIterM {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList = it.toIterM.toList.run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.toListRev_eq_toListRev_toIterM {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev = it.toIterM.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toIter {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
{it : IterM (α := α) Id β} :
|
||||
it.toIter.toList = it.toList.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : IterM (α := α) Id β} :
|
||||
it.toIter.toListRev = it.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray.toList = it.toList := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toList_toArray]
|
||||
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.toArray = it.toArray := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toArray_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.reverse_toListRev [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev.reverse = it.toList := by
|
||||
simp [toListRev_eq_toListRev_toIterM, toList_eq_toList_toIterM, ← IterM.reverse_toListRev]
|
||||
|
||||
theorem Iter.toListRev_eq {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toListRev = it.toList.reverse := by
|
||||
simp [Iter.toListRev_eq_toListRev_toIterM, Iter.toList_eq_toList_toIterM, IterM.toListRev_eq]
|
||||
|
||||
theorem Iter.toArray_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray = match it.step with
|
||||
| .yield it' out _ => #[out] ++ it'.toArray
|
||||
| .skip it' _ => it'.toArray
|
||||
| .done _ => #[] := by
|
||||
simp only [Iter.toArray_eq_toArray_toIterM, Iter.step]
|
||||
rw [IterM.toArray_eq_match_step, Id.run_bind]
|
||||
generalize it.toIterM.step.run = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem Iter.toList_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList = match it.step with
|
||||
| .yield it' out _ => out :: it'.toList
|
||||
| .skip it' _ => it'.toList
|
||||
| .done _ => [] := by
|
||||
rw [← Iter.toList_toArray, Iter.toArray_eq_match_step]
|
||||
split <;> simp [Iter.toList_toArray]
|
||||
|
||||
theorem Iter.toListRev_eq_match_step {α β} [Iterator α Id β] [Finite α Id] {it : Iter (α := α) β} :
|
||||
it.toListRev = match it.step with
|
||||
| .yield it' out _ => it'.toListRev ++ [out]
|
||||
| .skip it' _ => it'.toListRev
|
||||
| .done _ => [] := by
|
||||
rw [Iter.toListRev_eq_toListRev_toIterM, IterM.toListRev_eq_match_step, Iter.step, Id.run_bind]
|
||||
generalize it.toIterM.step.run = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {k : Nat} :
|
||||
it.toList[k]? = it.atIdxSlow? k := by
|
||||
induction it using Iter.inductSteps generalizing k with | step it ihy ihs =>
|
||||
rw [toList_eq_match_step, atIdxSlow?]
|
||||
obtain ⟨step, h⟩ := it.step
|
||||
cases step
|
||||
· cases k <;> simp [ihy h]
|
||||
· simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_of_atIdxSlow?_eq {α₁ α₂ β}
|
||||
[Iterator α₁ Id β] [Finite α₁ Id] [IteratorCollect α₁ Id Id] [LawfulIteratorCollect α₁ Id Id]
|
||||
[Iterator α₂ Id β] [Finite α₂ Id] [IteratorCollect α₂ Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
{it₁ : Iter (α := α₁) β} {it₂ : Iter (α := α₂) β}
|
||||
(h : ∀ k, it₁.atIdxSlow? k = it₂.atIdxSlow? k) :
|
||||
it₁.toList = it₂.toList := by
|
||||
ext; simp [getElem?_toList_eq_atIdxSlow?, h]
|
||||
|
||||
end Std.Iterators
|
||||
285
src/Init/Data/Iterators/Lemmas/Consumers/Loop.lean
Normal file
285
src/Init/Data/Iterators/Lemmas/Consumers/Loop.lean
Normal file
@@ -0,0 +1,285 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
import all Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ c => pure c.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init
|
||||
(fun out h acc => (⟨·, .intro⟩) <$>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (b : β) → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ c => pure c.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init
|
||||
(fun out _ acc => (⟨·, .intro⟩) <$>
|
||||
f out acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f =
|
||||
letI : MonadLift Id m := ⟨Std.Internal.idToMonad (α := _)⟩
|
||||
letI : ForIn' m (IterM (α := α) Id β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it.toIterM init
|
||||
(fun out h acc => f out (isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
letI : MonadLift Id m := ⟨Std.Internal.idToMonad (α := _)⟩
|
||||
ForIn.forIn it.toIterM init f := by
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn'_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = (do
|
||||
match it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| .yield c =>
|
||||
ForIn'.forIn' it' c
|
||||
fun out h'' acc => f out (.indirect ⟨_, rfl, h⟩ h'') acc
|
||||
| .done c => return c
|
||||
| .skip it' h =>
|
||||
ForIn'.forIn' it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
rw [Iter.forIn'_eq_forIn'_toIterM, @IterM.forIn'_eq_match_step, Iter.step]
|
||||
simp only [liftM, monadLift, pure_bind]
|
||||
generalize it.toIterM.step = step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· apply bind_congr
|
||||
intro forInStep
|
||||
rfl
|
||||
· rfl
|
||||
· rfl
|
||||
|
||||
theorem Iter.forIn_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f = (do
|
||||
match it.step with
|
||||
| .yield it' out _ =>
|
||||
match ← f out init with
|
||||
| .yield c => ForIn.forIn it' c f
|
||||
| .done c => return c
|
||||
| .skip it' _ => ForIn.forIn it' init f
|
||||
| .done _ => return init) := by
|
||||
rw [Iter.forIn_eq_forIn_toIterM, @IterM.forIn_eq_match_step, Iter.step]
|
||||
simp only [liftM, monadLift, pure_bind]
|
||||
generalize it.toIterM.step = step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· apply bind_congr
|
||||
intro forInStep
|
||||
rfl
|
||||
· rfl
|
||||
· rfl
|
||||
|
||||
private theorem Iter.forIn'_toList.aux {ρ : Type u} {α : Type v} {γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] {_ : Membership α ρ} [ForIn' m ρ α inferInstance]
|
||||
{r s : ρ} {init : γ} {f : (a : α) → _ → γ → m (ForInStep γ)} (h : r = s) :
|
||||
forIn' r init f = forIn' s init (fun a h' acc => f a (h ▸ h') acc) := by
|
||||
cases h; rfl
|
||||
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulPureIterator α]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toList init f = ForIn'.forIn' it init (fun out h acc => f out (LawfulPureIterator.mem_toList_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
induction it using Iter.inductSteps generalizing init with case step it ihy ihs =>
|
||||
have := it.toList_eq_match_step
|
||||
generalize hs : it.step = step at this
|
||||
rw [forIn'_toList.aux this]
|
||||
rw [forIn'_eq_match_step]
|
||||
rw [List.forIn'_eq_foldlM] at *
|
||||
simp only [map_eq_pure_bind, List.foldlM_map, hs]
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· rename_i it' out h
|
||||
simp only [List.attach_cons, List.foldlM_cons, bind_pure_comp, map_bind]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· induction it'.toList.attach <;> simp [*]
|
||||
· simp only [List.foldlM_map]
|
||||
simp only [List.forIn'_eq_foldlM] at ihy
|
||||
simp only at this
|
||||
simp only [ihy h (f := fun out h acc => f out (by rw [this]; exact List.mem_cons_of_mem _ h) acc)]
|
||||
· rename_i it' h
|
||||
simp only [bind_pure_comp]
|
||||
simp only [List.forIn'_eq_foldlM] at ihs
|
||||
simp only at this
|
||||
simp only [ihs h (f := fun out h acc => f out (this ▸ h) acc)]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulPureIterator α]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toList init (fun out h acc => f out (LawfulPureIterator.mem_toList_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toList]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toList init f = ForIn.forIn it init f := by
|
||||
rw [List.forIn_eq_foldlM]
|
||||
induction it using Iter.inductSteps generalizing init with case step it ihy ihs =>
|
||||
rw [forIn_eq_match_step, Iter.toList_eq_match_step]
|
||||
simp only [map_eq_pure_bind]
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· rename_i it' out h
|
||||
simp only [List.foldlM_cons, bind_pure_comp, map_bind]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· induction it'.toList <;> simp [*]
|
||||
· simp only [ForIn.forIn, forIn', List.forIn'] at ihy
|
||||
simp [ihy h, forIn_eq_forIn_toIterM]
|
||||
· rename_i it' h
|
||||
simp only [bind_pure_comp]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.foldM_eq_forIn {α β γ : Type w} [Iterator α Id β] [Finite α Id] {m : Type w → Type w'}
|
||||
[Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
it.foldM (init := init) f = ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x) :=
|
||||
(rfl)
|
||||
|
||||
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]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ} {f : γ → β → m γ} :
|
||||
it.foldM (init := init) f = letI : MonadLift Id m := ⟨pure⟩; it.toIterM.foldM (init := init) f :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.forIn_yield_eq_foldM {α β γ δ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] {f : β → γ → m δ} {g : β → γ → δ → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
ForIn.forIn it init (fun c b => (fun d => .yield (g c b d)) <$> f c b) =
|
||||
it.foldM (fun b c => g c b <$> f c b) init := by
|
||||
simp [Iter.foldM_eq_forIn]
|
||||
|
||||
theorem Iter.foldM_eq_match_step {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type w → Type w'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] {f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.foldM (init := init) f = (do
|
||||
match it.step with
|
||||
| .yield it' out _ => it'.foldM (init := ← f init out) f
|
||||
| .skip it' _ => it'.foldM (init := init) f
|
||||
| .done _ => return init) := by
|
||||
rw [Iter.foldM_eq_forIn, Iter.forIn_eq_match_step]
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp [foldM_eq_forIn]
|
||||
|
||||
theorem Iter.foldlM_toList {α β γ : Type w} [Iterator α Id β] [Finite α Id] {m : Type w → Type w'}
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
it.toList.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
forIn it init f = ForInStep.value <$>
|
||||
it.foldM (fun c b => match c with
|
||||
| .yield c => f b c
|
||||
| .done c => pure (.done c)) (ForInStep.yield init) := by
|
||||
simp only [← Iter.forIn_toList, List.forIn_eq_foldlM, ← Iter.foldlM_toList]; rfl
|
||||
|
||||
theorem Iter.fold_eq_forIn {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f =
|
||||
(ForIn.forIn (m := Id) it init (fun x acc => pure (ForInStep.yield (f acc x)))).run := by
|
||||
rfl
|
||||
|
||||
theorem Iter.fold_eq_foldM {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
[LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
ForIn.forIn (m := Id) it init (fun c b => pure (.yield (f c b))) =
|
||||
pure (it.fold (fun b c => f c b) init) := by
|
||||
simp only [fold_eq_forIn]
|
||||
rfl
|
||||
|
||||
theorem Iter.fold_eq_match_step {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (match it.step with
|
||||
| .yield it' out _ => it'.fold (init := f init out) f
|
||||
| .skip it' _ => it'.fold (init := init) f
|
||||
| .done _ => init) := by
|
||||
rw [fold_eq_foldM, foldM_eq_match_step]
|
||||
simp only [fold_eq_foldM]
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem Iter.foldl_toList {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toList.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
|
||||
|
||||
end Std.Iterators
|
||||
@@ -3,7 +3,8 @@ 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
|
||||
import Std.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Std.Data.Iterators.Consumers.Monadic.Loop
|
||||
import Std.Data.Iterators.Consumers.Monadic.Partial
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
157
src/Init/Data/Iterators/Lemmas/Consumers/Monadic/Collect.lean
Normal file
157
src/Init/Data/Iterators/Lemmas/Consumers/Monadic/Collect.lean
Normal file
@@ -0,0 +1,157 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Iterators.Lemmas.Monadic.Basic
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
variable {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{lift : ⦃δ : Type w⦄ → m δ → n δ} {f : β → n γ} {it : IterM (α := α) m β}
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped.go.aux₁ [Monad n] [LawfulMonad n] [Iterator α m β]
|
||||
[Finite α m] {b : γ} {bs : Array γ} :
|
||||
IterM.DefaultConsumers.toArrayMapped.go lift f it (#[b] ++ bs) (m := m) =
|
||||
(#[b] ++ ·) <$> IterM.DefaultConsumers.toArrayMapped.go lift f it bs (m := m) := by
|
||||
induction it, bs using IterM.DefaultConsumers.toArrayMapped.go.induct
|
||||
next it bs ih₁ ih₂ =>
|
||||
rw [go, map_eq_pure_bind, go, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split
|
||||
· simp [ih₁ _ _ ‹_›]
|
||||
· simp [ih₂ _ ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped.go.aux₂ [Monad n] [LawfulMonad n] [Iterator α m β]
|
||||
[Finite α m] {acc : Array γ} :
|
||||
IterM.DefaultConsumers.toArrayMapped.go lift f it acc (m := m) =
|
||||
(acc ++ ·) <$> IterM.DefaultConsumers.toArrayMapped lift f it (m := m) := by
|
||||
rw [← Array.toArray_toList (xs := acc)]
|
||||
generalize acc.toList = acc
|
||||
induction acc with
|
||||
| nil => simp [toArrayMapped]
|
||||
| cons x xs ih =>
|
||||
rw [List.toArray_cons, IterM.DefaultConsumers.toArrayMapped.go.aux₁, ih]
|
||||
simp only [Functor.map_map, Array.append_assoc]
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped_eq_match_step [Monad n] [LawfulMonad n]
|
||||
[Iterator α m β] [Finite α m] :
|
||||
IterM.DefaultConsumers.toArrayMapped lift f it (m := m) = letI : MonadLift m n := ⟨lift (δ := _)⟩; (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ =>
|
||||
return #[← f out] ++ (← IterM.DefaultConsumers.toArrayMapped lift f it' (m := m))
|
||||
| .skip it' _ => IterM.DefaultConsumers.toArrayMapped lift f it' (m := m)
|
||||
| .done _ => return #[]) := by
|
||||
rw [IterM.DefaultConsumers.toArrayMapped, IterM.DefaultConsumers.toArrayMapped.go]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split <;> simp [IterM.DefaultConsumers.toArrayMapped.go.aux₂]
|
||||
|
||||
theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] :
|
||||
it.toArray = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ => return #[out] ++ (← it'.toArray)
|
||||
| .skip it' _ => it'.toArray
|
||||
| .done _ => return #[]) := by
|
||||
simp only [IterM.toArray, LawfulIteratorCollect.toArrayMapped_eq]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind, toArray]
|
||||
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.toArray = it.toList := by
|
||||
simp [IterM.toList]
|
||||
|
||||
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.toList = it.toArray := by
|
||||
simp [IterM.toList]
|
||||
|
||||
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
it.toList = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ => return out :: (← it'.toList)
|
||||
| .skip it' _ => it'.toList
|
||||
| .done _ => return []) := by
|
||||
simp [← IterM.toList_toArray]
|
||||
rw [IterM.toArray_eq_match_step, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split <;> simp
|
||||
|
||||
theorem IterM.toListRev.go.aux₁ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {b : β} {bs : List β} :
|
||||
IterM.toListRev.go it (bs ++ [b]) = (· ++ [b]) <$> IterM.toListRev.go it bs:= by
|
||||
induction it, bs using IterM.toListRev.go.induct
|
||||
next it bs ih₁ ih₂ =>
|
||||
rw [go, go, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
simp only [List.cons_append] at ih₁
|
||||
split <;> simp [*]
|
||||
|
||||
theorem IterM.toListRev.go.aux₂ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {acc : List β} :
|
||||
IterM.toListRev.go it acc = (· ++ acc) <$> it.toListRev := by
|
||||
rw [← List.reverse_reverse (as := acc)]
|
||||
generalize acc.reverse = acc
|
||||
induction acc with
|
||||
| nil => simp [toListRev]
|
||||
| cons x xs ih => simp [IterM.toListRev.go.aux₁, ih]
|
||||
|
||||
theorem IterM.toListRev_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toListRev = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ => return (← it'.toListRev) ++ [out]
|
||||
| .skip it' _ => it'.toListRev
|
||||
| .done _ => return []) := by
|
||||
simp [IterM.toListRev]
|
||||
rw [toListRev.go]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp [IterM.toListRev.go.aux₂]
|
||||
|
||||
theorem IterM.reverse_toListRev [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
List.reverse <$> it.toListRev = it.toList := by
|
||||
apply Eq.symm
|
||||
induction it using IterM.inductSteps
|
||||
rename_i it ihy ihs
|
||||
rw [toListRev_eq_match_step, toList_eq_match_step, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split <;> simp (discharger := assumption) [ihy, ihs]
|
||||
|
||||
theorem IterM.toListRev_eq [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toListRev = List.reverse <$> it.toList := by
|
||||
rw [← IterM.reverse_toListRev]
|
||||
simp
|
||||
|
||||
theorem LawfulIteratorCollect.toArray_eq {α β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = (letI : IteratorCollect α m m := .defaultImplementation; it.toArray) := by
|
||||
simp only [IterM.toArray, toArrayMapped_eq]
|
||||
|
||||
theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq]
|
||||
|
||||
end Std.Iterators
|
||||
277
src/Init/Data/Iterators/Lemmas/Consumers/Monadic/Loop.lean
Normal file
277
src/Init/Data/Iterators/Lemmas/Consumers/Monadic/Loop.lean
Normal file
@@ -0,0 +1,277 @@
|
||||
/-
|
||||
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
|
||||
import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β]
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
{lift : ∀ γ, m γ → n γ} {γ : Type w}
|
||||
{plausible_forInStep : β → γ → ForInStep γ → Prop}
|
||||
{wf : IteratorLoop.WellFounded α m plausible_forInStep}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))} :
|
||||
IterM.DefaultConsumers.forIn' lift γ plausible_forInStep wf it init f = (do
|
||||
match ← lift _ it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c
|
||||
fun out h'' acc => f out (.indirect ⟨_, rfl, h⟩ h'') acc
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
rw [forIn']
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> rfl
|
||||
|
||||
theorem IterM.forIn'_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad n] [IteratorLoop α m n] [hl : LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → n (ForInStep γ)} :
|
||||
letI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it init f = IterM.DefaultConsumers.forIn' (fun _ => monadLift) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init ((⟨·, .intro⟩) <$> f · · ·) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad n] [IteratorLoop α m n] [hl : LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : β → γ → n (ForInStep γ)} :
|
||||
ForIn.forIn it init f = IterM.DefaultConsumers.forIn' (fun _ => monadLift) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : (out : β) → _ → γ → n (ForInStep γ)} :
|
||||
letI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it init f = (do
|
||||
match ← it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| .yield c =>
|
||||
ForIn'.forIn' it' c
|
||||
fun out h'' acc => f out (.indirect ⟨_, rfl, h⟩ h'') acc
|
||||
| .done c => return c
|
||||
| .skip it' h =>
|
||||
ForIn'.forIn' it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
rw [IterM.forIn'_eq, DefaultConsumers.forIn'_eq_match_step]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep <;> simp [IterM.forIn'_eq]
|
||||
· simp [IterM.forIn'_eq]
|
||||
· simp
|
||||
|
||||
theorem IterM.forIn_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : β → γ → n (ForInStep γ)} :
|
||||
ForIn.forIn it init f = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ =>
|
||||
match ← f out init with
|
||||
| .yield c => ForIn.forIn it' c f
|
||||
| .done c => return c
|
||||
| .skip it' _ => ForIn.forIn it' init f
|
||||
| .done _ => return init) := by
|
||||
rw [IterM.forIn_eq, DefaultConsumers.forIn'_eq_match_step]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep <;> simp [IterM.forIn_eq]
|
||||
· simp [IterM.forIn_eq]
|
||||
· simp
|
||||
|
||||
theorem IterM.forM_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {it : IterM (α := α) m β}
|
||||
{f : β → n PUnit} :
|
||||
ForM.forM it f = ForIn.forIn it PUnit.unit (fun out _ => do f out; return .yield .unit) :=
|
||||
rfl
|
||||
|
||||
theorem IterM.forM_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {it : IterM (α := α) m β}
|
||||
{f : β → n PUnit} :
|
||||
ForM.forM it f = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ =>
|
||||
f out
|
||||
ForM.forM it' f
|
||||
| .skip it' _ => ForM.forM it' f
|
||||
| .done _ => return) := by
|
||||
rw [forM_eq_forIn, forIn_eq_match_step]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp [forM_eq_forIn]
|
||||
|
||||
theorem IterM.foldM_eq_forIn {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad n] [IteratorLoop α m n] [MonadLiftT m n] {f : γ → β → n γ}
|
||||
{init : γ} {it : IterM (α := α) m β} :
|
||||
it.foldM (init := init) f = ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.forIn_yield_eq_foldM {α β γ δ : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n] [IteratorLoop α m n]
|
||||
[LawfulIteratorLoop α m n] [MonadLiftT m n] {f : β → γ → n δ} {g : β → γ → δ → γ} {init : γ}
|
||||
{it : IterM (α := α) m β} :
|
||||
ForIn.forIn it init (fun c b => (fun d => .yield (g c b d)) <$> f c b) =
|
||||
it.foldM (fun b c => g c b <$> f c b) init := by
|
||||
simp [IterM.foldM_eq_forIn]
|
||||
|
||||
theorem IterM.foldM_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad n] [LawfulMonad n] [IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {f : γ → β → n γ} {init : γ} {it : IterM (α := α) m β} :
|
||||
it.foldM (init := init) f = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ => it'.foldM (init := ← f init out) f
|
||||
| .skip it' _ => it'.foldM (init := init) f
|
||||
| .done _ => return init) := by
|
||||
rw [IterM.foldM_eq_forIn, IterM.forIn_eq_match_step]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp [foldM_eq_forIn]
|
||||
|
||||
theorem IterM.fold_eq_forIn {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m]
|
||||
[IteratorLoop α m m] {f : γ → β → γ} {init : γ} {it : IterM (α := α) m β} :
|
||||
it.fold (init := init) f =
|
||||
ForIn.forIn (m := m) it init (fun x acc => pure (ForInStep.yield (f acc x))) := by
|
||||
rfl
|
||||
|
||||
theorem IterM.fold_eq_foldM {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] {f : γ → β → γ} {init : γ}
|
||||
{it : IterM (α := α) m β} :
|
||||
it.fold (init := init) f = it.foldM (init := init) (pure <| f · ·) := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.forIn_pure_yield_eq_fold {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m]
|
||||
[LawfulIteratorLoop α m m] {f : β → γ → γ} {init : γ}
|
||||
{it : IterM (α := α) m β} :
|
||||
ForIn.forIn it init (fun c b => pure (.yield (f c b))) =
|
||||
it.fold (fun b c => f c b) init := by
|
||||
simp [IterM.fold_eq_forIn]
|
||||
|
||||
theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{f : γ → β → γ} {init : γ} {it : IterM (α := α) m β} :
|
||||
it.fold (init := init) f = (do
|
||||
match ← it.step with
|
||||
| .yield it' out _ => it'.fold (init := f init out) f
|
||||
| .skip it' _ => it'.fold (init := init) f
|
||||
| .done _ => return init) := by
|
||||
rw [fold_eq_foldM, foldM_eq_match_step]
|
||||
simp only [fold_eq_foldM]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
suffices h : ∀ l' : List β, (l' ++ ·) <$> it.toList =
|
||||
it.fold (init := l') (fun l out => l ++ [out]) by
|
||||
specialize h []
|
||||
simpa using h
|
||||
induction it using IterM.inductSteps with | step it ihy ihs =>
|
||||
intro l'
|
||||
rw [IterM.toList_eq_match_step, IterM.fold_eq_match_step]
|
||||
simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· rename_i it' out h
|
||||
specialize ihy h (l' ++ [out])
|
||||
simpa using ihy
|
||||
· rename_i it' h
|
||||
simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.drain_eq_foldM {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.foldM (init := PUnit.unit) (fun _ _ => pure .unit) := by
|
||||
simp [IterM.drain_eq_fold, IterM.fold_eq_foldM]
|
||||
|
||||
theorem IterM.drain_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = ForIn.forIn (m := m) it PUnit.unit (fun _ _ => pure (ForInStep.yield .unit)) := by
|
||||
simp [IterM.drain_eq_fold, IterM.fold_eq_forIn]
|
||||
|
||||
theorem IterM.drain_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.drain = (do
|
||||
match ← it.step with
|
||||
| .yield it' _ _ => it'.drain
|
||||
| .skip it' _ => it'.drain
|
||||
| .done _ => return .unit) := by
|
||||
rw [IterM.drain_eq_fold, IterM.fold_eq_match_step]
|
||||
simp [IterM.drain_eq_fold]
|
||||
|
||||
theorem IterM.drain_eq_map_toList {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs =>
|
||||
rw [IterM.drain_eq_match_step, IterM.toList_eq_match_step]
|
||||
simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· rename_i it' out h
|
||||
simp [ihy h]
|
||||
· rename_i it' h
|
||||
simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.drain_eq_map_toListRev {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toListRev := by
|
||||
simp [IterM.drain_eq_map_toList, IterM.toListRev_eq]
|
||||
|
||||
theorem IterM.drain_eq_map_toArray {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
simp [IterM.drain_eq_map_toList]
|
||||
|
||||
end Std.Iterators
|
||||
@@ -3,8 +3,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
|
||||
import Std.Data.Iterators.Basic
|
||||
import Init.Data.Iterators.Basic
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
@@ -3,6 +3,8 @@ 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
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Data.Subtype
|
||||
@@ -48,6 +50,11 @@ def PostconditionT.lift {α : Type w} {m : Type w → Type w'} [Functor m] (x :
|
||||
PostconditionT m α :=
|
||||
⟨fun _ => True, (⟨·, .intro⟩) <$> x⟩
|
||||
|
||||
@[always_inline, inline]
|
||||
protected def PostconditionT.pure {m : Type w → Type w'} [Pure m] {α : Type w}
|
||||
(a : α) : PostconditionT m α :=
|
||||
⟨fun y => a = y, pure <| ⟨a, rfl⟩⟩
|
||||
|
||||
/--
|
||||
Lifts a monadic value from `m { a : α // P a }` to a value `PostconditionT m α`.
|
||||
-/
|
||||
@@ -107,52 +114,93 @@ def PostconditionT.run {m : Type w → Type w'} [Monad m] {α : Type w} (x : Pos
|
||||
(fun a => a.val) <$> x.operation
|
||||
|
||||
instance {m : Type w → Type w'} [Functor m] : Functor (PostconditionT m) where
|
||||
map f x := ⟨fun b => ∃ a, f a = b, (fun b => ⟨f b.1, b.1, rfl⟩) <$> x.operation ⟩
|
||||
map := PostconditionT.map
|
||||
|
||||
instance {m : Type w → Type w'} [Monad m] : Monad (PostconditionT m) where
|
||||
pure x := ⟨fun y => x = y, pure <| ⟨x, rfl⟩⟩
|
||||
bind x f := ⟨fun b => ∃ a, (f a).Property b,
|
||||
x.operation >>= fun a => (fun b => ⟨b.val, a, b.property⟩) <$> (f a).operation⟩
|
||||
pure := PostconditionT.pure
|
||||
bind := PostconditionT.bind
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.computation_pure {m : Type w → Type w'} [Monad m] {α : Type w}
|
||||
{x : α} :
|
||||
(pure x : PostconditionT m α).operation = pure ⟨x, rfl⟩ :=
|
||||
theorem PostconditionT.pure_eq_pure {m : Type w → Type w'} [Monad m] {α} {a : α} :
|
||||
pure a = PostconditionT.pure (m := m) a :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.property_pure {m : Type w → Type w'} [Monad m] {α : Type w}
|
||||
{x : α} :
|
||||
(pure x : PostconditionT m α).Property = (x = ·) :=
|
||||
(pure x : PostconditionT m α).Property = (x = ·) := by
|
||||
rfl
|
||||
|
||||
private theorem congrArg₂ {α : Sort u} {β : α → Type v} {γ : (a : α) → (b : β a) → Sort w}
|
||||
(f : (a : α) → (b : β a) → γ a b)
|
||||
{α α' a a'} (h : α = α') (h' : HEq a a') : HEq (f α a) (f α' a') := by
|
||||
cases h; cases h'; rfl
|
||||
@[simp]
|
||||
theorem PostconditionT.operation_pure {m : Type w → Type w'} [Monad m] {α : Type w}
|
||||
{x : α} :
|
||||
(pure x : PostconditionT m α).operation = pure ⟨x, property_pure (m := m) ▸ rfl⟩ := by
|
||||
rfl
|
||||
|
||||
private theorem congrArg₄ {α : Sort u} {β : (a : α) → Sort v} {γ : (a : α) → (b : β a) → Sort w}
|
||||
{δ : (a : α) → (b : β a) → (c : γ a b) → Sort x} {ε : (a : α) → (b : β a) → (c : γ a b) →
|
||||
(d : δ a b c) → Sort y}
|
||||
(f : (a : α) → (b : β a) → (c : γ a b) → (d : δ a b c) → ε a b c d)
|
||||
{a a' b b' c c' d d'} (h₁ : a = a') (h₂ : HEq b b') (h₃ : HEq c c') (h₄ : HEq d d') :
|
||||
HEq (f a b c d) (f a' b' c' d') := by
|
||||
cases h₁; cases h₂; cases h₃; cases h₄; rfl
|
||||
theorem PostconditionT.ext {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {x y : PostconditionT m α}
|
||||
(h : x.Property = y.Property) (h' : (fun p => ⟨p.1, h ▸ p.2⟩) <$> x.operation = y.operation) :
|
||||
x = y := by
|
||||
cases x; cases y; cases h
|
||||
simpa using h'
|
||||
|
||||
theorem PostconditionT.ext_iff {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {x y : PostconditionT m α} :
|
||||
x = y ↔ ∃ h : x.Property = y.Property, (fun p => ⟨p.1, h ▸ p.2⟩) <$> x.operation = y.operation := by
|
||||
constructor
|
||||
· rintro rfl
|
||||
exact ⟨rfl, by simp⟩
|
||||
· rintro ⟨h, h'⟩
|
||||
exact PostconditionT.ext h h'
|
||||
|
||||
@[simp]
|
||||
protected theorem PostconditionT.map_eq_pure_bind {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {β : Type w} {f : α → β} {x : PostconditionT m α} :
|
||||
x.map f = x.bind (pure ∘ f) := by
|
||||
apply PostconditionT.ext <;> simp [PostconditionT.map, PostconditionT.bind]
|
||||
|
||||
@[simp]
|
||||
protected theorem PostconditionT.pure_bind {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {β : Type w} {f : α → PostconditionT m β} {a : α} :
|
||||
(pure a : PostconditionT m α).bind f = f a := by
|
||||
apply PostconditionT.ext <;> simp [pure, PostconditionT.pure, PostconditionT.bind]
|
||||
|
||||
@[simp]
|
||||
protected theorem PostconditionT.bind_pure {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {x : PostconditionT m α} :
|
||||
x.bind pure = x := by
|
||||
apply PostconditionT.ext <;> simp [pure, PostconditionT.pure, PostconditionT.bind]
|
||||
|
||||
@[simp]
|
||||
protected theorem PostconditionT.bind_assoc {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α β γ: Type w} {x : PostconditionT m α} {f : α → PostconditionT m β} {g : β → PostconditionT m γ} :
|
||||
(x.bind f).bind g = x.bind (fun a => (f a).bind g) := by
|
||||
apply PostconditionT.ext
|
||||
· simp [PostconditionT.bind]
|
||||
· simp only [PostconditionT.bind, bind_assoc, bind_map_left, map_bind, Functor.map_map]
|
||||
ext c
|
||||
constructor
|
||||
· rintro ⟨b, ⟨a, ha, hb⟩, h⟩
|
||||
exact ⟨a, ha, b, hb, h⟩
|
||||
· rintro ⟨a, ha, b, hb, h⟩
|
||||
exact ⟨b, ⟨a, ha, hb⟩, h⟩
|
||||
|
||||
@[simp]
|
||||
protected theorem PostconditionT.map_pure {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {β : Type w} {f : α → β} {a : α} :
|
||||
(pure a : PostconditionT m α).map f = pure (f a) := by
|
||||
simp only [PostconditionT.map, pure, map_pure, mk.injEq, Subtype.exists, exists_prop,
|
||||
exists_eq_left', true_and]
|
||||
apply congrArg₂ (f := fun α (a : α) => (pure a : m _)) (by simp)
|
||||
apply congrArg₂ (f := fun α (a : α) => a)
|
||||
· simp
|
||||
· apply congrArg₄ fun β (p : β → Prop) (x : β) (h : p x) => Subtype.mk x h
|
||||
· rfl
|
||||
· simp
|
||||
· rfl
|
||||
· simp
|
||||
apply PostconditionT.ext <;> simp [pure, PostconditionT.map, PostconditionT.pure]
|
||||
|
||||
instance [Monad m] [LawfulMonad m] : LawfulMonad (PostconditionT m) where
|
||||
map_const {α β} := by ext a x; simp [Functor.mapConst, Functor.map]
|
||||
id_map {α} x := by simp [Functor.map]
|
||||
comp_map {α β γ} g h := by intro x; simp [Functor.map]; rfl
|
||||
seqLeft_eq {α β} x y := by simp [SeqLeft.seqLeft, Functor.map, Seq.seq]; rfl
|
||||
seqRight_eq {α β} x y := by simp [Seq.seq, SeqRight.seqRight, Functor.map]
|
||||
pure_seq g x := by simp [Seq.seq, Functor.map]
|
||||
bind_pure_comp f x := by simp [Functor.map, Bind.bind]; rfl
|
||||
bind_map f x := by simp [Seq.seq, Functor.map]; rfl
|
||||
pure_bind x f := PostconditionT.pure_bind
|
||||
bind_assoc x f g := PostconditionT.bind_assoc
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.property_map {m : Type w → Type w'} [Functor m] {α : Type w} {β : Type w}
|
||||
@@ -168,12 +216,19 @@ theorem PostconditionT.property_map {m : Type w → Type w'} [Functor m] {α : T
|
||||
@[simp]
|
||||
theorem PostconditionT.operation_map {m : Type w → Type w'} [Functor m] {α : Type w} {β : Type w}
|
||||
{x : PostconditionT m α} {f : α → β} :
|
||||
(x.map f).operation = (fun a => ⟨_, a, rfl⟩) <$> x.operation :=
|
||||
(x.map f).operation =
|
||||
(fun a => ⟨_, (property_map (m := m)).mpr ⟨a.1, rfl, a.2⟩⟩) <$> x.operation := by
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.operation_lift {m : Type w →Type w'} [Functor m] {α : Type w}
|
||||
{x : m α} : (lift x : PostconditionT m α).operation = (⟨·, True.intro⟩) <$> x :=
|
||||
theorem PostconditionT.property_lift {m : Type w → Type w'} [Functor m] {α : Type w}
|
||||
{x : m α} : (lift x : PostconditionT m α).Property = (fun _ => True) := by
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.operation_lift {m : Type w → Type w'} [Functor m] {α : Type w}
|
||||
{x : m α} : (lift x : PostconditionT m α).operation =
|
||||
(⟨·, property_lift (m := m) ▸ True.intro⟩) <$> x := by
|
||||
rfl
|
||||
|
||||
end Std.Iterators
|
||||
@@ -69,14 +69,14 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
| cons _ l', hL' => congrArg _ <| go l' fun _ hx => hL' (.tail _ hx)
|
||||
exact go l h'
|
||||
|
||||
@[simp] theorem pmap_nil {P : α → Prop} {f : ∀ a, P a → β} : pmap f [] (by simp) = [] := rfl
|
||||
@[simp, grind =] theorem pmap_nil {P : α → Prop} {f : ∀ a, P a → β} : pmap f [] (by simp) = [] := rfl
|
||||
|
||||
@[simp] theorem pmap_cons {P : α → Prop} {f : ∀ a, P a → β} {a : α} {l : List α} (h : ∀ b ∈ a :: l, P b) :
|
||||
@[simp, grind =] theorem pmap_cons {P : α → Prop} {f : ∀ a, P a → β} {a : α} {l : List α} (h : ∀ b ∈ a :: l, P b) :
|
||||
pmap f (a :: l) h = f a (forall_mem_cons.1 h).1 :: pmap f l (forall_mem_cons.1 h).2 := rfl
|
||||
|
||||
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||
@[simp, grind =] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||
|
||||
@[simp] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
|
||||
@[simp, grind =] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map {p : α → Prop} {f : α → β} {l : List α} (H) :
|
||||
@@ -92,12 +92,14 @@ theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a,
|
||||
| cons x l ih =>
|
||||
rw [pmap, pmap, h _ mem_cons_self, ih fun a ha => h a (mem_cons_of_mem _ ha)]
|
||||
|
||||
@[grind =]
|
||||
theorem map_pmap {p : α → Prop} {g : β → γ} {f : ∀ a, p a → β} {l : List α} (H) :
|
||||
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
|
||||
induction l
|
||||
· rfl
|
||||
· simp only [*, pmap, map]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_map {p : β → Prop} {g : ∀ b, p b → γ} {f : α → β} {l : List α} (H) :
|
||||
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem h) := by
|
||||
induction l
|
||||
@@ -114,7 +116,7 @@ theorem attachWith_congr {l₁ l₂ : List α} (w : l₁ = l₂) {P : α → Pro
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_cons {x : α} {xs : List α} :
|
||||
@[simp, grind =] theorem attach_cons {x : α} {xs : List α} :
|
||||
(x :: xs).attach =
|
||||
⟨x, mem_cons_self⟩ :: xs.attach.map fun ⟨y, h⟩ => ⟨y, mem_cons_of_mem x h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, cons.injEq, true_and]
|
||||
@@ -122,7 +124,7 @@ theorem attachWith_congr {l₁ l₂ : List α} (w : l₁ = l₂) {P : α → Pro
|
||||
intros a _ m' _
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem attachWith_cons {x : α} {xs : List α} {p : α → Prop} (h : ∀ a ∈ x :: xs, p a) :
|
||||
(x :: xs).attachWith p h = ⟨x, h x (mem_cons_self)⟩ ::
|
||||
xs.attachWith p (fun a ha ↦ h a (mem_cons_of_mem x ha)) :=
|
||||
@@ -162,14 +164,14 @@ theorem attachWith_map_subtype_val {p : α → Prop} {l : List α} (H : ∀ a
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_val _).trans (List.map_id _)
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem mem_attachWith {l : List α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
induction l with
|
||||
@@ -182,27 +184,28 @@ theorem mem_attachWith {l : List α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
· simp [← h]
|
||||
· simp_all
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
· rfl
|
||||
· simp only [*, pmap, length]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem length_attach {l : List α} : l.attach.length = l.length :=
|
||||
length_pmap
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem length_attachWith {p : α → Prop} {l H} : length (l.attachWith p H) = length l :=
|
||||
length_pmap
|
||||
|
||||
@@ -237,7 +240,7 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
|
||||
l.attachWith P H ≠ [] ↔ l ≠ [] :=
|
||||
pmap_ne_nil_iff _ _
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} (h : ∀ a ∈ l, p a) (i : Nat) :
|
||||
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
|
||||
induction l generalizing i with
|
||||
@@ -252,10 +255,10 @@ set_option linter.deprecated false in
|
||||
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
|
||||
simp only [get?_eq_getElem?]
|
||||
simp [getElem?_pmap, h]
|
||||
simp [getElem?_pmap]
|
||||
|
||||
-- The argument `f` is explicit to allow rewriting from right to left.
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {i : Nat}
|
||||
(hn : i < (pmap f l h).length) :
|
||||
(pmap f l h)[i] =
|
||||
@@ -279,109 +282,111 @@ theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attach {xs : List α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_attachWith {xs : List α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).length) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap ..
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem pmap_attach {l : List α} {p : {x // x ∈ l} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
@[simp, grind =] theorem pmap_attach {l : List α} {p : {x // x ∈ l} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
pmap f l.attach H =
|
||||
l.pmap (P := fun a => ∃ h : a ∈ l, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem pmap_attachWith {l : List α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
@[simp, grind =] theorem pmap_attachWith {l : List α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
pmap f (l.attachWith q H₁) H₂ =
|
||||
l.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem head?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem head?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).head? = xs.attach.head?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp at ih
|
||||
simp [head?_pmap, ih]
|
||||
simp
|
||||
|
||||
@[simp] theorem head_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem head_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (h : xs.pmap f H ≠ []) :
|
||||
(xs.pmap f H).head h = f (xs.head (by simpa using h)) (H _ (head_mem _)) := by
|
||||
induction xs with
|
||||
| nil => simp at h
|
||||
| cons x xs ih => simp [head_pmap, ih]
|
||||
| cons x xs ih => simp
|
||||
|
||||
@[simp] theorem head?_attachWith {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem head?_attachWith {P : α → Prop} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.attachWith P H).head? = xs.head?.pbind (fun a h => some ⟨a, H _ (mem_of_head? h)⟩) := by
|
||||
cases xs <;> simp_all
|
||||
|
||||
@[simp] theorem head_attachWith {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem head_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} (h : xs.attachWith P H ≠ []) :
|
||||
(xs.attachWith P H).head h = ⟨xs.head (by simpa using h), H _ (head_mem _)⟩ := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
| cons x xs => simp [head_attachWith, h]
|
||||
| cons x xs => simp
|
||||
|
||||
@[simp] theorem head?_attach {xs : List α} :
|
||||
@[simp, grind =] theorem head?_attach {xs : List α} :
|
||||
xs.attach.head? = xs.head?.pbind (fun a h => some ⟨a, mem_of_head? h⟩) := by
|
||||
cases xs <;> simp_all
|
||||
|
||||
@[simp] theorem head_attach {xs : List α} (h) :
|
||||
@[simp, grind =] theorem head_attach {xs : List α} (h) :
|
||||
xs.attach.head h = ⟨xs.head (by simpa using h), head_mem (by simpa using h)⟩ := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
| cons x xs => simp [head_attach, h]
|
||||
| cons x xs => simp
|
||||
|
||||
@[simp] theorem tail_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem tail_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).tail = xs.tail.pmap f (fun a h => H a (mem_of_mem_tail h)) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[simp] theorem tail_attachWith {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem tail_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).tail = xs.tail.attachWith P (fun a h => H a (mem_of_mem_tail h)) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[simp] theorem tail_attach {xs : List α} :
|
||||
@[simp, grind =] theorem tail_attach {xs : List α} :
|
||||
xs.attach.tail = xs.tail.attach.map (fun ⟨x, h⟩ => ⟨x, mem_of_mem_tail h⟩) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind]
|
||||
theorem foldl_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind]
|
||||
theorem foldr_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
@[simp] theorem foldl_attachWith
|
||||
@[simp, grind =] theorem foldl_attachWith
|
||||
{l : List α} {q : α → Prop} (H : ∀ a, a ∈ l → q a) {f : β → { x // q x } → β} {b} :
|
||||
(l.attachWith q H).foldl f b = l.attach.foldl (fun b ⟨a, h⟩ => f b ⟨a, H _ h⟩) b := by
|
||||
induction l generalizing b with
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, foldl_map]
|
||||
|
||||
@[simp] theorem foldr_attachWith
|
||||
@[simp, grind =] theorem foldr_attachWith
|
||||
{l : List α} {q : α → Prop} (H : ∀ a, a ∈ l → q a) {f : { x // q x } → β → β} {b} :
|
||||
(l.attachWith q H).foldr f b = l.attach.foldr (fun a acc => f ⟨a.1, H _ a.2⟩ acc) b := by
|
||||
induction l generalizing b with
|
||||
@@ -420,16 +425,18 @@ theorem foldr_attach {l : List α} {f : α → β → β} {b : β} :
|
||||
| nil => simp
|
||||
| cons a l ih => rw [foldr_cons, attach_cons, foldr_cons, foldr_map, ih]
|
||||
|
||||
@[grind =]
|
||||
theorem attach_map {l : List α} {f : α → β} :
|
||||
(l.map f).attach = l.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem h⟩) := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[grind =]
|
||||
theorem attachWith_map {l : List α} {f : α → β} {P : β → Prop} (H : ∀ (b : β), b ∈ l.map f → P b) :
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp] theorem map_attachWith {l : List α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
@[simp, grind =] theorem map_attachWith {l : List α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
{f : { x // P x } → β} :
|
||||
(l.attachWith P H).map f = l.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
induction l <;> simp_all
|
||||
@@ -458,13 +465,14 @@ theorem map_attach_eq_pmap {l : List α} {f : { x // x ∈ l } → β} :
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [filterMap_cons, attach_cons, ih, filterMap_map]
|
||||
simp only [filterMap_cons, attach_cons, filterMap_map]
|
||||
split <;> rename_i h
|
||||
· simp only [Option.pbind_eq_none_iff, reduceCtorEq, exists_false,
|
||||
or_false] at h
|
||||
@@ -488,6 +496,7 @@ theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
ext
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filter {l : List α} (p : α → Bool) :
|
||||
(l.filter p).attach = l.attach.filterMap
|
||||
fun x => if w : p x.1 then some ⟨x.1, mem_filter.mpr ⟨x.2, w⟩⟩ else none := by
|
||||
@@ -499,7 +508,7 @@ theorem attach_filter {l : List α} (p : α → Bool) :
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem filterMap_attachWith {q : α → Prop} {l : List α} {f : {x // q x} → Option β} (H) :
|
||||
(l.attachWith q H).filterMap f = l.attach.filterMap (fun ⟨x, h⟩ => f ⟨x, H _ h⟩) := by
|
||||
induction l with
|
||||
@@ -508,7 +517,7 @@ theorem filterMap_attachWith {q : α → Prop} {l : List α} {f : {x // q x} →
|
||||
simp only [attachWith_cons, filterMap_cons]
|
||||
split <;> simp_all [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem filter_attachWith {q : α → Prop} {l : List α} {p : {x // q x} → Bool} (H) :
|
||||
(l.attachWith q H).filter p =
|
||||
(l.attach.filter (fun ⟨x, h⟩ => p ⟨x, H _ h⟩)).map (fun ⟨x, h⟩ => ⟨x, H _ h⟩) := by
|
||||
@@ -518,13 +527,14 @@ theorem filter_attachWith {q : α → Prop} {l : List α} {p : {x // q x} → Bo
|
||||
simp only [attachWith_cons, filter_cons]
|
||||
split <;> simp_all [Function.comp_def, filter_map]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f : ∀ b, q b → γ} {l} (H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
pmap (α := { x // x ∈ l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
|
||||
(fun a _ => H₁ a a.2) := by
|
||||
simp [pmap_eq_map_attach, attach_map]
|
||||
|
||||
@[simp] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {l₁ l₂ : List ι}
|
||||
@[simp, grind =] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {l₁ l₂ : List ι}
|
||||
(h : ∀ a ∈ l₁ ++ l₂, p a) :
|
||||
(l₁ ++ l₂).pmap f h =
|
||||
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
|
||||
@@ -541,47 +551,50 @@ theorem pmap_append' {p : α → Prop} {f : ∀ a : α, p a → β} {l₁ l₂ :
|
||||
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
|
||||
pmap_append _
|
||||
|
||||
@[simp] theorem attach_append {xs ys : List α} :
|
||||
@[simp, grind =] theorem attach_append {xs ys : List α} :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, pmap_append]
|
||||
simp only [attach, attachWith, map_pmap, pmap_append]
|
||||
congr 1 <;>
|
||||
exact pmap_congr_left _ fun _ _ _ _ => rfl
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : List α}
|
||||
@[simp, grind =] theorem attachWith_append {P : α → Prop} {xs ys : List α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp only [attachWith, attach_append, map_pmap, pmap_append]
|
||||
simp only [attachWith, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem pmap_reverse {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
induction xs <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem attachWith_reverse {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse :=
|
||||
pmap_reverse ..
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) :=
|
||||
reverse_pmap ..
|
||||
|
||||
@[simp] theorem attach_reverse {xs : List α} :
|
||||
@[simp, grind =] theorem attach_reverse {xs : List α} :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
simp only [attach, attachWith, reverse_pmap, map_pmap]
|
||||
apply pmap_congr_left
|
||||
intros
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attach {xs : List α} :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
simp only [attach, attachWith, reverse_pmap, map_pmap]
|
||||
@@ -589,7 +602,7 @@ theorem reverse_attach {xs : List α} :
|
||||
intros
|
||||
rfl
|
||||
|
||||
@[simp] theorem getLast?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem getLast?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).getLast? = xs.attach.getLast?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
simp only [getLast?_eq_head?_reverse]
|
||||
@@ -597,30 +610,30 @@ theorem reverse_attach {xs : List α} :
|
||||
simp only [Option.map_map]
|
||||
congr
|
||||
|
||||
@[simp] theorem getLast_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
@[simp, grind =] theorem getLast_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (h : xs.pmap f H ≠ []) :
|
||||
(xs.pmap f H).getLast h = f (xs.getLast (by simpa using h)) (H _ (getLast_mem _)) := by
|
||||
simp only [getLast_eq_head_reverse]
|
||||
simp only [reverse_pmap, head_pmap, head_reverse]
|
||||
|
||||
@[simp] theorem getLast?_attachWith {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem getLast?_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).getLast? = xs.getLast?.pbind (fun a h => some ⟨a, H _ (mem_of_getLast? h)⟩) := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attachWith, head?_attachWith]
|
||||
simp
|
||||
|
||||
@[simp] theorem getLast_attachWith {P : α → Prop} {xs : List α}
|
||||
@[simp, grind =] theorem getLast_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} (h : xs.attachWith P H ≠ []) :
|
||||
(xs.attachWith P H).getLast h = ⟨xs.getLast (by simpa using h), H _ (getLast_mem _)⟩ := by
|
||||
simp only [getLast_eq_head_reverse, reverse_attachWith, head_attachWith, head_map]
|
||||
simp only [getLast_eq_head_reverse, reverse_attachWith, head_attachWith]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getLast?_attach {xs : List α} :
|
||||
xs.attach.getLast? = xs.getLast?.pbind fun a h => some ⟨a, mem_of_getLast? h⟩ := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attach, head?_map, head?_attach]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getLast_attach {xs : List α} (h : xs.attach ≠ []) :
|
||||
xs.attach.getLast h = ⟨xs.getLast (by simpa using h), getLast_mem (by simpa using h)⟩ := by
|
||||
simp only [getLast_eq_head_reverse, reverse_attach, head_map, head_attach]
|
||||
@@ -638,14 +651,14 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {l : List α} (H :
|
||||
@[simp]
|
||||
theorem count_attach [BEq α] {l : List α} {a : {x // x ∈ l}} :
|
||||
l.attach.count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attach
|
||||
Eq.trans (countP_congr fun _ _ => by simp) <| countP_attach
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem count_attachWith [BEq α] {p : α → Prop} {l : List α} (H : ∀ a ∈ l, p a) {a : {x // p x}} :
|
||||
(l.attachWith p H).count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _
|
||||
Eq.trans (countP_congr fun _ _ => by simp) <| countP_attachWith _
|
||||
|
||||
@[simp] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {l : List α} (H₁) :
|
||||
@[simp, grind =] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {l : List α} (H₁) :
|
||||
(l.pmap g H₁).countP f =
|
||||
l.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
|
||||
@@ -704,7 +717,7 @@ def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) : List α :
|
||||
unfold unattach
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Function.comp_def]
|
||||
| cons a l ih => simp [ih]
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : List { x // p x }} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
import Init.SimpLemmas
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.List.Notation
|
||||
import Init.Data.Nat.Div.Basic
|
||||
|
||||
@[expose] section
|
||||
|
||||
@@ -672,7 +673,7 @@ instance : Std.Associative (α := List α) (· ++ ·) := ⟨append_assoc⟩
|
||||
theorem append_cons (as : List α) (b : α) (bs : List α) : as ++ b :: bs = as ++ [b] ++ bs := by
|
||||
simp
|
||||
|
||||
@[simp] theorem concat_eq_append {as : List α} {a : α} : as.concat a = as ++ [a] := by
|
||||
@[simp, grind =] theorem concat_eq_append {as : List α} {a : α} : as.concat a = as ++ [a] := by
|
||||
induction as <;> simp [concat, *]
|
||||
|
||||
theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux as [] ++ bs := by
|
||||
@@ -729,9 +730,9 @@ Examples:
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
@[simp, grind] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [flatten, List.flatMap]
|
||||
@[simp, grind] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [flatten, List.flatMap]
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@@ -752,7 +753,7 @@ def replicate : (n : Nat) → (a : α) → List α
|
||||
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp only [ih, replicate_succ, length_cons, Nat.succ_eq_add_one]
|
||||
| succ n ih => simp only [ih, replicate_succ, length_cons]
|
||||
|
||||
/-! ## Additional functions -/
|
||||
|
||||
@@ -891,7 +892,7 @@ theorem mem_of_elem_eq_true [BEq α] [LawfulBEq α] {a : α} {as : List α} : el
|
||||
| a'::as =>
|
||||
simp [elem]
|
||||
split
|
||||
next h => intros; simp [BEq.beq] at h; subst h; apply Mem.head
|
||||
next h => intros; simp at h; subst h; apply Mem.head
|
||||
next _ => intro h; exact Mem.tail _ (mem_of_elem_eq_true h)
|
||||
|
||||
theorem elem_eq_true_of_mem [BEq α] [ReflBEq α] {a : α} {as : List α} (h : a ∈ as) : elem a as = true := by
|
||||
@@ -1624,8 +1625,8 @@ def find? (p : α → Bool) : List α → Option α
|
||||
| true => some a
|
||||
| false => find? p as
|
||||
|
||||
@[simp] theorem find?_nil : ([] : List α).find? p = none := rfl
|
||||
theorem find?_cons : (a::as).find? p = match p a with | true => some a | false => as.find? p :=
|
||||
@[simp, grind =] theorem find?_nil : ([] : List α).find? p = none := rfl
|
||||
@[grind =]theorem find?_cons : (a::as).find? p = match p a with | true => some a | false => as.find? p :=
|
||||
rfl
|
||||
|
||||
/-! ### findSome? -/
|
||||
@@ -1779,7 +1780,7 @@ where
|
||||
| a :: l, i, h =>
|
||||
if p a then
|
||||
some ⟨i, by
|
||||
simp only [Nat.add_comm _ i, ← Nat.add_assoc] at h
|
||||
simp only [Nat.add_comm _ i] at h
|
||||
exact Nat.lt_of_add_right_lt (Nat.lt_of_succ_le (Nat.le_of_eq h))⟩
|
||||
else
|
||||
go l (i + 1) (by simp at h; simpa [← Nat.add_assoc, Nat.add_right_comm] using h)
|
||||
@@ -1845,8 +1846,8 @@ def lookup [BEq α] : α → List (α × β) → Option β
|
||||
| true => some b
|
||||
| false => lookup a as
|
||||
|
||||
@[simp] theorem lookup_nil [BEq α] : ([] : List (α × β)).lookup a = none := rfl
|
||||
theorem lookup_cons [BEq α] {k : α} :
|
||||
@[simp, grind =] theorem lookup_nil [BEq α] : ([] : List (α × β)).lookup a = none := rfl
|
||||
@[grind =] theorem lookup_cons [BEq α] {k : α} :
|
||||
((k, b)::as).lookup a = match a == k with | true => some b | false => as.lookup a :=
|
||||
rfl
|
||||
|
||||
@@ -2014,7 +2015,7 @@ def zip : List α → List β → List (Prod α β) :=
|
||||
zipWith Prod.mk
|
||||
|
||||
@[simp] theorem zip_nil_left : zip ([] : List α) (l : List β) = [] := rfl
|
||||
@[simp] theorem zip_nil_right : zip (l : List α) ([] : List β) = [] := by simp [zip, zipWith]
|
||||
@[simp] theorem zip_nil_right : zip (l : List α) ([] : List β) = [] := by simp [zip]
|
||||
@[simp] theorem zip_cons_cons : zip (a :: as) (b :: bs) = (a, b) :: zip as bs := rfl
|
||||
|
||||
/-! ### zipWithAll -/
|
||||
|
||||
@@ -276,7 +276,7 @@ theorem getElem_append_right {as bs : List α} {i : Nat} (h₁ : as.length ≤ i
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
cases i with simp [Nat.succ_sub_succ] <;> simp [Nat.succ_sub_succ] at h₁
|
||||
cases i with simp [Nat.succ_sub_succ] <;> simp at h₁
|
||||
| succ i => apply ih; simp [h₁]
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2025-02-13")]
|
||||
|
||||
@@ -237,8 +237,8 @@ def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} : (f : s
|
||||
let s' ← f s a
|
||||
List.foldlM f s' as
|
||||
|
||||
@[simp, grind] theorem foldlM_nil [Monad m] {f : β → α → m β} {b : β} : [].foldlM f b = pure b := rfl
|
||||
@[simp, grind] theorem foldlM_cons [Monad m] {f : β → α → m β} {b : β} {a : α} {l : List α} :
|
||||
@[simp, grind =] theorem foldlM_nil [Monad m] {f : β → α → m β} {b : β} : [].foldlM f b = pure b := rfl
|
||||
@[simp, grind =] theorem foldlM_cons [Monad m] {f : β → α → m β} {b : β} {a : α} {l : List α} :
|
||||
(a :: l).foldlM f b = f b a >>= l.foldlM f := by
|
||||
simp [List.foldlM]
|
||||
|
||||
@@ -261,7 +261,7 @@ example [Monad m] (f : α → β → m β) :
|
||||
def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} (f : α → s → m s) (init : s) (l : List α) : m s :=
|
||||
l.reverse.foldlM (fun s a => f a s) init
|
||||
|
||||
@[simp, grind] theorem foldrM_nil [Monad m] {f : α → β → m β} {b : β} : [].foldrM f b = pure b := rfl
|
||||
@[simp, grind =] theorem foldrM_nil [Monad m] {f : α → β → m β} {b : β} : [].foldrM f b = pure b := rfl
|
||||
|
||||
/--
|
||||
Maps `f` over the list and collects the results with `<|>`. The result for the end of the list is
|
||||
@@ -347,7 +347,7 @@ theorem findM?_pure {m} [Monad m] [LawfulMonad m] (p : α → Bool) (as : List
|
||||
| true => simp
|
||||
| false => simp [ih]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem idRun_findM? (p : α → Id Bool) (as : List α) :
|
||||
(findM? p as).run = as.find? (p · |>.run) :=
|
||||
findM?_pure _ _
|
||||
@@ -400,7 +400,7 @@ theorem findSomeM?_pure [Monad m] [LawfulMonad m] {f : α → Option β} {as : L
|
||||
| some b => simp
|
||||
| none => simp [ih]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem idRun_findSomeM? (f : α → Id (Option β)) (as : List α) :
|
||||
(findSomeM? f as).run = as.findSome? (f · |>.run) :=
|
||||
findSomeM?_pure
|
||||
@@ -444,23 +444,23 @@ instance : ForIn' m (List α) α inferInstance where
|
||||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||||
|
||||
-- We simplify `List.forIn'` to `forIn'`.
|
||||
@[simp] theorem forIn'_eq_forIn' [Monad m] : @List.forIn' α β m _ = forIn' := rfl
|
||||
@[simp, grind =] theorem forIn'_eq_forIn' [Monad m] : @List.forIn' α β m _ = forIn' := rfl
|
||||
|
||||
@[simp] theorem forIn'_nil [Monad m] {f : (a : α) → a ∈ [] → β → m (ForInStep β)} {b : β} : forIn' [] b f = pure b :=
|
||||
@[simp, grind =] theorem forIn'_nil [Monad m] {f : (a : α) → a ∈ [] → β → m (ForInStep β)} {b : β} : forIn' [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_nil [Monad m] {f : α → β → m (ForInStep β)} {b : β} : forIn [] b f = pure b :=
|
||||
@[simp, grind =] theorem forIn_nil [Monad m] {f : α → β → m (ForInStep β)} {b : β} : forIn [] b f = pure b :=
|
||||
rfl
|
||||
|
||||
instance : ForM m (List α) α where
|
||||
forM := List.forM
|
||||
|
||||
-- We simplify `List.forM` to `forM`.
|
||||
@[simp] theorem forM_eq_forM [Monad m] : @List.forM m _ α = forM := rfl
|
||||
@[simp, grind =] theorem forM_eq_forM [Monad m] : @List.forM m _ α = forM := rfl
|
||||
|
||||
@[simp] theorem forM_nil [Monad m] {f : α → m PUnit} : forM [] f = pure ⟨⟩ :=
|
||||
@[simp, grind =] theorem forM_nil [Monad m] {f : α → m PUnit} : forM [] f = pure ⟨⟩ :=
|
||||
rfl
|
||||
@[simp] theorem forM_cons [Monad m] {f : α → m PUnit} {a : α} {as : List α} : forM (a::as) f = f a >>= fun _ => forM as f :=
|
||||
@[simp, grind =] theorem forM_cons [Monad m] {f : α → m PUnit} {a : α} {as : List α} : forM (a::as) f = f a >>= fun _ => forM as f :=
|
||||
rfl
|
||||
|
||||
instance : Functor List where
|
||||
|
||||
@@ -64,8 +64,8 @@ theorem length_eq_countP_add_countP (p : α → Bool) {l : List α} : length l =
|
||||
· rfl
|
||||
· simp [h]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_eq_length_filter {l : List α} : countP p l = length (filter p l) := by
|
||||
@[grind _=_] -- This to quite aggressive, as it introduces `filter` based reasoning whenever we see `countP`.
|
||||
theorem countP_eq_length_filter {l : List α} : countP p l = (filter p l).length := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x l ih =>
|
||||
@@ -82,11 +82,11 @@ theorem countP_le_length : countP p l ≤ l.length := by
|
||||
simp only [countP_eq_length_filter]
|
||||
apply length_filter_le
|
||||
|
||||
@[simp] theorem countP_append {l₁ l₂ : List α} : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
|
||||
@[simp, grind =] theorem countP_append {l₁ l₂ : List α} : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
|
||||
simp only [countP_eq_length_filter, filter_append, length_append]
|
||||
|
||||
@[simp] theorem countP_pos_iff {p} : 0 < countP p l ↔ ∃ a ∈ l, p a := by
|
||||
simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter, exists_prop]
|
||||
simp only [countP_eq_length_filter, length_pos_iff_exists_mem, mem_filter]
|
||||
|
||||
@[simp] theorem one_le_countP_iff {p} : 1 ≤ countP p l ↔ ∃ a ∈ l, p a :=
|
||||
countP_pos_iff
|
||||
@@ -120,10 +120,24 @@ theorem Sublist.countP_le (s : l₁ <+ l₂) : countP p l₁ ≤ countP p l₂ :
|
||||
simp only [countP_eq_length_filter]
|
||||
apply s.filter _ |>.length_le
|
||||
|
||||
grind_pattern Sublist.countP_le => l₁ <+ l₂, countP p l₁
|
||||
grind_pattern Sublist.countP_le => l₁ <+ l₂, countP p l₂
|
||||
|
||||
theorem IsPrefix.countP_le (s : l₁ <+: l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le
|
||||
|
||||
grind_pattern IsPrefix.countP_le => l₁ <+: l₂, countP p l₁
|
||||
grind_pattern IsPrefix.countP_le => l₁ <+: l₂, countP p l₂
|
||||
|
||||
theorem IsSuffix.countP_le (s : l₁ <:+ l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le
|
||||
|
||||
grind_pattern IsSuffix.countP_le => l₁ <:+ l₂, countP p l₁
|
||||
grind_pattern IsSuffix.countP_le => l₁ <:+ l₂, countP p l₂
|
||||
|
||||
theorem IsInfix.countP_le (s : l₁ <:+: l₂) : countP p l₁ ≤ countP p l₂ := s.sublist.countP_le
|
||||
|
||||
grind_pattern IsInfix.countP_le => l₁ <:+: l₂, countP p l₁
|
||||
grind_pattern IsInfix.countP_le => l₁ <:+: l₂, countP p l₂
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `Sublist.le_countP : countP p l₂ - (l₂.length - l₁.length) ≤ countP p l₁`.
|
||||
|
||||
@[grind]
|
||||
@@ -155,7 +169,7 @@ theorem length_filterMap_eq_countP {f : α → Option β} {l : List α} :
|
||||
| nil => rfl
|
||||
| cons x l ih =>
|
||||
simp only [filterMap_cons, countP_cons]
|
||||
split <;> simp [ih, *]
|
||||
split <;> simp [*]
|
||||
|
||||
theorem countP_filterMap {p : β → Bool} {f : α → Option β} {l : List α} :
|
||||
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l := by
|
||||
@@ -174,7 +188,7 @@ theorem countP_flatMap {p : β → Bool} {l : List α} {f : α → List β} :
|
||||
countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by
|
||||
rw [List.flatMap, countP_flatten, map_map]
|
||||
|
||||
@[simp] theorem countP_reverse {l : List α} : countP p l.reverse = countP p l := by
|
||||
@[simp, grind =] theorem countP_reverse {l : List α} : countP p l.reverse = countP p l := by
|
||||
simp [countP_eq_length_filter, filter_reverse]
|
||||
|
||||
theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by
|
||||
@@ -203,18 +217,22 @@ section count
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem count_nil {a : α} : count a [] = 0 := rfl
|
||||
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
|
||||
|
||||
@[grind]
|
||||
theorem count_cons {a b : α} {l : List α} :
|
||||
count a (b :: l) = count a l + if b == a then 1 else 0 := by
|
||||
simp [count, countP_cons]
|
||||
|
||||
@[grind =] theorem count_eq_countP {a : α} {l : List α} : count a l = countP (· == a) l := rfl
|
||||
theorem count_eq_countP {a : α} {l : List α} : count a l = countP (· == a) l := rfl
|
||||
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
funext l
|
||||
apply count_eq_countP
|
||||
|
||||
@[grind =]
|
||||
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
|
||||
simp [count, countP_eq_length_filter]
|
||||
|
||||
@[grind]
|
||||
theorem count_tail : ∀ {l : List α} {a : α},
|
||||
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
|
||||
@@ -223,12 +241,28 @@ theorem count_tail : ∀ {l : List α} {a : α},
|
||||
|
||||
theorem count_le_length {a : α} {l : List α} : count a l ≤ l.length := countP_le_length
|
||||
|
||||
grind_pattern count_le_length => count a l
|
||||
|
||||
theorem Sublist.count_le (a : α) (h : l₁ <+ l₂) : count a l₁ ≤ count a l₂ := h.countP_le
|
||||
|
||||
grind_pattern Sublist.count_le => l₁ <+ l₂, count a l₁
|
||||
grind_pattern Sublist.count_le => l₁ <+ l₂, count a l₂
|
||||
|
||||
theorem IsPrefix.count_le (a : α) (h : l₁ <+: l₂) : count a l₁ ≤ count a l₂ := h.sublist.count_le a
|
||||
|
||||
grind_pattern IsPrefix.count_le => l₁ <+: l₂, count a l₁
|
||||
grind_pattern IsPrefix.count_le => l₁ <+: l₂, count a l₂
|
||||
|
||||
theorem IsSuffix.count_le (a : α) (h : l₁ <:+ l₂) : count a l₁ ≤ count a l₂ := h.sublist.count_le a
|
||||
|
||||
grind_pattern IsSuffix.count_le => l₁ <:+ l₂, count a l₁
|
||||
grind_pattern IsSuffix.count_le => l₁ <:+ l₂, count a l₂
|
||||
|
||||
theorem IsInfix.count_le (a : α) (h : l₁ <:+: l₂) : count a l₁ ≤ count a l₂ := h.sublist.count_le a
|
||||
|
||||
grind_pattern IsInfix.count_le => l₁ <:+: l₂, count a l₁
|
||||
grind_pattern IsInfix.count_le => l₁ <:+: l₂, count a l₂
|
||||
|
||||
-- See `Init.Data.List.Nat.Count` for `Sublist.le_count : count a l₂ - (l₂.length - l₁.length) ≤ countP a l₁`.
|
||||
|
||||
theorem count_tail_le {a : α} {l : List α} : count a l.tail ≤ count a l :=
|
||||
@@ -245,10 +279,11 @@ theorem count_singleton {a b : α} : count a [b] = if b == a then 1 else 0 := by
|
||||
@[simp, grind =] theorem count_append {a : α} {l₁ l₂ : List α} : count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
|
||||
countP_append
|
||||
|
||||
@[grind =]
|
||||
theorem count_flatten {a : α} {l : List (List α)} : count a l.flatten = (l.map (count a)).sum := by
|
||||
simp only [count_eq_countP, countP_flatten, count_eq_countP']
|
||||
|
||||
@[simp] theorem count_reverse {a : α} {l : List α} : count a l.reverse = count a l := by
|
||||
@[simp, grind =] theorem count_reverse {a : α} {l : List α} : count a l.reverse = count a l := by
|
||||
simp only [count_eq_countP, countP_eq_length_filter, filter_reverse, length_reverse]
|
||||
|
||||
@[grind]
|
||||
|
||||
@@ -23,9 +23,9 @@ open Nat
|
||||
|
||||
/-! ### eraseP -/
|
||||
|
||||
@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
@[simp, grind =] theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
|
||||
theorem eraseP_cons {a : α} {l : List α} :
|
||||
@[grind =] theorem eraseP_cons {a : α} {l : List α} :
|
||||
(a :: l).eraseP p = bif p a then l else a :: l.eraseP p := rfl
|
||||
|
||||
@[simp] theorem eraseP_cons_of_pos {l : List α} {p} (h : p a) : (a :: l).eraseP p = l := by
|
||||
@@ -92,7 +92,7 @@ theorem exists_or_eq_self_of_eraseP (p) (l : List α) :
|
||||
let ⟨_, l₁, l₂, _, _, e₁, e₂⟩ := exists_of_eraseP al pa
|
||||
rw [e₂]; simp [length_append, e₁]
|
||||
|
||||
theorem length_eraseP {l : List α} : (l.eraseP p).length = if l.any p then l.length - 1 else l.length := by
|
||||
@[grind =] theorem length_eraseP {l : List α} : (l.eraseP p).length = if l.any p then l.length - 1 else l.length := by
|
||||
split <;> rename_i h
|
||||
· simp only [any_eq_true] at h
|
||||
obtain ⟨x, m, h⟩ := h
|
||||
@@ -106,8 +106,13 @@ theorem eraseP_sublist {l : List α} : l.eraseP p <+ l := by
|
||||
| .inl h => rw [h]; apply Sublist.refl
|
||||
| .inr ⟨c, l₁, l₂, _, _, h₃, h₄⟩ => rw [h₄, h₃]; simp
|
||||
|
||||
grind_pattern eraseP_sublist => l.eraseP p, List.Sublist
|
||||
|
||||
theorem eraseP_subset {l : List α} : l.eraseP p ⊆ l := eraseP_sublist.subset
|
||||
|
||||
grind_pattern eraseP_subset => l.eraseP p, List.Subset
|
||||
|
||||
@[grind ←]
|
||||
protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP p
|
||||
| .slnil => Sublist.refl _
|
||||
| .cons a s => by
|
||||
@@ -141,16 +146,18 @@ theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (erase
|
||||
@[simp] theorem eraseP_eq_self_iff {p} {l : List α} : l.eraseP p = l ↔ ∀ a ∈ l, ¬ p a := by
|
||||
rw [← Sublist.length_eq eraseP_sublist, length_eraseP]
|
||||
split <;> rename_i h
|
||||
· simp only [any_eq_true, length_eq_zero_iff] at h
|
||||
· simp only [any_eq_true] at h
|
||||
constructor
|
||||
· intro; simp_all [Nat.sub_one_eq_self]
|
||||
· intro; obtain ⟨x, m, h⟩ := h; simp_all
|
||||
· simp_all
|
||||
|
||||
@[grind _=_]
|
||||
theorem eraseP_map {f : β → α} : ∀ {l : List β}, (map f l).eraseP p = map f (l.eraseP (p ∘ f))
|
||||
| [] => rfl
|
||||
| b::l => by by_cases h : p (f b) <;> simp [h, eraseP_map, eraseP_cons_of_pos]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filterMap {f : α → Option β} : ∀ {l : List α},
|
||||
(filterMap f l).eraseP p = filterMap f (l.eraseP (fun x => match f x with | some y => p y | none => false))
|
||||
| [] => rfl
|
||||
@@ -165,6 +172,7 @@ theorem eraseP_filterMap {f : α → Option β} : ∀ {l : List α},
|
||||
· simp only [w, cond_false]
|
||||
rw [filterMap_cons_some h, eraseP_filterMap]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filter {f : α → Bool} {l : List α} :
|
||||
(filter f l).eraseP p = filter f (l.eraseP (fun x => p x && f x)) := by
|
||||
rw [← filterMap_eq_filter, eraseP_filterMap]
|
||||
@@ -174,18 +182,19 @@ theorem eraseP_filter {f : α → Bool} {l : List α} :
|
||||
split <;> split at * <;> simp_all
|
||||
|
||||
theorem eraseP_append_left {a : α} (pa : p a) :
|
||||
∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁++l₂).eraseP p = l₁.eraseP p ++ l₂
|
||||
∀ {l₁ : List α} l₂, a ∈ l₁ → (l₁ ++ l₂).eraseP p = l₁.eraseP p ++ l₂
|
||||
| x :: xs, l₂, h => by
|
||||
by_cases h' : p x <;> simp [h']
|
||||
rw [eraseP_append_left pa l₂ ((mem_cons.1 h).resolve_left (mt _ h'))]
|
||||
intro | rfl => exact pa
|
||||
|
||||
theorem eraseP_append_right :
|
||||
∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁++l₂) = l₁ ++ l₂.eraseP p
|
||||
∀ {l₁ : List α} l₂, (∀ b ∈ l₁, ¬p b) → eraseP p (l₁ ++ l₂) = l₁ ++ l₂.eraseP p
|
||||
| [], _, _ => rfl
|
||||
| _ :: _, _, h => by
|
||||
simp [(forall_mem_cons.1 h).1, eraseP_append_right _ (forall_mem_cons.1 h).2]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_append {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).eraseP p = if l₁.any p then l₁.eraseP p ++ l₂ else l₁ ++ l₂.eraseP p := by
|
||||
split <;> rename_i h
|
||||
@@ -196,6 +205,7 @@ theorem eraseP_append {l₁ l₂ : List α} :
|
||||
rw [eraseP_append_right _]
|
||||
simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).eraseP p = if p a then replicate (n - 1) a else replicate n a := by
|
||||
induction n with
|
||||
@@ -212,6 +222,7 @@ theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).eraseP p = replicate n a := by
|
||||
rw [eraseP_of_forall_not (by simp_all)]
|
||||
|
||||
@[grind ←]
|
||||
protected theorem IsPrefix.eraseP (h : l₁ <+: l₂) : l₁.eraseP p <+: l₂.eraseP p := by
|
||||
rw [IsPrefix] at h
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
@@ -258,13 +269,15 @@ theorem eraseP_eq_iff {p} {l : List α} :
|
||||
subst p
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) :=
|
||||
Pairwise.sublist <| eraseP_sublist
|
||||
|
||||
@[grind]
|
||||
@[grind ←]
|
||||
theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) :=
|
||||
Pairwise.eraseP p
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
|
||||
induction l with
|
||||
@@ -274,9 +287,9 @@ theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
by_cases h₁ : p a
|
||||
· by_cases h₂ : q a
|
||||
· simp_all
|
||||
· simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))]
|
||||
· simp [h₁, h₂]
|
||||
· by_cases h₂ : q a
|
||||
· simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))]
|
||||
· simp [h₁, h₂]
|
||||
· simp [h₁, h₂, ih (fun b m => h b (mem_cons_of_mem _ m))]
|
||||
|
||||
theorem head_eraseP_mem {xs : List α} {p : α → Bool} (h) : (xs.eraseP p).head h ∈ xs :=
|
||||
@@ -357,6 +370,7 @@ theorem exists_erase_eq [LawfulBEq α] {a : α} {l : List α} (h : a ∈ l) :
|
||||
length (l.erase a) = length l - 1 := by
|
||||
rw [erase_eq_eraseP]; exact length_eraseP_of_mem h (beq_self_eq_true a)
|
||||
|
||||
@[grind =]
|
||||
theorem length_erase [LawfulBEq α] {a : α} {l : List α} :
|
||||
length (l.erase a) = if a ∈ l then length l - 1 else length l := by
|
||||
rw [erase_eq_eraseP, length_eraseP]
|
||||
@@ -365,11 +379,17 @@ theorem length_erase [LawfulBEq α] {a : α} {l : List α} :
|
||||
theorem erase_sublist {a : α} {l : List α} : l.erase a <+ l :=
|
||||
erase_eq_eraseP' a l ▸ eraseP_sublist ..
|
||||
|
||||
grind_pattern length_erase => l.erase a, List.Sublist
|
||||
|
||||
theorem erase_subset {a : α} {l : List α} : l.erase a ⊆ l := erase_sublist.subset
|
||||
|
||||
grind_pattern erase_subset => l.erase a, List.Subset
|
||||
|
||||
@[grind ←]
|
||||
theorem Sublist.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₁.erase a <+ l₂.erase a := by
|
||||
simp only [erase_eq_eraseP']; exact h.eraseP
|
||||
|
||||
@[grind ←]
|
||||
theorem IsPrefix.erase (a : α) {l₁ l₂ : List α} (h : l₁ <+: l₂) : l₁.erase a <+: l₂.erase a := by
|
||||
simp only [erase_eq_eraseP']; exact h.eraseP
|
||||
|
||||
@@ -391,6 +411,7 @@ theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈
|
||||
rw [erase_eq_eraseP', eraseP_eq_self_iff]
|
||||
simp [forall_mem_ne']
|
||||
|
||||
@[grind _=_]
|
||||
theorem erase_filter [LawfulBEq α] {f : α → Bool} {l : List α} :
|
||||
(filter f l).erase a = filter f (l.erase a) := by
|
||||
induction l with
|
||||
@@ -418,10 +439,12 @@ theorem erase_append_right [LawfulBEq α] {a : α} {l₁ : List α} (l₂ : List
|
||||
rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_append_right]
|
||||
intros b h' h''; rw [eq_of_beq h''] at h; exact h h'
|
||||
|
||||
@[grind =]
|
||||
theorem erase_append [LawfulBEq α] {a : α} {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).erase a = if a ∈ l₁ then l₁.erase a ++ l₂ else l₁ ++ l₂.erase a := by
|
||||
simp [erase_eq_eraseP, eraseP_append]
|
||||
|
||||
@[grind =]
|
||||
theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
(replicate n a).erase b = if b == a then replicate (n - 1) a else replicate n a := by
|
||||
rw [erase_eq_eraseP]
|
||||
@@ -429,6 +452,7 @@ theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
|
||||
-- The arguments `a b` are explicit,
|
||||
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
|
||||
@[grind =]
|
||||
theorem erase_comm [LawfulBEq α] (a b : α) {l : List α} :
|
||||
(l.erase a).erase b = (l.erase b).erase a := by
|
||||
if ab : a == b then rw [eq_of_beq ab] else ?_
|
||||
@@ -468,6 +492,7 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {l : List α} :
|
||||
rw [erase_of_not_mem]
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.erase [LawfulBEq α] {l : List α} (a) : Pairwise p l → Pairwise p (l.erase a) :=
|
||||
Pairwise.sublist <| erase_sublist
|
||||
|
||||
@@ -520,6 +545,7 @@ end erase
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem length_eraseIdx {l : List α} {i : Nat} :
|
||||
(l.eraseIdx i).length = if i < l.length then l.length - 1 else l.length := by
|
||||
induction l generalizing i with
|
||||
@@ -537,8 +563,9 @@ theorem length_eraseIdx_of_lt {l : List α} {i} (h : i < length l) :
|
||||
(l.eraseIdx i).length = length l - 1 := by
|
||||
simp [length_eraseIdx, h]
|
||||
|
||||
@[simp] theorem eraseIdx_zero {l : List α} : eraseIdx l 0 = l.tail := by cases l <;> rfl
|
||||
@[simp, grind =] theorem eraseIdx_zero {l : List α} : eraseIdx l 0 = l.tail := by cases l <;> rfl
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_eq_take_drop_succ :
|
||||
∀ (l : List α) (i : Nat), l.eraseIdx i = l.take i ++ l.drop (i + 1)
|
||||
| nil, _ => by simp
|
||||
@@ -551,7 +578,7 @@ theorem eraseIdx_eq_take_drop_succ :
|
||||
match l, i with
|
||||
| [], _
|
||||
| a::l, 0
|
||||
| a::l, i + 1 => simp [Nat.succ_inj]
|
||||
| a::l, i + 1 => simp
|
||||
|
||||
@[deprecated eraseIdx_eq_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_eq_nil := @eraseIdx_eq_nil_iff
|
||||
@@ -560,11 +587,12 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
match l with
|
||||
| []
|
||||
| [a]
|
||||
| a::b::l => simp [Nat.succ_inj]
|
||||
| a::b::l => simp
|
||||
|
||||
@[deprecated eraseIdx_ne_nil_iff (since := "2025-01-30")]
|
||||
abbrev eraseIdx_ne_nil := @eraseIdx_ne_nil_iff
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
| [], _ => by simp
|
||||
| a::l, 0 => by simp
|
||||
@@ -573,6 +601,7 @@ theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a ∈ l.eraseIdx i) : a ∈ l :=
|
||||
(eraseIdx_sublist _ _).mem h
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k ⊆ l :=
|
||||
(eraseIdx_sublist _ _).subset
|
||||
|
||||
@@ -612,6 +641,15 @@ theorem eraseIdx_append_of_length_le {l : List α} {k : Nat} (hk : length l ≤
|
||||
| zero => simp_all
|
||||
| succ k => simp_all [eraseIdx_cons_succ, Nat.succ_sub_succ]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_append :
|
||||
eraseIdx (l ++ l') k = if k < length l then eraseIdx l k ++ l' else l ++ eraseIdx l' (k - length l) := by
|
||||
split <;> rename_i h
|
||||
· simp [eraseIdx_append_of_lt_length h]
|
||||
· rw [eraseIdx_append_of_length_le]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
(replicate n a).eraseIdx k = if k < n then replicate (n - 1) a else replicate n a := by
|
||||
split <;> rename_i h
|
||||
@@ -623,12 +661,15 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
exact m.2
|
||||
· rw [eraseIdx_of_length_le (by simpa using h)]
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) :=
|
||||
Pairwise.sublist <| eraseIdx_sublist _ _
|
||||
|
||||
@[grind ←]
|
||||
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) :=
|
||||
Pairwise.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
eraseIdx l k <+: eraseIdx l' k := by
|
||||
rcases h with ⟨t, rfl⟩
|
||||
|
||||
@@ -23,14 +23,14 @@ Examples:
|
||||
-/
|
||||
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp] theorem length_finRange {n : Nat} : (List.finRange n).length = n := by
|
||||
@[simp, grind =] theorem length_finRange {n : Nat} : (List.finRange n).length = n := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem getElem_finRange {i : Nat} (h : i < (List.finRange n).length) :
|
||||
@[simp, grind =] theorem getElem_finRange {i : Nat} (h : i < (List.finRange n).length) :
|
||||
(finRange n)[i] = Fin.cast length_finRange ⟨i, h⟩ := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem finRange_zero : finRange 0 = [] := by simp [finRange]
|
||||
@[simp, grind =] theorem finRange_zero : finRange 0 = [] := by simp [finRange]
|
||||
|
||||
theorem finRange_succ {n} : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by
|
||||
apply List.ext_getElem; simp; intro i; cases i <;> simp
|
||||
@@ -46,6 +46,7 @@ theorem finRange_succ_last {n} :
|
||||
· rfl
|
||||
· next h => exact Fin.eq_last_of_not_lt h
|
||||
|
||||
@[grind _=_]
|
||||
theorem finRange_reverse {n} : (finRange n).reverse = (finRange n).map Fin.rev := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
@@ -61,7 +62,7 @@ end List
|
||||
|
||||
namespace Fin
|
||||
|
||||
theorem foldlM_eq_foldlM_finRange [Monad m] (f : α → Fin n → m α) (x : α) :
|
||||
@[grind =] theorem foldlM_eq_foldlM_finRange [Monad m] (f : α → Fin n → m α) (x : α) :
|
||||
foldlM n f x = (List.finRange n).foldlM f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
@@ -71,21 +72,21 @@ theorem foldlM_eq_foldlM_finRange [Monad m] (f : α → Fin n → m α) (x : α)
|
||||
funext y
|
||||
simp [ih, List.foldlM_map]
|
||||
|
||||
theorem foldrM_eq_foldrM_finRange [Monad m] [LawfulMonad m] (f : Fin n → α → m α) (x : α) :
|
||||
@[grind =] theorem foldrM_eq_foldrM_finRange [Monad m] [LawfulMonad m] (f : Fin n → α → m α) (x : α) :
|
||||
foldrM n f x = (List.finRange n).foldrM f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldrM_succ, List.finRange_succ, ih, List.foldrM_map]
|
||||
|
||||
theorem foldl_eq_finRange_foldl (f : α → Fin n → α) (x : α) :
|
||||
@[grind =] theorem foldl_eq_finRange_foldl (f : α → Fin n → α) (x : α) :
|
||||
foldl n f x = (List.finRange n).foldl f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [foldl_succ, List.finRange_succ, ih, List.foldl_map]
|
||||
|
||||
theorem foldr_eq_finRange_foldr (f : Fin n → α → α) (x : α) :
|
||||
@[grind =] theorem foldr_eq_finRange_foldr (f : Fin n → α → α) (x : α) :
|
||||
foldr n f x = (List.finRange n).foldr f x := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
|
||||
@@ -45,7 +45,7 @@ theorem exists_of_findSome?_eq_some {l : List α} {f : α → Option β} (w : l.
|
||||
simp_all only [findSome?_cons, mem_cons, exists_eq_or_imp]
|
||||
split at w <;> simp_all
|
||||
|
||||
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none ↔ ∀ x ∈ l, p x = none := by
|
||||
@[simp, grind =] theorem findSome?_eq_none_iff : findSome? p l = none ↔ ∀ x ∈ l, p x = none := by
|
||||
induction l <;> simp [findSome?_cons]; split <;> simp [*]
|
||||
|
||||
@[simp] theorem findSome?_isSome_iff {f : α → Option β} {l : List α} :
|
||||
@@ -91,7 +91,7 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
|
||||
obtain ⟨⟨rfl, rfl⟩, rfl⟩ := h₁
|
||||
exact ⟨l₁, a, l₂, rfl, h₂, fun a' w => h₃ a' (mem_cons_of_mem p w)⟩
|
||||
|
||||
@[simp] theorem findSome?_guard {l : List α} : findSome? (Option.guard fun x => p x) l = find? p l := by
|
||||
@[simp, grind =] theorem findSome?_guard {l : List α} : findSome? (Option.guard p) l = find? p l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
@@ -103,32 +103,33 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
|
||||
· simp only [Option.guard_eq_none_iff] at h
|
||||
simp [ih, h]
|
||||
|
||||
theorem find?_eq_findSome?_guard {l : List α} : find? p l = findSome? (Option.guard fun x => p x) l :=
|
||||
theorem find?_eq_findSome?_guard {l : List α} : find? p l = findSome? (Option.guard p) l :=
|
||||
findSome?_guard.symm
|
||||
|
||||
@[simp] theorem head?_filterMap {f : α → Option β} {l : List α} : (l.filterMap f).head? = l.findSome? f := by
|
||||
@[simp, grind =] theorem head?_filterMap {f : α → Option β} {l : List α} : (l.filterMap f).head? = l.findSome? f := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [filterMap_cons, findSome?_cons]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp] theorem head_filterMap {f : α → Option β} {l : List α} (h) :
|
||||
@[simp, grind =] theorem head_filterMap {f : α → Option β} {l : List α} (h) :
|
||||
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem getLast?_filterMap {f : α → Option β} {l : List α} : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
@[simp, grind =] theorem getLast?_filterMap {f : α → Option β} {l : List α} : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filterMap_reverse]
|
||||
|
||||
@[simp] theorem getLast_filterMap {f : α → Option β} {l : List α} (h) :
|
||||
@[simp, grind =] theorem getLast_filterMap {f : α → Option β} {l : List α} (h) :
|
||||
(l.filterMap f).getLast h = (l.reverse.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast?_eq_some]
|
||||
|
||||
@[simp] theorem map_findSome? {f : α → Option β} {g : β → γ} {l : List α} :
|
||||
@[simp, grind _=_] theorem map_findSome? {f : α → Option β} {g : β → γ} {l : List α} :
|
||||
(l.findSome? f).map g = l.findSome? (Option.map g ∘ f) := by
|
||||
induction l <;> simp [findSome?_cons]; split <;> simp [*]
|
||||
|
||||
@[grind _=_]
|
||||
theorem findSome?_map {f : β → γ} {l : List β} : findSome? p (l.map f) = l.findSome? (p ∘ f) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -136,15 +137,18 @@ theorem findSome?_map {f : β → γ} {l : List β} : findSome? p (l.map f) = l.
|
||||
simp only [map_cons, findSome?]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem head_flatten {L : List (List α)} (h : ∃ l, l ∈ L ∧ l ≠ []) :
|
||||
(flatten L).head (by simpa using h) = (L.findSome? fun l => l.head?).get (by simpa using h) := by
|
||||
(flatten L).head (by simpa using h) = (L.findSome? head?).get (by simpa using h) := by
|
||||
simp [head_eq_iff_head?_eq_some, head?_flatten]
|
||||
|
||||
@[grind =]
|
||||
theorem getLast_flatten {L : List (List α)} (h : ∃ l, l ∈ L ∧ l ≠ []) :
|
||||
(flatten L).getLast (by simpa using h) =
|
||||
(L.reverse.findSome? fun l => l.getLast?).get (by simpa using h) := by
|
||||
(L.reverse.findSome? getLast?).get (by simpa using h) := by
|
||||
simp [getLast_eq_iff_getLast?_eq_some, getLast?_flatten]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
@@ -174,9 +178,12 @@ theorem Sublist.findSome?_isSome {l₁ l₂ : List α} (h : l₁ <+ l₂) :
|
||||
· simp_all
|
||||
· exact ih
|
||||
|
||||
grind_pattern Sublist.findSome?_isSome => l₁ <+ l₂, l₁.findSome? f
|
||||
grind_pattern Sublist.findSome?_isSome => l₁ <+ l₂, l₂.findSome? f
|
||||
|
||||
theorem Sublist.findSome?_eq_none {l₁ l₂ : List α} (h : l₁ <+ l₂) :
|
||||
l₂.findSome? f = none → l₁.findSome? f = none := by
|
||||
simp only [List.findSome?_eq_none_iff, Bool.not_eq_true]
|
||||
simp only [List.findSome?_eq_none_iff]
|
||||
exact fun w x m => w x (Sublist.mem m h)
|
||||
|
||||
theorem IsPrefix.findSome?_eq_some {l₁ l₂ : List α} {f : α → Option β} (h : l₁ <+: l₂) :
|
||||
@@ -185,16 +192,30 @@ theorem IsPrefix.findSome?_eq_some {l₁ l₂ : List α} {f : α → Option β}
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
simp +contextual [findSome?_append]
|
||||
|
||||
grind_pattern IsPrefix.findSome?_eq_some => l₁ <+: l₂, l₁.findSome? f, some b
|
||||
grind_pattern IsPrefix.findSome?_eq_some => l₁ <+: l₂, l₂.findSome? f, some b
|
||||
|
||||
theorem IsPrefix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (h : l₁ <+: l₂) :
|
||||
List.findSome? f l₂ = none → List.findSome? f l₁ = none :=
|
||||
h.sublist.findSome?_eq_none
|
||||
|
||||
grind_pattern IsPrefix.findSome?_eq_none => l₁ <+: l₂, l₂.findSome? f
|
||||
grind_pattern IsPrefix.findSome?_eq_none => l₁ <+: l₂, l₁.findSome? f
|
||||
|
||||
theorem IsSuffix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (h : l₁ <:+ l₂) :
|
||||
List.findSome? f l₂ = none → List.findSome? f l₁ = none :=
|
||||
h.sublist.findSome?_eq_none
|
||||
|
||||
grind_pattern IsSuffix.findSome?_eq_none => l₁ <+: l₂, l₂.findSome? f
|
||||
grind_pattern IsSuffix.findSome?_eq_none => l₁ <+: l₂, l₁.findSome? f
|
||||
|
||||
theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (h : l₁ <:+: l₂) :
|
||||
List.findSome? f l₂ = none → List.findSome? f l₁ = none :=
|
||||
h.sublist.findSome?_eq_none
|
||||
|
||||
grind_pattern IsInfix.findSome?_eq_none => l₁ <+: l₂, l₂.findSome? f
|
||||
grind_pattern IsInfix.findSome?_eq_none => l₁ <+: l₂, l₁.findSome? f
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp] theorem find?_cons_of_pos {l} (h : p a) : find? p (a :: l) = some a := by
|
||||
@@ -203,7 +224,7 @@ theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (
|
||||
@[simp] theorem find?_cons_of_neg {l} (h : ¬p a) : find? p (a :: l) = find? p l := by
|
||||
simp [find?, h]
|
||||
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
@[simp, grind =] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
induction l <;> simp [find?_cons]; split <;> simp [*]
|
||||
|
||||
theorem find?_eq_some_iff_append :
|
||||
@@ -248,25 +269,28 @@ theorem find?_cons_eq_some : (a :: xs).find? p = some b ↔ (p a ∧ a = b) ∨
|
||||
rw [find?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem find?_isSome {xs : List α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
@[simp, grind =] theorem find?_isSome {xs : List α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [find?_cons, mem_cons, exists_eq_or_imp]
|
||||
split <;> simp_all
|
||||
|
||||
@[grind →]
|
||||
theorem find?_some : ∀ {l}, find? p l = some a → p a
|
||||
| b :: l, H => by
|
||||
by_cases h : p b <;> simp [find?, h] at H
|
||||
· exact H ▸ h
|
||||
· exact find?_some H
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
|
||||
| b :: l, H => by
|
||||
by_cases h : p b <;> simp [find?, h] at H
|
||||
· exact H ▸ .head _
|
||||
· exact .tail _ (mem_of_find?_eq_some H)
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h ∈ xs := by
|
||||
induction xs with
|
||||
| nil => simp at h
|
||||
@@ -278,7 +302,7 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
right
|
||||
apply ih
|
||||
|
||||
@[simp] theorem find?_filter {xs : List α} {p : α → Bool} {q : α → Bool} :
|
||||
@[simp, grind =] theorem find?_filter {xs : List α} {p : α → Bool} {q : α → Bool} :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
@@ -288,22 +312,22 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
· simp only [find?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem head?_filter {p : α → Bool} {l : List α} : (l.filter p).head? = l.find? p := by
|
||||
@[simp, grind =] theorem head?_filter {p : α → Bool} {l : List α} : (l.filter p).head? = l.find? p := by
|
||||
rw [← filterMap_eq_filter, head?_filterMap, findSome?_guard]
|
||||
|
||||
@[simp] theorem head_filter {p : α → Bool} {l : List α} (h) :
|
||||
@[simp, grind =] theorem head_filter {p : α → Bool} {l : List α} (h) :
|
||||
(l.filter p).head h = (l.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem getLast?_filter {p : α → Bool} {l : List α} : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
@[simp, grind =] theorem getLast?_filter {p : α → Bool} {l : List α} : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filter_reverse]
|
||||
|
||||
@[simp] theorem getLast_filter {p : α → Bool} {l : List α} (h) :
|
||||
@[simp, grind =] theorem getLast_filter {p : α → Bool} {l : List α} (h) :
|
||||
(l.filter p).getLast h = (l.reverse.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast?_eq_some]
|
||||
|
||||
@[simp] theorem find?_filterMap {xs : List α} {f : α → Option β} {p : β → Bool} :
|
||||
@[simp, grind =] theorem find?_filterMap {xs : List α} {f : α → Option β} {p : β → Bool} :
|
||||
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
@@ -313,15 +337,15 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
· simp only [find?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem find?_map {f : β → α} {l : List β} : find? p (l.map f) = (l.find? (p ∘ f)).map f := by
|
||||
@[simp, grind =] theorem find?_map {f : β → α} {l : List β} : find? p (l.map f) = (l.find? (p ∘ f)).map f := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, find?]
|
||||
by_cases h : p (f x) <;> simp [h, ih]
|
||||
|
||||
@[simp] theorem find?_flatten {xss : List (List α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (·.find? p) := by
|
||||
@[simp, grind _=_] theorem find?_flatten {xss : List (List α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (find? p) := by
|
||||
induction xss with
|
||||
| nil => simp
|
||||
| cons _ _ ih =>
|
||||
@@ -359,7 +383,7 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
|
||||
· simpa using h₂ x (by simpa using ⟨l, ma, m⟩)
|
||||
· specialize h₁ _ mb
|
||||
simp_all
|
||||
· simp [h₁]
|
||||
· simp
|
||||
refine ⟨as, bs, ?_⟩
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· simp_all
|
||||
@@ -378,7 +402,7 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp] theorem find?_flatMap {xs : List α} {f : α → List β} {p : β → Bool} :
|
||||
@[simp, grind =] theorem find?_flatMap {xs : List α} {f : α → List β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
simp [flatMap_def, findSome?_map]; rfl
|
||||
|
||||
@@ -386,6 +410,7 @@ theorem find?_flatMap_eq_none_iff {xs : List α} {f : α → List β} {p : β
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem find?_replicate : find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
cases n
|
||||
· simp
|
||||
@@ -430,6 +455,9 @@ theorem Sublist.find?_isSome {l₁ l₂ : List α} (h : l₁ <+ l₂) : (l₁.fi
|
||||
· simp
|
||||
· simpa using ih
|
||||
|
||||
grind_pattern Sublist.find?_isSome => l₁ <+ l₂, l₁.find? p
|
||||
grind_pattern Sublist.find?_isSome => l₁ <+ l₂, l₂.find? p
|
||||
|
||||
theorem Sublist.find?_eq_none {l₁ l₂ : List α} (h : l₁ <+ l₂) : l₂.find? p = none → l₁.find? p = none := by
|
||||
simp only [List.find?_eq_none, Bool.not_eq_true]
|
||||
exact fun w x m => w x (Sublist.mem m h)
|
||||
@@ -440,16 +468,31 @@ theorem IsPrefix.find?_eq_some {l₁ l₂ : List α} {p : α → Bool} (h : l₁
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
simp +contextual [find?_append]
|
||||
|
||||
grind_pattern IsPrefix.find?_eq_some => l₁ <+: l₂, l₁.find? p, some b
|
||||
grind_pattern IsPrefix.find?_eq_some => l₁ <+: l₂, l₂.find? p, some b
|
||||
|
||||
theorem IsPrefix.find?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂) :
|
||||
List.find? p l₂ = none → List.find? p l₁ = none :=
|
||||
h.sublist.find?_eq_none
|
||||
|
||||
grind_pattern Sublist.find?_eq_none => l₁ <+ l₂, l₂.find? p
|
||||
grind_pattern Sublist.find?_eq_none => l₁ <+ l₂, l₁.find? p
|
||||
|
||||
theorem IsSuffix.find?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <:+ l₂) :
|
||||
List.find? p l₂ = none → List.find? p l₁ = none :=
|
||||
h.sublist.find?_eq_none
|
||||
|
||||
grind_pattern IsPrefix.find?_eq_none => l₁ <+: l₂, l₂.find? p
|
||||
grind_pattern IsPrefix.find?_eq_none => l₁ <+: l₂, l₁.find? p
|
||||
|
||||
theorem IsInfix.find?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <:+: l₂) :
|
||||
List.find? p l₂ = none → List.find? p l₁ = none :=
|
||||
h.sublist.find?_eq_none
|
||||
|
||||
grind_pattern IsSuffix.find?_eq_none => l₁ <:+ l₂, l₂.find? p
|
||||
grind_pattern IsSuffix.find?_eq_none => l₁ <:+ l₂, l₁.find? p
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : List α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
(xs.pmap f H).find? p = (xs.attach.find? (fun ⟨a, m⟩ => p (f a (H a m)))).map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
@@ -482,9 +525,9 @@ private theorem findIdx?_go_eq {p : α → Bool} {xs : List α} {i : Nat} :
|
||||
ext
|
||||
simp only [Nat.add_comm i, Function.comp_apply, Nat.add_assoc]
|
||||
|
||||
@[simp] theorem findIdx?_nil : ([] : List α).findIdx? p = none := rfl
|
||||
@[simp, grind =] theorem findIdx?_nil : ([] : List α).findIdx? p = none := rfl
|
||||
|
||||
theorem findIdx?_cons :
|
||||
@[grind =] theorem findIdx?_cons :
|
||||
(x :: xs).findIdx? p = if p x then some 0 else (xs.findIdx? p).map fun i => i + 1 := by
|
||||
simp [findIdx?, findIdx?_go_eq]
|
||||
|
||||
@@ -493,6 +536,7 @@ theorem findIdx?_cons :
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_cons {p : α → Bool} {b : α} {l : List α} :
|
||||
(b :: l).findIdx p = bif p b then 0 else (l.findIdx p) + 1 := by
|
||||
cases H : p b with
|
||||
@@ -511,6 +555,7 @@ where
|
||||
@[simp] theorem findIdx_singleton {a : α} {p : α → Bool} : [a].findIdx p = if p a then 0 else 1 := by
|
||||
simp [findIdx_cons, findIdx_nil]
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
@@ -520,6 +565,8 @@ theorem findIdx_getElem {xs : List α} {w : xs.findIdx p < xs.length} :
|
||||
p xs[xs.findIdx p] :=
|
||||
xs.findIdx_of_getElem?_eq_some (getElem?_eq_getElem w)
|
||||
|
||||
grind_pattern findIdx_getElem => xs[xs.findIdx p]
|
||||
|
||||
theorem findIdx_lt_length_of_exists {xs : List α} (h : ∃ x ∈ xs, p x) :
|
||||
xs.findIdx p < xs.length := by
|
||||
induction xs with
|
||||
@@ -545,7 +592,7 @@ theorem findIdx_eq_length {p : α → Bool} {xs : List α} :
|
||||
| cons x xs ih =>
|
||||
rw [findIdx_cons, length_cons]
|
||||
simp only [cond_eq_if]
|
||||
split <;> simp_all [Nat.succ.injEq]
|
||||
split <;> simp_all
|
||||
|
||||
theorem findIdx_eq_length_of_false {p : α → Bool} {xs : List α} (h : ∀ x ∈ xs, p x = false) :
|
||||
xs.findIdx p = xs.length := by
|
||||
@@ -558,6 +605,8 @@ theorem findIdx_le_length {p : α → Bool} {xs : List α} : xs.findIdx p ≤ xs
|
||||
· simp at e
|
||||
exact Nat.le_of_eq (findIdx_eq_length.mpr e)
|
||||
|
||||
grind_pattern findIdx_le_length => xs.findIdx p, xs.length
|
||||
|
||||
@[simp]
|
||||
theorem findIdx_lt_length {p : α → Bool} {xs : List α} :
|
||||
xs.findIdx p < xs.length ↔ ∃ x ∈ xs, p x := by
|
||||
@@ -567,6 +616,8 @@ theorem findIdx_lt_length {p : α → Bool} {xs : List α} :
|
||||
rw [← this, findIdx_eq_length, not_exists]
|
||||
simp only [Bool.not_eq_true, not_and]
|
||||
|
||||
grind_pattern findIdx_lt_length => xs.findIdx p, xs.length
|
||||
|
||||
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
|
||||
theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.findIdx p) :
|
||||
p (xs[i]'(Nat.le_trans h findIdx_le_length)) = false := by
|
||||
@@ -591,6 +642,8 @@ theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs
|
||||
rw [← ipm, Nat.succ_lt_succ_iff] at h
|
||||
simpa using ih h
|
||||
|
||||
grind_pattern not_of_lt_findIdx => xs.findIdx p, xs[i]
|
||||
|
||||
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
|
||||
theorem le_findIdx_of_not {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length)
|
||||
(h2 : ∀ j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i ≤ xs.findIdx p := by
|
||||
@@ -618,6 +671,7 @@ theorem findIdx_eq {p : α → Bool} {xs : List α} {i : Nat} (h : i < xs.length
|
||||
simp at h3
|
||||
simp_all [not_of_lt_findIdx h3]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_append {p : α → Bool} {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).findIdx p =
|
||||
if l₁.findIdx p < l₁.length then l₁.findIdx p else l₂.findIdx p + l₁.length := by
|
||||
@@ -639,6 +693,9 @@ theorem IsPrefix.findIdx_le {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+
|
||||
· exact Nat.le_refl ..
|
||||
· simp_all [findIdx_eq_length_of_false]
|
||||
|
||||
grind_pattern IsPrefix.findIdx_le => l₁ <:+ l₂, l₁.findIdx p
|
||||
grind_pattern IsPrefix.findIdx_le => l₁ <:+ l₂, l₂.findIdx p
|
||||
|
||||
theorem IsPrefix.findIdx_eq_of_findIdx_lt_length {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂)
|
||||
(lt : l₁.findIdx p < l₁.length) : l₂.findIdx p = l₁.findIdx p := by
|
||||
rw [IsPrefix] at h
|
||||
@@ -648,6 +705,8 @@ theorem IsPrefix.findIdx_eq_of_findIdx_lt_length {l₁ l₂ : List α} {p : α
|
||||
· rfl
|
||||
· simp_all
|
||||
|
||||
grind_pattern IsPrefix.findIdx_eq_of_findIdx_lt_length => l₁ <:+ l₂, l₁.findIdx p, l₂.findIdx p
|
||||
|
||||
theorem findIdx_le_findIdx {l : List α} {p q : α → Bool} (h : ∀ x ∈ l, p x → q x) : l.findIdx q ≤ l.findIdx p := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -671,16 +730,16 @@ theorem findIdx_le_findIdx {l : List α} {p q : α → Bool} (h : ∀ x ∈ l, p
|
||||
|
||||
/-! ### findIdx? -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_eq_none_iff {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ ∀ x, x ∈ xs → p x = false := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx?_cons]
|
||||
split <;> simp_all [cond_eq_if]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_isSome {xs : List α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isSome = xs.any p := by
|
||||
induction xs with
|
||||
@@ -689,7 +748,7 @@ theorem findIdx?_isSome {xs : List α} {p : α → Bool} :
|
||||
simp only [findIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem findIdx?_isNone {xs : List α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
|
||||
induction xs with
|
||||
@@ -740,13 +799,13 @@ theorem findIdx?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {i : Nat}
|
||||
induction xs generalizing i with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx?_cons, Nat.zero_add]
|
||||
simp only [findIdx?_cons]
|
||||
split
|
||||
· simp only [Option.some.injEq, Bool.not_eq_true, length_cons]
|
||||
cases i with
|
||||
| zero => simp_all
|
||||
| succ i =>
|
||||
simp only [Bool.not_eq_true, zero_ne_add_one, getElem_cons_succ, false_iff, not_exists,
|
||||
simp only [zero_ne_add_one, getElem_cons_succ, false_iff, not_exists,
|
||||
not_and, Classical.not_forall, Bool.not_eq_false]
|
||||
intros
|
||||
refine ⟨0, zero_lt_succ i, ‹_›⟩
|
||||
@@ -771,8 +830,8 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
induction xs generalizing i with
|
||||
| nil => simp_all
|
||||
| cons x xs ih =>
|
||||
simp_all only [findIdx?_cons, Nat.zero_add]
|
||||
split at w <;> cases i <;> simp_all [succ_inj]
|
||||
simp_all only [findIdx?_cons]
|
||||
split at w <;> cases i <;> simp_all
|
||||
|
||||
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
|
||||
@@ -783,7 +842,7 @@ theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
induction xs generalizing i with
|
||||
| nil => simp_all
|
||||
| cons x xs ih =>
|
||||
simp_all only [Bool.not_eq_true, findIdx?_cons, Nat.zero_add]
|
||||
simp_all only [Bool.not_eq_true, findIdx?_cons]
|
||||
cases i with
|
||||
| zero =>
|
||||
split at w <;> simp_all
|
||||
@@ -795,14 +854,14 @@ theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
@[deprecated of_findIdx?_eq_none (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
|
||||
|
||||
@[simp] theorem findIdx?_map {f : β → α} {l : List β} : findIdx? p (l.map f) = l.findIdx? (p ∘ f) := by
|
||||
@[simp, grind _=_] theorem findIdx?_map {f : β → α} {l : List β} : findIdx? p (l.map f) = l.findIdx? (p ∘ f) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, findIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem findIdx?_append :
|
||||
@[simp, grind =] theorem findIdx?_append :
|
||||
(xs ++ ys : List α).findIdx? p =
|
||||
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.length) := by
|
||||
induction xs with simp [findIdx?_cons]
|
||||
@@ -824,12 +883,12 @@ theorem findIdx?_flatten {l : List (List α)} {p : α → Bool} :
|
||||
· rw [Option.or_of_isNone (by simp_all [findIdx?_isNone])]
|
||||
simp [Function.comp_def, Nat.add_comm, Nat.add_assoc]
|
||||
|
||||
@[simp] theorem findIdx?_replicate :
|
||||
@[simp, grind =] theorem findIdx?_replicate :
|
||||
(replicate n a).findIdx? p = if 0 < n ∧ p a then some 0 else none := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
simp only [replicate, findIdx?_cons, Nat.zero_add, zero_lt_succ, true_and]
|
||||
simp only [replicate, findIdx?_cons, zero_lt_succ, true_and]
|
||||
split <;> simp_all
|
||||
|
||||
theorem findIdx?_eq_findSome?_zipIdx {xs : List α} {p : α → Bool} :
|
||||
@@ -840,7 +899,7 @@ theorem findIdx?_eq_findSome?_zipIdx {xs : List α} {p : α → Bool} :
|
||||
simp only [findIdx?_cons, Nat.zero_add, zipIdx]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all only [zipIdx_cons, ite_false, Option.isNone_none, findSome?_cons_of_isNone, reduceCtorEq]
|
||||
· simp_all only [ite_false, Option.isNone_none, findSome?_cons_of_isNone, reduceCtorEq]
|
||||
rw [← map_snd_add_zipIdx_eq_zipIdx (n := 1) (k := 0)]
|
||||
simp [Function.comp_def, findSome?_map]
|
||||
|
||||
@@ -878,29 +937,45 @@ theorem Sublist.findIdx?_eq_none {l₁ l₂ : List α} (h : l₁ <+ l₂) :
|
||||
simp only [findIdx?_eq_none_iff]
|
||||
exact fun w x m => w x (h.mem m)
|
||||
|
||||
grind_pattern Sublist.findIdx?_eq_none => l₁ <+ l₂, l₁.findIdx? p
|
||||
grind_pattern Sublist.findIdx?_eq_none => l₁ <+ l₂, l₂.findIdx? p
|
||||
|
||||
theorem IsPrefix.findIdx?_eq_some {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂) :
|
||||
List.findIdx? p l₁ = some i → List.findIdx? p l₂ = some i := by
|
||||
rw [IsPrefix] at h
|
||||
obtain ⟨t, rfl⟩ := h
|
||||
intro h
|
||||
simp [findIdx?_append, h]
|
||||
|
||||
theorem IsPrefix.findIdx?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <+: l₂) :
|
||||
List.findIdx? p l₂ = none → List.findIdx? p l₁ = none :=
|
||||
h.sublist.findIdx?_eq_none
|
||||
|
||||
grind_pattern IsPrefix.findIdx?_eq_none => l₁ <+: l₂, l₁.findIdx? p
|
||||
grind_pattern IsPrefix.findIdx?_eq_none => l₁ <+: l₂, l₂.findIdx? p
|
||||
|
||||
theorem IsSuffix.findIdx?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <:+ l₂) :
|
||||
List.findIdx? p l₂ = none → List.findIdx? p l₁ = none :=
|
||||
h.sublist.findIdx?_eq_none
|
||||
|
||||
grind_pattern IsSuffix.findIdx?_eq_none => l₁ <:+ l₂, l₁.findIdx? p
|
||||
grind_pattern IsSuffix.findIdx?_eq_none => l₁ <:+ l₂, l₂.findIdx? p
|
||||
|
||||
theorem IsInfix.findIdx?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l₁ <:+: l₂) :
|
||||
List.findIdx? p l₂ = none → List.findIdx? p l₁ = none :=
|
||||
h.sublist.findIdx?_eq_none
|
||||
|
||||
grind_pattern IsInfix.findIdx?_eq_none => l₁ <:+: l₂, l₁.findIdx? p
|
||||
grind_pattern IsInfix.findIdx?_eq_none => l₁ <:+: l₂, l₂.findIdx? p
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx p = (xs.findIdx? p).getD xs.length := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx_cons, findIdx?_cons]
|
||||
split <;> simp_all [ih]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem findIdx?_subtype {p : α → Prop} {l : List { x // p x }}
|
||||
{f : { x // p x } → Bool} {g : α → Bool} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
@@ -910,11 +985,11 @@ theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp [hf, findIdx?_cons]
|
||||
split <;> simp [ih, Function.comp_def]
|
||||
split <;> simp [ih]
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[simp] theorem findFinIdx?_nil {p : α → Bool} : findFinIdx? p [] = none := rfl
|
||||
@[simp, grind =] theorem findFinIdx?_nil {p : α → Bool} : findFinIdx? p [] = none := rfl
|
||||
|
||||
theorem findIdx?_go_eq_map_findFinIdx?_go_val {xs : List α} {p : α → Bool} {i : Nat} {h} :
|
||||
List.findIdx?.go p xs i =
|
||||
@@ -940,6 +1015,7 @@ theorem findFinIdx?_eq_pmap_findIdx? {xs : List α} {p : α → Bool} :
|
||||
(fun i h => h) := by
|
||||
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_cons {p : α → Bool} {x : α} {xs : List α} :
|
||||
findFinIdx? p (x :: xs) = if p x then some 0 else (findFinIdx? p xs).map Fin.succ := by
|
||||
rw [← Option.map_inj_right (f := Fin.val) (fun a b => Fin.eq_of_val_eq)]
|
||||
@@ -950,6 +1026,7 @@ theorem findFinIdx?_cons {p : α → Bool} {x : α} {xs : List α} :
|
||||
· rw [findIdx?_eq_map_findFinIdx?_val]
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_append {xs ys : List α} {p : α → Bool} :
|
||||
(xs ++ ys).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or
|
||||
@@ -959,11 +1036,11 @@ theorem findFinIdx?_append {xs ys : List α} {p : α → Bool} :
|
||||
· simp [h, Option.pmap_map, Option.map_pmap, Nat.add_comm]
|
||||
· simp [h]
|
||||
|
||||
@[simp] theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
[a].findFinIdx? p = if p a then some ⟨0, by simp⟩ else none := by
|
||||
simp [findFinIdx?_cons, findFinIdx?_nil]
|
||||
|
||||
@[simp] theorem findFinIdx?_eq_none_iff {l : List α} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findFinIdx?_eq_none_iff {l : List α} {p : α → Bool} :
|
||||
l.findFinIdx? p = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
simp [findFinIdx?_eq_pmap_findIdx?]
|
||||
|
||||
@@ -979,7 +1056,7 @@ theorem findFinIdx?_eq_some_iff {xs : List α} {p : α → Bool} {i : Fin xs.len
|
||||
· rintro ⟨h, w⟩
|
||||
exact ⟨i, ⟨i.2, h, fun j hji => w ⟨j, by omega⟩ hji⟩, rfl⟩
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isSome_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
(l.findFinIdx? p).isSome = l.any p := by
|
||||
induction l with
|
||||
@@ -988,7 +1065,7 @@ theorem isSome_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
simp only [findFinIdx?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isNone_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
(l.findFinIdx? p).isNone = l.all (fun x => ¬ p x) := by
|
||||
induction l with
|
||||
@@ -1001,7 +1078,7 @@ theorem isNone_findFinIdx? {l : List α} {p : α → Bool} :
|
||||
{f : { x // p x } → Bool} {g : α → Bool} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
l.findFinIdx? f = (l.unattach.findFinIdx? g).map (fun i => i.cast (by simp)) := by
|
||||
induction l with
|
||||
| nil => simp [unattach]
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp [hf, findFinIdx?_cons]
|
||||
split <;> simp [ih, Function.comp_def]
|
||||
@@ -1013,6 +1090,7 @@ The verification API for `idxOf` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
|
||||
-/
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_cons [BEq α] :
|
||||
(x :: xs : List α).idxOf y = bif x == y then 0 else xs.idxOf y + 1 := by
|
||||
dsimp [idxOf]
|
||||
@@ -1027,6 +1105,7 @@ abbrev indexOf_cons := @idxOf_cons
|
||||
@[deprecated idxOf_cons_self (since := "2025-01-29")]
|
||||
abbrev indexOf_cons_self := @idxOf_cons_self
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).idxOf a = if a ∈ l₁ then l₁.idxOf a else l₂.idxOf a + l₁.length := by
|
||||
rw [idxOf, findIdx_append]
|
||||
@@ -1050,21 +1129,36 @@ theorem idxOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.
|
||||
@[deprecated idxOf_eq_length (since := "2025-01-29")]
|
||||
abbrev indexOf_eq_length := @idxOf_eq_length
|
||||
|
||||
theorem idxOf_lt_length [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.idxOf a < l.length := by
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.idxOf a < l.length := by
|
||||
induction l with
|
||||
| nil => simp at h
|
||||
| cons x xs ih =>
|
||||
simp only [mem_cons] at h
|
||||
obtain rfl | h := h
|
||||
· simp
|
||||
· simp only [idxOf_cons, cond_eq_if, beq_iff_eq, length_cons]
|
||||
· simp only [idxOf_cons, cond_eq_if, length_cons]
|
||||
specialize ih h
|
||||
split
|
||||
· exact zero_lt_succ xs.length
|
||||
· exact Nat.add_lt_add_right ih 1
|
||||
|
||||
@[deprecated idxOf_lt_length (since := "2025-01-29")]
|
||||
abbrev indexOf_lt_length := @idxOf_lt_length
|
||||
theorem idxOf_le_length [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.idxOf a ≤ l.length := by
|
||||
simpa [idxOf] using findIdx_le_length
|
||||
|
||||
grind_pattern idxOf_le_length => l.idxOf a, l.length
|
||||
|
||||
theorem idxOf_lt_length_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.idxOf a < l.length ↔ a ∈ l := by
|
||||
constructor
|
||||
· intro h
|
||||
simpa [idxOf] using h
|
||||
· exact idxOf_lt_length_of_mem
|
||||
|
||||
grind_pattern idxOf_lt_length_iff => l.idxOf a, l.length
|
||||
|
||||
@[deprecated idxOf_lt_length_of_mem (since := "2025-01-29")]
|
||||
abbrev indexOf_lt_length := @idxOf_lt_length_of_mem
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
@@ -1076,14 +1170,14 @@ theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : List α} {a : α} :
|
||||
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
|
||||
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
|
||||
|
||||
@[simp] theorem finIdxOf?_nil [BEq α] : ([] : List α).finIdxOf? a = none := rfl
|
||||
@[simp, grind =] theorem finIdxOf?_nil [BEq α] : ([] : List α).finIdxOf? a = none := rfl
|
||||
|
||||
theorem finIdxOf?_cons [BEq α] {a : α} {xs : List α} :
|
||||
@[grind =] theorem finIdxOf?_cons [BEq α] {a : α} {xs : List α} :
|
||||
(a :: xs).finIdxOf? b =
|
||||
if a == b then some ⟨0, by simp⟩ else (xs.finIdxOf? b).map (·.succ) := by
|
||||
simp [finIdxOf?, findFinIdx?_cons]
|
||||
|
||||
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
@[simp, grind =] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.finIdxOf? a = none ↔ a ∉ l := by
|
||||
simp only [finIdxOf?, findFinIdx?_eq_none_iff, beq_iff_eq]
|
||||
constructor
|
||||
@@ -1096,18 +1190,19 @@ theorem finIdxOf?_cons [BEq α] {a : α} {xs : List α} :
|
||||
l.finIdxOf? a = some i ↔ l[i] = a ∧ ∀ j (_ : j < i), ¬l[j] = a := by
|
||||
simp only [finIdxOf?, findFinIdx?_eq_some_iff, beq_iff_eq]
|
||||
|
||||
@[simp]
|
||||
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isSome ↔ a ∈ l := by
|
||||
@[simp, grind =]
|
||||
theorem isSome_finIdxOf? [BEq α] [PartialEquivBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isSome = l.contains a := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [finIdxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
split <;> simp_all [BEq.comm]
|
||||
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isNone = ¬ a ∈ l := by
|
||||
simp
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [PartialEquivBEq α] {l : List α} {a : α} :
|
||||
(l.finIdxOf? a).isNone = !l.contains a := by
|
||||
rw [← isSome_finIdxOf?, Option.not_isSome]
|
||||
|
||||
/-! ### idxOf?
|
||||
|
||||
@@ -1115,16 +1210,16 @@ The verification API for `idxOf?` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
|
||||
-/
|
||||
|
||||
@[simp] theorem idxOf?_nil [BEq α] : ([] : List α).idxOf? a = none := rfl
|
||||
@[simp, grind =] theorem idxOf?_nil [BEq α] : ([] : List α).idxOf? a = none := rfl
|
||||
|
||||
theorem idxOf?_cons [BEq α] {a : α} {xs : List α} {b : α} :
|
||||
@[grind =] theorem idxOf?_cons [BEq α] {a : α} {xs : List α} {b : α} :
|
||||
(a :: xs).idxOf? b = if a == b then some 0 else (xs.idxOf? b).map (· + 1) := by
|
||||
simp [idxOf?, findIdx?_cons]
|
||||
|
||||
@[simp] theorem idxOf?_singleton [BEq α] {a b : α} : [a].idxOf? b = if a == b then some 0 else none := by
|
||||
simp [idxOf?_cons, idxOf?_nil]
|
||||
|
||||
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
@[simp, grind =] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.idxOf? a = none ↔ a ∉ l := by
|
||||
simp only [idxOf?, findIdx?_eq_none_iff, beq_eq_false_iff_ne, ne_eq]
|
||||
constructor
|
||||
@@ -1137,7 +1232,7 @@ theorem idxOf?_cons [BEq α] {a : α} {xs : List α} {b : α} :
|
||||
@[deprecated idxOf?_eq_none_iff (since := "2025-01-29")]
|
||||
abbrev indexOf?_eq_none_iff := @idxOf?_eq_none_iff
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isSome ↔ a ∈ l := by
|
||||
induction l with
|
||||
@@ -1146,6 +1241,7 @@ theorem isSome_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
simp only [idxOf?_cons]
|
||||
split <;> simp_all [@eq_comm _ x a]
|
||||
|
||||
@[grind =]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
(l.idxOf? a).isNone = ¬ a ∈ l := by
|
||||
simp
|
||||
@@ -1172,7 +1268,7 @@ theorem lookup_eq_findSome? {l : List (α × β)} {k : α} :
|
||||
simp only [lookup_cons, findSome?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem lookup_eq_none_iff {l : List (α × β)} {k : α} :
|
||||
@[simp, grind =] theorem lookup_eq_none_iff {l : List (α × β)} {k : α} :
|
||||
l.lookup k = none ↔ ∀ p ∈ l, k != p.1 := by
|
||||
simp [lookup_eq_findSome?]
|
||||
|
||||
@@ -1192,10 +1288,12 @@ theorem lookup_eq_some_iff {l : List (α × β)} {k : α} {b : β} :
|
||||
· rintro ⟨l₁, l₂, rfl, h⟩
|
||||
exact ⟨l₁, (k, b), l₂, rfl, by simp, by simpa using h⟩
|
||||
|
||||
@[grind =]
|
||||
theorem lookup_append {l₁ l₂ : List (α × β)} {k : α} :
|
||||
(l₁ ++ l₂).lookup k = (l₁.lookup k).or (l₂.lookup k) := by
|
||||
simp [lookup_eq_findSome?, findSome?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem lookup_replicate {k : α} :
|
||||
(replicate n (a,b)).lookup k = if n = 0 then none else if k == a then some b else none := by
|
||||
induction n with
|
||||
@@ -1230,6 +1328,9 @@ theorem Sublist.lookup_eq_none {l₁ l₂ : List (α × β)} (h : l₁ <+ l₂)
|
||||
simp only [lookup_eq_findSome?]
|
||||
exact h.findSome?_eq_none
|
||||
|
||||
grind_pattern Sublist.lookup_isSome => l₁ <+ l₂, l₁.lookup k
|
||||
grind_pattern Sublist.lookup_isSome => l₁ <+ l₂, l₂.lookup k
|
||||
|
||||
theorem IsPrefix.lookup_eq_some {l₁ l₂ : List (α × β)} (h : l₁ <+: l₂) :
|
||||
List.lookup k l₁ = some b → List.lookup k l₂ = some b := by
|
||||
simp only [lookup_eq_findSome?]
|
||||
@@ -1238,13 +1339,24 @@ theorem IsPrefix.lookup_eq_some {l₁ l₂ : List (α × β)} (h : l₁ <+: l₂
|
||||
theorem IsPrefix.lookup_eq_none {l₁ l₂ : List (α × β)} (h : l₁ <+: l₂) :
|
||||
List.lookup k l₂ = none → List.lookup k l₁ = none :=
|
||||
h.sublist.lookup_eq_none
|
||||
|
||||
grind_pattern IsPrefix.lookup_eq_none => l₁ <+: l₂, l₁.lookup k
|
||||
grind_pattern IsPrefix.lookup_eq_none => l₁ <+: l₂, l₂.lookup k
|
||||
|
||||
theorem IsSuffix.lookup_eq_none {l₁ l₂ : List (α × β)} (h : l₁ <:+ l₂) :
|
||||
List.lookup k l₂ = none → List.lookup k l₁ = none :=
|
||||
h.sublist.lookup_eq_none
|
||||
|
||||
grind_pattern IsSuffix.lookup_eq_none => l₁ <:+ l₂, l₁.lookup k
|
||||
grind_pattern IsSuffix.lookup_eq_none => l₁ <:+ l₂, l₂.lookup k
|
||||
|
||||
theorem IsInfix.lookup_eq_none {l₁ l₂ : List (α × β)} (h : l₁ <:+: l₂) :
|
||||
List.lookup k l₂ = none → List.lookup k l₁ = none :=
|
||||
h.sublist.lookup_eq_none
|
||||
|
||||
grind_pattern IsInfix.lookup_eq_none => l₁ <:+: l₂, l₁.lookup k
|
||||
grind_pattern IsInfix.lookup_eq_none => l₁ <:+: l₂, l₂.lookup k
|
||||
|
||||
end lookup
|
||||
|
||||
end List
|
||||
|
||||
@@ -234,7 +234,7 @@ Examples:
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [takeWhile, takeWhileTR.go]
|
||||
| cons x xs IH =>
|
||||
simp only [takeWhileTR.go, Array.toListImpl_eq, takeWhile]
|
||||
simp only [takeWhileTR.go, takeWhile]
|
||||
split
|
||||
· intro h; rw [IH] <;> simp_all
|
||||
· simp [*]
|
||||
@@ -261,11 +261,11 @@ Examples:
|
||||
/-- Tail recursive implementation of `findRev?`. This is only used at runtime. -/
|
||||
def findRev?TR (p : α → Bool) (l : List α) : Option α := l.reverse.find? p
|
||||
|
||||
@[simp] theorem find?_singleton {a : α} : [a].find? p = if p a then some a else none := by
|
||||
@[simp, grind =] theorem find?_singleton {a : α} : [a].find? p = if p a then some a else none := by
|
||||
simp only [find?]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem find?_append {xs ys : List α} : (xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
|
||||
@[simp, grind =] theorem find?_append {xs ys : List α} : (xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
|
||||
induction xs with
|
||||
| nil => simp [find?]
|
||||
| cons x xs ih =>
|
||||
@@ -287,12 +287,12 @@ def findRev?TR (p : α → Bool) (l : List α) : Option α := l.reverse.find? p
|
||||
/-- Tail recursive implementation of `finSomedRev?`. This is only used at runtime. -/
|
||||
def findSomeRev?TR (f : α → Option β) (l : List α) : Option β := l.reverse.findSome? f
|
||||
|
||||
@[simp] theorem findSome?_singleton {a : α} :
|
||||
@[simp, grind =] theorem findSome?_singleton {a : α} :
|
||||
[a].findSome? f = f a := by
|
||||
simp only [findSome?_cons, findSome?_nil]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem findSome?_append {xs ys : List α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
|
||||
@[simp, grind =] theorem findSome?_append {xs ys : List α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
|
||||
induction xs with
|
||||
| nil => simp [findSome?]
|
||||
| cons x xs ih =>
|
||||
|
||||
@@ -109,9 +109,11 @@ abbrev length_eq_zero := @length_eq_zero_iff
|
||||
theorem eq_nil_iff_length_eq_zero : l = [] ↔ length l = 0 :=
|
||||
length_eq_zero_iff.symm
|
||||
|
||||
@[grind →] theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
|
||||
theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
|
||||
| _::_, _ => Nat.zero_lt_succ _
|
||||
|
||||
grind_pattern length_pos_of_mem => a ∈ l, length l
|
||||
|
||||
theorem exists_mem_of_length_pos : ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l
|
||||
| _::_, _ => ⟨_, .head ..⟩
|
||||
|
||||
@@ -253,7 +255,7 @@ theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
|
||||
cases i <;> simp [getElem?_cons_zero]
|
||||
cases i <;> simp
|
||||
|
||||
theorem getElem?_eq_some_iff {l : List α} : l[i]? = some a ↔ ∃ h : i < l.length, l[i] = a :=
|
||||
match l with
|
||||
@@ -285,16 +287,16 @@ theorem getElem_eq_iff {l : List α} {i : Nat} (h : i < l.length) : l[i] = x ↔
|
||||
exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
|
||||
|
||||
theorem getElem_eq_getElem?_get {l : List α} {i : Nat} (h : i < l.length) :
|
||||
l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
|
||||
simp [getElem_eq_iff]
|
||||
l[i] = l[i]?.get (by simp [h]) := by
|
||||
simp
|
||||
|
||||
theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
|
||||
l[i]?.getD d = if p : i < l.length then l[i]'p else d := by
|
||||
if h : i < l.length then
|
||||
simp [h, getElem?_def]
|
||||
simp [h]
|
||||
else
|
||||
have p : i ≥ l.length := Nat.le_of_not_gt h
|
||||
simp [getElem?_eq_none p, h]
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : [a][i] = a := by
|
||||
match i, h with
|
||||
@@ -330,7 +332,7 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length), l₁[i]'h₁ = l₂[i]'h₂) : l₁ = l₂ :=
|
||||
ext_getElem? fun n =>
|
||||
if h₁ : n < length l₁ then by
|
||||
simp_all [getElem?_eq_getElem]
|
||||
simp_all
|
||||
else by
|
||||
have h₁ := Nat.le_of_not_lt h₁
|
||||
rw [getElem?_eq_none h₁, getElem?_eq_none]; rwa [← hl]
|
||||
@@ -634,7 +636,7 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
|
||||
|
||||
@[simp] theorem getElem?_set_self {l : List α} {i : Nat} {a : α} (h : i < l.length) :
|
||||
(l.set i a)[i]? = some a := by
|
||||
simp_all [getElem?_eq_some_iff]
|
||||
simp_all
|
||||
|
||||
/-- This differs from `getElem?_set_self` by monadically mapping `Function.const _ a` over the `Option`
|
||||
returned by `l[i]?`. -/
|
||||
@@ -677,7 +679,7 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
|
||||
subst h
|
||||
rw [if_pos rfl]
|
||||
split <;> rename_i h
|
||||
· simp only [getElem?_set_self (by simpa), h]
|
||||
· simp only [getElem?_set_self (by simpa)]
|
||||
· simp_all
|
||||
else
|
||||
simp [h]
|
||||
@@ -1274,9 +1276,9 @@ theorem length_filter_le (p : α → Bool) (l : List α) :
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, length_cons, succ_eq_add_one]
|
||||
simp only [filter_cons, length_cons]
|
||||
split
|
||||
· simp only [length_cons, succ_eq_add_one]
|
||||
· simp only [length_cons]
|
||||
exact Nat.succ_le_succ ih
|
||||
· exact Nat.le_trans ih (Nat.le_add_right _ _)
|
||||
|
||||
@@ -1294,7 +1296,7 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, length_cons, succ_eq_add_one, mem_cons, forall_eq_or_imp]
|
||||
simp only [filter_cons, length_cons, mem_cons, forall_eq_or_imp]
|
||||
split <;> rename_i h
|
||||
· simp_all [Nat.add_one_inj] -- Why does the simproc not fire here?
|
||||
· have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filter_le p l))
|
||||
@@ -1318,6 +1320,19 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
|
||||
(∀ (i) (_ : i ∈ l.filter p), P i) ↔ ∀ (j) (_ : j ∈ l), p j → P j := by
|
||||
simp
|
||||
|
||||
@[grind] theorem getElem_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length) :
|
||||
p (xs.filter p)[i] :=
|
||||
(mem_filter.mp (getElem_mem h)).2
|
||||
|
||||
theorem getElem?_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
|
||||
grind_pattern getElem?_filter => (xs.filter p)[i]?, some a
|
||||
|
||||
@[simp] theorem filter_filter : ∀ {l}, filter p (filter q l) = filter (fun a => p a && q a) l
|
||||
| [] => rfl
|
||||
| a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter]
|
||||
@@ -1373,7 +1388,7 @@ theorem filter_eq_cons_iff {l} {a} {as} :
|
||||
· obtain ⟨l₁, l₂, rfl, w₁, w₂, w₃⟩ := ih h
|
||||
exact ⟨x :: l₁, l₂, by simp_all⟩
|
||||
· rintro ⟨l₁, l₂, rfl, h₁, h, h₂⟩
|
||||
simp [h₂, filter_cons, filter_eq_nil_iff.mpr h₁, h]
|
||||
simp [h₂, filter_eq_nil_iff.mpr h₁, h]
|
||||
|
||||
theorem filter_congr {p q : α → Bool} :
|
||||
∀ {l : List α}, (∀ x ∈ l, p x = q x) → filter p l = filter q l
|
||||
@@ -1389,7 +1404,7 @@ theorem head_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p
|
||||
| nil => simp
|
||||
| cons =>
|
||||
simp only [head_cons] at h
|
||||
simp [filter_cons, h]
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem filter_sublist {p : α → Bool} : ∀ {l : List α}, filter p l <+ l
|
||||
| [] => .slnil
|
||||
@@ -1405,7 +1420,7 @@ theorem head_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p
|
||||
|
||||
@[simp]
|
||||
theorem filterMap_eq_map {f : α → β} : filterMap (some ∘ f) = map f := by
|
||||
funext l; induction l <;> simp [*, filterMap_cons]
|
||||
funext l; induction l <;> simp [*]
|
||||
|
||||
/-- Variant of `filterMap_eq_map` with `some ∘ f` expanded out to a lambda. -/
|
||||
@[simp]
|
||||
@@ -1438,7 +1453,7 @@ theorem filterMap_length_eq_length {l} :
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, length_cons, succ_eq_add_one, mem_cons, forall_eq_or_imp]
|
||||
simp only [filterMap_cons, length_cons, mem_cons, forall_eq_or_imp]
|
||||
split <;> rename_i h
|
||||
· have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filterMap_le f l))
|
||||
simp_all
|
||||
@@ -1450,7 +1465,7 @@ theorem filterMap_eq_filter {p : α → Bool} :
|
||||
funext l
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons a l IH => by_cases pa : p a <;> simp [filterMap_cons, Option.guard, pa, ← IH]
|
||||
| cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, ← IH]
|
||||
|
||||
@[grind]
|
||||
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {l : List α} :
|
||||
@@ -1497,7 +1512,7 @@ theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Pr
|
||||
|
||||
theorem map_filterMap_of_inv
|
||||
{f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {l : List α} :
|
||||
map g (filterMap f l) = l := by simp only [map_filterMap, H, filterMap_some, id]
|
||||
map g (filterMap f l) = l := by simp only [map_filterMap, H, filterMap_some]
|
||||
|
||||
theorem head_filterMap_of_eq_some {f : α → Option β} {l : List α} (w : l ≠ []) {b : β} (h : f (l.head w) = some b) :
|
||||
(filterMap f l).head ((ne_nil_of_mem (mem_filterMap.2 ⟨_, head_mem w, h⟩))) =
|
||||
@@ -1506,7 +1521,7 @@ theorem head_filterMap_of_eq_some {f : α → Option β} {l : List α} (w : l
|
||||
| nil => simp at w
|
||||
| cons a l =>
|
||||
simp only [head_cons] at h
|
||||
simp [filterMap_cons, h]
|
||||
simp [h]
|
||||
|
||||
@[grind →]
|
||||
theorem forall_none_of_filterMap_eq_nil (h : filterMap f xs = []) : ∀ x ∈ xs, f x = none := by
|
||||
@@ -1598,7 +1613,7 @@ theorem getElem?_append_left {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.leng
|
||||
(l₁ ++ l₂)[i]? = l₁[i]? := by
|
||||
have hn' : i < (l₁ ++ l₂).length := Nat.lt_of_lt_of_le hn <|
|
||||
length_append .. ▸ Nat.le_add_right ..
|
||||
simp_all [getElem?_eq_getElem, getElem_append]
|
||||
simp_all
|
||||
|
||||
theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length ≤ i →
|
||||
(l₁ ++ l₂)[i]? = l₂[i - l₁.length]?
|
||||
@@ -1802,10 +1817,10 @@ theorem filterMap_eq_append_iff {f : α → Option β} :
|
||||
intro h
|
||||
rcases cons_eq_append_iff.mp h with (⟨rfl, rfl⟩ | ⟨_, ⟨rfl, h⟩⟩)
|
||||
· refine ⟨[], x :: l, ?_⟩
|
||||
simp [filterMap_cons, w]
|
||||
simp [w]
|
||||
· obtain ⟨l₁, l₂, rfl, rfl, rfl⟩ := ih ‹_›
|
||||
refine ⟨x :: l₁, l₂, ?_⟩
|
||||
simp [filterMap_cons, w]
|
||||
simp [w]
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||||
simp
|
||||
|
||||
@@ -1870,7 +1885,7 @@ theorem append_concat {a : α} {l₁ l₂ : List α} : l₁ ++ concat l₂ a = c
|
||||
theorem map_concat {f : α → β} {a : α} {l : List α} : map f (concat l a) = concat (map f l) (f a) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih => simp [ih]
|
||||
| cons x xs ih => simp
|
||||
|
||||
theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ l' b, l = concat l' b
|
||||
| [] => .inl rfl
|
||||
@@ -2176,7 +2191,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
· rw [getElem?_eq_none (by simpa using h), if_neg h]
|
||||
|
||||
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
|
||||
simp [getElem?_replicate, h]
|
||||
simp [h]
|
||||
|
||||
@[grind] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
|
||||
cases n <;> simp [replicate_succ]
|
||||
@@ -2314,8 +2329,8 @@ theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [replicate_succ, flatten_cons, ih, replicate_append_replicate, replicate_inj, or_true,
|
||||
and_true, add_one_mul, Nat.add_comm]
|
||||
simp only [replicate_succ, flatten_cons, ih, replicate_append_replicate,
|
||||
add_one_mul, Nat.add_comm]
|
||||
|
||||
theorem flatMap_replicate {β} {f : α → List β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
|
||||
induction n with
|
||||
@@ -2398,7 +2413,7 @@ theorem reverse_ne_nil_iff {xs : List α} : xs.reverse ≠ [] ↔ xs ≠ [] :=
|
||||
theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
|
||||
l.reverse[i]? = l[j]?
|
||||
| [], _, _, _ => rfl
|
||||
| a::l, i, 0, h => by simp [Nat.succ.injEq] at h; simp [h, getElem?_append_right, Nat.succ.injEq]
|
||||
| a::l, i, 0, h => by simp [Nat.succ.injEq] at h; simp [h]
|
||||
| a::l, i, j+1, h => by
|
||||
have := Nat.succ.inj h; simp at this ⊢
|
||||
rw [getElem?_append_left, getElem?_reverse' this]
|
||||
@@ -2634,7 +2649,7 @@ theorem foldl_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldl_map_hom (since := "2025-01-20")] abbrev foldl_map' := @foldl_map_hom
|
||||
|
||||
@@ -2643,7 +2658,7 @@ theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β →
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
· simp [*]
|
||||
|
||||
@[deprecated foldr_map_hom (since := "2025-01-20")] abbrev foldr_map' := @foldr_map_hom
|
||||
|
||||
@@ -2727,11 +2742,11 @@ def foldlRecOn {motive : β → Sort _} : ∀ (l : List α) (op : β → α →
|
||||
foldlRecOn tl op (hl b hb hd mem_cons_self)
|
||||
fun y hy x hx => hl y hy x (mem_cons_of_mem hd hx)
|
||||
|
||||
@[simp] theorem foldlRecOn_nil {motive : β → Sort _} {op : β → α → β} (hb : motive b)
|
||||
@[simp, grind =] theorem foldlRecOn_nil {motive : β → Sort _} {op : β → α → β} (hb : motive b)
|
||||
(hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op b a)) :
|
||||
foldlRecOn [] op hb hl = hb := rfl
|
||||
|
||||
@[simp] theorem foldlRecOn_cons {motive : β → Sort _} {op : β → α → β} (hb : motive b)
|
||||
@[simp, grind =] theorem foldlRecOn_cons {motive : β → Sort _} {op : β → α → β} (hb : motive b)
|
||||
(hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op b a)) :
|
||||
foldlRecOn (x :: l) op hb hl =
|
||||
foldlRecOn l op (hl b hb x mem_cons_self)
|
||||
@@ -2762,11 +2777,11 @@ def foldrRecOn {motive : β → Sort _} : ∀ (l : List α) (op : α → β →
|
||||
hl (foldr op b l)
|
||||
(foldrRecOn l op hb fun b c a m => hl b c a (mem_cons_of_mem x m)) x mem_cons_self
|
||||
|
||||
@[simp] theorem foldrRecOn_nil {motive : β → Sort _} {op : α → β → β} (hb : motive b)
|
||||
@[simp, grind =] theorem foldrRecOn_nil {motive : β → Sort _} {op : α → β → β} (hb : motive b)
|
||||
(hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op a b)) :
|
||||
foldrRecOn [] op hb hl = hb := rfl
|
||||
|
||||
@[simp] theorem foldrRecOn_cons {motive : β → Sort _} {op : α → β → β} (hb : motive b)
|
||||
@[simp, grind =] theorem foldrRecOn_cons {motive : β → Sort _} {op : α → β → β} (hb : motive b)
|
||||
(hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op a b)) :
|
||||
foldrRecOn (x :: l) op hb hl =
|
||||
hl _ (foldrRecOn l op hb fun b c a m => hl b c a (mem_cons_of_mem x m))
|
||||
@@ -2778,8 +2793,8 @@ We can prove that two folds over the same list are related (by some arbitrary re
|
||||
if we know that the initial elements are related and the folding function, for each element of the list,
|
||||
preserves the relation.
|
||||
-/
|
||||
theorem foldl_rel {l : List α} {f g : β → α → β} {a b : β} {r : β → β → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) :
|
||||
theorem foldl_rel {l : List α} {f : β → α → β} {g : γ → α → γ} {a : β} {b : γ} {r : β → γ → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c : β) (c' : γ), r c c' → r (f c a) (g c' a)) :
|
||||
r (l.foldl (fun acc a => f acc a) a) (l.foldl (fun acc a => g acc a) b) := by
|
||||
induction l generalizing a b with
|
||||
| nil => simp_all
|
||||
@@ -2794,8 +2809,8 @@ We can prove that two folds over the same list are related (by some arbitrary re
|
||||
if we know that the initial elements are related and the folding function, for each element of the list,
|
||||
preserves the relation.
|
||||
-/
|
||||
theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} {r : β → β → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f a c) (g a c')) :
|
||||
theorem foldr_rel {l : List α} {f : α → β → β} {g : α → γ → γ} {a : β} {b : γ} {r : β → γ → Prop}
|
||||
(h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c : β) (c' : γ), r c c' → r (f a c) (g a c')) :
|
||||
r (l.foldr (fun a acc => f a acc) a) (l.foldr (fun a acc => g a acc) b) := by
|
||||
induction l generalizing a b with
|
||||
| nil => simp_all
|
||||
@@ -2832,7 +2847,7 @@ theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} {r : β →
|
||||
by_cases h' : l = []
|
||||
· simp_all
|
||||
· simp only [head_eq_iff_head?_eq_some, head?_reverse] at ih
|
||||
simp [ih, h, h', getLast_cons, head_eq_iff_head?_eq_some]
|
||||
simp [ih, h', getLast_cons, head_eq_iff_head?_eq_some]
|
||||
|
||||
theorem getLast_eq_head_reverse {l : List α} (h : l ≠ []) :
|
||||
l.getLast h = l.reverse.head (by simp_all) := by
|
||||
@@ -2902,13 +2917,13 @@ theorem getLast_filterMap_of_eq_some {f : α → Option β} {l : List α} (w : l
|
||||
rw [head_filterMap_of_eq_some (by simp_all)]
|
||||
simp_all
|
||||
|
||||
theorem getLast?_flatMap {l : List α} {f : α → List β} :
|
||||
@[grind =] theorem getLast?_flatMap {l : List α} {f : α → List β} :
|
||||
(l.flatMap f).getLast? = l.reverse.findSome? fun a => (f a).getLast? := by
|
||||
simp only [← head?_reverse, reverse_flatMap]
|
||||
rw [head?_flatMap]
|
||||
rfl
|
||||
|
||||
theorem getLast?_flatten {L : List (List α)} :
|
||||
@[grind =] theorem getLast?_flatten {L : List (List α)} :
|
||||
(flatten L).getLast? = L.reverse.findSome? fun l => l.getLast? := by
|
||||
simp [← flatMap_id, getLast?_flatMap]
|
||||
|
||||
@@ -2923,7 +2938,7 @@ theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n
|
||||
/-! ### leftpad -/
|
||||
|
||||
-- We unfold `leftpad` and `rightpad` for verification purposes.
|
||||
attribute [simp] leftpad rightpad
|
||||
attribute [simp, grind] leftpad rightpad
|
||||
|
||||
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
|
||||
|
||||
@@ -3027,6 +3042,9 @@ we do not separately develop much theory about it.
|
||||
theorem mem_partition : a ∈ l ↔ a ∈ (partition p l).1 ∨ a ∈ (partition p l).2 := by
|
||||
by_cases p a <;> simp_all
|
||||
|
||||
grind_pattern mem_partition => a ∈ (partition p l).1
|
||||
grind_pattern mem_partition => a ∈ (partition p l).2
|
||||
|
||||
/-! ### dropLast
|
||||
|
||||
`dropLast` is the specification for `Array.pop`, so theorems about `List.dropLast`
|
||||
@@ -3098,7 +3116,7 @@ theorem dropLast_concat_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l +
|
||||
congr
|
||||
exact dropLast_concat_getLast (cons_ne_nil b l)
|
||||
|
||||
@[simp] theorem map_dropLast {f : α → β} {l : List α} : l.dropLast.map f = (l.map f).dropLast := by
|
||||
@[simp, grind _=_] theorem map_dropLast {f : α → β} {l : List α} : l.dropLast.map f = (l.map f).dropLast := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih => cases xs <;> simp [ih]
|
||||
@@ -3110,6 +3128,7 @@ theorem dropLast_concat_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l +
|
||||
rw [cons_append, dropLast, dropLast_append_of_ne_nil h, cons_append]
|
||||
simp [h]
|
||||
|
||||
@[grind =]
|
||||
theorem dropLast_append {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).dropLast = if l₂.isEmpty then l₁.dropLast else l₁ ++ l₂.dropLast := by
|
||||
split <;> simp_all
|
||||
@@ -3117,9 +3136,9 @@ theorem dropLast_append {l₁ l₂ : List α} :
|
||||
theorem dropLast_append_cons : dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (b :: l₂) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
|
||||
@[simp, grind =] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
|
||||
|
||||
@[simp] theorem dropLast_replicate {n : Nat} {a : α} : dropLast (replicate n a) = replicate (n - 1) a := by
|
||||
@[simp, grind =] theorem dropLast_replicate {n : Nat} {a : α} : dropLast (replicate n a) = replicate (n - 1) a := by
|
||||
match n with
|
||||
| 0 => simp
|
||||
| 1 => simp [replicate_succ]
|
||||
@@ -3132,7 +3151,7 @@ theorem dropLast_append_cons : dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (
|
||||
dropLast (a :: replicate n a) = replicate n a := by
|
||||
rw [← replicate_succ, dropLast_replicate, Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem tail_reverse {l : List α} : l.reverse.tail = l.dropLast.reverse := by
|
||||
@[simp, grind _=_] theorem tail_reverse {l : List α} : l.reverse.tail = l.dropLast.reverse := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
@@ -3372,20 +3391,21 @@ theorem replace_append_right [LawfulBEq α] {l₁ l₂ : List α} (h : ¬ a ∈
|
||||
(l₁ ++ l₂).replace a b = l₁ ++ l₂.replace a b := by
|
||||
simp [replace_append, h]
|
||||
|
||||
@[grind _=_]
|
||||
theorem replace_take {l : List α} {i : Nat} :
|
||||
(l.take i).replace a b = (l.replace a b).take i := by
|
||||
induction l generalizing i with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
cases i with
|
||||
| zero => simp [ih]
|
||||
| zero => simp
|
||||
| succ i =>
|
||||
simp only [replace_cons, take_succ_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem replace_replicate_self [LawfulBEq α] {a : α} (h : 0 < n) :
|
||||
(replicate n a).replace a b = b :: replicate (n - 1) a := by
|
||||
cases n <;> simp_all [replicate_succ, replace_cons]
|
||||
cases n <;> simp_all [replicate_succ]
|
||||
|
||||
@[simp] theorem replace_replicate_ne [LawfulBEq α] {a b c : α} (h : !b == a) :
|
||||
(replicate n a).replace b c = replicate n a := by
|
||||
@@ -3487,11 +3507,11 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_insert]
|
||||
split
|
||||
· simp [getElem?_eq_getElem, h]
|
||||
· simp [h]
|
||||
· split
|
||||
· rfl
|
||||
· have h' : i - 1 < l.length := Nat.lt_of_le_of_lt (Nat.pred_le _) h
|
||||
simp [getElem?_eq_getElem, h']
|
||||
simp [h']
|
||||
|
||||
theorem head?_insert {l : List α} {a : α} :
|
||||
(l.insert a).head? = some (if h : a ∈ l then l.head (ne_nil_of_mem h) else a) := by
|
||||
@@ -3512,7 +3532,7 @@ theorem head_insert {l : List α} {a : α} (w) :
|
||||
|
||||
theorem insert_append_of_mem_left {l₁ l₂ : List α} (h : a ∈ l₂) :
|
||||
(l₁ ++ l₂).insert a = l₁ ++ l₂ := by
|
||||
simp [insert_append, h]
|
||||
simp [h]
|
||||
|
||||
theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂) :
|
||||
(l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
|
||||
@@ -3538,10 +3558,10 @@ end insert
|
||||
|
||||
/-! ### `removeAll` -/
|
||||
|
||||
@[simp] theorem removeAll_nil [BEq α] {xs : List α} : xs.removeAll [] = xs := by
|
||||
@[simp, grind =] theorem removeAll_nil [BEq α] {xs : List α} : xs.removeAll [] = xs := by
|
||||
simp [removeAll]
|
||||
|
||||
theorem cons_removeAll [BEq α] {x : α} {xs ys : List α} :
|
||||
@[grind =] theorem cons_removeAll [BEq α] {x : α} {xs ys : List α} :
|
||||
(x :: xs).removeAll ys =
|
||||
if ys.contains x = false then
|
||||
x :: xs.removeAll ys
|
||||
@@ -3549,6 +3569,7 @@ theorem cons_removeAll [BEq α] {x : α} {xs ys : List α} :
|
||||
xs.removeAll ys := by
|
||||
simp [removeAll, filter_cons]
|
||||
|
||||
@[grind =]
|
||||
theorem removeAll_cons [BEq α] {xs : List α} {y : α} {ys : List α} :
|
||||
xs.removeAll (y :: ys) = (xs.filter fun x => !x == y).removeAll ys := by
|
||||
simp [removeAll, Bool.and_comm]
|
||||
@@ -3568,7 +3589,7 @@ theorem removeAll_cons [BEq α] {xs : List α} {y : α} {ys : List α} :
|
||||
|
||||
/-! ### `eraseDupsBy` and `eraseDups` -/
|
||||
|
||||
@[simp] theorem eraseDupsBy_nil : ([] : List α).eraseDupsBy r = [] := rfl
|
||||
@[simp, grind =] theorem eraseDupsBy_nil : ([] : List α).eraseDupsBy r = [] := rfl
|
||||
|
||||
private theorem eraseDupsBy_loop_cons {as bs : List α} {r : α → α → Bool} :
|
||||
eraseDupsBy.loop r as bs = bs.reverse ++ eraseDupsBy.loop r (as.filter fun a => !bs.any (r a)) [] := by
|
||||
@@ -3588,17 +3609,19 @@ private theorem eraseDupsBy_loop_cons {as bs : List α} {r : α → α → Bool}
|
||||
simp
|
||||
termination_by as.length
|
||||
|
||||
@[grind =]
|
||||
theorem eraseDupsBy_cons :
|
||||
(a :: as).eraseDupsBy r = a :: (as.filter fun b => r b a = false).eraseDupsBy r := by
|
||||
simp only [eraseDupsBy, eraseDupsBy.loop, any_nil]
|
||||
rw [eraseDupsBy_loop_cons]
|
||||
simp
|
||||
|
||||
@[simp] theorem eraseDups_nil [BEq α] : ([] : List α).eraseDups = [] := rfl
|
||||
theorem eraseDups_cons [BEq α] {a : α} {as : List α} :
|
||||
@[simp, grind =] theorem eraseDups_nil [BEq α] : ([] : List α).eraseDups = [] := rfl
|
||||
@[grind =] theorem eraseDups_cons [BEq α] {a : α} {as : List α} :
|
||||
(a :: as).eraseDups = a :: (as.filter fun b => !b == a).eraseDups := by
|
||||
simp [eraseDups, eraseDupsBy_cons]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseDups_append [BEq α] [LawfulBEq α] {as bs : List α} :
|
||||
(as ++ bs).eraseDups = as.eraseDups ++ (bs.removeAll as).eraseDups := by
|
||||
match as with
|
||||
@@ -3670,7 +3693,7 @@ theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {i : Nat}, l[i]?
|
||||
rw [getElem!_pos] <;> simp_all
|
||||
| _::l, _+1, e => by
|
||||
simp at e
|
||||
simp_all [getElem!_of_getElem? (l := l) e]
|
||||
simp_all
|
||||
|
||||
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
(h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
|
||||
|
||||
@@ -91,7 +91,7 @@ is valid.
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapFinIdx_nil {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx [] f = [] :=
|
||||
rfl
|
||||
|
||||
@@ -101,7 +101,7 @@ theorem mapFinIdx_nil {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx
|
||||
| nil => simpa using h
|
||||
| cons _ _ ih => simp [mapFinIdx.go, ih]
|
||||
|
||||
@[simp] theorem length_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} :
|
||||
@[simp, grind =] theorem length_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} :
|
||||
(as.mapFinIdx f).length = as.length := by
|
||||
simp [mapFinIdx, length_mapFinIdx_go]
|
||||
|
||||
@@ -129,7 +129,7 @@ theorem getElem_mapFinIdx_go {as : List α} {f : (i : Nat) → α → (h : i < a
|
||||
· have h₃ : i - acc.size = (i - (acc.size + 1)) + 1 := by omega
|
||||
simp [h₃]
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} {i : Nat} {h} :
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} {i : Nat} {h} :
|
||||
(as.mapFinIdx f)[i] = f i (as[i]'(by simp at h; omega)) (by simp at h; omega) := by
|
||||
simp [mapFinIdx, getElem_mapFinIdx_go]
|
||||
|
||||
@@ -137,18 +137,19 @@ theorem mapFinIdx_eq_ofFn {as : List α} {f : (i : Nat) → α → (h : i < as.l
|
||||
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] i.2 := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapFinIdx {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {i : Nat} :
|
||||
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => some <| f i x (by simp [getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapFinIdx_cons {l : List α} {a : α} {f : (i : Nat) → α → (h : i < l.length + 1) → β} :
|
||||
mapFinIdx (a :: l) f = f 0 a (by omega) :: mapFinIdx l (fun i a h => f (i + 1) a (by omega)) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· rintro (_|i) h₁ h₂ <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem mapFinIdx_append {xs ys : List α} {f : (i : Nat) → α → (h : i < (xs ++ ys).length) → β} :
|
||||
(xs ++ ys).mapFinIdx f =
|
||||
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||||
@@ -165,7 +166,7 @@ theorem mapFinIdx_append {xs ys : List α} {f : (i : Nat) → α → (h : i < (x
|
||||
congr
|
||||
omega
|
||||
|
||||
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : (i : Nat) → α → (h : i < (l ++ [e]).length) → β}:
|
||||
@[simp, grind =] theorem mapFinIdx_concat {l : List α} {e : α} {f : (i : Nat) → α → (h : i < (l ++ [e]).length) → β}:
|
||||
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i a h => f i a (by simp; omega)) ++ [f l.length e (by simp)] := by
|
||||
simp [mapFinIdx_append]
|
||||
|
||||
@@ -201,7 +202,7 @@ theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) → α →
|
||||
obtain ⟨h', rfl⟩ := h
|
||||
exact ⟨i, h', rfl⟩
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
@[simp, grind =] theorem mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Nat) (h : i < l.length), f i l[i] h = b := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -217,8 +218,8 @@ theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) → α → (
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons x l' =>
|
||||
simp only [mapFinIdx_cons, cons.injEq, length_cons, Fin.zero_eta, Fin.cast_succ_eq,
|
||||
exists_and_left]
|
||||
simp only [mapFinIdx_cons, cons.injEq,
|
||||
]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
refine ⟨x, l', ⟨rfl, rfl⟩, by simp⟩
|
||||
@@ -266,7 +267,7 @@ theorem mapFinIdx_eq_append_iff {l : List α} {f : (i : Nat) → α → (h : i <
|
||||
· simp
|
||||
omega
|
||||
· intro i hi₁ hi₂
|
||||
simp only [getElem_mapFinIdx, getElem_take]
|
||||
simp only [getElem_mapFinIdx]
|
||||
simp only [length_take, getElem_drop]
|
||||
have : l₁.length ≤ l.length := by omega
|
||||
simp only [Nat.min_eq_left this, Nat.add_comm]
|
||||
@@ -285,9 +286,9 @@ theorem mapFinIdx_eq_append_iff {l : List α} {f : (i : Nat) → α → (h : i <
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Nat) (h : i < l.length), f i l[i] h = g i l[i] h := by
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp [Fin.forall_iff]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : List α}
|
||||
@[simp, grind =] theorem mapFinIdx_mapFinIdx {l : List α}
|
||||
{f : (i : Nat) → α → (h : i < l.length) → β}
|
||||
{g : (i : Nat) → β → (h : i < (l.mapFinIdx f).length) → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa)) := by
|
||||
@@ -303,7 +304,7 @@ theorem mapFinIdx_eq_replicate_iff {l : List α} {f : (i : Nat) → α → (h :
|
||||
· rintro w b i h rfl
|
||||
exact w i h
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {l : List α} {f : (i : Nat) → α → (h : i < l.reverse.length) → β} :
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {l : List α} {f : (i : Nat) → α → (h : i < l.reverse.length) → β} :
|
||||
l.reverse.mapFinIdx f =
|
||||
(l.mapFinIdx (fun i a h => f (l.length - 1 - i) a (by simp; omega))).reverse := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
@@ -313,7 +314,7 @@ theorem mapFinIdx_eq_replicate_iff {l : List α} {f : (i : Nat) → α → (h :
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_nil {f : Nat → α → β} : mapIdx f [] = [] :=
|
||||
rfl
|
||||
|
||||
@@ -333,14 +334,14 @@ theorem length_mapIdx_go : ∀ {l : List α} {acc : Array β},
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem length_mapIdx {l : List α} : (l.mapIdx f).length = l.length := by
|
||||
@[simp, grind =] theorem length_mapIdx {l : List α} : (l.mapIdx f).length = l.length := by
|
||||
simp [mapIdx, length_mapIdx_go]
|
||||
|
||||
theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
|
||||
(mapIdx.go f l acc)[i]? =
|
||||
if h : i < acc.size then some acc[i] else Option.map (f i) l[i - acc.size]?
|
||||
| [], acc, i => by
|
||||
simp only [mapIdx.go, Array.toListImpl_eq, getElem?_def, Array.length_toList,
|
||||
simp only [mapIdx.go, getElem?_def, Array.length_toList,
|
||||
← Array.getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none]
|
||||
| a :: l, acc, i => by
|
||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||
@@ -356,11 +357,11 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
|
||||
· have : i - acc.size = i - (acc.size + 1) + 1 := by omega
|
||||
simp_all
|
||||
|
||||
@[simp] theorem getElem?_mapIdx {l : List α} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapIdx {l : List α} {i : Nat} :
|
||||
(l.mapIdx f)[i]? = Option.map (f i) l[i]? := by
|
||||
simp [mapIdx, getElem?_mapIdx_go]
|
||||
|
||||
@[simp] theorem getElem_mapIdx {l : List α} {f : Nat → α → β} {i : Nat} {h : i < (l.mapIdx f).length} :
|
||||
@[simp, grind =] theorem getElem_mapIdx {l : List α} {f : Nat → α → β} {i : Nat} {h : i < (l.mapIdx f).length} :
|
||||
(l.mapIdx f)[i] = f i (l[i]'(by simpa using h)) := by
|
||||
apply Option.some_inj.mp
|
||||
rw [← getElem?_eq_getElem, getElem?_mapIdx, getElem?_eq_getElem (by simpa using h)]
|
||||
@@ -384,18 +385,19 @@ theorem mapIdx_eq_zipIdx_map {l : List α} {f : Nat → α → β} :
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_enum_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_cons {l : List α} {a : α} :
|
||||
mapIdx f (a :: l) = f 0 a :: mapIdx (fun i => f (i + 1)) l := by
|
||||
simp [mapIdx_eq_zipIdx_map, List.zipIdx_succ]
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs ys : List α} :
|
||||
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx fun i => f (i + xs.length) := by
|
||||
induction xs generalizing f with
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp [ih (f := fun i => f (i + 1)), Nat.add_assoc]
|
||||
|
||||
@[simp] theorem mapIdx_concat {l : List α} {e : α} :
|
||||
@[simp, grind =] theorem mapIdx_concat {l : List α} {e : α} :
|
||||
mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by
|
||||
simp [mapIdx_append]
|
||||
|
||||
@@ -415,7 +417,7 @@ theorem exists_of_mem_mapIdx {b : β} {l : List α}
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {l : List α} :
|
||||
@[simp, grind =] theorem mem_mapIdx {b : β} {l : List α} :
|
||||
b ∈ mapIdx f l ↔ ∃ (i : Nat) (h : i < l.length), f i l[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -470,7 +472,7 @@ theorem mapIdx_eq_mapIdx_iff {l : List α} :
|
||||
· intro i h₁ h₂
|
||||
simp [w]
|
||||
|
||||
@[simp] theorem mapIdx_set {l : List α} {i : Nat} {a : α} :
|
||||
@[simp, grind =] theorem mapIdx_set {l : List α} {i : Nat} {a : α} :
|
||||
(l.set i a).mapIdx f = (l.mapIdx f).set i (f i a) := by
|
||||
simp only [mapIdx_eq_iff, getElem?_set, length_mapIdx, getElem?_mapIdx]
|
||||
intro i
|
||||
@@ -478,16 +480,16 @@ theorem mapIdx_eq_mapIdx_iff {l : List α} :
|
||||
· split <;> simp_all
|
||||
· rfl
|
||||
|
||||
@[simp] theorem head_mapIdx {l : List α} {f : Nat → α → β} {w : mapIdx f l ≠ []} :
|
||||
@[simp, grind =] theorem head_mapIdx {l : List α} {f : Nat → α → β} {w : mapIdx f l ≠ []} :
|
||||
(mapIdx f l).head w = f 0 (l.head (by simpa using w)) := by
|
||||
cases l with
|
||||
| nil => simp at w
|
||||
| cons _ _ => simp
|
||||
|
||||
@[simp] theorem head?_mapIdx {l : List α} {f : Nat → α → β} : (mapIdx f l).head? = l.head?.map (f 0) := by
|
||||
@[simp, grind =] theorem head?_mapIdx {l : List α} {f : Nat → α → β} : (mapIdx f l).head? = l.head?.map (f 0) := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem getLast_mapIdx {l : List α} {f : Nat → α → β} {h} :
|
||||
@[simp, grind =] theorem getLast_mapIdx {l : List α} {f : Nat → α → β} {h} :
|
||||
(mapIdx f l).getLast h = f (l.length - 1) (l.getLast (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
@@ -498,13 +500,13 @@ theorem mapIdx_eq_mapIdx_iff {l : List α} :
|
||||
simp only [← mapIdx_cons, getElem_mapIdx]
|
||||
simp
|
||||
|
||||
@[simp] theorem getLast?_mapIdx {l : List α} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem getLast?_mapIdx {l : List α} {f : Nat → α → β} :
|
||||
(mapIdx f l).getLast? = (getLast? l).map (f (l.length - 1)) := by
|
||||
cases l
|
||||
· simp
|
||||
· rw [getLast?_eq_getLast, getLast?_eq_getLast, getLast_mapIdx] <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_mapIdx {l : List α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
@[simp, grind =] theorem mapIdx_mapIdx {l : List α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(l.mapIdx f).mapIdx g = l.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
@@ -517,12 +519,12 @@ theorem mapIdx_eq_replicate_iff {l : List α} {f : Nat → α → β} {b : β} :
|
||||
· rintro w _ i h rfl
|
||||
exact w i h
|
||||
|
||||
@[simp] theorem mapIdx_reverse {l : List α} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem mapIdx_reverse {l : List α} {f : Nat → α → β} :
|
||||
l.reverse.mapIdx f = (mapIdx (fun i => f (l.length - 1 - i)) l).reverse := by
|
||||
simp [mapIdx_eq_iff]
|
||||
intro i
|
||||
by_cases h : i < l.length
|
||||
· simp [getElem?_reverse, h]
|
||||
· simp [h]
|
||||
congr
|
||||
omega
|
||||
· simp at h
|
||||
|
||||
@@ -60,27 +60,27 @@ theorem mapM'_eq_mapM [Monad m] [LawfulMonad m] {f : α → m β} {l : List α}
|
||||
| [], acc => by simp [mapM.loop, mapM']
|
||||
| a::l, acc => by simp [go l, mapM.loop, mapM']
|
||||
|
||||
@[simp] theorem mapM_nil [Monad m] {f : α → m β} : [].mapM f = pure [] := rfl
|
||||
@[simp, grind =] theorem mapM_nil [Monad m] {f : α → m β} : [].mapM f = pure [] := rfl
|
||||
|
||||
@[simp] theorem mapM_cons [Monad m] [LawfulMonad m] {f : α → m β} :
|
||||
@[simp, grind =] theorem mapM_cons [Monad m] [LawfulMonad m] {f : α → m β} :
|
||||
(a :: l).mapM f = (return (← f a) :: (← l.mapM f)) := by simp [← mapM'_eq_mapM, mapM']
|
||||
|
||||
@[simp] theorem mapM_pure [Monad m] [LawfulMonad m] {l : List α} {f : α → β} :
|
||||
l.mapM (m := m) (pure <| f ·) = pure (l.map f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem idRun_mapM {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
@[simp, grind =] theorem idRun_mapM {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {l : List α} :
|
||||
@[simp, grind =] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {l : List α} :
|
||||
(l.map f).mapM g = l.mapM (g ∘ f) := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {l₁ l₂ : List α} :
|
||||
@[simp, grind =] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).mapM f = (return (← l₁.mapM f) ++ (← l₂.mapM f)) := by induction l₁ <;> simp [*]
|
||||
|
||||
/-- Auxiliary lemma for `mapM_eq_reverse_foldlM_cons`. -/
|
||||
@@ -90,8 +90,8 @@ theorem foldlM_cons_eq_append [Monad m] [LawfulMonad m] {f : α → m β} {as :
|
||||
induction as generalizing b bs with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [bind_pure_comp] at ih
|
||||
simp [ih, _root_.map_bind, Functor.map_map, Function.comp_def]
|
||||
simp only at ih
|
||||
simp [ih, _root_.map_bind, Functor.map_map]
|
||||
|
||||
theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] {f : α → m β} {l : List α} :
|
||||
mapM f l = reverse <$> (l.foldlM (fun acc a => (· :: acc) <$> f a) []) := by
|
||||
@@ -99,14 +99,14 @@ theorem mapM_eq_reverse_foldlM_cons [Monad m] [LawfulMonad m] {f : α → m β}
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [mapM'_cons, ih, bind_map_left, foldlM_cons, LawfulMonad.bind_assoc, pure_bind,
|
||||
foldlM_cons_eq_append, _root_.map_bind, Functor.map_map, Function.comp_def, reverse_append,
|
||||
simp only [mapM'_cons, ih, bind_map_left, foldlM_cons,
|
||||
foldlM_cons_eq_append, _root_.map_bind, Functor.map_map, reverse_append,
|
||||
reverse_cons, reverse_nil, nil_append, singleton_append]
|
||||
simp [bind_pure_comp]
|
||||
|
||||
/-! ### filterMapM -/
|
||||
|
||||
@[simp] theorem filterMapM_nil [Monad m] {f : α → m (Option β)} : [].filterMapM f = pure [] := rfl
|
||||
@[simp, grind =] theorem filterMapM_nil [Monad m] {f : α → m (Option β)} : [].filterMapM f = pure [] := rfl
|
||||
|
||||
theorem filterMapM_loop_eq [Monad m] [LawfulMonad m] {f : α → m (Option β)} {l : List α} {acc : List β} :
|
||||
filterMapM.loop f l acc = (acc.reverse ++ ·) <$> filterMapM.loop f l [] := by
|
||||
@@ -121,7 +121,7 @@ theorem filterMapM_loop_eq [Monad m] [LawfulMonad m] {f : α → m (Option β)}
|
||||
· rw [ih, ih (acc := [b])]
|
||||
simp
|
||||
|
||||
@[simp] theorem filterMapM_cons [Monad m] [LawfulMonad m] {f : α → m (Option β)} :
|
||||
@[simp, grind =] theorem filterMapM_cons [Monad m] [LawfulMonad m] {f : α → m (Option β)} :
|
||||
(a :: l).filterMapM f = do
|
||||
match (← f a) with
|
||||
| none => filterMapM f l
|
||||
@@ -137,20 +137,20 @@ theorem filterMapM_loop_eq [Monad m] [LawfulMonad m] {f : α → m (Option β)}
|
||||
|
||||
/-! ### flatMapM -/
|
||||
|
||||
@[simp] theorem flatMapM_nil [Monad m] {f : α → m (List β)} : [].flatMapM f = pure [] := rfl
|
||||
@[simp, grind =] theorem flatMapM_nil [Monad m] {f : α → m (List β)} : [].flatMapM f = pure [] := rfl
|
||||
|
||||
theorem flatMapM_loop_eq [Monad m] [LawfulMonad m] {f : α → m (List β)} {l : List α} {acc : List (List β)} :
|
||||
flatMapM.loop f l acc = (acc.reverse.flatten ++ ·) <$> flatMapM.loop f l [] := by
|
||||
induction l generalizing acc with
|
||||
| nil => simp [flatMapM.loop]
|
||||
| cons a l ih =>
|
||||
simp only [flatMapM.loop, append_nil, _root_.map_bind]
|
||||
simp only [flatMapM.loop, _root_.map_bind]
|
||||
congr
|
||||
funext bs
|
||||
rw [ih, ih (acc := [bs])]
|
||||
simp
|
||||
|
||||
@[simp] theorem flatMapM_cons [Monad m] [LawfulMonad m] {f : α → m (List β)} :
|
||||
@[simp, grind =] theorem flatMapM_cons [Monad m] [LawfulMonad m] {f : α → m (List β)} :
|
||||
(a :: l).flatMapM f = do
|
||||
let bs ← f a
|
||||
return (bs ++ (← l.flatMapM f)) := by
|
||||
@@ -230,11 +230,11 @@ theorem forM_cons' [Monad m] :
|
||||
(a::as).forM f = (f a >>= fun _ => as.forM f : m PUnit) :=
|
||||
List.forM_cons
|
||||
|
||||
@[simp] theorem forM_append [Monad m] [LawfulMonad m] {l₁ l₂ : List α} {f : α → m PUnit} :
|
||||
@[simp, grind =] theorem forM_append [Monad m] [LawfulMonad m] {l₁ l₂ : List α} {f : α → m PUnit} :
|
||||
forM (l₁ ++ l₂) f = (do forM l₁ f; forM l₂ f) := by
|
||||
induction l₁ <;> simp [*]
|
||||
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] {l : List α} {g : α → β} {f : β → m PUnit} :
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] {l : List α} {g : α → β} {f : β → m PUnit} :
|
||||
forM (l.map g) f = forM l (fun a => f (g a)) := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@@ -257,7 +257,7 @@ theorem forIn'_loop_congr [Monad m] {as bs : List α}
|
||||
· simp
|
||||
rw [ih]
|
||||
|
||||
@[simp] theorem forIn'_cons [Monad m] {a : α} {as : List α}
|
||||
@[simp, grind =] theorem forIn'_cons [Monad m] {a : α} {as : List α}
|
||||
(f : (a' : α) → a' ∈ a :: as → β → m (ForInStep β)) (b : β) :
|
||||
forIn' (a::as) b f = f a mem_cons_self b >>=
|
||||
fun | ForInStep.done b => pure b | ForInStep.yield b => forIn' as b fun a' m b => f a' (mem_cons_of_mem a m) b := by
|
||||
@@ -270,7 +270,7 @@ theorem forIn'_loop_congr [Monad m] {as bs : List α}
|
||||
intros
|
||||
rfl
|
||||
|
||||
@[simp] theorem forIn_cons [Monad m] (f : α → β → m (ForInStep β)) (a : α) (as : List α) (b : β) :
|
||||
@[simp, grind =] theorem forIn_cons [Monad m] (f : α → β → m (ForInStep β)) (a : α) (as : List α) (b : β) :
|
||||
forIn (a::as) b f = f a b >>= fun | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f := by
|
||||
have := forIn'_cons (a := a) (as := as) (fun a' _ b => f a' b) b
|
||||
simpa only [forIn'_eq_forIn]
|
||||
@@ -363,7 +363,7 @@ theorem forIn'_yield_eq_foldl
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} (g : α → β) (f : (b : β) → b ∈ l.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem h) y := by
|
||||
induction l generalizing init <;> simp_all
|
||||
@@ -381,7 +381,7 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
induction l generalizing init with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [foldlM_cons, bind_pure_comp, forIn_cons, _root_.map_bind]
|
||||
simp only [foldlM_cons, forIn_cons, _root_.map_bind]
|
||||
congr 1
|
||||
funext x
|
||||
match x with
|
||||
@@ -422,7 +422,7 @@ theorem forIn_yield_eq_foldl
|
||||
l.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
|
||||
induction l generalizing init <;> simp_all
|
||||
@@ -444,7 +444,7 @@ theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] {p : α → m Bool} {as :
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp only [anyM, ih, pure_bind, all_cons]
|
||||
simp only [anyM, ih, pure_bind]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem allM_pure [Monad m] [LawfulMonad m] {p : α → Bool} {as : List α} :
|
||||
@@ -486,7 +486,7 @@ and simplifies these to the function directly taking the value.
|
||||
induction l generalizing x with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp [ih, hf, foldrM_cons]
|
||||
simp [ih, foldrM_cons]
|
||||
congr
|
||||
funext b
|
||||
simp [hf]
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace List
|
||||
|
||||
/-! ### dropLast -/
|
||||
|
||||
@[grind _=_]
|
||||
theorem tail_dropLast {l : List α} : tail (dropLast l) = dropLast (tail l) := by
|
||||
ext1
|
||||
simp only [getElem?_tail, getElem?_dropLast, length_tail]
|
||||
@@ -35,7 +36,7 @@ theorem tail_dropLast {l : List α} : tail (dropLast l) = dropLast (tail l) := b
|
||||
· omega
|
||||
· rfl
|
||||
|
||||
@[simp] theorem dropLast_reverse {l : List α} : l.reverse.dropLast = l.tail.reverse := by
|
||||
@[simp, grind _=_] theorem dropLast_reverse {l : List α} : l.reverse.dropLast = l.tail.reverse := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
@@ -67,7 +68,7 @@ theorem length_filterMap_pos_iff {xs : List α} {f : α → Option β} :
|
||||
| cons x xs ih =>
|
||||
simp only [filterMap, mem_cons, exists_prop, exists_eq_or_imp]
|
||||
split
|
||||
· simp_all [ih]
|
||||
· simp_all
|
||||
· simp_all
|
||||
|
||||
@[simp]
|
||||
@@ -114,8 +115,8 @@ section intersperse
|
||||
|
||||
variable {l : List α} {sep : α} {i : Nat}
|
||||
|
||||
@[simp] theorem length_intersperse : (l.intersperse sep).length = 2 * l.length - 1 := by
|
||||
fun_induction intersperse <;> simp only [intersperse, length_cons, length_nil] at *
|
||||
@[simp, grind =] theorem length_intersperse : (l.intersperse sep).length = 2 * l.length - 1 := by
|
||||
fun_induction intersperse <;> simp only [length_cons, length_nil] at *
|
||||
rename_i h _
|
||||
have := length_pos_iff.mpr h
|
||||
omega
|
||||
@@ -193,7 +194,7 @@ theorem mem_eraseIdx_iff_getElem {x : α} :
|
||||
| a::l, 0 => by simp [mem_iff_getElem, Nat.succ_lt_succ_iff]
|
||||
| a::l, k+1 => by
|
||||
rw [← Nat.or_exists_add_one]
|
||||
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, succ_inj, Nat.succ_lt_succ_iff]
|
||||
simp [mem_eraseIdx_iff_getElem, @eq_comm _ a, Nat.succ_lt_succ_iff]
|
||||
|
||||
theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃ i ≠ k, l[i]? = some x := by
|
||||
simp only [mem_eraseIdx_iff_getElem, getElem_eq_iff, exists_and_left]
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace List
|
||||
|
||||
open Nat
|
||||
|
||||
@[grind =]
|
||||
theorem countP_set {p : α → Bool} {l : List α} {i : Nat} {a : α} (h : i < l.length) :
|
||||
(l.set i a).countP p = l.countP p - (if p l[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||||
induction l generalizing i with
|
||||
@@ -29,10 +30,12 @@ theorem countP_set {p : α → Bool} {l : List α} {i : Nat} {a : α} (h : i < l
|
||||
have : (if p l[i] = true then 1 else 0) ≤ l.countP p := boole_getElem_le_countP (p := p) h
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem count_set [BEq α] {a b : α} {l : List α} {i : Nat} (h : i < l.length) :
|
||||
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
simp [count_eq_countP, countP_set, h]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_replace [BEq α] [LawfulBEq α] {a b : α} {l : List α} {p : α → Bool} :
|
||||
(l.replace a b).countP p =
|
||||
if l.contains a then l.countP p + (if p b then 1 else 0) - (if p a then 1 else 0) else l.countP p := by
|
||||
@@ -42,7 +45,7 @@ theorem countP_replace [BEq α] [LawfulBEq α] {a b : α} {l : List α} {p : α
|
||||
simp [replace_cons]
|
||||
split <;> rename_i h
|
||||
· simp at h
|
||||
simp [h, ih, countP_cons]
|
||||
simp [h, countP_cons]
|
||||
omega
|
||||
· simp only [beq_eq_false_iff_ne, ne_eq] at h
|
||||
simp only [countP_cons, ih, contains_eq_mem, decide_eq_true_eq, mem_cons, h, false_or]
|
||||
@@ -55,11 +58,31 @@ theorem countP_replace [BEq α] [LawfulBEq α] {a b : α} {l : List α} {p : α
|
||||
omega
|
||||
· omega
|
||||
|
||||
@[grind =]
|
||||
theorem count_replace [BEq α] [LawfulBEq α] {a b c : α} {l : List α} :
|
||||
(l.replace a b).count c =
|
||||
if l.contains a then l.count c + (if b == c then 1 else 0) - (if a == c then 1 else 0) else l.count c := by
|
||||
simp [count_eq_countP, countP_replace]
|
||||
|
||||
@[grind =] theorem count_insert [BEq α] [LawfulBEq α] {a b : α} {l : List α} :
|
||||
count a (List.insert b l) = max (count a l) (if b == a then 1 else 0) := by
|
||||
simp only [List.insert, contains_eq_mem, decide_eq_true_eq, beq_iff_eq]
|
||||
split <;> rename_i h
|
||||
· split <;> rename_i h'
|
||||
· rw [Nat.max_def]
|
||||
simp only [beq_iff_eq] at h'
|
||||
split
|
||||
· have := List.count_pos_iff.mpr (h' ▸ h)
|
||||
omega
|
||||
· rfl
|
||||
· simp
|
||||
· rw [count_cons]
|
||||
split <;> rename_i h'
|
||||
· simp only [beq_iff_eq] at h'
|
||||
rw [count_eq_zero.mpr (h' ▸ h)]
|
||||
simp
|
||||
· simp
|
||||
|
||||
/--
|
||||
The number of elements satisfying a predicate in a sublist is at least the number of elements satisfying the predicate in the list,
|
||||
minus the difference in the lengths.
|
||||
@@ -98,6 +121,8 @@ theorem le_countP_tail {l} : countP p l - 1 ≤ countP p l.tail := by
|
||||
simp only [length_tail] at this
|
||||
omega
|
||||
|
||||
grind_pattern le_countP_tail => countP p l.tail
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
theorem Sublist.le_count (s : l₁ <+ l₂) (a : α) : count a l₂ - (l₂.length - l₁.length) ≤ count a l₁ :=
|
||||
@@ -115,4 +140,6 @@ theorem IsInfix.le_count (s : l₁ <:+: l₂) (a : α) : count a l₂ - (l₂.le
|
||||
theorem le_count_tail {a : α} {l : List α} : count a l - 1 ≤ count a l.tail :=
|
||||
le_countP_tail
|
||||
|
||||
grind_pattern le_count_tail => count a l.tail
|
||||
|
||||
end List
|
||||
|
||||
@@ -14,6 +14,7 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace List
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_eraseIdx {l : List α} {i : Nat} {j : Nat} :
|
||||
(l.eraseIdx i)[j]? = if j < i then l[j]? else l[j + 1]? := by
|
||||
rw [eraseIdx_eq_take_drop_succ, getElem?_append]
|
||||
@@ -28,7 +29,7 @@ theorem getElem?_eraseIdx {l : List α} {i : Nat} {j : Nat} :
|
||||
· simp only [length_take, Nat.min_def, Nat.not_lt] at h
|
||||
split at h
|
||||
· omega
|
||||
· simp_all [getElem?_eq_none]
|
||||
· simp_all
|
||||
omega
|
||||
· simp only [length_take]
|
||||
simp only [length_take, Nat.min_def, Nat.not_lt] at h
|
||||
@@ -45,10 +46,11 @@ theorem getElem?_eraseIdx_of_lt {l : List α} {i : Nat} {j : Nat} (h : j < i) :
|
||||
theorem getElem?_eraseIdx_of_ge {l : List α} {i : Nat} {j : Nat} (h : i ≤ j) :
|
||||
(l.eraseIdx i)[j]? = l[j + 1]? := by
|
||||
rw [getElem?_eraseIdx]
|
||||
simp only [dite_eq_ite, ite_eq_right_iff]
|
||||
simp only [ite_eq_right_iff]
|
||||
intro h'
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_eraseIdx {l : List α} {i : Nat} {j : Nat} (h : j < (l.eraseIdx i).length) :
|
||||
(l.eraseIdx i)[j] = if h' : j < i then
|
||||
l[j]'(by have := length_eraseIdx_le l i; omega)
|
||||
@@ -123,6 +125,48 @@ theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
|
||||
· have t : i ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_set {xs : List α} {i : Nat} {a : α} {j : Nat} :
|
||||
(xs.set i a).eraseIdx j =
|
||||
if j < i then
|
||||
(xs.eraseIdx j).set (i - 1) a
|
||||
else if j = i then
|
||||
xs.eraseIdx i
|
||||
else
|
||||
(xs.eraseIdx j).set i a := by
|
||||
split <;> rename_i h'
|
||||
· rw [eraseIdx_set_lt]
|
||||
omega
|
||||
· split <;> rename_i h''
|
||||
· subst h''
|
||||
rw [eraseIdx_set_eq]
|
||||
· rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
theorem set_eraseIdx_le {xs : List α} {i : Nat} {j : Nat} {a : α} (h : i ≤ j) :
|
||||
(xs.eraseIdx i).set j a = (xs.set (j + 1) a).eraseIdx i := by
|
||||
rw [eraseIdx_set_lt]
|
||||
· simp
|
||||
· omega
|
||||
|
||||
theorem set_eraseIdx_gt {xs : List α} {i : Nat} {j : Nat} {a : α} (h : j < i) :
|
||||
(xs.eraseIdx i).set j a = (xs.set j a).eraseIdx i := by
|
||||
rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_eraseIdx {xs : List α} {i : Nat} {j : Nat} {a : α} :
|
||||
(xs.eraseIdx i).set j a =
|
||||
if i ≤ j then
|
||||
(xs.set (j + 1) a).eraseIdx i
|
||||
else
|
||||
(xs.set j a).eraseIdx i := by
|
||||
split <;> rename_i h'
|
||||
· rw [set_eraseIdx_le]
|
||||
omega
|
||||
· rw [set_eraseIdx_gt]
|
||||
omega
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{l : List α} {i : Nat} (h : i + 1 < l.length) :
|
||||
(l.eraseIdx (i + 1)).set i l[i + 1] = l.eraseIdx i := by
|
||||
@@ -143,7 +187,7 @@ theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
|
||||
· have t : ¬ n < i := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem eraseIdx_length_sub_one {l : List α} :
|
||||
@[simp, grind =] theorem eraseIdx_length_sub_one {l : List α} :
|
||||
(l.eraseIdx (l.length - 1)) = l.dropLast := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
|
||||
@@ -15,8 +15,7 @@ Proves various lemmas about `List.insertIdx`.
|
||||
-/
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
-- TODO: restore after an update-stage0
|
||||
-- set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
open Function Nat
|
||||
|
||||
@@ -30,19 +29,20 @@ section InsertIdx
|
||||
|
||||
variable {a : α}
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem insertIdx_zero {xs : List α} {x : α} : xs.insertIdx 0 x = x :: xs :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem insertIdx_succ_nil {n : Nat} {a : α} : ([] : List α).insertIdx (n + 1) a = [] :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem insertIdx_succ_cons {xs : List α} {hd x : α} {i : Nat} :
|
||||
(hd :: xs).insertIdx (i + 1) x = hd :: xs.insertIdx i x :=
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem length_insertIdx : ∀ {i} {as : List α}, (as.insertIdx i a).length = if i ≤ as.length then as.length + 1 else as.length
|
||||
| 0, _ => by simp
|
||||
| n + 1, [] => by simp
|
||||
@@ -56,14 +56,9 @@ theorem length_insertIdx_of_le_length (h : i ≤ length as) (a : α) : (as.inser
|
||||
theorem length_insertIdx_of_length_lt (h : length as < i) (a : α) : (as.insertIdx i a).length = as.length := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
@[simp]
|
||||
theorem eraseIdx_insertIdx {i : Nat} {l : List α} (a : α) : (l.insertIdx i a).eraseIdx i = l := by
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge :
|
||||
∀ {i m as},
|
||||
i < length as → i ≤ m → (as.eraseIdx i).insertIdx m a = (as.insertIdx (m + 1) a).eraseIdx i
|
||||
∀ {i j as},
|
||||
i < length as → i ≤ j → (as.eraseIdx i).insertIdx j a = (as.insertIdx (j + 1) a).eraseIdx i
|
||||
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
|
||||
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
|
||||
| 0, _ + 1, _ :: _, _, _ => rfl
|
||||
@@ -79,6 +74,15 @@ theorem insertIdx_eraseIdx_of_le :
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_le (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_eraseIdx (h : i < length as) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
if i ≤ j then (as.insertIdx (j + 1) a).eraseIdx i else (as.insertIdx j a).eraseIdx (i + 1) := by
|
||||
split <;> rename_i h'
|
||||
· rw [insertIdx_eraseIdx_of_ge h h']
|
||||
· rw [insertIdx_eraseIdx_of_le h (by omega)]
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_comm (a b : α) :
|
||||
∀ {i j : Nat} {l : List α} (_ : i ≤ j) (_ : j ≤ length l),
|
||||
(l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a
|
||||
@@ -110,6 +114,14 @@ theorem insertIdx_of_length_lt {l : List α} {x : α} {i : Nat} (h : l.length <
|
||||
· simp only [Nat.succ_lt_succ_iff, length] at h
|
||||
simpa using ih h
|
||||
|
||||
@[simp, grind =]
|
||||
theorem eraseIdx_insertIdx_self {i : Nat} {l : List α} (a : α) : (l.insertIdx i a).eraseIdx i = l := by
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-18")]
|
||||
abbrev eraseIdx_insertIdx := @eraseIdx_insertIdx_self
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self {l : List α} {x : α} : l.insertIdx l.length x = l ++ [x] := by
|
||||
induction l with
|
||||
@@ -185,6 +197,7 @@ theorem getElem_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (hn : i < j)
|
||||
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
|
||||
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (l.insertIdx i x).length) :
|
||||
(l.insertIdx i x)[j] =
|
||||
if h₁ : j < i then
|
||||
@@ -201,6 +214,7 @@ theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (l.insertI
|
||||
rw [getElem_insertIdx_self h]
|
||||
· rw [getElem_insertIdx_of_gt (by omega)]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_insertIdx {l : List α} {x : α} {i j : Nat} :
|
||||
(l.insertIdx i x)[j]? =
|
||||
if j < i then
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace List
|
||||
|
||||
/-! ### modifyHead -/
|
||||
|
||||
@[simp] theorem length_modifyHead {f : α → α} {l : List α} : (l.modifyHead f).length = l.length := by
|
||||
@[simp, grind =] theorem length_modifyHead {f : α → α} {l : List α} : (l.modifyHead f).length = l.length := by
|
||||
cases l <;> simp [modifyHead]
|
||||
|
||||
theorem modifyHead_eq_set [Inhabited α] (f : α → α) (l : List α) :
|
||||
@@ -26,9 +26,10 @@ theorem modifyHead_eq_set [Inhabited α] (f : α → α) (l : List α) :
|
||||
@[simp] theorem modifyHead_eq_nil_iff {f : α → α} {l : List α} :
|
||||
l.modifyHead f = [] ↔ l = [] := by cases l <;> simp [modifyHead]
|
||||
|
||||
@[simp] theorem modifyHead_modifyHead {l : List α} {f g : α → α} :
|
||||
@[simp, grind =] theorem modifyHead_modifyHead {l : List α} {f g : α → α} :
|
||||
(l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> simp [modifyHead]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_modifyHead {l : List α} {f : α → α} {i} (h : i < (l.modifyHead f).length) :
|
||||
(l.modifyHead f)[i] = if h' : i = 0 then f (l[0]'(by simp at h; omega)) else l[i]'(by simpa using h) := by
|
||||
cases l with
|
||||
@@ -41,6 +42,7 @@ theorem getElem_modifyHead {l : List α} {f : α → α} {i} (h : i < (l.modifyH
|
||||
@[simp] theorem getElem_modifyHead_succ {l : List α} {f : α → α} {n} (h : n + 1 < (l.modifyHead f).length) :
|
||||
(l.modifyHead f)[n + 1] = l[n + 1]'(by simpa using h) := by simp [getElem_modifyHead]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_modifyHead {l : List α} {f : α → α} {i} :
|
||||
(l.modifyHead f)[i]? = if i = 0 then l[i]?.map f else l[i]? := by
|
||||
cases l with
|
||||
@@ -53,19 +55,19 @@ theorem getElem?_modifyHead {l : List α} {f : α → α} {i} :
|
||||
@[simp] theorem getElem?_modifyHead_succ {l : List α} {f : α → α} {n} :
|
||||
(l.modifyHead f)[n + 1]? = l[n + 1]? := by simp [getElem?_modifyHead]
|
||||
|
||||
@[simp] theorem head_modifyHead (f : α → α) (l : List α) (h) :
|
||||
@[simp, grind =] theorem head_modifyHead (f : α → α) (l : List α) (h) :
|
||||
(l.modifyHead f).head h = f (l.head (by simpa using h)) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons hd tl => simp
|
||||
|
||||
@[simp] theorem head?_modifyHead {l : List α} {f : α → α} :
|
||||
@[simp, grind =] theorem head?_modifyHead {l : List α} {f : α → α} :
|
||||
(l.modifyHead f).head? = l.head?.map f := by cases l <;> simp
|
||||
|
||||
@[simp] theorem tail_modifyHead {f : α → α} {l : List α} :
|
||||
@[simp, grind =] theorem tail_modifyHead {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).tail = l.tail := by cases l <;> simp
|
||||
|
||||
@[simp] theorem take_modifyHead {f : α → α} {l : List α} {i} :
|
||||
@[simp, grind =] theorem take_modifyHead {f : α → α} {l : List α} {i} :
|
||||
(l.modifyHead f).take i = (l.take i).modifyHead f := by
|
||||
cases l <;> cases i <;> simp
|
||||
|
||||
@@ -73,6 +75,7 @@ theorem getElem?_modifyHead {l : List α} {f : α → α} {i} :
|
||||
(l.modifyHead f).drop i = l.drop i := by
|
||||
cases l <;> cases i <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
(l.modifyHead f).eraseIdx 0 = l.eraseIdx 0 := by simp
|
||||
|
||||
@@ -81,7 +84,7 @@ theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
|
||||
@[simp] theorem modifyHead_id : modifyHead (id : α → α) = id := by funext l; cases l <;> simp
|
||||
|
||||
@[simp] theorem modifyHead_dropLast {l : List α} {f : α → α} :
|
||||
@[simp, grind _=_] theorem modifyHead_dropLast {l : List α} {f : α → α} :
|
||||
l.dropLast.modifyHead f = (l.modifyHead f).dropLast := by
|
||||
rcases l with _|⟨a, l⟩
|
||||
· simp
|
||||
@@ -99,7 +102,7 @@ theorem eraseIdx_eq_modifyTailIdx : ∀ i (l : List α), eraseIdx l i = l.modify
|
||||
| _+1, [] => rfl
|
||||
| _+1, _ :: _ => congrArg (cons _) (eraseIdx_eq_modifyTailIdx _ _)
|
||||
|
||||
@[simp] theorem length_modifyTailIdx (f : List α → List α) (H : ∀ l, (f l).length = l.length) :
|
||||
@[simp, grind =] theorem length_modifyTailIdx (f : List α → List α) (H : ∀ l, (f l).length = l.length) :
|
||||
∀ (l : List α) i, (l.modifyTailIdx i f).length = l.length
|
||||
| _, 0 => H _
|
||||
| [], _+1 => rfl
|
||||
@@ -142,7 +145,7 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (i : Nat) (
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem modify_nil (f : α → α) (i) : [].modify i f = [] := by cases i <;> rfl
|
||||
@[simp, grind =] theorem modify_nil (f : α → α) (i) : [].modify i f = [] := by cases i <;> rfl
|
||||
|
||||
@[simp] theorem modify_zero_cons (f : α → α) (a : α) (l : List α) :
|
||||
(a :: l).modify 0 f = f a :: l := rfl
|
||||
@@ -150,6 +153,15 @@ theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (i : Nat) (
|
||||
@[simp] theorem modify_succ_cons (f : α → α) (a : α) (l : List α) (i) :
|
||||
(a :: l).modify (i + 1) f = a :: l.modify i f := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem modify_cons {f : α → α} {a : α} {l : List α} {i : Nat} :
|
||||
(a :: l).modify i f =
|
||||
if i = 0 then f a :: l else a :: l.modify (i - 1) f := by
|
||||
split <;> rename_i h
|
||||
· subst h
|
||||
simp
|
||||
· match i, h with | i + 1, _ => simp
|
||||
|
||||
theorem modifyHead_eq_modify_zero (f : α → α) (l : List α) :
|
||||
l.modifyHead f = l.modify 0 f := by cases l <;> simp
|
||||
|
||||
@@ -160,12 +172,12 @@ theorem modifyHead_eq_modify_zero (f : α → α) (l : List α) :
|
||||
∀ i (l : List α) j, (l.modify i f)[j]? = (fun a => if i = j then f a else a) <$> l[j]?
|
||||
| n, l, 0 => by cases l <;> cases n <;> simp
|
||||
| n, [], _+1 => by cases n <;> rfl
|
||||
| 0, _ :: l, j+1 => by cases h : l[j]? <;> simp [h, modify, j.succ_ne_zero.symm]
|
||||
| 0, _ :: l, j+1 => by cases h : l[j]? <;> simp [h, modify]
|
||||
| i+1, a :: l, j+1 => by
|
||||
simp only [modify_succ_cons, getElem?_cons_succ, Nat.reduceEqDiff, Option.map_eq_map]
|
||||
refine (getElem?_modify f i l j).trans ?_
|
||||
cases h' : l[j]? <;> by_cases h : i = j <;>
|
||||
simp [h, if_pos, if_neg, Option.map, mt Nat.succ.inj, not_false_iff, h']
|
||||
simp [h, Option.map]
|
||||
|
||||
@[simp, grind =] theorem length_modify (f : α → α) : ∀ (l : List α) i, (l.modify i f).length = l.length :=
|
||||
length_modifyTailIdx _ fun l => by cases l <;> rfl
|
||||
@@ -200,6 +212,7 @@ theorem modify_eq_self {f : α → α} {i} {l : List α} (h : l.length ≤ i) :
|
||||
intro h
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem modify_modify_eq (f g : α → α) (i) (l : List α) :
|
||||
(l.modify i f).modify i g = l.modify i (g ∘ f) := by
|
||||
apply ext_getElem
|
||||
@@ -213,7 +226,7 @@ theorem modify_modify_ne (f g : α → α) {i j} (l : List α) (h : i ≠ j) :
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m' h₁ h₂
|
||||
simp only [getElem_modify, getElem_modify_ne, h₂]
|
||||
simp only [getElem_modify]
|
||||
split <;> split <;> first | rfl | omega
|
||||
|
||||
theorem modify_eq_set [Inhabited α] (f : α → α) (i) (l : List α) :
|
||||
@@ -221,7 +234,7 @@ theorem modify_eq_set [Inhabited α] (f : α → α) (i) (l : List α) :
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m h₁ h₂
|
||||
simp [getElem_modify, getElem_set, h₂]
|
||||
simp [getElem_modify, getElem_set]
|
||||
split <;> rename_i h
|
||||
· subst h
|
||||
simp only [length_modify] at h₁
|
||||
@@ -245,7 +258,7 @@ theorem exists_of_modify (f : α → α) {i} {l : List α} (h : i < l.length) :
|
||||
@[simp] theorem modify_id (i) (l : List α) : l.modify i id = l := by
|
||||
simp [modify]
|
||||
|
||||
@[grind =]
|
||||
@[grind _=_]
|
||||
theorem take_modify (f : α → α) (i j) (l : List α) :
|
||||
(l.modify i f).take j = (l.take j).modify i f := by
|
||||
induction j generalizing l i with
|
||||
@@ -274,7 +287,7 @@ theorem drop_modify_of_ge (f : α → α) (i j) (l : List α) (h : i ≥ j) :
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro m' h₁ h₂
|
||||
simp [getElem_drop, getElem_modify, ite_eq_right_iff]
|
||||
simp [getElem_drop, getElem_modify]
|
||||
split <;> split <;> first | rfl | omega
|
||||
|
||||
theorem eraseIdx_modify_of_eq (f : α → α) (i) (l : List α) :
|
||||
|
||||
@@ -27,11 +27,12 @@ open Nat
|
||||
|
||||
/-! ### range' -/
|
||||
|
||||
@[simp] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by
|
||||
@[simp, grind =] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by
|
||||
simp [mem_range']; exact ⟨
|
||||
fun ⟨i, h, e⟩ => e ▸ ⟨Nat.le_add_right .., Nat.add_lt_add_left h _⟩,
|
||||
fun ⟨h₁, h₂⟩ => ⟨m - s, Nat.sub_lt_left_of_lt_add h₁ h₂, (Nat.add_sub_cancel' h₁).symm⟩⟩
|
||||
|
||||
@[grind =]
|
||||
theorem getLast?_range' {n : Nat} : (range' s n).getLast? = if n = 0 then none else some (s + n - 1) := by
|
||||
induction n generalizing s with
|
||||
| zero => simp
|
||||
@@ -43,7 +44,7 @@ theorem getLast?_range' {n : Nat} : (range' s n).getLast? = if n = 0 then none e
|
||||
· rw [if_neg h]
|
||||
simp
|
||||
|
||||
@[simp] theorem getLast_range' {n : Nat} (h) : (range' s n).getLast h = s + n - 1 := by
|
||||
@[simp, grind =] theorem getLast_range' {n : Nat} (h) : (range' s n).getLast h = s + n - 1 := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp [getLast?_range', getLast_eq_iff_getLast?_eq_some]
|
||||
@@ -158,6 +159,26 @@ theorem erase_range' :
|
||||
simp [p]
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range' {a s n step} (h : 0 < step := by simp) :
|
||||
count a (range' s n step) = if ∃ i, i < n ∧ a = s + step * i then 1 else 0 := by
|
||||
rw [(nodup_range' step h).count]
|
||||
simp only [mem_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range_1' {a s n} :
|
||||
count a (range' s n) = if s ≤ a ∧ a < s + n then 1 else 0 := by
|
||||
rw [count_range' (by simp)]
|
||||
split <;> rename_i h
|
||||
· obtain ⟨i, h, rfl⟩ := h
|
||||
simp [h]
|
||||
· simp at h
|
||||
rw [if_neg]
|
||||
simp only [not_and, Nat.not_lt]
|
||||
intro w
|
||||
specialize h (a - s)
|
||||
omega
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
theorem reverse_range' : ∀ {s n : Nat}, reverse (range' s n) = map (s + n - 1 - ·) (range n)
|
||||
@@ -167,7 +188,7 @@ theorem reverse_range' : ∀ {s n : Nat}, reverse (range' s n) = map (s + n - 1
|
||||
show s + (n + 1) - 1 = s + n from rfl, map, map_map]
|
||||
simp [reverse_range', Nat.sub_right_comm, Nat.sub_sub]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mem_range {m n : Nat} : m ∈ range n ↔ m < n := by
|
||||
simp only [range_eq_range', mem_range'_1, Nat.zero_le, true_and, Nat.zero_add]
|
||||
|
||||
@@ -181,7 +202,7 @@ theorem pairwise_lt_range {n : Nat} : Pairwise (· < ·) (range n) := by
|
||||
theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
|
||||
Pairwise.imp Nat.le_of_lt pairwise_lt_range
|
||||
|
||||
@[simp] theorem take_range {i n : Nat} : take i (range n) = range (min i n) := by
|
||||
@[simp, grind =] theorem take_range {i n : Nat} : take i (range n) = range (min i n) := by
|
||||
apply List.ext_getElem
|
||||
· simp
|
||||
· simp +contextual [getElem_take, Nat.lt_min]
|
||||
@@ -189,10 +210,11 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem nodup_range {n : Nat} : Nodup (range n) := by
|
||||
simp +decide only [range_eq_range', nodup_range']
|
||||
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[grind]
|
||||
theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp
|
||||
@@ -200,6 +222,12 @@ theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n - (i + 1)) := by
|
||||
simp [range_eq_range', erase_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range {a n} :
|
||||
count a (range n) = if a < n then 1 else 0 := by
|
||||
rw [range_eq_range', count_range_1']
|
||||
simp
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
section
|
||||
@@ -348,15 +376,15 @@ end
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx [x] k = [(x, k)] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem head?_zipIdx {l : List α} {k : Nat} :
|
||||
@[simp, grind =] theorem head?_zipIdx {l : List α} {k : Nat} :
|
||||
(zipIdx l k).head? = l.head?.map fun a => (a, k) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getLast?_zipIdx {l : List α} {k : Nat} :
|
||||
@[simp, grind =] theorem getLast?_zipIdx {l : List α} {k : Nat} :
|
||||
(zipIdx l k).getLast? = l.getLast?.map fun a => (a, k + l.length - 1) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp
|
||||
@@ -379,6 +407,7 @@ to avoid the inequality and the subtraction. -/
|
||||
theorem mk_mem_zipIdx_iff_getElem? {i : Nat} {x : α} {l : List α} : (x, i) ∈ zipIdx l ↔ l[i]? = some x := by
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
@[grind =]
|
||||
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : List α} {k : Nat} :
|
||||
x ∈ zipIdx l k ↔ k ≤ x.2 ∧ l[x.2 - k]? = some x.1 := by
|
||||
cases x
|
||||
@@ -441,6 +470,7 @@ theorem zipIdx_map {l : List α} {k : Nat} {f : α → β} :
|
||||
rw [map_cons, zipIdx_cons', zipIdx_cons', map_cons, map_map, IH, map_map]
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem zipIdx_append {xs ys : List α} {k : Nat} :
|
||||
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + xs.length) := by
|
||||
induction xs generalizing ys k with
|
||||
@@ -478,7 +508,7 @@ theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [zipIdx_eq_zip_range']
|
||||
refine ⟨l₁', l₂', range' k l₁'.length, range' (k + l₁'.length) l₂'.length, ?_⟩
|
||||
simp [Nat.add_comm]
|
||||
simp
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
@@ -605,7 +635,7 @@ theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [enumFrom_eq_zip_range']
|
||||
refine ⟨range' n l₁'.length, range' (n + l₁'.length) l₂'.length, l₁', l₂', ?_⟩
|
||||
simp [Nat.add_comm]
|
||||
simp
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ theorem suffix_iff_eq_append : l₁ <:+ l₂ ↔ take (length l₂ - length l₁
|
||||
⟨by rintro ⟨r, rfl⟩; simp only [length_append, Nat.add_sub_cancel_right, take_left], fun e =>
|
||||
⟨_, e⟩⟩
|
||||
|
||||
@[grind =]
|
||||
theorem prefix_take_iff {xs ys : List α} {i : Nat} : xs <+: ys.take i ↔ xs <+: ys ∧ xs.length ≤ i := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -140,7 +141,7 @@ theorem suffix_iff_eq_drop : l₁ <:+ l₂ ↔ l₁ = drop (length l₂ - length
|
||||
xs.take i <+: xs.take j ↔ i ≤ j := by
|
||||
simp only [prefix_iff_eq_take, length_take]
|
||||
induction i generalizing xs j with
|
||||
| zero => simp [Nat.min_eq_left, eq_self_iff_true, Nat.zero_le, take]
|
||||
| zero => simp [Nat.min_eq_left, Nat.zero_le, take]
|
||||
| succ i IH =>
|
||||
cases xs with
|
||||
| nil => simp_all
|
||||
@@ -149,7 +150,7 @@ theorem suffix_iff_eq_drop : l₁ <:+ l₂ ↔ l₁ = drop (length l₂ - length
|
||||
| zero =>
|
||||
simp
|
||||
| succ j =>
|
||||
simp only [length_cons, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right] at hm
|
||||
simp only [length_cons, Nat.add_lt_add_iff_right] at hm
|
||||
simp [← @IH j xs hm, Nat.min_eq_left, Nat.le_of_lt hm]
|
||||
|
||||
@[simp] theorem append_left_sublist_self {xs : List α} (ys : List α) : xs ++ ys <+ ys ↔ xs = [] := by
|
||||
@@ -192,7 +193,7 @@ theorem append_sublist_of_sublist_right {xs ys zs : List α} (h : zs <+ ys) :
|
||||
have hl' := h'.length_le
|
||||
simp only [length_append] at hl'
|
||||
have : xs.length = 0 := by omega
|
||||
simp_all only [Nat.zero_add, length_eq_zero_iff, true_and, append_nil]
|
||||
simp_all only [Nat.zero_add, length_eq_zero_iff, true_and]
|
||||
exact Sublist.eq_of_length_le h' hl
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
simp
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user