mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-24 22:04:29 +00:00
Compare commits
194 Commits
sr/setup-l
...
grind_bitv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
838f3593fb | ||
|
|
2f7ba07e67 | ||
|
|
5778df510d | ||
|
|
846dbda4bc | ||
|
|
dec10fd2dd | ||
|
|
8f7d090829 | ||
|
|
8a34ea1004 | ||
|
|
d6adde535f | ||
|
|
10c4d3f379 | ||
|
|
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 |
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
|
||||
|
||||
@@ -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
|
||||
@@ -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'")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Prelude
|
||||
meta import Init.Prelude
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
/-!
|
||||
|
||||
@@ -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]
|
||||
@@ -70,7 +70,7 @@ protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad
|
||||
cases b <;> simp [comp, 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)
|
||||
|
||||
/--
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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,6 +220,7 @@ 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]
|
||||
|
||||
@@ -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⟩
|
||||
@@ -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⟩
|
||||
@@ -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⟩
|
||||
@@ -339,6 +356,7 @@ theorem getElem?_eraseIdx_of_ge {xs : Array α} {i : Nat} (h : i < xs.size) {j :
|
||||
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
|
||||
|
||||
@@ -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₂
|
||||
@@ -169,7 +169,7 @@ theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
|
||||
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]
|
||||
|
||||
@[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 [← 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,7 +305,7 @@ 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]
|
||||
@@ -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]
|
||||
@@ -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,6 +482,7 @@ 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]
|
||||
@@ -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⟩
|
||||
@@ -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
|
||||
@@ -729,9 +800,9 @@ 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]
|
||||
|
||||
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
|
||||
@@ -106,6 +124,7 @@ theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k ≤
|
||||
simp [getElem_insertIdx, w, h]
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -1498,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'
|
||||
@@ -3621,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')
|
||||
@@ -3632,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')
|
||||
@@ -4526,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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -140,7 +140,7 @@ abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
@[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) :
|
||||
|
||||
@@ -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,7 +213,7 @@ 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]
|
||||
|
||||
@@ -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`.
|
||||
-/
|
||||
|
||||
@@ -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
|
||||
@@ -518,9 +520,6 @@ 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} :
|
||||
@@ -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 -/
|
||||
|
||||
/--
|
||||
@@ -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)]
|
||||
|
||||
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, getLsbD]
|
||||
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, ↓reduceIte]
|
||||
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
|
||||
@@ -2,7 +2,6 @@
|
||||
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
|
||||
|
||||
@@ -19,6 +18,7 @@ import Init.Data.Int.Bitwise.Lemmas
|
||||
import Init.Data.Int.LemmasAux
|
||||
import Init.Data.Int.Pow
|
||||
import Init.Data.Int.LemmasAux
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@@ -27,19 +27,9 @@ namespace BitVec
|
||||
@[simp] theorem mk_zero : BitVec.ofFin (w := w) ⟨0, h⟩ = 0#w := rfl
|
||||
@[simp] theorem ofNatLT_zero : BitVec.ofNatLT (w := w) 0 h = 0#w := rfl
|
||||
|
||||
@[simp] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
|
||||
(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
|
||||
|
||||
@[simp] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
rw [getMsbD]
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
@@ -127,10 +117,6 @@ This normalized a bitvec using `ofFin` to `ofNat`.
|
||||
theorem ofFin_eq_ofNat : @BitVec.ofFin w (Fin.mk x lt) = BitVec.ofNat w x := by
|
||||
simp only [BitVec.ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
|
||||
/-- 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
|
||||
|
||||
/-- Prove nonequality of bitvectors in terms of nat operations. -/
|
||||
theorem toNat_ne_iff_ne {n} {x y : BitVec n} : x.toNat ≠ y.toNat ↔ x ≠ y := by
|
||||
constructor
|
||||
@@ -153,26 +139,28 @@ protected theorem toNat_lt_twoPow_of_le (h : m ≤ n) {x : BitVec m} :
|
||||
apply Nat.pow_le_pow_of_le
|
||||
<;> omega
|
||||
|
||||
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
|
||||
theorem two_pow_le_toNat_of_getElem_eq_true {i : Nat} {x : BitVec w}
|
||||
(hi : i < w) (hx : x[i] = true) : 2^i ≤ x.toNat := by
|
||||
apply Nat.ge_two_pow_of_testBit
|
||||
rw [← getElem_eq_testBit_toNat x i hi]
|
||||
exact hx
|
||||
|
||||
theorem getMsb'_eq_getLsb' (x : BitVec w) (i : Fin w) :
|
||||
x.getMsb' i = x.getLsb' ⟨w - 1 - i, by omega⟩ := by
|
||||
simp only [getMsb', getLsb']
|
||||
theorem getMsb_eq_getLsb (x : BitVec w) (i : Fin w) :
|
||||
x.getMsb i = x.getLsb ⟨w - 1 - i, by omega⟩ := by
|
||||
simp only [getMsb, getLsb]
|
||||
|
||||
theorem getMsb?_eq_getLsb? (x : BitVec w) (i : Nat) :
|
||||
x.getMsb? i = if i < w then x.getLsb? (w - 1 - i) else none := by
|
||||
simp only [getMsb?, getLsb?_eq_getElem?]
|
||||
split <;> simp [getMsb'_eq_getLsb']
|
||||
split <;> simp [getMsb_eq_getLsb]
|
||||
|
||||
theorem getMsbD_eq_getLsbD (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i < w) && x.getLsbD (w - 1 - i)) := by
|
||||
rw [getMsbD, getLsbD]
|
||||
|
||||
@[deprecated getMsb_eq_getLsb (since := "2025-06-17")]
|
||||
theorem getMsb'_eq_getLsb' (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i < w) && x.getLsbD (w - 1 - i)) := by
|
||||
rw [getMsbD, getLsbD]
|
||||
|
||||
theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i < w) && x.getMsbD (w - 1 - i)) := by
|
||||
rw [getMsbD]
|
||||
by_cases h₁ : i < w <;> by_cases h₂ : w - 1 - i < w <;>
|
||||
@@ -241,21 +229,6 @@ theorem getMsbD_eq_getMsb?_getD (x : BitVec w) (i : Nat) :
|
||||
intros
|
||||
omega
|
||||
|
||||
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]
|
||||
|
||||
@[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 ↑·)
|
||||
|
||||
theorem eq_of_getLsbD_eq_iff {w : Nat} {x y : BitVec w} :
|
||||
x = y ↔ ∀ (i : Nat), i < w → x.getLsbD i = y.getLsbD i := by
|
||||
have iff := @BitVec.eq_of_getElem_eq_iff w x y
|
||||
@@ -342,9 +315,6 @@ open Fin.NatCast in
|
||||
@[simp, norm_cast] theorem toFin_natCast (n : Nat) : toFin (n : BitVec w) = (n : Fin (2^w)) := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp] theorem toInt_ofBool (b : Bool) : (ofBool b).toInt = -b.toInt := by
|
||||
cases b <;> simp
|
||||
|
||||
@@ -368,10 +338,6 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
|
||||
@[simp] theorem ofBool_xor_ofBool : ofBool b ^^^ ofBool b' = ofBool (b ^^ b') := by
|
||||
cases b <;> cases b' <;> rfl
|
||||
|
||||
@[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
|
||||
|
||||
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
|
||||
theorem toNat_ofNatLt (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||||
|
||||
@@ -391,9 +357,6 @@ theorem getLsbD_ofNatLt {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
|
||||
theorem getMsbD_ofNatLt {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := getMsbD_ofNatLT h
|
||||
|
||||
@[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]
|
||||
|
||||
theorem ofNatLT_eq_ofNat {w : Nat} {n : Nat} (hn) : BitVec.ofNatLT n hn = BitVec.ofNat w n :=
|
||||
eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt hn])
|
||||
|
||||
@@ -581,7 +544,6 @@ theorem msb_eq_getMsbD_zero (x : BitVec w) : x.msb = x.getMsbD 0 := by
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_cast (h : w = v) (x : BitVec w) : (x.cast h).toNat = x.toNat := rfl
|
||||
@[simp] theorem toFin_cast (h : w = v) (x : BitVec w) :
|
||||
(x.cast h).toFin = x.toFin.cast (by rw [h]) :=
|
||||
rfl
|
||||
@@ -882,6 +844,19 @@ theorem slt_eq_sle_and_ne {x y : BitVec w} : x.slt y = (x.sle y && x != y) := by
|
||||
apply Bool.eq_iff_iff.2
|
||||
simp [BitVec.slt, BitVec.sle, Int.lt_iff_le_and_ne, BitVec.toInt_inj]
|
||||
|
||||
/-- For all bitvectors `x, y`, either `x` is signed less than `y`,
|
||||
or is equal to `y`, or is signed greater than `y`. -/
|
||||
theorem slt_trichotomy (x y : BitVec w) : x.slt y ∨ x = y ∨ y.slt x := by
|
||||
simpa [slt_iff_toInt_lt, ← toInt_inj]
|
||||
using Int.lt_trichotomy x.toInt y.toInt
|
||||
|
||||
/-- For all bitvectors `x, y`, either `x` is unsigned less than `y`,
|
||||
or is equal to `y`, or is unsigned greater than `y`. -/
|
||||
theorem lt_trichotomy (x y : BitVec w) :
|
||||
x < y ∨ x = y ∨ y < x := by
|
||||
simpa [← ult_iff_lt, ult_eq_decide, decide_eq_true_eq, ← toNat_inj]
|
||||
using Nat.lt_trichotomy x.toNat y.toNat
|
||||
|
||||
/-! ### setWidth, zeroExtend and truncate -/
|
||||
|
||||
@[simp]
|
||||
@@ -892,20 +867,6 @@ theorem truncate_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
zeroExtend v x = setWidth v x := rfl
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
(setWidth' p x).toNat = x.toNat := by
|
||||
simp [setWidth']
|
||||
|
||||
@[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 toInt_setWidth (x : BitVec w) :
|
||||
(x.setWidth v).toInt = Int.bmod x.toNat (2^v) := by
|
||||
simp [toInt_eq_toNat_bmod, toNat_setWidth, Int.emod_bmod, -Int.natCast_pow]
|
||||
@@ -923,10 +884,6 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
apply eq_of_toNat_eq
|
||||
simp [toNat_setWidth]
|
||||
|
||||
@[simp] theorem ofNat_toNat (m : Nat) (x : BitVec n) : BitVec.ofNat m x.toNat = setWidth m x := by
|
||||
apply eq_of_toNat_eq
|
||||
simp
|
||||
|
||||
/-- Moves one-sided left toNat equality to BitVec equality. -/
|
||||
theorem toNat_eq_nat {x : BitVec w} {y : Nat}
|
||||
: (x.toNat = y) ↔ (y < 2^w ∧ (x = BitVec.ofNat w y)) := by
|
||||
@@ -942,19 +899,6 @@ theorem nat_eq_toNat {x : BitVec w} {y : Nat}
|
||||
rw [@eq_comm _ _ x.toNat]
|
||||
apply toNat_eq_nat
|
||||
|
||||
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 [getElem_eq_testBit_toNat, getLsbD]
|
||||
omega
|
||||
|
||||
theorem getElem?_setWidth' (x : BitVec w) (i : Nat) (h : w ≤ v) :
|
||||
(setWidth' h x)[i]? = if i < v then some (x.getLsbD i) else none := by
|
||||
simp [getElem?_eq, getElem_setWidth']
|
||||
@@ -1919,6 +1863,63 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
exact Nat.mul_lt_mul_of_pos_right x.isLt (Nat.two_pow_pos _)
|
||||
· omega
|
||||
|
||||
@[simp]
|
||||
theorem toNat_shiftLeftZeroExtend {x : BitVec w} :
|
||||
(shiftLeftZeroExtend x n).toNat = x.toNat <<< n := by
|
||||
rcases n with _|n
|
||||
· simp [shiftLeftZeroExtend]
|
||||
· simp only [shiftLeftZeroExtend_eq, toNat_shiftLeft, toNat_setWidth]
|
||||
have := Nat.pow_lt_pow_of_lt (a := 2) (n := w) (m := w + (n + 1)) (by omega) (by omega)
|
||||
have : x.toNat <<< (n + 1) < 2 ^ (w + (n + 1)) := by
|
||||
rw [Nat.shiftLeft_eq, Nat.pow_add (m := w) (n := n + 1), Nat.mul_lt_mul_right (by apply Nat.two_pow_pos (w := n + 1))]
|
||||
omega
|
||||
rw [Nat.mod_eq_of_lt (by rw [Nat.mod_eq_of_lt (by omega)]; omega), Nat.mod_eq_of_lt (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem toInt_shiftLeftZeroExtend {x : BitVec w} :
|
||||
(shiftLeftZeroExtend x n).toInt = x.toInt * 2 ^ n := by
|
||||
rw [shiftLeftZeroExtend_eq]
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero, shiftLeftZeroExtend_eq]
|
||||
· rcases n with _|n
|
||||
· simp [shiftLeftZeroExtend_eq]
|
||||
· have := Nat.pow_pos (a := 2) (n := n + 1) (by omega)
|
||||
have : x.toNat <<< (n + 1) < 2 ^ (w + 1 + (n + 1)) := by
|
||||
rw [Nat.shiftLeft_eq, Nat.pow_add (a := 2) (m := w + 1) (n := n + 1), Nat.mul_lt_mul_right (by omega)]
|
||||
omega
|
||||
simp only [shiftLeftZeroExtend_eq, toInt_shiftLeft, toNat_setWidth, Nat.lt_add_right_iff_pos,
|
||||
Nat.zero_lt_succ, toNat_mod_cancel_of_lt, Int.bmod_def]
|
||||
by_cases hmsb : x.msb
|
||||
· have hge := toNat_ge_of_msb_true hmsb
|
||||
simp only [Nat.add_one_sub_one, ge_iff_le] at hge
|
||||
rw [Int.emod_eq_of_lt (by norm_cast; rw [Nat.shiftLeft_eq]; omega) (by omega)]
|
||||
rw_mod_cast [← Nat.add_assoc]
|
||||
rw [show (2 ^ (w + 1 + n + 1) + 1) / 2 = 2 ^ (w + 1 + n) by omega, Int.natCast_pow,
|
||||
Int.cast_ofNat_Int, Nat.shiftLeft_eq, Nat.add_assoc, Nat.pow_add (a := 2) (m := w) (n := 1 + n),
|
||||
Nat.add_comm 1 n]
|
||||
simp only [Nat.mul_lt_mul_right (by omega), show ¬x.toNat < 2 ^ w by omega, reduceIte,
|
||||
Int.natCast_mul, Int.natCast_pow, Int.cast_ofNat_Int, toInt_eq_toNat_cond,
|
||||
show ¬2 * x.toNat < 2 ^ (w + 1) by simp [Nat.pow_add, Nat.mul_comm (2 ^ w) 2, hge]]
|
||||
norm_cast
|
||||
simp [Int.natCast_mul, Int.natCast_pow, Int.cast_ofNat_Int, Int.sub_mul,
|
||||
Int.sub_right_inj, show w + (n + 1) + 1 = (w + 1) + (n + 1) by omega, Nat.pow_add]
|
||||
· simp only [Bool.not_eq_true] at hmsb
|
||||
have hle := toNat_lt_of_msb_false (x := x) hmsb
|
||||
simp only [Nat.add_one_sub_one] at hle
|
||||
rw [Int.emod_eq_of_lt (by norm_cast; rw [Nat.shiftLeft_eq]; omega) (by omega)]
|
||||
rw_mod_cast [← Nat.add_assoc]
|
||||
rw [show (2 ^ (w + 1 + n + 1) + 1) / 2 = 2 ^ (w + 1 + n) by omega, Int.natCast_pow,
|
||||
Int.cast_ofNat_Int, Nat.shiftLeft_eq, Nat.add_assoc, Nat.pow_add (a := 2) (m := w) (n := 1 + n), Nat.add_comm 1 n]
|
||||
simp [Nat.mul_lt_mul_right (b := x.toNat) (c := 2 ^ w) (a := 2 ^ (n + 1)) (by omega), hle,
|
||||
reduceIte, Int.natCast_mul, Int.natCast_pow, Int.cast_ofNat_Int, toInt_eq_toNat_of_msb hmsb]
|
||||
|
||||
theorem toFin_shiftLeftZeroExtend {x : BitVec w} :
|
||||
(shiftLeftZeroExtend x n).toFin = Fin.ofNat (2 ^ (w + n)) (x.toNat * 2 ^ n) := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero, shiftLeftZeroExtend_eq]
|
||||
· have := Nat.pow_le_pow_of_le (a := 2) (n := w + 1) (m := w + 1 + n) (by omega) (by omega)
|
||||
rw [shiftLeftZeroExtend_eq, toFin_shiftLeft, toNat_setWidth, Nat.mod_eq_of_lt (by omega), Nat.shiftLeft_eq]
|
||||
|
||||
@[simp] theorem getElem_shiftLeftZeroExtend {x : BitVec m} {n : Nat} (h : i < m + n) :
|
||||
(shiftLeftZeroExtend x n)[i] = if h' : i < n then false else x[i - n] := by
|
||||
rw [shiftLeftZeroExtend_eq]
|
||||
@@ -2660,10 +2661,6 @@ theorem toFin_signExtend (x : BitVec w) :
|
||||
theorem append_def (x : BitVec v) (y : BitVec w) :
|
||||
x ++ y = (shiftLeftZeroExtend x w ||| setWidth' (Nat.le_add_left w v) y) := rfl
|
||||
|
||||
@[simp] theorem toNat_append (x : BitVec m) (y : BitVec n) :
|
||||
(x ++ y).toNat = x.toNat <<< n ||| y.toNat :=
|
||||
rfl
|
||||
|
||||
theorem getLsbD_append {x : BitVec n} {y : BitVec m} :
|
||||
getLsbD (x ++ y) i = if i < m then getLsbD y i else getLsbD x (i - m) := by
|
||||
simp only [append_def, getLsbD_or, getLsbD_shiftLeftZeroExtend, getLsbD_setWidth']
|
||||
@@ -3048,11 +3045,6 @@ theorem getMsbD_rev (x : BitVec w) (i : Fin w) :
|
||||
|
||||
/-! ### cons -/
|
||||
|
||||
@[simp] theorem toNat_cons (b : Bool) (x : BitVec w) :
|
||||
(cons b x).toNat = (b.toNat <<< w) ||| x.toNat := by
|
||||
let ⟨x, _⟩ := x
|
||||
simp [cons, toNat_append, toNat_ofBool]
|
||||
|
||||
/-- Variant of `toNat_cons` using `+` instead of `|||`. -/
|
||||
theorem toNat_cons' {x : BitVec w} :
|
||||
(cons a x).toNat = (a.toNat <<< w) + x.toNat := by
|
||||
@@ -3072,21 +3064,6 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
|
||||
have p2 : i - n ≠ 0 := by omega
|
||||
simp [p1, p2, Nat.testBit_bool_to_nat]
|
||||
|
||||
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, getLsbD]
|
||||
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, ↓reduceIte]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
have p2 : i - n ≠ 0 := by omega
|
||||
simp [p1, p2, Nat.testBit_bool_to_nat]
|
||||
|
||||
@[simp] theorem msb_cons : (cons a x).msb = a := by
|
||||
simp [cons, msb_cast, msb_append]
|
||||
|
||||
@@ -3106,15 +3083,6 @@ theorem setWidth_succ (x : BitVec w) :
|
||||
have j_lt : j < i := Nat.lt_of_le_of_ne (Nat.le_of_succ_le_succ h) j_eq
|
||||
simp [j_eq, j_lt]
|
||||
|
||||
@[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
|
||||
· omega
|
||||
|
||||
@[simp] theorem not_cons (x : BitVec w) (b : Bool) : ~~~(cons b x) = cons (!b) (~~~x) := by
|
||||
simp [cons]
|
||||
|
||||
@@ -3341,6 +3309,17 @@ theorem toNat_add_of_not_uaddOverflow {x y : BitVec w} (h : ¬ uaddOverflow x y)
|
||||
· simp only [uaddOverflow, ge_iff_le, decide_eq_true_eq, Nat.not_le] at h
|
||||
rw [toNat_add, Nat.mod_eq_of_lt h]
|
||||
|
||||
/--
|
||||
Unsigned addition overflow reassociation.
|
||||
If `(x + y)` and `(y + z)` do not overflow, then `(x + y) + z` overflows iff `x + (y + z)` overflows.
|
||||
-/
|
||||
theorem uaddOverflow_assoc {x y z : BitVec w} (h : ¬ x.uaddOverflow y) (h' : ¬ y.uaddOverflow z) :
|
||||
(x + y).uaddOverflow z = x.uaddOverflow (y + z) := by
|
||||
simp only [uaddOverflow, ge_iff_le, decide_eq_true_eq, Nat.not_le] at h h'
|
||||
simp only [uaddOverflow, toNat_add, ge_iff_le, decide_eq_decide]
|
||||
repeat rw [Nat.mod_eq_of_lt (by omega)]
|
||||
omega
|
||||
|
||||
protected theorem add_assoc (x y z : BitVec n) : x + y + z = x + (y + z) := by
|
||||
apply eq_of_toNat_eq ; simp [Nat.add_assoc]
|
||||
instance : Std.Associative (α := BitVec n) (· + ·) := ⟨BitVec.add_assoc⟩
|
||||
@@ -3379,6 +3358,20 @@ theorem toInt_add_of_not_saddOverflow {x y : BitVec w} (h : ¬ saddOverflow x y)
|
||||
_root_.not_or, Int.not_le, Int.not_lt] at h
|
||||
rw [toInt_add, Int.bmod_eq_of_le (by push_cast; omega) (by push_cast; omega)]
|
||||
|
||||
/--
|
||||
Signed addition overflow reassociation.
|
||||
If `(x + y)` and `(y + z)` do not overflow, then `(x + y) + z` overflows iff `x + (y + z)` overflows.
|
||||
-/
|
||||
theorem saddOverflow_assoc {x y z : BitVec w} (h : ¬ x.saddOverflow y) (h' : ¬ y.saddOverflow z) :
|
||||
(x + y).saddOverflow z = x.saddOverflow (y + z) := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· simp only [saddOverflow, Nat.add_one_sub_one, ge_iff_le, Bool.or_eq_true, decide_eq_true_eq,
|
||||
_root_.not_or, Int.not_le, Int.not_lt] at h h'
|
||||
simp only [bool_to_prop, saddOverflow, toInt_add, ge_iff_le, Nat.add_one_sub_one]
|
||||
repeat rw [Int.bmod_eq_of_le (by push_cast; omega) (by push_cast; omega)]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_add_distrib {x y : BitVec w} {n : Nat} :
|
||||
(x + y) <<< n = x <<< n + y <<< n := by
|
||||
@@ -3486,9 +3479,6 @@ theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y =
|
||||
· simp
|
||||
· exact Nat.le_of_lt x.isLt
|
||||
|
||||
@[simp, bitvec_to_nat] theorem toNat_neg (x : BitVec n) : (- x).toNat = (2^n - x.toNat) % 2^n := by
|
||||
simp [Neg.neg, BitVec.neg]
|
||||
|
||||
theorem toNat_neg_of_pos {x : BitVec n} (h : 0#n < x) :
|
||||
(- x).toNat = 2^n - x.toNat := by
|
||||
change 0 < x.toNat at h
|
||||
@@ -3807,6 +3797,18 @@ theorem toNat_mul_of_not_umulOverflow {x y : BitVec w} (h : ¬ umulOverflow x y)
|
||||
· simp only [umulOverflow, ge_iff_le, decide_eq_true_eq, Nat.not_le] at h
|
||||
rw [toNat_mul, Nat.mod_eq_of_lt h]
|
||||
|
||||
/--
|
||||
Unsigned multiplication overflow reassociation.
|
||||
If `(x * y)` and `(y * z)` do not overflow, then `(x * y) * z` overflows iff `x * (y * z)` overflows.
|
||||
-/
|
||||
theorem umulOverflow_assoc {x y z : BitVec w} (h : ¬ x.umulOverflow y) (h' : ¬ y.umulOverflow z) :
|
||||
|
||||
(x * y).umulOverflow z = x.umulOverflow (y * z) := by
|
||||
simp only [umulOverflow, ge_iff_le, decide_eq_true_eq, Nat.not_le] at h h'
|
||||
simp only [umulOverflow, toNat_mul, ge_iff_le, decide_eq_decide]
|
||||
repeat rw [Nat.mod_eq_of_lt (by omega)]
|
||||
rw [Nat.mul_assoc]
|
||||
|
||||
@[simp]
|
||||
theorem toInt_mul_of_not_smulOverflow {x y : BitVec w} (h : ¬ smulOverflow x y) :
|
||||
(x * y).toInt = x.toInt * y.toInt := by
|
||||
@@ -3816,6 +3818,20 @@ theorem toInt_mul_of_not_smulOverflow {x y : BitVec w} (h : ¬ smulOverflow x y)
|
||||
_root_.not_or, Int.not_le, Int.not_lt] at h
|
||||
rw [toInt_mul, Int.bmod_eq_of_le (by push_cast; omega) (by push_cast; omega)]
|
||||
|
||||
/--
|
||||
Signed multiplication overflow reassociation.
|
||||
If `(x * y)` and `(y * z)` do not overflow, then `(x * y) * z` overflows iff `x * (y * z)` overflows.
|
||||
-/
|
||||
theorem smulOverflow_assoc {x y z : BitVec w} (h : ¬ x.smulOverflow y) (h' : ¬ y.smulOverflow z) :
|
||||
(x * y).smulOverflow z = x.smulOverflow (y * z) := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· simp only [smulOverflow, Nat.add_one_sub_one, ge_iff_le, Bool.or_eq_true, decide_eq_true_eq,
|
||||
_root_.not_or, Int.not_le, Int.not_lt] at h h'
|
||||
simp only [smulOverflow, toInt_mul, Nat.add_one_sub_one, ge_iff_le, bool_to_prop]
|
||||
repeat rw [Int.bmod_eq_of_le (by push_cast; omega) (by push_cast; omega)]
|
||||
rw [Int.mul_assoc]
|
||||
|
||||
theorem ofInt_mul {n} (x y : Int) : BitVec.ofInt n (x * y) =
|
||||
BitVec.ofInt n x * BitVec.ofInt n y := by
|
||||
apply eq_of_toInt_eq
|
||||
@@ -5108,9 +5124,6 @@ theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y)
|
||||
|
||||
/-! ### intMin -/
|
||||
|
||||
/-- The bitvector of width `w` that has the smallest value when interpreted as an integer. -/
|
||||
def intMin (w : Nat) := twoPow w (w - 1)
|
||||
|
||||
theorem getLsbD_intMin (w : Nat) : (intMin w).getLsbD i = decide (i + 1 = w) := by
|
||||
simp only [intMin, getLsbD_twoPow, bool_to_prop]
|
||||
omega
|
||||
@@ -5261,9 +5274,6 @@ theorem neg_le_intMin_of_msb_eq_true {x : BitVec w} (hx : x.msb = true) : -x ≤
|
||||
|
||||
/-! ### intMax -/
|
||||
|
||||
/-- The bitvector of width `w` that has the largest value when interpreted as an integer. -/
|
||||
def intMax (w : Nat) := (twoPow w (w - 1)) - 1
|
||||
|
||||
@[simp, bitvec_to_nat]
|
||||
theorem toNat_intMax : (intMax w).toNat = 2 ^ (w - 1) - 1 := by
|
||||
simp only [intMax]
|
||||
@@ -5615,68 +5625,54 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
|
||||
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
|
||||
cases n <;> cases w <;> simp
|
||||
|
||||
/-! ### 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
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
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
|
||||
rw [w]
|
||||
apply h
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
simp [BitVec.ule, BitVec.ult, ← decide_not]
|
||||
|
||||
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 _))
|
||||
/-- 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
|
||||
|
||||
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
|
||||
/-- 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
|
||||
|
||||
instance instDecidableExistsBitVecZero (P : BitVec 0 → Prop) [Decidable (P 0#0)] :
|
||||
Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
/-- 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)
|
||||
|
||||
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
|
||||
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']
|
||||
|
||||
/--
|
||||
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
|
||||
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
|
||||
|
||||
/--
|
||||
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
|
||||
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_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]
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
|
||||
@@ -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 ..
|
||||
|
||||
@@ -1079,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) :
|
||||
|
||||
@@ -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
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -1665,7 +1665,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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? -/
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,7 +82,7 @@ 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
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -147,10 +152,12 @@ theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (erase
|
||||
· 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
|
||||
@@ -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
|
||||
@@ -565,6 +592,7 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
@[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
|
||||
|
||||
@@ -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,6 +178,9 @@ 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]
|
||||
@@ -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 =>
|
||||
@@ -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
|
||||
@@ -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,7 +730,7 @@ 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
|
||||
@@ -680,7 +739,7 @@ theorem findIdx?_eq_none_iff {xs : List α} {p : α → Bool} :
|
||||
simp only [findIdx?_cons]
|
||||
split <;> simp_all [cond_eq_if]
|
||||
|
||||
@[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
|
||||
@@ -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,7 +883,7 @@ 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
|
||||
@@ -878,22 +937,38 @@ 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
|
||||
@@ -914,7 +989,7 @@ theorem findIdx_eq_getD_findIdx? {xs : List α} {p : α → Bool} :
|
||||
|
||||
/-! ### 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
|
||||
@@ -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,7 +1129,7 @@ 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 =>
|
||||
@@ -1063,8 +1142,23 @@ theorem idxOf_lt_length [BEq α] [EquivBEq α] {l : List α} (h : a ∈ l) : l.i
|
||||
· 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
|
||||
|
||||
@@ -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 ..⟩
|
||||
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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,6 +3391,7 @@ 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -287,7 +288,7 @@ theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : (i : Nat) → α → (h
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp [Fin.forall_iff]
|
||||
|
||||
@[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,7 +334,7 @@ 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},
|
||||
@@ -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,7 +519,7 @@ 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
|
||||
|
||||
@@ -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₂
|
||||
@@ -114,7 +115,7 @@ section intersperse
|
||||
|
||||
variable {l : List α} {sep : α} {i : Nat}
|
||||
|
||||
@[simp] theorem length_intersperse : (l.intersperse sep).length = 2 * l.length - 1 := by
|
||||
@[simp, grind =] theorem length_intersperse : (l.intersperse sep).length = 2 * l.length - 1 := by
|
||||
fun_induction intersperse <;> simp only [intersperse, length_cons, length_nil] at *
|
||||
rename_i h _
|
||||
have := length_pos_iff.mpr h
|
||||
|
||||
@@ -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
|
||||
@@ -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 [h']
|
||||
· rw [count_cons]
|
||||
split <;> rename_i h'
|
||||
· simp only [beq_iff_eq] at h'
|
||||
rw [count_eq_zero.mpr (h' ▸ h)]
|
||||
simp [h']
|
||||
· 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]
|
||||
@@ -49,6 +50,7 @@ theorem getElem?_eraseIdx_of_ge {l : List α} {i : Nat} {j : Nat} (h : i ≤ j)
|
||||
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]
|
||||
|
||||
@@ -30,19 +30,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 +57,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 +75,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 +115,11 @@ 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 _ _
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self {l : List α} {x : α} : l.insertIdx l.length x = l ++ [x] := by
|
||||
induction l with
|
||||
@@ -185,6 +195,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 +212,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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -99,6 +99,7 @@ theorem getLast_take {l : List α} (h : l.take i ≠ []) :
|
||||
· rw [getElem?_eq_none (by omega), getLast_eq_getElem]
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem take_take : ∀ {i j} {l : List α}, take i (take j l) = take (min i j) l
|
||||
| n, 0, l => by rw [Nat.min_zero, take_zero, take_nil]
|
||||
| 0, m, l => by rw [Nat.zero_min, take_zero, take_zero]
|
||||
@@ -117,19 +118,19 @@ theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
|
||||
@[deprecated take_set_of_le (since := "2025-02-04")]
|
||||
abbrev take_set_of_lt := @take_set_of_le
|
||||
|
||||
@[simp] theorem take_replicate {a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
|
||||
@[simp, grind =] theorem take_replicate {a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
|
||||
| n, 0 => by simp [Nat.min_zero]
|
||||
| 0, m => by simp [Nat.zero_min]
|
||||
| succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
|
||||
|
||||
@[simp] theorem drop_replicate {a : α} : ∀ {i n : Nat}, drop i (replicate n a) = replicate (n - i) a
|
||||
@[simp, grind =] theorem drop_replicate {a : α} : ∀ {i n : Nat}, drop i (replicate n a) = replicate (n - i) a
|
||||
| n, 0 => by simp
|
||||
| 0, m => by simp
|
||||
| succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]
|
||||
|
||||
/-- Taking the first `i` elements in `l₁ ++ l₂` is the same as appending the first `i` elements
|
||||
of `l₁` to the first `n - l₁.length` elements of `l₂`. -/
|
||||
theorem take_append_eq_append_take {l₁ l₂ : List α} {i : Nat} :
|
||||
theorem take_append {l₁ l₂ : List α} {i : Nat} :
|
||||
take i (l₁ ++ l₂) = take i l₁ ++ take (i - l₁.length) l₂ := by
|
||||
induction l₁ generalizing i
|
||||
· simp
|
||||
@@ -140,15 +141,18 @@ theorem take_append_eq_append_take {l₁ l₂ : List α} {i : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[deprecated take_append (since := "2025-06-16")]
|
||||
abbrev take_append_eq_append_take := @take_append
|
||||
|
||||
theorem take_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
|
||||
(l₁ ++ l₂).take i = l₁.take i := by
|
||||
simp [take_append_eq_append_take, Nat.sub_eq_zero_of_le h]
|
||||
simp [take_append, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
/-- Taking the first `l₁.length + i` elements in `l₁ ++ l₂` is the same as appending the first
|
||||
`i` elements of `l₂` to `l₁`. -/
|
||||
theorem take_append {l₁ l₂ : List α} (i : Nat) :
|
||||
theorem take_length_add_append {l₁ l₂ : List α} (i : Nat) :
|
||||
take (l₁.length + i) (l₁ ++ l₂) = l₁ ++ take i l₂ := by
|
||||
rw [take_append_eq_append_take, take_of_length_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left]
|
||||
rw [take_append, take_of_length_le (Nat.le_add_right _ _), Nat.add_sub_cancel_left]
|
||||
|
||||
@[simp]
|
||||
theorem take_eq_take_iff :
|
||||
@@ -162,11 +166,12 @@ theorem take_eq_take_iff :
|
||||
@[deprecated take_eq_take_iff (since := "2025-02-16")]
|
||||
abbrev take_eq_take := @take_eq_take_iff
|
||||
|
||||
@[grind =]
|
||||
theorem take_add {l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j := by
|
||||
suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
|
||||
rw [take_append_drop] at this
|
||||
assumption
|
||||
rw [take_append_eq_append_take, take_of_length_le, append_right_inj]
|
||||
rw [take_append, take_of_length_le, append_right_inj]
|
||||
· simp only [take_eq_take_iff, length_take, length_drop]
|
||||
omega
|
||||
apply Nat.le_trans (m := i)
|
||||
@@ -236,7 +241,7 @@ dropping the first `i` elements. Version designed to rewrite from the small list
|
||||
exact Nat.add_lt_of_lt_sub (length_drop ▸ h)) := by
|
||||
rw [getElem_drop']
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_drop {xs : List α} {i j : Nat} : (xs.drop i)[j]? = xs[i + j]? := by
|
||||
ext
|
||||
simp only [getElem?_eq_some_iff, getElem_drop]
|
||||
@@ -285,7 +290,7 @@ theorem getLast?_drop {l : List α} : (l.drop i).getLast? = if l.length ≤ i th
|
||||
congr
|
||||
omega
|
||||
|
||||
@[simp] theorem getLast_drop {l : List α} (h : l.drop i ≠ []) :
|
||||
@[simp, grind =] theorem getLast_drop {l : List α} (h : l.drop i ≠ []) :
|
||||
(l.drop i).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
|
||||
simp only [ne_eq, drop_eq_nil_iff] at h
|
||||
apply Option.some_inj.1
|
||||
@@ -306,7 +311,8 @@ theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) :
|
||||
|
||||
/-- Dropping the elements up to `i` in `l₁ ++ l₂` is the same as dropping the elements up to `i`
|
||||
in `l₁`, dropping the elements up to `i - l₁.length` in `l₂`, and appending them. -/
|
||||
theorem drop_append_eq_append_drop {l₁ l₂ : List α} {i : Nat} :
|
||||
@[grind =]
|
||||
theorem drop_append {l₁ l₂ : List α} {i : Nat} :
|
||||
drop i (l₁ ++ l₂) = drop i l₁ ++ drop (i - l₁.length) l₂ := by
|
||||
induction l₁ generalizing i
|
||||
· simp
|
||||
@@ -316,15 +322,18 @@ theorem drop_append_eq_append_drop {l₁ l₂ : List α} {i : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[deprecated drop_append (since := "2025-06-16")]
|
||||
abbrev drop_append_eq_append_drop := @drop_append
|
||||
|
||||
theorem drop_append_of_le_length {l₁ l₂ : List α} {i : Nat} (h : i ≤ l₁.length) :
|
||||
(l₁ ++ l₂).drop i = l₁.drop i ++ l₂ := by
|
||||
simp [drop_append_eq_append_drop, Nat.sub_eq_zero_of_le h]
|
||||
simp [drop_append, Nat.sub_eq_zero_of_le h]
|
||||
|
||||
/-- Dropping the elements up to `l₁.length + i` in `l₁ + l₂` is the same as dropping the elements
|
||||
up to `i` in `l₂`. -/
|
||||
@[simp]
|
||||
theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by
|
||||
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
|
||||
theorem drop_length_add_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l₁ ++ l₂) = drop i l₂ := by
|
||||
rw [drop_append, drop_eq_nil_of_le] <;>
|
||||
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
|
||||
|
||||
theorem set_eq_take_append_cons_drop {l : List α} {i : Nat} {a : α} :
|
||||
@@ -458,7 +467,7 @@ theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs
|
||||
obtain ⟨i, h, rfl⟩ := h
|
||||
exact not_of_lt_findIdx (by omega)
|
||||
|
||||
@[simp] theorem findIdx_take {xs : List α} {i : Nat} {p : α → Bool} :
|
||||
@[simp, grind =] theorem findIdx_take {xs : List α} {i : Nat} {p : α → Bool} :
|
||||
(xs.take i).findIdx p = min i (xs.findIdx p) := by
|
||||
induction xs generalizing i with
|
||||
| nil => simp
|
||||
@@ -470,7 +479,7 @@ theorem false_of_mem_take_findIdx {xs : List α} {p : α → Bool} (h : x ∈ xs
|
||||
· simp
|
||||
· rw [Nat.add_min_add_right]
|
||||
|
||||
@[simp] theorem min_findIdx_findIdx {xs : List α} {p q : α → Bool} :
|
||||
@[simp, grind =] theorem min_findIdx_findIdx {xs : List α} {p q : α → Bool} :
|
||||
min (xs.findIdx p) (xs.findIdx q) = xs.findIdx (fun a => p a || q a) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
@@ -512,7 +521,7 @@ theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
|
||||
@[simp] theorem rotateLeft_replicate {n} {a : α} : rotateLeft (replicate m a) n = replicate m a := by
|
||||
@[simp, grind =] theorem rotateLeft_replicate {n} {a : α} : rotateLeft (replicate m a) n = replicate m a := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
@@ -525,7 +534,7 @@ theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
|
||||
/-! ### rotateRight -/
|
||||
|
||||
@[simp] theorem rotateRight_replicate {n} {a : α} : rotateRight (replicate m a) n = replicate m a := by
|
||||
@[simp, grind =] theorem rotateRight_replicate {n} {a : α} : rotateRight (replicate m a) n = replicate m a := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
@@ -538,7 +547,7 @@ theorem dropWhile_eq_drop_findIdx_not {xs : List α} {p : α → Bool} :
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
@[simp] theorem length_zipWith {f : α → β → γ} {l₁ : List α} {l₂ : List β} :
|
||||
@[simp, grind =] theorem length_zipWith {f : α → β → γ} {l₁ : List α} {l₂ : List β} :
|
||||
length (zipWith f l₁ l₂) = min (length l₁) (length l₂) := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;>
|
||||
simp_all [succ_min_succ, Nat.zero_min, Nat.min_zero]
|
||||
@@ -549,7 +558,7 @@ theorem lt_length_left_of_zipWith {f : α → β → γ} {i : Nat} {l : List α}
|
||||
theorem lt_length_right_of_zipWith {f : α → β → γ} {i : Nat} {l : List α} {l' : List β}
|
||||
(h : i < (zipWith f l l').length) : i < l'.length := by rw [length_zipWith] at h; omega
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
|
||||
{i : Nat} {h : i < (zipWith f l l').length} :
|
||||
(zipWith f l l')[i] =
|
||||
@@ -566,6 +575,7 @@ theorem zipWith_eq_zipWith_take_min : ∀ {l₁ : List α} {l₂ : List β},
|
||||
| _, [] => by simp
|
||||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zipWith_eq_zipWith_take_min (l₁ := l₁) (l₂ := l₂)]
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_zipWith (h : l.length = l'.length) :
|
||||
(zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
|
||||
induction l generalizing l' with
|
||||
@@ -578,14 +588,14 @@ theorem reverse_zipWith (h : l.length = l'.length) :
|
||||
have : tl.reverse.length = tl'.reverse.length := by simp [h]
|
||||
simp [hl h, zipWith_append this]
|
||||
|
||||
@[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
|
||||
rw [zipWith_eq_zipWith_take_min]
|
||||
simp
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
@[simp] theorem length_zip {l₁ : List α} {l₂ : List β} :
|
||||
@[simp, grind =] theorem length_zip {l₁ : List α} {l₂ : List β} :
|
||||
length (zip l₁ l₂) = min (length l₁) (length l₂) := by
|
||||
simp [zip]
|
||||
|
||||
@@ -597,7 +607,7 @@ theorem lt_length_right_of_zip {i : Nat} {l : List α} {l' : List β} (h : i < (
|
||||
i < l'.length :=
|
||||
lt_length_right_of_zipWith h
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_zip {l : List α} {l' : List β} {i : Nat} {h : i < (zip l l').length} :
|
||||
(zip l l')[i] =
|
||||
(l[i]'(lt_length_left_of_zip h), l'[i]'(lt_length_right_of_zip h)) :=
|
||||
@@ -609,7 +619,7 @@ theorem zip_eq_zip_take_min : ∀ {l₁ : List α} {l₂ : List β},
|
||||
| _, [] => by simp
|
||||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zip_eq_zip_take_min (l₁ := l₁) (l₂ := l₂)]
|
||||
|
||||
@[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
|
||||
rw [zip_eq_zip_take_min]
|
||||
simp
|
||||
|
||||
@@ -6,7 +6,7 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.Nat.Div.Basic
|
||||
meta import Init.Data.Nat.Div.Basic
|
||||
|
||||
/-!
|
||||
# Notation for `List` literals.
|
||||
|
||||
@@ -34,14 +34,14 @@ to each potential index in order, starting at `0`.
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (List α) :=
|
||||
List.reverse <$> Fin.foldlM n (fun xs i => (· :: xs) <$> f i) []
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem length_ofFn {f : Fin n → α} : (ofFn f).length = n := by
|
||||
simp only [ofFn]
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [Fin.foldr_succ, ih]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
protected theorem getElem_ofFn {f : Fin n → α} (h : i < (ofFn f).length) :
|
||||
(ofFn f)[i] = f ⟨i, by simp_all⟩ := by
|
||||
simp only [ofFn]
|
||||
@@ -55,7 +55,7 @@ protected theorem getElem_ofFn {f : Fin n → α} (h : i < (ofFn f).length) :
|
||||
apply ih
|
||||
simp_all
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
protected theorem getElem?_ofFn {f : Fin n → α} :
|
||||
(ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none :=
|
||||
if h : i < (ofFn f).length
|
||||
@@ -67,7 +67,7 @@ protected theorem getElem?_ofFn {f : Fin n → α} :
|
||||
simpa using h
|
||||
|
||||
/-- `ofFn` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem ofFn_zero {f : Fin 0 → α} : ofFn f = [] := by
|
||||
rw [ofFn, Fin.foldr_zero]
|
||||
|
||||
@@ -98,7 +98,7 @@ theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
@[simp 500]
|
||||
@[simp 500, grind =]
|
||||
theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
@@ -107,17 +107,17 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
theorem head_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
@[grind =] theorem head_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
List.getElem_ofFn]
|
||||
|
||||
theorem getLast_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
@[grind =]theorem getLast_ofFn {n} {f : Fin n → α} (h : ofFn f ≠ []) :
|
||||
(ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
|
||||
|
||||
/-- `ofFnM` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem ofFnM_zero [Monad m] [LawfulMonad m] {f : Fin 0 → m α} : ofFnM f = pure [] := by
|
||||
simp [ofFnM]
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
|
||||
@[grind =] theorem pairwise_middle {R : α → α → Prop} (s : ∀ {x y}, R x y → R y x) {a : α} {l₁ l₂ : List α} :
|
||||
Pairwise R (l₁ ++ a :: l₂) ↔ Pairwise R (a :: (l₁ ++ l₂)) := by
|
||||
show Pairwise R (l₁ ++ ([a] ++ l₂)) ↔ Pairwise R ([a] ++ l₁ ++ l₂)
|
||||
change Pairwise R (l₁ ++ ([a] ++ l₂)) ↔ Pairwise R ([a] ++ l₁ ++ l₂)
|
||||
rw [← append_assoc, pairwise_append, @pairwise_append _ _ ([a] ++ l₁), pairwise_append_comm s]
|
||||
simp only [mem_append, or_comm]
|
||||
|
||||
@@ -279,7 +279,11 @@ theorem nodup_nil : @Nodup α [] :=
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
@[grind →] theorem Nodup.sublist : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
@[grind =] theorem nodup_append {l₁ l₂ : List α} :
|
||||
(l₁ ++ l₂).Nodup ↔ l₁.Nodup ∧ l₂.Nodup ∧ ∀ a ∈ l₁, ∀ b ∈ l₂, a ≠ b :=
|
||||
pairwise_append
|
||||
|
||||
theorem Nodup.sublist : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
Pairwise.sublist
|
||||
|
||||
grind_pattern Nodup.sublist => l₁ <+ l₂, Nodup l₁
|
||||
@@ -312,4 +316,48 @@ theorem getElem?_inj {xs : List α}
|
||||
@[simp, grind =] theorem nodup_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).Nodup ↔ n ≤ 1 := by simp [Nodup]
|
||||
|
||||
theorem Nodup.count [BEq α] [LawfulBEq α] {a : α} {l : List α} (h : Nodup l) : count a l = if a ∈ l then 1 else 0 := by
|
||||
split <;> rename_i h'
|
||||
· obtain ⟨s, t, rfl⟩ := List.append_of_mem h'
|
||||
rw [nodup_append] at h
|
||||
simp_all
|
||||
rw [count_eq_zero.mpr ?_, count_eq_zero.mpr ?_]
|
||||
· exact h.2.1.1
|
||||
· intro w
|
||||
simpa using h.2.2 _ w
|
||||
· rw [count_eq_zero_of_not_mem h']
|
||||
|
||||
grind_pattern Nodup.count => count a l, Nodup l
|
||||
|
||||
@[grind =]
|
||||
theorem nodup_iff_count [BEq α] [LawfulBEq α] {l : List α} : l.Nodup ↔ ∀ a, count a l ≤ 1 := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih =>
|
||||
constructor
|
||||
· intro h a
|
||||
simp at h
|
||||
rw [count_cons]
|
||||
split <;> rename_i h'
|
||||
· simp at h'
|
||||
rw [count_eq_zero.mpr ?_]
|
||||
· exact Nat.le_refl _
|
||||
· exact h' ▸ h.1
|
||||
· simp at h'
|
||||
refine ih.mp h.2 a
|
||||
· intro h
|
||||
simp only [count_cons] at h
|
||||
simp only [nodup_cons]
|
||||
constructor
|
||||
· intro w
|
||||
specialize h x
|
||||
simp at h
|
||||
have := count_pos_iff.mpr w
|
||||
replace h := le_of_lt_succ h
|
||||
apply Nat.lt_irrefl _ (Nat.lt_of_lt_of_le this h)
|
||||
· rw [ih]
|
||||
intro a
|
||||
specialize h a
|
||||
exact le_of_add_right_le h
|
||||
|
||||
end List
|
||||
|
||||
@@ -23,8 +23,7 @@ The notation `~` is used for permutation equivalence.
|
||||
-/
|
||||
|
||||
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 Nat
|
||||
|
||||
@@ -90,6 +89,9 @@ theorem Perm.mem_iff {a : α} {l₁ l₂ : List α} (p : l₁ ~ l₂) : a ∈ l
|
||||
| swap => simp only [mem_cons, or_left_comm]
|
||||
| trans _ _ ih₁ ih₂ => simp only [ih₁, ih₂]
|
||||
|
||||
grind_pattern Perm.mem_iff => l₁ ~ l₂, a ∈ l₁
|
||||
grind_pattern Perm.mem_iff => l₁ ~ l₂, a ∈ l₂
|
||||
|
||||
theorem Perm.subset {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁ ⊆ l₂ := fun _ => p.mem_iff.mp
|
||||
|
||||
theorem Perm.append_right {l₁ l₂ : List α} (t₁ : List α) (p : l₁ ~ l₂) : l₁ ++ t₁ ~ l₂ ++ t₁ := by
|
||||
@@ -106,9 +108,15 @@ theorem Perm.append_left {t₁ t₂ : List α} : ∀ l : List α, t₁ ~ t₂
|
||||
theorem Perm.append {l₁ l₂ t₁ t₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : t₁ ~ t₂) : l₁ ++ t₁ ~ l₂ ++ t₂ :=
|
||||
(p₁.append_right t₁).trans (p₂.append_left l₂)
|
||||
|
||||
grind_pattern Perm.append => l₁ ~ l₂, t₁ ~ t₂, l₁ ++ t₁
|
||||
grind_pattern Perm.append => l₁ ~ l₂, t₁ ~ t₂, l₂ ++ t₂
|
||||
|
||||
theorem Perm.append_cons (a : α) {l₁ l₂ r₁ r₂ : List α} (p₁ : l₁ ~ l₂) (p₂ : r₁ ~ r₂) :
|
||||
l₁ ++ a :: r₁ ~ l₂ ++ a :: r₂ := p₁.append (p₂.cons a)
|
||||
|
||||
grind_pattern Perm.append_cons => l₁ ~ l₂, r₁ ~ r₂, l₁ ++ a :: r₁
|
||||
grind_pattern Perm.append_cons => l₁ ~ l₂, r₁ ~ r₂, l₂ ++ a :: r₂
|
||||
|
||||
@[simp] theorem perm_middle {a : α} : ∀ {l₁ l₂ : List α}, l₁ ++ a :: l₂ ~ a :: (l₁ ++ l₂)
|
||||
| [], _ => .refl _
|
||||
| b :: _, _ => (Perm.cons _ perm_middle).trans (swap a b _)
|
||||
@@ -194,9 +202,15 @@ theorem Perm.filterMap (f : α → Option β) {l₁ l₂ : List α} (p : l₁ ~
|
||||
| swap x y l₂ => cases hx : f x <;> cases hy : f y <;> simp [hx, hy, filterMap_cons, swap]
|
||||
| trans _p₁ _p₂ IH₁ IH₂ => exact IH₁.trans IH₂
|
||||
|
||||
grind_pattern Perm.filterMap => l₁ ~ l₂, filterMap f l₁
|
||||
grind_pattern Perm.filterMap => l₁ ~ l₂, filterMap f l₂
|
||||
|
||||
theorem Perm.map (f : α → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) : map f l₁ ~ map f l₂ :=
|
||||
filterMap_eq_map ▸ p.filterMap _
|
||||
|
||||
grind_pattern Perm.map => l₁ ~ l₂, map f l₁
|
||||
grind_pattern Perm.map => l₁ ~ l₂, map f l₂
|
||||
|
||||
theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α} (p : l₁ ~ l₂) {H₁ H₂} :
|
||||
pmap f l₁ H₁ ~ pmap f l₂ H₂ := by
|
||||
induction p with
|
||||
@@ -205,12 +219,18 @@ theorem Perm.pmap {p : α → Prop} (f : ∀ a, p a → β) {l₁ l₂ : List α
|
||||
| swap x y => simp [swap]
|
||||
| trans _p₁ p₂ IH₁ IH₂ => exact IH₁.trans (IH₂ (H₁ := fun a m => H₂ a (p₂.subset m)))
|
||||
|
||||
grind_pattern Perm.pmap => l₁ ~ l₂, pmap f l₁ H₁
|
||||
grind_pattern Perm.pmap => l₁ ~ l₂, pmap f l₂ H₂
|
||||
|
||||
theorem Perm.unattach {α : Type u} {p : α → Prop} {l₁ l₂ : List { x // p x }} (h : l₁ ~ l₂) :
|
||||
l₁.unattach.Perm l₂.unattach := h.map _
|
||||
|
||||
theorem Perm.filter (p : α → Bool) {l₁ l₂ : List α} (s : l₁ ~ l₂) :
|
||||
filter p l₁ ~ filter p l₂ := by rw [← filterMap_eq_filter]; apply s.filterMap
|
||||
|
||||
grind_pattern Perm.filter => l₁ ~ l₂, filter p l₁
|
||||
grind_pattern Perm.filter => l₁ ~ l₂, filter p l₂
|
||||
|
||||
theorem filter_append_perm (p : α → Bool) (l : List α) :
|
||||
filter p l ++ filter (fun x => !p x) l ~ l := by
|
||||
induction l with
|
||||
@@ -388,12 +408,16 @@ theorem Perm.erase (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) : l₁.erase
|
||||
have h₂ : a ∉ l₂ := mt p.mem_iff.2 h₁
|
||||
rw [erase_of_not_mem h₁, erase_of_not_mem h₂]; exact p
|
||||
|
||||
grind_pattern Perm.erase => l₁ ~ l₂, l₁.erase a
|
||||
grind_pattern Perm.erase => l₁ ~ l₂, l₂.erase a
|
||||
|
||||
theorem cons_perm_iff_perm_erase {a : α} {l₁ l₂ : List α} :
|
||||
a :: l₁ ~ l₂ ↔ a ∈ l₂ ∧ l₁ ~ l₂.erase a := by
|
||||
refine ⟨fun h => ?_, fun ⟨m, h⟩ => (h.cons a).trans (perm_cons_erase m).symm⟩
|
||||
have : a ∈ l₂ := h.subset mem_cons_self
|
||||
exact ⟨this, (h.trans <| perm_cons_erase this).cons_inv⟩
|
||||
|
||||
@[grind =]
|
||||
theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l₁ = count a l₂ := by
|
||||
refine ⟨Perm.count_eq, fun H => ?_⟩
|
||||
induction l₁ generalizing l₂ with
|
||||
@@ -410,6 +434,12 @@ theorem perm_iff_count {l₁ l₂ : List α} : l₁ ~ l₂ ↔ ∀ a, count a l
|
||||
rw [(perm_cons_erase this).count_eq] at H
|
||||
by_cases h : b = a <;> simpa [h, count_cons, Nat.succ_inj] using H
|
||||
|
||||
theorem Perm.count (h : l₁ ~ l₂) (a : α) : count a l₁ = count a l₂ := by
|
||||
rw [perm_iff_count.mp h]
|
||||
|
||||
grind_pattern Perm.count => l₁ ~ l₂, count a l₁
|
||||
grind_pattern Perm.count => l₁ ~ l₂, count a l₂
|
||||
|
||||
theorem isPerm_iff : ∀ {l₁ l₂ : List α}, l₁.isPerm l₂ ↔ l₁ ~ l₂
|
||||
| [], [] => by simp [isPerm, isEmpty]
|
||||
| [], _ :: _ => by simp [isPerm, isEmpty, Perm.nil_eq]
|
||||
@@ -425,6 +455,9 @@ protected theorem Perm.insert (a : α) {l₁ l₂ : List α} (p : l₁ ~ l₂) :
|
||||
have := p.cons a
|
||||
simpa [h, mt p.mem_iff.2 h] using this
|
||||
|
||||
grind_pattern Perm.insert => l₁ ~ l₂, l₁.insert a
|
||||
grind_pattern Perm.insert => l₁ ~ l₂, l₂.insert a
|
||||
|
||||
theorem perm_insert_swap (x y : α) (l : List α) :
|
||||
List.insert x (List.insert y l) ~ List.insert y (List.insert x l) := by
|
||||
by_cases xl : x ∈ l <;> by_cases yl : y ∈ l <;> simp [xl, yl]
|
||||
@@ -491,6 +524,9 @@ theorem Perm.nodup {l l' : List α} (hl : l ~ l') (hR : l.Nodup) : l'.Nodup := h
|
||||
theorem Perm.nodup_iff {l₁ l₂ : List α} : l₁ ~ l₂ → (Nodup l₁ ↔ Nodup l₂) :=
|
||||
Perm.pairwise_iff <| @Ne.symm α
|
||||
|
||||
grind_pattern Perm.nodup_iff => l₁ ~ l₂, Nodup l₁
|
||||
grind_pattern Perm.nodup_iff => l₁ ~ l₂, Nodup l₂
|
||||
|
||||
theorem Perm.flatten {l₁ l₂ : List (List α)} (h : l₁ ~ l₂) : l₁.flatten ~ l₂.flatten := by
|
||||
induction h with
|
||||
| nil => rfl
|
||||
@@ -541,20 +577,30 @@ theorem perm_insertIdx {α} (x : α) (l : List α) {i} (h : i ≤ l.length) :
|
||||
|
||||
namespace Perm
|
||||
|
||||
theorem take {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.drop n ~ l₂.drop n) :
|
||||
l₁.take n ~ l₂.take n := by
|
||||
theorem take {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : l₁.drop i ~ l₂.drop i) :
|
||||
l₁.take i ~ l₂.take i := by
|
||||
classical
|
||||
rw [perm_iff_count] at h w ⊢
|
||||
rw [← take_append_drop n l₁, ← take_append_drop n l₂] at h
|
||||
rw [← take_append_drop i l₁, ← take_append_drop i l₂] at h
|
||||
simpa only [count_append, w, Nat.add_right_cancel_iff] using h
|
||||
|
||||
theorem drop {l₁ l₂ : List α} (h : l₁ ~ l₂) {n : Nat} (w : l₁.take n ~ l₂.take n) :
|
||||
l₁.drop n ~ l₂.drop n := by
|
||||
theorem drop {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : l₁.take i ~ l₂.take i) :
|
||||
l₁.drop i ~ l₂.drop i := by
|
||||
classical
|
||||
rw [perm_iff_count] at h w ⊢
|
||||
rw [← take_append_drop n l₁, ← take_append_drop n l₂] at h
|
||||
rw [← take_append_drop i l₁, ← take_append_drop i l₂] at h
|
||||
simpa only [count_append, w, Nat.add_left_cancel_iff] using h
|
||||
|
||||
theorem sum_nat {l₁ l₂ : List Nat} (h : l₁ ~ l₂) : l₁.sum = l₂.sum := by
|
||||
induction h with
|
||||
| nil => simp
|
||||
| cons _ _ ih => simp [ih]
|
||||
| swap => simpa [List.sum_cons] using Nat.add_left_comm ..
|
||||
| trans _ _ ih₁ ih₂ => simp [ih₁, ih₂]
|
||||
|
||||
grind_pattern Perm.sum_nat => l₁ ~ l₂, l₁.sum
|
||||
grind_pattern Perm.sum_nat => l₁ ~ l₂, l₂.sum
|
||||
|
||||
end Perm
|
||||
|
||||
end List
|
||||
|
||||
@@ -225,7 +225,7 @@ theorem zipIdx_eq_nil_iff {l : List α} {i : Nat} : List.zipIdx l i = [] ↔ l =
|
||||
| [], _ => rfl
|
||||
| _ :: _, _ => congrArg Nat.succ length_zipIdx
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_zipIdx :
|
||||
∀ {l : List α} {i j}, (zipIdx l i)[j]? = l[j]?.map fun a => (a, i + j)
|
||||
| [], _, _ => rfl
|
||||
@@ -234,7 +234,7 @@ theorem getElem?_zipIdx :
|
||||
simp only [zipIdx_cons, getElem?_cons_succ]
|
||||
exact getElem?_zipIdx.trans <| by rw [Nat.add_right_comm]; rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_zipIdx {l : List α} (h : i < (l.zipIdx j).length) :
|
||||
(l.zipIdx j)[i] = (l[i]'(by simpa [length_zipIdx] using h), j + i) := by
|
||||
simp only [length_zipIdx] at h
|
||||
@@ -242,7 +242,7 @@ theorem getElem_zipIdx {l : List α} (h : i < (l.zipIdx j).length) :
|
||||
simp only [getElem?_zipIdx, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem tail_zipIdx {l : List α} {i : Nat} : (zipIdx l i).tail = zipIdx l.tail (i + 1) := by
|
||||
induction l generalizing i with
|
||||
| nil => simp
|
||||
|
||||
@@ -467,7 +467,7 @@ theorem replace_takeWhile [BEq α] [LawfulBEq α] {l : List α} {p : α → Bool
|
||||
|
||||
/-! ### splitAt -/
|
||||
|
||||
@[simp] theorem splitAt_eq {i : Nat} {l : List α} : splitAt i l = (l.take i, l.drop i) := by
|
||||
@[simp, grind =] theorem splitAt_eq {i : Nat} {l : List α} : splitAt i l = (l.take i, l.drop i) := by
|
||||
rw [splitAt, splitAt_go, reverse_nil, nil_append]
|
||||
split <;> simp_all [take_of_length_le, drop_of_length_le]
|
||||
|
||||
|
||||
@@ -685,7 +685,7 @@ theorem replace_toArray [BEq α] [LawfulBEq α] (l : List α) (a b : α) :
|
||||
· rw [if_pos (by omega), if_pos, if_neg]
|
||||
· simp only [mem_take_iff_getElem, not_exists]
|
||||
intro k hk
|
||||
simpa using h.2 ⟨k, by omega⟩ (by show k < i.1; omega)
|
||||
simpa using h.2 ⟨k, by omega⟩ (by change k < i.1; omega)
|
||||
· subst h₃
|
||||
simpa using h.1
|
||||
· rw [if_neg (by omega)]
|
||||
|
||||
@@ -46,6 +46,7 @@ theorem zipWith_self {f : α → α → δ} : ∀ {l : List α}, zipWith f l l =
|
||||
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
|
||||
@@ -83,33 +84,39 @@ theorem getElem?_zip_eq_some {l₁ : List α} {l₂ : List β} {z : α × β} {i
|
||||
· rintro ⟨h₀, h₁⟩
|
||||
exact ⟨_, _, h₀, h₁, rfl⟩
|
||||
|
||||
@[grind =]
|
||||
theorem head?_zipWith {f : α → β → γ} :
|
||||
(List.zipWith f as bs).head? = match as.head?, bs.head? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
simp [head?_eq_getElem?, getElem?_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem head_zipWith {f : α → β → γ} (h):
|
||||
(List.zipWith f as bs).head h = f (as.head (by rintro rfl; simp_all)) (bs.head (by rintro rfl; simp_all)) := by
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_zipWith, head?_eq_head, head?_eq_head]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipWith_map {μ} {f : γ → δ → μ} {g : α → γ} {h : β → δ} {l₁ : List α} {l₂ : List β} :
|
||||
zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_left {l₁ : List α} {l₂ : List β} {f : α → α'} {g : α' → β → γ} :
|
||||
zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_right {l₁ : List α} {l₂ : List β} {f : β → β'} {g : α → β' → γ} :
|
||||
zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} {i : δ} {g : γ → δ → δ} :
|
||||
(zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} {g : δ → γ → δ} :
|
||||
(zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by
|
||||
induction l₁ generalizing i l₂ <;> cases l₂ <;> simp_all
|
||||
@@ -118,6 +125,7 @@ theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} {g : δ →
|
||||
theorem zipWith_eq_nil_iff {f : α → β → γ} {l l'} : zipWith f l l' = [] ↔ l = [] ∨ l' = [] := by
|
||||
cases l <;> cases l' <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {l : List γ} {l' : List δ} :
|
||||
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
|
||||
induction l generalizing l' with
|
||||
@@ -127,6 +135,7 @@ theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {l : Li
|
||||
· simp
|
||||
· simp [hl]
|
||||
|
||||
@[grind =]
|
||||
theorem take_zipWith : (zipWith f l l').take i = zipWith f (l.take i) (l'.take i) := by
|
||||
induction l generalizing l' i with
|
||||
| nil => simp
|
||||
@@ -137,6 +146,7 @@ theorem take_zipWith : (zipWith f l l').take i = zipWith f (l.take i) (l'.take i
|
||||
· simp
|
||||
· simp [hl]
|
||||
|
||||
@[grind =]
|
||||
theorem drop_zipWith : (zipWith f l l').drop i = zipWith f (l.drop i) (l'.drop i) := by
|
||||
induction l generalizing l' i with
|
||||
| nil => simp
|
||||
@@ -147,10 +157,11 @@ theorem drop_zipWith : (zipWith f l l').drop i = zipWith f (l.drop i) (l'.drop i
|
||||
· simp
|
||||
· simp [hl]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem tail_zipWith : (zipWith f l l').tail = zipWith f l.tail l'.tail := by
|
||||
rw [← drop_one]; simp [drop_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_append {f : α → β → γ} {l₁ l₁' : List α} {l₂ l₂' : List β}
|
||||
(h : l₁.length = l₂.length) :
|
||||
zipWith f (l₁ ++ l₁') (l₂ ++ l₂') = zipWith f l₁ l₂ ++ zipWith f l₁' l₂' := by
|
||||
@@ -254,22 +265,26 @@ theorem zip_eq_zipWith : ∀ {l₁ : List α} {l₂ : List β}, zip l₁ l₂ =
|
||||
| _, [] => rfl
|
||||
| a :: l₁, b :: l₂ => by simp [zip_cons_cons, zip_eq_zipWith (l₁ := l₁)]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map {f : α → γ} {g : β → δ} :
|
||||
∀ {l₁ : List α} {l₂ : List β}, zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g)
|
||||
| [], _ => rfl
|
||||
| _, [] => by simp only [map, zip_nil_right]
|
||||
| _ :: _, _ :: _ => by simp only [map, zip_cons_cons, zip_map, Prod.map]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {l₁ : List α} {l₂ : List β} :
|
||||
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_right {f : β → γ} {l₁ : List α} {l₂ : List β} :
|
||||
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
@[simp] theorem tail_zip {l₁ : List α} {l₂ : List β} :
|
||||
@[simp, grind =] theorem tail_zip {l₁ : List α} {l₂ : List β} :
|
||||
(zip l₁ l₂).tail = zip l₁.tail l₂.tail := by
|
||||
cases l₁ <;> cases l₂ <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem zip_append :
|
||||
∀ {l₁ r₁ : List α} {l₂ r₂ : List β} (_h : length l₁ = length l₂),
|
||||
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂
|
||||
@@ -278,6 +293,7 @@ theorem zip_append :
|
||||
| _ :: _, _, _ :: _, _, h => by
|
||||
simp only [cons_append, zip_cons_cons, zip_append (Nat.succ.inj h)]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_map' {f : α → β} {g : α → γ} :
|
||||
∀ {l : List α}, zip (l.map f) (l.map g) = l.map fun a => (f a, g a)
|
||||
| [] => rfl
|
||||
@@ -296,7 +312,7 @@ theorem map_fst_zip :
|
||||
| [], _, _ => rfl
|
||||
| _ :: as, _ :: bs, h => by
|
||||
simp [Nat.succ_le_succ_iff] at h
|
||||
show _ :: map Prod.fst (zip as bs) = _ :: as
|
||||
change _ :: map Prod.fst (zip as bs) = _ :: as
|
||||
rw [map_fst_zip (l₁ := as) h]
|
||||
| _ :: _, [], h => by simp at h
|
||||
|
||||
@@ -308,7 +324,7 @@ theorem map_snd_zip :
|
||||
| [], b :: bs, h => by simp at h
|
||||
| a :: as, b :: bs, h => by
|
||||
simp [Nat.succ_le_succ_iff] at h
|
||||
show _ :: map Prod.snd (zip as bs) = _ :: bs
|
||||
change _ :: map Prod.snd (zip as bs) = _ :: bs
|
||||
rw [map_snd_zip (l₂ := bs) h]
|
||||
|
||||
theorem map_prod_left_eq_zip {l : List α} {f : α → β} :
|
||||
@@ -353,6 +369,7 @@ theorem zip_eq_append_iff {l₁ : List α} {l₂ : List β} :
|
||||
|
||||
/-! ### 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
|
||||
@@ -366,33 +383,38 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
cases i <;> simp_all
|
||||
| cons b bs => cases i <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem head?_zipWithAll {f : Option α → Option β → γ} :
|
||||
(zipWithAll f as bs).head? = match as.head?, bs.head? with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
simp [head?_eq_getElem?, getElem?_zipWithAll]
|
||||
|
||||
@[simp] theorem head_zipWithAll {f : Option α → Option β → γ} (h) :
|
||||
@[simp, grind =] theorem head_zipWithAll {f : Option α → Option β → γ} (h) :
|
||||
(zipWithAll f as bs).head h = f as.head? bs.head? := by
|
||||
apply Option.some.inj
|
||||
rw [← head?_eq_head, head?_zipWithAll]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem tail_zipWithAll {f : Option α → Option β → γ} :
|
||||
@[simp, grind =] theorem tail_zipWithAll {f : Option α → Option β → γ} :
|
||||
(zipWithAll f as bs).tail = zipWithAll f as.tail bs.tail := by
|
||||
cases as <;> cases bs <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map {μ} {f : Option γ → Option δ → μ} {g : α → γ} {h : β → δ} {l₁ : List α} {l₂ : List β} :
|
||||
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_left {l₁ : List α} {l₂ : List β} {f : α → α'} {g : Option α' → Option β → γ} :
|
||||
zipWithAll g (l₁.map f) l₂ = zipWithAll (fun a b => g (f <$> a) b) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_right {l₁ : List α} {l₂ : List β} {f : β → β'} {g : Option α → Option β' → γ} :
|
||||
zipWithAll g l₁ (l₂.map f) = zipWithAll (fun a b => g a (f <$> b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option δ → α} {l : List γ} {l' : List δ} :
|
||||
map f (zipWithAll g l l') = zipWithAll (fun x y => f (g x y)) l l' := by
|
||||
induction l generalizing l' with
|
||||
@@ -400,7 +422,7 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
|
||||
| cons hd tl hl =>
|
||||
cases l' <;> simp_all
|
||||
|
||||
@[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
|
||||
induction n with
|
||||
| zero => rfl
|
||||
@@ -408,12 +430,13 @@ theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
@[simp, grind =] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
@[simp, grind =] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem unzip_eq_map : ∀ {l : List (α × β)}, unzip l = (l.map Prod.fst, l.map Prod.snd)
|
||||
| [] => rfl
|
||||
| (a, b) :: l => by simp only [unzip_cons, map_cons, unzip_eq_map (l := l)]
|
||||
@@ -453,6 +476,6 @@ theorem tail_zip_fst {l : List (α × β)} : l.unzip.1.tail = l.tail.unzip.1 :=
|
||||
theorem tail_zip_snd {l : List (α × β)} : l.unzip.2.tail = l.tail.unzip.2 := by
|
||||
simp
|
||||
|
||||
@[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
|
||||
|
||||
@@ -406,6 +406,12 @@ theorem le_of_add_right_le {n m k : Nat} (h : n + k ≤ m) : n ≤ m :=
|
||||
theorem le_add_right_of_le {n m k : Nat} (h : n ≤ m) : n ≤ m + k :=
|
||||
Nat.le_trans h (le_add_right m k)
|
||||
|
||||
theorem le_of_add_left_le {n m k : Nat} (h : k + n ≤ m) : n ≤ m :=
|
||||
Nat.le_trans (le_add_left n k) h
|
||||
|
||||
theorem le_add_left_of_le {n m k : Nat} (h : n ≤ m) : n ≤ k + m :=
|
||||
Nat.le_trans h (le_add_left m k)
|
||||
|
||||
theorem lt_of_add_one_le {n m : Nat} (h : n + 1 ≤ m) : n < m := h
|
||||
|
||||
theorem add_one_le_of_lt {n m : Nat} (h : n < m) : n + 1 ≤ m := h
|
||||
@@ -1069,7 +1075,7 @@ protected theorem sub_lt_sub_right : ∀ {a b c : Nat}, c ≤ a → a < b → a
|
||||
exact Nat.sub_lt_sub_right (le_of_succ_le_succ hle) (lt_of_succ_lt_succ h)
|
||||
|
||||
protected theorem sub_self_add (n m : Nat) : n - (n + m) = 0 := by
|
||||
show (n + 0) - (n + m) = 0
|
||||
change (n + 0) - (n + m) = 0
|
||||
rw [Nat.add_sub_add_left, Nat.zero_sub]
|
||||
|
||||
@[simp] protected theorem sub_eq_zero_of_le {n m : Nat} (h : n ≤ m) : n - m = 0 := by
|
||||
|
||||
@@ -51,24 +51,24 @@ noncomputable def div2Induction {motive : Nat → Sort u}
|
||||
apply hyp
|
||||
exact Nat.div_lt_self n_pos (Nat.le_refl _)
|
||||
|
||||
@[simp] theorem zero_and (x : Nat) : 0 &&& x = 0 := by
|
||||
@[simp, grind =] theorem zero_and (x : Nat) : 0 &&& x = 0 := by
|
||||
simp only [HAnd.hAnd, AndOp.and, land]
|
||||
unfold bitwise
|
||||
simp
|
||||
|
||||
@[simp] theorem and_zero (x : Nat) : x &&& 0 = 0 := by
|
||||
@[simp, grind =] theorem and_zero (x : Nat) : x &&& 0 = 0 := by
|
||||
simp only [HAnd.hAnd, AndOp.and, land]
|
||||
unfold bitwise
|
||||
simp
|
||||
|
||||
@[simp] theorem one_and_eq_mod_two (n : Nat) : 1 &&& n = n % 2 := by
|
||||
@[simp, grind =] theorem one_and_eq_mod_two (n : Nat) : 1 &&& n = n % 2 := by
|
||||
if n0 : n = 0 then
|
||||
subst n0; decide
|
||||
else
|
||||
simp only [HAnd.hAnd, AndOp.and, land]
|
||||
cases mod_two_eq_zero_or_one n with | _ h => simp [bitwise, n0, h]
|
||||
|
||||
@[simp] theorem and_one_is_mod (x : Nat) : x &&& 1 = x % 2 := by
|
||||
@[simp, grind =] theorem and_one_is_mod (x : Nat) : x &&& 1 = x % 2 := by
|
||||
if xz : x = 0 then
|
||||
simp [xz, zero_and]
|
||||
else
|
||||
@@ -102,11 +102,12 @@ Depending on use cases either `testBit_add_one` or `testBit_div_two`
|
||||
may be more useful as a `simp` lemma, so neither is a global `simp` lemma.
|
||||
-/
|
||||
-- We turn `testBit_add_one` on as a `local simp` for this file.
|
||||
@[local simp]
|
||||
@[local simp, grind _=_]
|
||||
theorem testBit_add_one (x i : Nat) : testBit x (i + 1) = testBit (x/2) i := by
|
||||
unfold testBit
|
||||
simp [shiftRight_succ_inside]
|
||||
|
||||
@[grind _=_]
|
||||
theorem testBit_add (x i n : Nat) : testBit x (i + n) = testBit (x / 2 ^ n) i := by
|
||||
revert x
|
||||
induction n with
|
||||
@@ -122,6 +123,7 @@ theorem testBit_div_two (x i : Nat) : testBit (x / 2) i = testBit x (i + 1) := b
|
||||
theorem testBit_div_two_pow (x i : Nat) : testBit (x / 2 ^ n) i = testBit x (i + n) :=
|
||||
testBit_add .. |>.symm
|
||||
|
||||
@[grind =]
|
||||
theorem testBit_eq_decide_div_mod_eq {x : Nat} : testBit x i = decide (x / 2^i % 2 = 1) := by
|
||||
induction i generalizing x with
|
||||
| zero =>
|
||||
@@ -290,7 +292,7 @@ theorem testBit_two_pow_add_gt {i j : Nat} (j_lt_i : j < i) (x : Nat) :
|
||||
| d+1 =>
|
||||
simp [Nat.pow_succ, Nat.mul_comm _ 2, Nat.mul_add_mod]
|
||||
|
||||
@[simp] theorem testBit_mod_two_pow (x j i : Nat) :
|
||||
@[simp, grind =] theorem testBit_mod_two_pow (x j i : Nat) :
|
||||
testBit (x % 2^j) i = (decide (i < j) && testBit x i) := by
|
||||
induction x using Nat.strongRecOn generalizing j i with
|
||||
| ind x hyp =>
|
||||
@@ -322,6 +324,7 @@ theorem not_decide_mod_two_eq_one (x : Nat)
|
||||
: (!decide (x % 2 = 1)) = decide (x % 2 = 0) := by
|
||||
cases Nat.mod_two_eq_zero_or_one x <;> (rename_i p; simp [p])
|
||||
|
||||
@[grind =]
|
||||
theorem testBit_two_pow_sub_succ (h₂ : x < 2 ^ n) (i : Nat) :
|
||||
testBit (2^n - (x + 1)) i = (decide (i < n) && ! testBit x i) := by
|
||||
induction i generalizing n x with
|
||||
@@ -357,6 +360,7 @@ theorem testBit_one_eq_true_iff_self_eq_zero {i : Nat} :
|
||||
Nat.testBit 1 i = true ↔ i = 0 := by
|
||||
cases i <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem testBit_two_pow {n m : Nat} : testBit (2 ^ n) m = decide (n = m) := by
|
||||
rw [testBit, shiftRight_eq_div_pow]
|
||||
by_cases h : n = m
|
||||
@@ -482,18 +486,20 @@ theorem bitwise_mod_two_pow (of_false_false : f false false = false := by rfl) :
|
||||
|
||||
/-! ### and -/
|
||||
|
||||
@[simp] theorem testBit_and (x y i : Nat) : (x &&& y).testBit i = (x.testBit i && y.testBit i) := by
|
||||
@[simp, grind =] theorem testBit_and (x y i : Nat) : (x &&& y).testBit i = (x.testBit i && y.testBit i) := by
|
||||
simp [HAnd.hAnd, AndOp.and, land, testBit_bitwise ]
|
||||
|
||||
|
||||
@[simp] protected theorem and_self (x : Nat) : x &&& x = x := by
|
||||
@[simp, grind =] protected theorem and_self (x : Nat) : x &&& x = x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
protected theorem and_comm (x y : Nat) : x &&& y = y &&& x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_comm]
|
||||
|
||||
@[grind _=_]
|
||||
protected theorem and_assoc (x y z : Nat) : (x &&& y) &&& z = x &&& (y &&& z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_assoc]
|
||||
@@ -537,54 +543,63 @@ abbrev and_pow_two_sub_one_of_lt_two_pow := @and_two_pow_sub_one_of_lt_two_pow
|
||||
rw [testBit_and]
|
||||
simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_div_two_pow : (a &&& b) / 2 ^ n = a / 2 ^ n &&& b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_div_two : (a &&& b) / 2 = a / 2 &&& b / 2 :=
|
||||
and_div_two_pow (n := 1)
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_mod_two_pow : (a &&& b) % 2 ^ n = (a % 2 ^ n) &&& (b % 2 ^ n) :=
|
||||
bitwise_mod_two_pow
|
||||
|
||||
/-! ### lor -/
|
||||
|
||||
@[simp] theorem zero_or (x : Nat) : 0 ||| x = x := by
|
||||
@[simp, grind =] theorem zero_or (x : Nat) : 0 ||| x = x := by
|
||||
simp only [HOr.hOr, OrOp.or, lor]
|
||||
unfold bitwise
|
||||
simp [@eq_comm _ 0]
|
||||
|
||||
@[simp] theorem or_zero (x : Nat) : x ||| 0 = x := by
|
||||
@[simp, grind =] theorem or_zero (x : Nat) : x ||| 0 = x := by
|
||||
simp only [HOr.hOr, OrOp.or, lor]
|
||||
unfold bitwise
|
||||
simp [@eq_comm _ 0]
|
||||
|
||||
@[simp] theorem testBit_or (x y i : Nat) : (x ||| y).testBit i = (x.testBit i || y.testBit i) := by
|
||||
@[simp, grind =] theorem testBit_or (x y i : Nat) : (x ||| y).testBit i = (x.testBit i || y.testBit i) := by
|
||||
simp [HOr.hOr, OrOp.or, lor, testBit_bitwise ]
|
||||
|
||||
@[simp] protected theorem or_self (x : Nat) : x ||| x = x := by
|
||||
@[simp, grind =] protected theorem or_self (x : Nat) : x ||| x = x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
protected theorem or_comm (x y : Nat) : x ||| y = y ||| x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_comm]
|
||||
|
||||
@[grind _=_]
|
||||
protected theorem or_assoc (x y z : Nat) : (x ||| y) ||| z = x ||| (y ||| z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_assoc]
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_or_distrib_left (x y z : Nat) : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_or_distrib_left]
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_distrib_right (x y z : Nat) : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_or_distrib_right]
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_and_distrib_left (x y z : Nat) : x ||| (y &&& z) = (x ||| y) &&& (x ||| z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_and_distrib_left]
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_and_distrib_right (x y z : Nat) : (x &&& y) ||| z = (x ||| z) &&& (y ||| z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.or_and_distrib_right]
|
||||
@@ -610,37 +625,42 @@ theorem or_lt_two_pow {x y n : Nat} (left : x < 2^n) (right : y < 2^n) : x ||| y
|
||||
rw [testBit_or]
|
||||
simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_div_two_pow : (a ||| b) / 2 ^ n = a / 2 ^ n ||| b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_div_two : (a ||| b) / 2 = a / 2 ||| b / 2 :=
|
||||
or_div_two_pow (n := 1)
|
||||
|
||||
@[grind _=_]
|
||||
theorem or_mod_two_pow : (a ||| b) % 2 ^ n = a % 2 ^ n ||| b % 2 ^ n :=
|
||||
bitwise_mod_two_pow
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@[simp] theorem testBit_xor (x y i : Nat) :
|
||||
@[simp, grind =] theorem testBit_xor (x y i : Nat) :
|
||||
(x ^^^ y).testBit i = ((x.testBit i) ^^ (y.testBit i)) := by
|
||||
simp [HXor.hXor, Xor.xor, xor, testBit_bitwise ]
|
||||
|
||||
@[simp] theorem zero_xor (x : Nat) : 0 ^^^ x = x := by
|
||||
@[simp, grind =] theorem zero_xor (x : Nat) : 0 ^^^ x = x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
|
||||
@[simp] theorem xor_zero (x : Nat) : x ^^^ 0 = x := by
|
||||
@[simp, grind =] theorem xor_zero (x : Nat) : x ^^^ 0 = x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
|
||||
@[simp] protected theorem xor_self (x : Nat) : x ^^^ x = 0 := by
|
||||
@[simp, grind =] protected theorem xor_self (x : Nat) : x ^^^ x = 0 := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
protected theorem xor_comm (x y : Nat) : x ^^^ y = y ^^^ x := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.xor_comm]
|
||||
|
||||
@[grind _=_]
|
||||
protected theorem xor_assoc (x y z : Nat) : (x ^^^ y) ^^^ z = x ^^^ (y ^^^ z) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp
|
||||
@@ -658,10 +678,12 @@ instance : Std.LawfulCommIdentity (α := Nat) (· ^^^ ·) 0 where
|
||||
theorem xor_lt_two_pow {x y n : Nat} (left : x < 2^n) (right : y < 2^n) : x ^^^ y < 2^n :=
|
||||
bitwise_lt_two_pow left right
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_xor_distrib_right {a b c : Nat} : (a ^^^ b) &&& c = (a &&& c) ^^^ (b &&& c) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_xor_distrib_right]
|
||||
|
||||
@[grind _=_]
|
||||
theorem and_xor_distrib_left {a b c : Nat} : a &&& (b ^^^ c) = (a &&& b) ^^^ (a &&& c) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp [Bool.and_xor_distrib_left]
|
||||
@@ -671,12 +693,15 @@ theorem and_xor_distrib_left {a b c : Nat} : a &&& (b ^^^ c) = (a &&& b) ^^^ (a
|
||||
rw [testBit_xor]
|
||||
simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem xor_div_two_pow : (a ^^^ b) / 2 ^ n = a / 2 ^ n ^^^ b / 2 ^ n :=
|
||||
bitwise_div_two_pow
|
||||
|
||||
@[grind _=_]
|
||||
theorem xor_div_two : (a ^^^ b) / 2 = a / 2 ^^^ b / 2 :=
|
||||
xor_div_two_pow (n := 1)
|
||||
|
||||
@[grind _=_]
|
||||
theorem xor_mod_two_pow : (a ^^^ b) % 2 ^ n = a % 2 ^ n ^^^ b % 2 ^ n :=
|
||||
bitwise_mod_two_pow
|
||||
|
||||
@@ -713,6 +738,7 @@ theorem testBit_two_pow_mul_add (a : Nat) {b i : Nat} (b_lt : b < 2^i) (j : Nat)
|
||||
@[deprecated testBit_two_pow_mul_add (since := "2025-03-18")]
|
||||
abbrev testBit_mul_pow_two_add := @testBit_two_pow_mul_add
|
||||
|
||||
@[grind =]
|
||||
theorem testBit_two_pow_mul :
|
||||
testBit (2 ^ i * a) j = (decide (j ≥ i) && testBit a (j-i)) := by
|
||||
have gen := testBit_two_pow_mul_add a (Nat.two_pow_pos i) j
|
||||
@@ -721,6 +747,11 @@ theorem testBit_two_pow_mul :
|
||||
cases Nat.lt_or_ge j i with
|
||||
| _ p => simp [p, Nat.not_le_of_lt, Nat.not_lt_of_le]
|
||||
|
||||
@[grind =] -- Ideally `grind` could do this just with `testBit_two_pow_mul`.
|
||||
theorem testBit_mul_two_pow (x j i : Nat) :
|
||||
(x * 2 ^ i).testBit j = (decide (i ≤ j) && x.testBit (j - i)) := by
|
||||
rw [Nat.mul_comm, testBit_two_pow_mul]
|
||||
|
||||
@[deprecated testBit_two_pow_mul (since := "2025-03-18")]
|
||||
abbrev testBit_mul_pow_two := @testBit_two_pow_mul
|
||||
|
||||
@@ -744,21 +775,17 @@ abbrev mul_add_lt_is_or := @two_pow_add_eq_or_of_lt
|
||||
|
||||
/-! ### shiftLeft and shiftRight -/
|
||||
|
||||
@[simp] theorem testBit_shiftLeft (x : Nat) : testBit (x <<< i) j =
|
||||
@[simp, grind =] theorem testBit_shiftLeft (x : Nat) : testBit (x <<< i) j =
|
||||
(decide (j ≥ i) && testBit x (j-i)) := by
|
||||
simp [shiftLeft_eq, Nat.mul_comm _ (2^_), testBit_two_pow_mul]
|
||||
|
||||
@[simp] theorem testBit_shiftRight (x : Nat) : testBit (x >>> i) j = testBit x (i+j) := by
|
||||
@[simp, grind =] theorem testBit_shiftRight (x : Nat) : testBit (x >>> i) j = testBit x (i+j) := by
|
||||
simp [testBit, ←shiftRight_add]
|
||||
|
||||
@[simp] theorem shiftLeft_mod_two_eq_one : x <<< i % 2 = 1 ↔ i = 0 ∧ x % 2 = 1 := by
|
||||
rw [mod_two_eq_one_iff_testBit_zero, testBit_shiftLeft]
|
||||
simp
|
||||
|
||||
theorem testBit_mul_two_pow (x i n : Nat) :
|
||||
(x * 2 ^ n).testBit i = (decide (n ≤ i) && x.testBit (i - n)) := by
|
||||
rw [← testBit_shiftLeft, shiftLeft_eq]
|
||||
|
||||
theorem bitwise_mul_two_pow (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f x y) * 2 ^ n = bitwise f (x * 2 ^ n) (y * 2 ^ n) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
@@ -768,16 +795,20 @@ theorem bitwise_mul_two_pow (of_false_false : f false false = false := by rfl) :
|
||||
· simp [hn]
|
||||
· simp [hn, of_false_false]
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftLeft_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f a b) <<< i = bitwise f (a <<< i) (b <<< i) := by
|
||||
simp [shiftLeft_eq, bitwise_mul_two_pow of_false_false]
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftLeft_and_distrib {a b : Nat} : (a &&& b) <<< i = a <<< i &&& b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftLeft_or_distrib {a b : Nat} : (a ||| b) <<< i = a <<< i ||| b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftLeft_xor_distrib {a b : Nat} : (a ^^^ b) <<< i = a <<< i ^^^ b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
@@ -786,16 +817,20 @@ theorem shiftLeft_xor_distrib {a b : Nat} : (a ^^^ b) <<< i = a <<< i ^^^ b <<<
|
||||
simp only [testBit, one_and_eq_mod_two, mod_two_bne_zero]
|
||||
exact (Bool.beq_eq_decide_eq _ _).symm
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftRight_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f a b) >>> i = bitwise f (a >>> i) (b >>> i) := by
|
||||
simp [shiftRight_eq_div_pow, bitwise_div_two_pow of_false_false]
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftRight_and_distrib {a b : Nat} : (a &&& b) >>> i = a >>> i &&& b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftRight_or_distrib {a b : Nat} : (a ||| b) >>> i = a >>> i ||| b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
@[grind _=_]
|
||||
theorem shiftRight_xor_distrib {a b : Nat} : (a ^^^ b) >>> i = a >>> i ^^^ b >>> i :=
|
||||
shiftRight_bitwise_distrib
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
import Init.WF
|
||||
import Init.WFTactics
|
||||
import Init.Data.Nat.Basic
|
||||
meta import Init.MetaTypes
|
||||
|
||||
@[expose] section
|
||||
|
||||
@@ -75,7 +76,7 @@ private theorem div.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x <
|
||||
termination_by structural fuel1
|
||||
|
||||
theorem div_eq (x y : Nat) : x / y = if 0 < y ∧ y ≤ x then (x - y) / y + 1 else 0 := by
|
||||
show Nat.div _ _ = ite _ (Nat.div _ _ + 1) _
|
||||
change Nat.div _ _ = ite _ (Nat.div _ _ + 1) _
|
||||
unfold Nat.div
|
||||
split
|
||||
next =>
|
||||
@@ -257,7 +258,7 @@ protected def mod : @& Nat → @& Nat → Nat
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
show Nat.modCore n m = Nat.mod n m
|
||||
change Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
| 0, _ =>
|
||||
rw [Nat.modCore_eq]
|
||||
@@ -521,7 +522,7 @@ theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p -
|
||||
rw [Nat.mul_sub_right_distrib, Nat.mul_comm]
|
||||
exact Nat.sub_le_sub_left ((div_lt_iff_lt_mul npos).1 (lt_succ_self _)) _
|
||||
focus
|
||||
show succ (pred (n * p - x)) ≤ (succ (pred (p - x / n))) * n
|
||||
change succ (pred (n * p - x)) ≤ (succ (pred (p - x / n))) * n
|
||||
rw [succ_pred_eq_of_pos (Nat.sub_pos_of_lt h₁),
|
||||
fun h => succ_pred_eq_of_pos (Nat.sub_pos_of_lt h)] -- TODO: why is the function needed?
|
||||
focus
|
||||
|
||||
@@ -210,4 +210,19 @@ theorem mod_mod_eq_mod_mod_mod_of_dvd {a b c : Nat} (hb : b ∣ c) :
|
||||
have : b < c := Nat.lt_of_le_of_ne (Nat.le_of_dvd hc hb) hb'
|
||||
rw [Nat.mod_mod_of_dvd' hb, Nat.mod_eq_of_lt this, Nat.mod_mod_of_dvd _ hb]
|
||||
|
||||
theorem mod_eq_mod_iff {x y z : Nat} :
|
||||
x % z = y % z ↔ ∃ k₁ k₂, x + k₁ * z = y + k₂ * z := by
|
||||
constructor
|
||||
· rw [Nat.mod_def, Nat.mod_def]
|
||||
rw [Nat.sub_eq_iff_eq_add, Nat.add_comm, ← Nat.add_sub_assoc, eq_comm, Nat.sub_eq_iff_eq_add, eq_comm]
|
||||
· intro h
|
||||
refine ⟨(y / z), (x / z), ?_⟩
|
||||
rwa [Nat.mul_comm z, Nat.add_comm _ y, Nat.mul_comm z] at h
|
||||
· exact le_add_left_of_le (mul_div_le y z)
|
||||
· exact mul_div_le y z
|
||||
· exact mul_div_le x z
|
||||
· rintro ⟨k₁, k₂, h⟩
|
||||
replace h := congrArg (· % z) h
|
||||
simpa using h
|
||||
|
||||
end Nat
|
||||
|
||||
@@ -1772,6 +1772,12 @@ instance decidableExistsLE' {p : (m : Nat) → m ≤ k → Prop} [I : ∀ m h, D
|
||||
intro
|
||||
exact ⟨fun ⟨h, w⟩ => ⟨le_of_lt_succ h, w⟩, fun ⟨h, w⟩ => ⟨lt_add_one_of_le h, w⟩⟩
|
||||
|
||||
instance decidableExistsFin (P : Fin n → Prop) [DecidablePred P] : Decidable (∃ i, P i) :=
|
||||
decidable_of_iff (∃ k, k < n ∧ ((h: k < n) → P ⟨k, h⟩))
|
||||
⟨fun ⟨k, a⟩ => Exists.intro ⟨k, a.left⟩ (a.right a.left),
|
||||
fun ⟨i, e⟩ => Exists.intro i.val ⟨i.isLt, fun _ => e⟩⟩
|
||||
|
||||
|
||||
/-! ### Results about `List.sum` specialized to `Nat` -/
|
||||
|
||||
protected theorem sum_pos_iff_exists_pos {l : List Nat} : 0 < l.sum ↔ ∃ x ∈ l, 0 < x := by
|
||||
|
||||
@@ -149,7 +149,7 @@ instance : LawfulBEq PolyCnstr where
|
||||
rw [h₁, h₂, h₃]
|
||||
rfl {a} := by
|
||||
cases a; rename_i eq lhs rhs
|
||||
show (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
simp
|
||||
|
||||
structure ExprCnstr where
|
||||
|
||||
@@ -85,4 +85,4 @@ theorem Membership.get_elem_helper {i n : Nat} {r : Std.Range} (h₁ : i ∈ r)
|
||||
i < n := h₂ ▸ h₁.2.1
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
|
||||
| `(tactic| get_elem_tactic_extensible) => `(tactic| apply Membership.get_elem_helper; assumption; rfl)
|
||||
|
||||
@@ -342,11 +342,12 @@ instance : Repr Int where
|
||||
def hexDigitRepr (n : Nat) : String :=
|
||||
String.singleton <| Nat.digitChar n
|
||||
|
||||
def Char.quoteCore (c : Char) : String :=
|
||||
def Char.quoteCore (c : Char) (inString : Bool := false) : String :=
|
||||
if c = '\n' then "\\n"
|
||||
else if c = '\t' then "\\t"
|
||||
else if c = '\\' then "\\\\"
|
||||
else if c = '\"' then "\\\""
|
||||
else if !inString && c = '\'' then "\\\'"
|
||||
else if c.toNat <= 31 ∨ c = '\x7f' then "\\x" ++ smallCharToHex c
|
||||
else String.singleton c
|
||||
where
|
||||
@@ -383,7 +384,7 @@ Examples:
|
||||
-/
|
||||
def String.quote (s : String) : String :=
|
||||
if s.isEmpty then "\"\""
|
||||
else s.foldl (fun s c => s ++ c.quoteCore) "\"" ++ "\""
|
||||
else s.foldl (fun s c => s ++ c.quoteCore (inString := true)) "\"" ++ "\""
|
||||
|
||||
instance : Repr String where
|
||||
reprPrec s _ := s.quote
|
||||
|
||||
@@ -9,8 +9,8 @@ prelude
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
import all Init.Data.SInt.Basic
|
||||
import all Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Bitblast
|
||||
import all Init.Data.BitVec.Lemmas
|
||||
import Init.Data.Int.LemmasAux
|
||||
import all Init.Data.UInt.Basic
|
||||
import Init.Data.UInt.Lemmas
|
||||
|
||||
@@ -586,7 +586,7 @@ decreasing_by
|
||||
focus
|
||||
rename_i i₀ j₀ _ eq h'
|
||||
rw [show (s.next i₀ - sep.next j₀).1 = (i₀ - j₀).1 by
|
||||
show (_ + Char.utf8Size _) - (_ + Char.utf8Size _) = _
|
||||
change (_ + Char.utf8Size _) - (_ + Char.utf8Size _) = _
|
||||
rw [(beq_iff_eq ..).1 eq, Nat.add_sub_add_right]; rfl]
|
||||
right; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.le_add_right ..) (Nat.gt_of_not_le (mt decide_eq_true h')))
|
||||
|
||||
@@ -295,11 +295,11 @@ where
|
||||
termination_by text.utf8ByteSize - pos.byteIdx
|
||||
decreasing_by
|
||||
decreasing_with
|
||||
show text.utf8ByteSize - (text.next (text.next pos)).byteIdx < text.utf8ByteSize - pos.byteIdx
|
||||
change text.utf8ByteSize - (text.next (text.next pos)).byteIdx < text.utf8ByteSize - pos.byteIdx
|
||||
have k := Nat.gt_of_not_le <| mt decide_eq_true h
|
||||
exact Nat.sub_lt_sub_left k (Nat.lt_trans (String.lt_next text pos) (String.lt_next _ _))
|
||||
decreasing_with
|
||||
show text.utf8ByteSize - (text.next pos).byteIdx < text.utf8ByteSize - pos.byteIdx
|
||||
change text.utf8ByteSize - (text.next pos).byteIdx < text.utf8ByteSize - pos.byteIdx
|
||||
have k := Nat.gt_of_not_le <| mt decide_eq_true h
|
||||
exact Nat.sub_lt_sub_left k (String.lt_next _ _)
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Meta
|
||||
import Init.Data.ToString.Basic
|
||||
meta import Init.Meta
|
||||
|
||||
syntax:max "s!" interpolatedStr(term) : term
|
||||
|
||||
|
||||
@@ -10,10 +10,9 @@ import all Init.Data.UInt.Basic
|
||||
import all Init.Data.UInt.BasicAux
|
||||
import Init.Data.Fin.Lemmas
|
||||
import all Init.Data.Fin.Bitwise
|
||||
import all Init.Data.BitVec.Basic
|
||||
import all Init.Data.BitVec.BasicAux
|
||||
import all Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Bitblast
|
||||
import Init.Data.Nat.Div.Lemmas
|
||||
import Init.System.Platform
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Authors: Shreyas Srinivas, François G. Dorais, Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
meta import Init.Coe
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Array.InsertIdx
|
||||
|
||||
@@ -40,6 +40,7 @@ theorem countP_push {a : α} {xs : Vector α n} : countP p (xs.push a) = countP
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.countP_push]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_singleton {a : α} : countP p #v[a] = if p a then 1 else 0 := by
|
||||
simp
|
||||
|
||||
@@ -51,7 +52,7 @@ theorem countP_le_size {xs : Vector α n} : countP p xs ≤ n := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.countP_le_size (p := p)]
|
||||
|
||||
@[simp] theorem countP_append {xs : Vector α n} {ys : Vector α m} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
@[simp, grind =] theorem countP_append {xs : Vector α n} {ys : Vector α m} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
@@ -116,7 +117,7 @@ theorem countP_flatMap {p : β → Bool} {xs : Vector α n} {f : α → Vector
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.countP_flatMap, Function.comp_def]
|
||||
|
||||
@[simp] theorem countP_reverse {xs : Vector α n} : countP p xs.reverse = countP p xs := by
|
||||
@[simp, grind =] theorem countP_reverse {xs : Vector α n} : countP p xs.reverse = countP p xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@@ -136,7 +137,7 @@ section count
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem count_empty {a : α} : count a #v[] = 0 := rfl
|
||||
@[simp, grind =] theorem count_empty {a : α} : count a #v[] = 0 := rfl
|
||||
|
||||
theorem count_push {a b : α} {xs : Vector α n} :
|
||||
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
|
||||
@@ -151,23 +152,25 @@ theorem count_eq_countP' {a : α} : count (n := n) a = countP (· == a) := by
|
||||
|
||||
theorem count_le_size {a : α} {xs : Vector α n} : count a xs ≤ n := countP_le_size
|
||||
|
||||
grind_pattern count_le_size => count a xs
|
||||
|
||||
theorem count_le_count_push {a b : α} {xs : Vector α n} : count a xs ≤ count a (xs.push b) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.count_push]
|
||||
|
||||
@[simp] theorem count_singleton {a b : α} : count a #v[b] = if b == a then 1 else 0 := by
|
||||
@[simp, grind =] theorem count_singleton {a b : α} : count a #v[b] = if b == a then 1 else 0 := by
|
||||
simp [count_eq_countP]
|
||||
|
||||
@[simp] theorem count_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
@[simp, grind =] theorem count_append {a : α} {xs : Vector α n} {ys : Vector α m} :
|
||||
count a (xs ++ ys) = count a xs + count a ys :=
|
||||
countP_append ..
|
||||
|
||||
@[simp] theorem count_flatten {a : α} {xss : Vector (Vector α m) n} :
|
||||
@[simp, grind =] theorem count_flatten {a : α} {xss : Vector (Vector α m) n} :
|
||||
count a xss.flatten = (xss.map (count a)).sum := by
|
||||
rcases xss with ⟨xss, rfl⟩
|
||||
simp [Array.count_flatten, Function.comp_def]
|
||||
|
||||
@[simp] theorem count_reverse {a : α} {xs : Vector α n} : count a xs.reverse = count a xs := by
|
||||
@[simp, grind =] theorem count_reverse {a : α} {xs : Vector α n} : count a xs.reverse = count a xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
|
||||
@@ -22,11 +22,13 @@ open Nat
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_eq_take_drop_succ {xs : Vector α n} {i : Nat} (h) :
|
||||
xs.eraseIdx i = (xs.take i ++ xs.drop (i + 1)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.eraseIdx_eq_take_drop_succ, *]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_eraseIdx {xs : Vector α n} {i : Nat} (h : i < n) {j : Nat} :
|
||||
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -44,12 +46,14 @@ theorem getElem?_eraseIdx_of_ge {xs : Vector α n} {i : Nat} (h : i < n) {j : Na
|
||||
intro h'
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_eraseIdx {xs : Vector α n} {i : Nat} (h : i < n) {j : Nat} (h' : j < n - 1) :
|
||||
(xs.eraseIdx i)[j] = if h'' : j < i then xs[j] else xs[j + 1] := by
|
||||
apply Option.some.inj
|
||||
rw [← getElem?_eq_getElem, getElem?_eraseIdx]
|
||||
split <;> simp
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseIdx {xs : Vector α n} {i : Nat} {h} {a : α} (h : a ∈ xs.eraseIdx i) : a ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simpa using Array.mem_of_mem_eraseIdx (by simpa using h)
|
||||
@@ -64,13 +68,23 @@ theorem eraseIdx_append_of_length_le {xs : Vector α n} {k : Nat} (hk : n ≤ k)
|
||||
eraseIdx (xs ++ xs') k = (xs ++ eraseIdx xs' (k - n)).cast (by omega) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases xs' with ⟨xs'⟩
|
||||
simp [Array.eraseIdx_append_of_length_le, *]
|
||||
simp [Array.eraseIdx_append_of_size_le, *]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_append {xs : Vector α n} {ys : Vector α m} {k : Nat} (h : k < n + m) :
|
||||
eraseIdx (xs ++ ys) k = if h' : k < n then (eraseIdx xs k ++ ys).cast (by omega) else (xs ++ eraseIdx ys (k - n) (by omega)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp only [mk_append_mk, eraseIdx_mk, Array.eraseIdx_append]
|
||||
split <;> simp
|
||||
|
||||
@[grind = ]
|
||||
theorem eraseIdx_cast {xs : Vector α n} {k : Nat} (h : k < m) :
|
||||
eraseIdx (xs.cast w) k h = (eraseIdx xs k).cast (by omega) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
(replicate n a).eraseIdx k = replicate (n - 1) a := by
|
||||
rw [replicate_eq_mk_replicate, eraseIdx_mk]
|
||||
@@ -112,6 +126,45 @@ theorem eraseIdx_set_gt {xs : Vector α n} {i : Nat} {j : Nat} {a : α} (h : i <
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.eraseIdx_set_gt, *]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_set {xs : Vector α n} {i : Nat} {a : α} {hi : i < n} {j : Nat} {hj : j < n} :
|
||||
(xs.set i a).eraseIdx j =
|
||||
if h' : j < i then
|
||||
(xs.eraseIdx j).set (i - 1) a
|
||||
else if h'' : j = i then
|
||||
xs.eraseIdx i
|
||||
else
|
||||
(xs.eraseIdx j).set i a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [set_mk, eraseIdx_mk, Array.eraseIdx_set]
|
||||
split
|
||||
· simp
|
||||
· split <;> simp
|
||||
|
||||
theorem set_eraseIdx_le {xs : Vector α n} {i : Nat} {w : i < n} {j : Nat} {a : α} (h : i ≤ j) (hj : j < n - 1) :
|
||||
(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 : Vector α n} {i : Nat} {w : i < n} {j : Nat} {a : α} (h : j < i) (hj : j < n - 1) :
|
||||
(xs.eraseIdx i).set j a = (xs.set j a).eraseIdx i := by
|
||||
rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_eraseIdx {xs : Vector α n} {i : Nat} {w : i < n} {j : Nat} {a : α} (hj : j < n - 1) :
|
||||
(xs.eraseIdx i).set j a =
|
||||
if h' : 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
|
||||
{xs : Vector α n} {i : Nat} (h : i + 1 < n) :
|
||||
(xs.eraseIdx (i + 1)).set i xs[i + 1] = xs.eraseIdx i := by
|
||||
|
||||
@@ -28,19 +28,19 @@ set_option linter.indexVariables false
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp [h]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_push {xs : Vector α n} {b : α} {start stop : Nat} (h : stop ≤ n) :
|
||||
(xs.push b).extract start stop = (xs.extract start stop).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [h]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_eq_pop {xs : Vector α n} {stop : Nat} (h : stop = n - 1) :
|
||||
xs.extract 0 stop = xs.pop.cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [h]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind _=_]
|
||||
theorem extract_append_extract {xs : Vector α n} {i j k : Nat} :
|
||||
xs.extract i j ++ xs.extract j k =
|
||||
(xs.extract (min i j) (max j k)).cast (by omega) := by
|
||||
@@ -79,11 +79,12 @@ theorem getElem?_extract_of_succ {xs : Vector α n} {j : Nat} :
|
||||
· rw [if_neg (by omega)]
|
||||
simp_all
|
||||
|
||||
@[simp] theorem extract_extract {xs : Vector α n} {i j k l : Nat} :
|
||||
@[simp, grind =] theorem extract_extract {xs : Vector α n} {i j k l : Nat} :
|
||||
(xs.extract i j).extract k l = (xs.extract (i + k) (min (i + l) j)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem extract_set {xs : Vector α n} {i j k : Nat} (h : k < n) {a : α} :
|
||||
(xs.set k a).extract i j =
|
||||
if _ : k < i then
|
||||
@@ -97,12 +98,13 @@ theorem extract_set {xs : Vector α n} {i j k : Nat} (h : k < n) {a : α} :
|
||||
· simp
|
||||
· split <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem set_extract {xs : Vector α n} {i j k : Nat} (h : k < min j n - i) {a : α} :
|
||||
(xs.extract i j).set k a = (xs.set (i + k) a).extract i j := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.set_extract]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem extract_append {xs : Vector α n} {ys : Vector α m} {i j : Nat} :
|
||||
(xs ++ ys).extract i j =
|
||||
(xs.extract i j ++ ys.extract (i - n) (j - n)).cast (by omega) := by
|
||||
@@ -128,12 +130,12 @@ theorem extract_append_left {xs : Vector α n} {ys : Vector α m} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[simp] theorem map_extract {xs : Vector α n} {i j : Nat} :
|
||||
@[simp, grind =] theorem map_extract {xs : Vector α n} {i j : Nat} :
|
||||
(xs.extract i j).map f = (xs.map f).extract i j := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[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 i h
|
||||
simp
|
||||
@@ -161,6 +163,7 @@ theorem set_eq_push_extract_append_extract {xs : Vector α n} {i : Nat} (h : i <
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp [Array.set_eq_push_extract_append_extract, h]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_reverse {xs : Vector α n} {i j : Nat} :
|
||||
xs.reverse.extract i j = (xs.extract (n - j) (n - i)).reverse.cast (by omega) := by
|
||||
ext i h
|
||||
@@ -168,6 +171,7 @@ theorem extract_reverse {xs : Vector α n} {i j : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_extract {xs : Vector α n} {i j : Nat} :
|
||||
(xs.extract i j).reverse = (xs.reverse.extract (n - j) (n - i)).cast (by omega) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Vector
|
||||
/-- `finRange n` is the vector of all elements of `Fin n` in order. -/
|
||||
protected def finRange (n : Nat) : Vector (Fin n) n := ofFn fun i => i
|
||||
|
||||
@[simp] theorem getElem_finRange {i : Nat} (h : i < n) :
|
||||
@[simp, grind =] theorem getElem_finRange {i : Nat} (h : i < n) :
|
||||
(Vector.finRange n)[i] = ⟨i, h⟩ := by
|
||||
simp [Vector.finRange]
|
||||
|
||||
@@ -39,6 +39,7 @@ theorem finRange_succ_last {n} :
|
||||
· simp_all
|
||||
omega
|
||||
|
||||
@[grind _=_]
|
||||
theorem finRange_reverse {n} : (Vector.finRange n).reverse = (Vector.finRange n).map Fin.rev := by
|
||||
ext i h
|
||||
simp
|
||||
|
||||
@@ -44,12 +44,23 @@ theorem findSome?_singleton {a : α} {f : α → Option β} : #v[a].findSome? f
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp only [push_mk, findSomeRev?_mk, Array.findSomeRev?_push_of_isNone, h]
|
||||
|
||||
@[grind =]
|
||||
theorem findSomeRev?_push {xs : Vector α n} {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 : Vector α n} (w : xs.findSome? f = some b) :
|
||||
∃ a, a ∈ xs ∧ f a = some b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simpa using Array.exists_of_findSome?_eq_some (by simpa using w)
|
||||
|
||||
@[simp] theorem findSome?_eq_none_iff {f : α → Option β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem findSome?_eq_none_iff {f : α → Option β} {xs : Vector α n} :
|
||||
xs.findSome? f = none ↔ ∀ x ∈ xs, f x = none := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -72,24 +83,27 @@ theorem findSome?_eq_some_iff {f : α → Option β} {xs : Vector α n} {b : β}
|
||||
· rintro ⟨k₁, k₂, h, ys, a, zs, w, h₁, h₂⟩
|
||||
exact ⟨ys.toArray, a, zs.toArray, by simp [w], h₁, by simpa using h₂⟩
|
||||
|
||||
@[simp] theorem findSome?_guard {xs : Vector α n} : findSome? (Option.guard fun x => p x) xs = find? p xs := by
|
||||
@[simp, grind =] theorem findSome?_guard {xs : Vector α n} : findSome? (Option.guard p) xs = find? p xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
theorem find?_eq_findSome?_guard {xs : Vector α n} : find? p xs = findSome? (Option.guard fun x => p x) xs :=
|
||||
theorem find?_eq_findSome?_guard {xs : Vector α n} : find? p xs = findSome? (Option.guard p) xs :=
|
||||
findSome?_guard.symm
|
||||
|
||||
@[simp] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Vector α n} :
|
||||
(xs.findSome? f).map g = xs.findSome? (Option.map g ∘ f) := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem findSome?_map {f : β → γ} {xs : Vector β n} : findSome? p (xs.map f) = xs.findSome? (p ∘ f) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.findSome?_map]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_append {xs : Vector α n₁} {ys : Vector α n₂} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
|
||||
cases xs; cases ys; simp [Array.findSome?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_zero_flatten {xss : Vector (Vector α m) n} :
|
||||
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
|
||||
cases xss using vector₂_induction
|
||||
@@ -106,12 +120,14 @@ theorem getElem_zero_flatten.proof {xss : Vector (Vector α m) n} (h : 0 < n * m
|
||||
Option.isSome_some, and_true]
|
||||
exact ⟨⟨xss[0], h₂ _ (by simp)⟩, by simp⟩
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_zero_flatten {xss : Vector (Vector α m) n} (h : 0 < n * m) :
|
||||
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
|
||||
have t := getElem?_zero_flatten (xss := xss)
|
||||
simp [getElem?_eq_getElem, h] at t
|
||||
simp [← t]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
rw [replicate_eq_mk_replicate, findSome?_mk, Array.findSome?_replicate]
|
||||
|
||||
@@ -142,9 +158,9 @@ abbrev findSome?_mkVector_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp] theorem find?_empty : find? p #v[] = none := rfl
|
||||
@[simp, grind =] theorem find?_empty : find? p #v[] = none := rfl
|
||||
|
||||
theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
@[grind =]theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
#v[a].find? p = if p a then some a else none := by
|
||||
simp
|
||||
|
||||
@@ -152,11 +168,23 @@ 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 : Vector α n} (h : ¬p a) :
|
||||
@[simp] theorem findRev?_push_of_neg {xs : Vector α n} (h : ¬p a) :
|
||||
findRev? p (xs.push a) = findRev? p xs := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ 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 : Vector α n} :
|
||||
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]
|
||||
|
||||
@[simp, grind =] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
cases l; simp
|
||||
|
||||
theorem find?_eq_some_iff_append {xs : Vector α n} :
|
||||
@@ -181,35 +209,38 @@ theorem find?_push_eq_some {xs : Vector α n} :
|
||||
(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 : Vector α n} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
@[simp, grind =] theorem find?_isSome {xs : Vector α n} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind →]
|
||||
theorem find?_some {xs : Vector α n} (h : find? p xs = some a) : p a := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp at h
|
||||
exact Array.find?_some h
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a ∈ xs := by
|
||||
cases xs
|
||||
simp at h
|
||||
simpa using Array.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [Array.get_find?_mem]
|
||||
|
||||
@[simp] theorem find?_map {f : β → α} {xs : Vector β n} :
|
||||
@[simp, grind =] theorem find?_map {f : β → α} {xs : Vector β n} :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_append {xs : Vector α n₁} {ys : Vector α n₂} :
|
||||
@[simp, grind =] theorem find?_append {xs : Vector α n₁} {ys : Vector α n₂} :
|
||||
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_flatten {xs : Vector (Vector α m) n} {p : α → Bool} :
|
||||
xs.flatten.find? p = xs.findSome? (·.find? p) := by
|
||||
@[simp, grind =] theorem find?_flatten {xs : Vector (Vector α m) n} {p : α → Bool} :
|
||||
xs.flatten.find? p = xs.findSome? (find? p) := by
|
||||
cases xs using vector₂_induction
|
||||
simp [Array.findSome?_map, Function.comp_def]
|
||||
|
||||
@@ -217,7 +248,7 @@ theorem find?_flatten_eq_none_iff {xs : Vector (Vector α m) n} {p : α → Bool
|
||||
xs.flatten.find? p = none ↔ ∀ ys ∈ xs, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
@[simp, grind =] theorem find?_flatMap {xs : Vector α n} {f : α → Vector β m} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
simp [Array.find?_flatMap, Array.flatMap_toArray]
|
||||
@@ -227,6 +258,7 @@ theorem find?_flatMap_eq_none_iff {xs : Vector α n} {f : α → Vector β m} {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
|
||||
rw [replicate_eq_mk_replicate, find?_mk, Array.find?_replicate]
|
||||
@@ -278,6 +310,7 @@ abbrev find?_mkVector_eq_some_iff := @find?_replicate_eq_some_iff
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkVector := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Vector α n}
|
||||
(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
|
||||
@@ -291,8 +324,10 @@ theorem find?_eq_some_iff_getElem {xs : Vector α n} {p : α → Bool} {b : α}
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p (#v[] : Vector α 0) = 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
|
||||
@@ -302,6 +337,12 @@ theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem findFinIdx?_eq_none_iff {xs : Vector α n} {p : α → Bool} :
|
||||
xs.findFinIdx? p = none ↔ ∀ x, x ∈ xs → ¬ p x := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.findFinIdx?_eq_none_iff]
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_push {xs : Vector α n} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map Fin.castSucc).or (if p a then some ⟨n, by simp⟩ else none) := by
|
||||
@@ -309,6 +350,7 @@ theorem findFinIdx?_push {xs : Vector α n} {a : α} {p : α → Bool} :
|
||||
simp [Array.findFinIdx?_push, Option.map_or, Function.comp_def]
|
||||
congr
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_append {xs : Vector α n₁} {ys : Vector α n₂} {p : α → Bool} :
|
||||
(xs ++ ys).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or
|
||||
@@ -317,13 +359,13 @@ theorem findFinIdx?_append {xs : Vector α n₁} {ys : Vector α n₂} {p : α
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.findFinIdx?_append, Option.map_or, Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isSome_findFinIdx? {xs : Vector α n} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem isNone_findFinIdx? {xs : Vector α n} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -30,15 +30,20 @@ section InsertIdx
|
||||
|
||||
variable {a : α}
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem insertIdx_zero {xs : Vector α n} {x : α} : xs.insertIdx 0 x = (#v[x] ++ xs).cast (by omega) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Vector α n} {h : i ≤ n} :
|
||||
theorem eraseIdx_insertIdx_self {i : Nat} {xs : Vector α n} {h : i ≤ n} :
|
||||
(xs.insertIdx i a).eraseIdx i = xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp_all [Array.eraseIdx_insertIdx]
|
||||
simp_all [Array.eraseIdx_insertIdx_self]
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-15")]
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Vector α n} {h : i ≤ n} :
|
||||
(xs.insertIdx i a).eraseIdx i = xs := by
|
||||
simp [eraseIdx_insertIdx_self]
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge {xs : Vector α n}
|
||||
(w₁ : i < n) (w₂ : j ≤ n - 1) (h : i ≤ j) :
|
||||
@@ -54,6 +59,18 @@ theorem insertIdx_eraseIdx_of_le {xs : Vector α n}
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simpa using Array.insertIdx_eraseIdx_of_le (by simpa) (by simpa) (by simpa)
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_eraseIdx {as : Vector α n} (h₁ : i < n) (h₂ : j ≤ n - 1) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
if h : i ≤ j then
|
||||
((as.insertIdx (j + 1) a).eraseIdx i).cast (by omega)
|
||||
else
|
||||
((as.insertIdx j a).eraseIdx (i + 1) (by simp_all)).cast (by omega) := 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 : Vector α n} (_ : i ≤ j) (_ : j ≤ n) :
|
||||
(xs.insertIdx i a).insertIdx (j + 1) b =
|
||||
(xs.insertIdx j b).insertIdx i a := by
|
||||
@@ -70,6 +87,7 @@ theorem insertIdx_size_self {xs : Vector α n} {x : α} : xs.insertIdx n x = xs.
|
||||
rcases xs with ⟨as, rfl⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {xs : Vector α n} {x : α} {i k : Nat} (w : i ≤ n) (h : k < n + 1) :
|
||||
(xs.insertIdx i x)[k] =
|
||||
if h₁ : k < i then
|
||||
@@ -98,6 +116,7 @@ theorem getElem_insertIdx_of_gt {xs : Vector α n} {x : α} {i k : Nat} (w : k
|
||||
simp [Array.getElem_insertIdx, w, h]
|
||||
rw [dif_neg (by omega), dif_neg (by omega)]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_insertIdx {xs : Vector α n} {x : α} {i k : Nat} (h : i ≤ n) :
|
||||
(xs.insertIdx i x)[k]? =
|
||||
if k < i then
|
||||
|
||||
@@ -2538,23 +2538,23 @@ theorem foldr_hom (f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ :
|
||||
rw [Array.foldr_hom _ H]
|
||||
|
||||
/--
|
||||
We can prove that two folds over the same array are related (by some arbitrary relation)
|
||||
if we know that the initial elements are related and the folding function, for each element of the array,
|
||||
preserves the relation.
|
||||
We can prove that two folds over the same vector are related (by some arbitrary relation)
|
||||
if we know that the initial elements are related and the folding function, for each element of the
|
||||
vector, preserves the relation.
|
||||
-/
|
||||
theorem foldl_rel {xs : Vector α n} {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 : Vector α n} {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, rfl⟩
|
||||
simpa using Array.foldl_rel h (by simpa using h')
|
||||
|
||||
/--
|
||||
We can prove that two folds over the same array are related (by some arbitrary relation)
|
||||
if we know that the initial elements are related and the folding function, for each element of the array,
|
||||
preserves the relation.
|
||||
We can prove that two folds over the same vector are related (by some arbitrary relation)
|
||||
if we know that the initial elements are related and the folding function, for each element of the
|
||||
vector, preserves the relation.
|
||||
-/
|
||||
theorem foldr_rel {xs : Vector α n} {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 : Vector α n} {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, rfl⟩
|
||||
simpa using Array.foldr_rel h (by simpa using h')
|
||||
@@ -3076,7 +3076,7 @@ theorem getElem_push_last {xs : Vector α n} {x : α} : (xs.push x)[n] = x := by
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
@[simp] theorem getElem_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} {i : Nat}
|
||||
@[simp, grind =] theorem getElem_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} {i : Nat}
|
||||
(hi : i < n) : (zipWith f as bs)[i] = f as[i] bs[i] := by
|
||||
cases as
|
||||
cases bs
|
||||
|
||||
@@ -19,13 +19,13 @@ namespace Vector
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {i : Nat}
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {i : Nat}
|
||||
(h : i < n) :
|
||||
(xs.mapFinIdx f)[i] = f i xs[i] h := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapFinIdx {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {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, getElem_mapFinIdx]
|
||||
@@ -33,12 +33,12 @@ namespace Vector
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp] theorem getElem_mapIdx {f : Nat → α → β} {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
@[simp, grind =] theorem getElem_mapIdx {f : Nat → α → β} {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Vector α n} {i : Nat} :
|
||||
@[simp, grind =] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Vector α n} {i : Nat} :
|
||||
(xs.mapIdx f)[i]? = xs[i]?.map (f i) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -47,11 +47,11 @@ end Vector
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem mapFinIdx_toVector {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp, grind =] theorem mapFinIdx_toVector {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
xs.toVector.mapFinIdx f = (xs.mapFinIdx f).toVector.cast (by simp) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_toVector {f : Nat → α → β} {xs : Array α} :
|
||||
@[simp, grind =] theorem mapIdx_toVector {f : Nat → α → β} {xs : Array α} :
|
||||
xs.toVector.mapIdx f = (xs.mapIdx f).toVector.cast (by simp) := by
|
||||
ext <;> simp
|
||||
|
||||
@@ -61,12 +61,12 @@ namespace Vector
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp] theorem toList_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
@[simp, grind =] theorem toList_zipIdx {xs : Vector α n} (k : Nat := 0) :
|
||||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_zipIdx {xs : Vector α n} {i : Nat} {h : i < n} :
|
||||
@[simp, grind =] theorem getElem_zipIdx {xs : Vector α n} {i : Nat} {h : i < n} :
|
||||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -116,7 +116,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 #v[] f = #v[] :=
|
||||
rfl
|
||||
|
||||
@@ -125,6 +125,7 @@ theorem mapFinIdx_eq_ofFn {as : Vector α n} {f : (i : Nat) → α → (h : i <
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp [Array.mapFinIdx_eq_ofFn]
|
||||
|
||||
@[grind =]
|
||||
theorem mapFinIdx_append {xs : Vector α n} {ys : Vector α m} {f : (i : Nat) → α → (h : i < n + m) → β} :
|
||||
(xs ++ ys).mapFinIdx f =
|
||||
xs.mapFinIdx (fun i a h => f i a (by omega)) ++
|
||||
@@ -133,7 +134,7 @@ theorem mapFinIdx_append {xs : Vector α n} {ys : Vector α m} {f : (i : Nat)
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.mapFinIdx_append]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapFinIdx_push {xs : Vector α n} {a : α} {f : (i : Nat) → α → (h : i < n + 1) → β} :
|
||||
mapFinIdx (xs.push a) f =
|
||||
(mapFinIdx xs (fun i a h => f i a (by omega))).push (f n a (by simp)) := by
|
||||
@@ -154,7 +155,7 @@ theorem exists_of_mem_mapFinIdx {b : β} {xs : Vector α n} {f : (i : Nat) →
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
@[simp, grind =] theorem mem_mapFinIdx {b : β} {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
b ∈ xs.mapFinIdx f ↔ ∃ (i : Nat) (h : i < n), f i xs[i] h = b := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -215,7 +216,7 @@ theorem mapFinIdx_eq_mapFinIdx_iff {xs : Vector α n} {f g : (i : Nat) → α
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {xs : Vector α n}
|
||||
@[simp, grind =] theorem mapFinIdx_mapFinIdx {xs : Vector α n}
|
||||
{f : (i : Nat) → α → (h : i < n) → β}
|
||||
{g : (i : Nat) → β → (h : i < n) → γ} :
|
||||
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) h) := by
|
||||
@@ -229,14 +230,14 @@ theorem mapFinIdx_eq_replicate_iff {xs : Vector α n} {f : (i : Nat) → α →
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkVector_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (n - 1 - i) a (by omega))).reverse := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #v[] = #v[] :=
|
||||
rfl
|
||||
|
||||
@@ -256,13 +257,14 @@ theorem mapIdx_eq_zipIdx_map {xs : Vector α n} {f : Nat → α → β} :
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-27")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs : Vector α n} {ys : Vector α m} :
|
||||
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx fun i => f (i + n) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.mapIdx_append]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem mapIdx_push {xs : Vector α n} {a : α} :
|
||||
mapIdx f (xs.push a) = (mapIdx f xs).push (f n a) := by
|
||||
simp [← append_singleton, mapIdx_append]
|
||||
@@ -275,7 +277,7 @@ theorem exists_of_mem_mapIdx {b : β} {xs : Vector α n}
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {xs : Vector α n} :
|
||||
@[simp, grind =] theorem mem_mapIdx {b : β} {xs : Vector α n} :
|
||||
b ∈ xs.mapIdx f ↔ ∃ (i : Nat) (h : i < n), f i xs[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -332,7 +334,7 @@ theorem mapIdx_eq_mapIdx_iff {xs : Vector α n} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.mapIdx_eq_mapIdx_iff]
|
||||
|
||||
@[simp] theorem mapIdx_set {xs : Vector α n} {i : Nat} {h : i < n} {a : α} :
|
||||
@[simp, grind =] theorem mapIdx_set {xs : Vector α n} {i : Nat} {h : i < n} {a : α} :
|
||||
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
@@ -342,17 +344,17 @@ theorem mapIdx_eq_mapIdx_iff {xs : Vector α n} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_mapIdx {xs : Vector α n} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem back?_mapIdx {xs : Vector α n} {f : Nat → α → β} :
|
||||
(mapIdx f xs).back? = (xs.back?).map (f (n - 1)) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem back_mapIdx [NeZero n] {xs : Vector α n} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem back_mapIdx [NeZero n] {xs : Vector α n} {f : Nat → α → β} :
|
||||
(mapIdx f xs).back = f (n - 1) (xs.back) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem mapIdx_mapIdx {xs : Vector α n} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
@[simp, grind =] theorem mapIdx_mapIdx {xs : Vector α n} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
@@ -364,7 +366,7 @@ theorem mapIdx_eq_replicate_iff {xs : Vector α n} {f : Nat → α → β} {b :
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkVector_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp] theorem mapIdx_reverse {xs : Vector α n} {f : Nat → α → β} :
|
||||
@[simp, grind =] theorem mapIdx_reverse {xs : Vector α n} {f : Nat → α → β} :
|
||||
xs.reverse.mapIdx f = (mapIdx (fun i => f (n - 1 - i)) xs).reverse := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.mapIdx_reverse]
|
||||
|
||||
@@ -20,15 +20,15 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace Vector
|
||||
|
||||
@[simp] theorem getElem_ofFn {α n} {f : Fin n → α} (h : i < n) :
|
||||
@[simp, grind =] theorem getElem_ofFn {α n} {f : Fin n → α} (h : i < n) :
|
||||
(Vector.ofFn f)[i] = f ⟨i, by simpa using h⟩ := by
|
||||
simp [ofFn]
|
||||
|
||||
theorem getElem?_ofFn {α n} {f : Fin n → α} :
|
||||
@[simp, grind =] theorem getElem?_ofFn {α n} {f : Fin n → α} :
|
||||
(ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[simp 500]
|
||||
@[simp 500, grind =]
|
||||
theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
@@ -37,7 +37,7 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
theorem back_ofFn {n} [NeZero n] {f : Fin n → α} :
|
||||
@[grind =] theorem back_ofFn {n} [NeZero n] {f : Fin n → α} :
|
||||
(ofFn f).back = f ⟨n - 1, by have := NeZero.ne n; omega⟩ := by
|
||||
simp [back]
|
||||
|
||||
@@ -71,7 +71,7 @@ def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Vector α n) :=
|
||||
else
|
||||
pure ⟨acc, by omega⟩
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : Vector.ofFnM f = pure #v[] := by
|
||||
simp [ofFnM, ofFnM.go]
|
||||
|
||||
@@ -114,13 +114,13 @@ theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
| zero => simp
|
||||
| succ k ih => simp [ofFnM_succ, ih, ← push_append]
|
||||
|
||||
@[simp, grind] theorem toArray_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
@[simp, grind =] theorem toArray_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toArray <$> ofFnM f = Array.ofFnM f := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ, Array.ofFnM_succ, ← ih]
|
||||
|
||||
@[simp, grind] 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 <$> Vector.ofFnM f = List.ofFnM f := by
|
||||
unfold toList
|
||||
suffices Array.toList <$> (toArray <$> ofFnM f) = List.ofFnM f by
|
||||
|
||||
@@ -112,14 +112,25 @@ theorem range'_eq_append_iff : range' s (n + m) = xs ++ ys ↔ xs = range' s n
|
||||
· rintro ⟨h₁, h₂⟩
|
||||
exact ⟨n, by omega, by simp_all⟩
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind =] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
simp [range'_eq_mk_range']
|
||||
|
||||
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind =] theorem find?_range'_eq_none {s n : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = none ↔ ∀ i, s ≤ i → i < s + n → !p i := by
|
||||
simp [range'_eq_mk_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 [range'_eq_mk_range', count_mk, ← Array.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 [range'_eq_mk_range', count_mk, ← Array.count_range_1']
|
||||
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@[simp, grind =] theorem getElem_range {i : Nat} (hi : i < n) : (Vector.range n)[i] = i := by
|
||||
@@ -171,9 +182,15 @@ theorem self_mem_range_succ {n : Nat} : n ∈ range (n + 1) := by simp
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp [range_eq_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
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem?_zipIdx {xs : Vector α n} {i j} : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@@ -216,7 +233,7 @@ theorem zipIdx_eq_map_add {xs : Vector α n} {i : Nat} :
|
||||
simp only [zipIdx_mk, map_mk, eq_mk]
|
||||
rw [Array.zipIdx_eq_map_add]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx (#v[x]) k = #v[(x, k)] :=
|
||||
rfl
|
||||
|
||||
@@ -265,6 +282,7 @@ theorem zipIdx_map {f : α → β} {xs : Vector α n} {k : Nat} :
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp [Array.zipIdx_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipIdx_append {xs : Vector α n} {ys : Vector α m} {k : Nat} :
|
||||
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + n) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
|
||||
@@ -46,6 +46,7 @@ theorem zipWith_self {f : α → α → δ} {xs : Vector α n} : 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
|
||||
@@ -74,53 +75,61 @@ theorem getElem?_zip_eq_some {as : Vector α n} {bs : Vector β n} {z : α × β
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.getElem?_zip_eq_some]
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem zipWith_map {μ} {f : γ → δ → μ} {g : α → γ} {h : β → δ} {as : Vector α n} {bs : Vector β n} :
|
||||
zipWith f (as.map g) (bs.map h) = zipWith (fun a b => f (g a) (h b)) as bs := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.zipWith_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_left {as : Vector α n} {bs : Vector β n} {f : α → α'} {g : α' → β → γ} :
|
||||
zipWith g (as.map f) bs = zipWith (fun a b => g (f a) b) as bs := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.zipWith_map_left]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_right {as : Vector α n} {bs : Vector β n} {f : β → β'} {g : α → β' → γ} :
|
||||
zipWith g as (bs.map f) = zipWith (fun a b => g a (f b)) as bs := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.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
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simpa using Array.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
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simpa using Array.zipWith_foldl_eq_zip_foldl
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {as : Vector γ n} {bs : Vector δ n} :
|
||||
map f (zipWith g as bs) = zipWith (fun x y => f (g x y)) as bs := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.map_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem take_zipWith : (zipWith f as bs).take i = zipWith f (as.take i) (bs.take i) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.take_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_zipWith : (zipWith f as bs).extract i j = zipWith f (as.extract i j) (bs.extract i j) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.extract_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_append {f : α → β → γ}
|
||||
{as : Vector α n} {as' : Vector α m} {bs : Vector β n} {bs' : Vector β m} :
|
||||
zipWith f (as ++ as') (bs ++ bs') = zipWith f as bs ++ zipWith f as' bs' := by
|
||||
@@ -147,7 +156,8 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Vector α (n + m)} {b
|
||||
simp only at w₁ w₂
|
||||
exact ⟨as₁, as₂, bs₁, bs₂, by simpa [hw, hy] using ⟨w₁, w₂⟩⟩
|
||||
|
||||
@[simp] theorem zipWith_replicate {a : α} {b : β} {n : Nat} :
|
||||
@[simp, grind =]
|
||||
theorem zipWith_replicate {a : α} {b : β} {n : Nat} :
|
||||
zipWith f (replicate n a) (replicate n b) = replicate n (f a b) := by
|
||||
ext
|
||||
simp
|
||||
@@ -167,6 +177,7 @@ theorem map_zip_eq_zipWith {f : α × β → γ} {as : Vector α n} {bs : Vector
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.map_zip_eq_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
(zipWith f as bs).reverse = zipWith f as.reverse bs.reverse := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
@@ -175,7 +186,7 @@ theorem reverse_zipWith {f : α → β → γ} {as : Vector α n} {bs : Vector
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
@[simp]
|
||||
@[simp, grind =]
|
||||
theorem getElem_zip {as : Vector α n} {bs : Vector β n} {i : Nat} {h : i < n} :
|
||||
(zip as bs)[i] = (as[i], bs[i]) :=
|
||||
getElem_zipWith ..
|
||||
@@ -185,18 +196,22 @@ theorem zip_eq_zipWith {as : Vector α n} {bs : Vector β n} : zip as bs = zipWi
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.zip_eq_zipWith, h]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map {f : α → γ} {g : β → δ} {as : Vector α n} {bs : Vector β n} :
|
||||
zip (as.map f) (bs.map g) = (zip as bs).map (Prod.map f g) := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
rcases bs with ⟨bs, h⟩
|
||||
simp [Array.zip_map, h]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {as : Vector α n} {bs : Vector β n} :
|
||||
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 : Vector α n} {bs : Vector β n} :
|
||||
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_append {as : Vector α n} {bs : Vector β n} {as' : Vector α m} {bs' : Vector β m} :
|
||||
zip (as ++ as') (bs ++ bs') = zip as bs ++ zip as' bs' := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
@@ -205,6 +220,7 @@ theorem zip_append {as : Vector α n} {bs : Vector β n} {as' : Vector α m} {bs
|
||||
rcases bs' with ⟨bs', h'⟩
|
||||
simp [Array.zip_append, h, h']
|
||||
|
||||
@[grind =]
|
||||
theorem zip_map' {f : α → β} {g : α → γ} {xs : Vector α n} :
|
||||
zip (xs.map f) (xs.map g) = xs.map fun a => (f a, g a) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
@@ -248,7 +264,8 @@ theorem zip_eq_append_iff {as : Vector α (n + m)} {bs : Vector β (n + m)} {xs
|
||||
∃ as₁ as₂ bs₁ bs₂, 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 : β} {n : Nat} :
|
||||
@[simp, grind =]
|
||||
theorem zip_replicate {a : α} {b : β} {n : Nat} :
|
||||
zip (replicate n a) (replicate n b) = replicate n (a, b) := by
|
||||
ext <;> simp
|
||||
|
||||
@@ -257,14 +274,17 @@ abbrev zip_mkVector := @zip_replicate
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem unzip_fst : (unzip xs).fst = xs.map Prod.fst := by
|
||||
@[simp, grind =]
|
||||
theorem unzip_fst : (unzip xs).fst = xs.map Prod.fst := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@[simp] theorem unzip_snd : (unzip xs).snd = xs.map Prod.snd := by
|
||||
@[simp, grind =]
|
||||
theorem unzip_snd : (unzip xs).snd = xs.map Prod.snd := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem unzip_eq_map {xs : Vector (α × β) n} : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
|
||||
cases xs
|
||||
simp [List.unzip_eq_map]
|
||||
@@ -296,7 +316,8 @@ theorem zip_of_prod {as : Vector α n} {bs : Vector β n} {xs : Vector (α × β
|
||||
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem unzip_replicate {a : α} {b : β} {n : Nat} :
|
||||
@[simp, grind =]
|
||||
theorem unzip_replicate {a : α} {b : β} {n : Nat} :
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ proof in the context using `have`, because `get_elem_tactic` tries
|
||||
|
||||
The proof side-condition `valid xs i` is automatically dispatched by the
|
||||
`get_elem_tactic` tactic; this tactic can be extended by adding more clauses to
|
||||
`get_elem_tactic_trivial` using `macro_rules`.
|
||||
`get_elem_tactic_extensible` using `macro_rules`.
|
||||
|
||||
`xs[i]?` and `xs[i]!` do not impose a proof obligation; the former returns
|
||||
an `Option elem`, with `none` signalling that the value isn't present, and
|
||||
@@ -281,7 +281,7 @@ instance [GetElem? cont Nat elem dom] [h : LawfulGetElem cont Nat elem dom] :
|
||||
@[simp, grind =] theorem getElem!_fin [GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n) [Inhabited Elem] : a[i]! = a[i.1]! := rfl
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| (with_reducible apply Fin.val_lt_of_le); get_elem_tactic_trivial; done)
|
||||
| `(tactic| get_elem_tactic_extensible) => `(tactic| (with_reducible apply Fin.val_lt_of_le); get_elem_tactic_extensible; done)
|
||||
|
||||
end Fin
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import Init.Grind.Propagator
|
||||
import Init.Grind.Util
|
||||
import Init.Grind.Offset
|
||||
import Init.Grind.PP
|
||||
import Init.Grind.CommRing
|
||||
import Init.Grind.Ring
|
||||
import Init.Grind.Module
|
||||
import Init.Grind.Ordered
|
||||
import Init.Grind.Ext
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.CommRing.Basic
|
||||
import Init.Grind.CommRing.Int
|
||||
import Init.Grind.CommRing.UInt
|
||||
import Init.Grind.CommRing.SInt
|
||||
import Init.Grind.CommRing.Fin
|
||||
import Init.Grind.CommRing.BitVec
|
||||
import Init.Grind.CommRing.Poly
|
||||
import Init.Grind.CommRing.Field
|
||||
@@ -7,12 +7,15 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Data.Int.Order
|
||||
import Init.Grind.ToInt
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class AddRightCancel (M : Type u) [Add M] where
|
||||
add_right_cancel : ∀ a b c : M, a + c = b + c → a = b
|
||||
|
||||
class NatModule (M : Type u) extends Zero M, Add M, HMul Nat M M where
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
zero_add : ∀ a : M, 0 + a = a
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
zero_hmul : ∀ a : M, 0 * a = 0
|
||||
@@ -26,7 +29,6 @@ attribute [instance 100] NatModule.toZero NatModule.toAdd NatModule.toHMul
|
||||
|
||||
class IntModule (M : Type u) extends Zero M, Add M, Neg M, Sub M, HMul Int M M where
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
zero_add : ∀ a : M, 0 + a = a
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
zero_hmul : ∀ a : M, (0 : Int) * a = 0
|
||||
@@ -38,6 +40,15 @@ class IntModule (M : Type u) extends Zero M, Add M, Neg M, Sub M, HMul Int M M w
|
||||
neg_add_cancel : ∀ a : M, -a + a = 0
|
||||
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
|
||||
|
||||
namespace NatModule
|
||||
|
||||
variable {M : Type u} [NatModule M]
|
||||
|
||||
theorem zero_add (a : M) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
end NatModule
|
||||
|
||||
namespace IntModule
|
||||
|
||||
attribute [instance 100] IntModule.toZero IntModule.toAdd IntModule.toNeg IntModule.toSub IntModule.toHMul
|
||||
@@ -52,9 +63,21 @@ instance toNatModule (M : Type u) [i : IntModule M] : NatModule M :=
|
||||
|
||||
variable {M : Type u} [IntModule M]
|
||||
|
||||
instance (priority := 100) (M : Type u) [IntModule M] : SMul Nat M where
|
||||
smul a x := (a : Int) * x
|
||||
|
||||
instance (priority := 100) (M : Type u) [IntModule M] : SMul Int M where
|
||||
smul a x := a * x
|
||||
|
||||
theorem zero_add (a : M) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
theorem add_neg_cancel (a : M) : a + -a = 0 := by
|
||||
rw [add_comm, neg_add_cancel]
|
||||
|
||||
theorem add_left_comm (a b c : M) : a + (b + c) = b + (a + c) := by
|
||||
rw [← add_assoc, ← add_assoc, add_comm a]
|
||||
|
||||
theorem add_left_inj {a b : M} (c : M) : a + c = b + c ↔ a = b :=
|
||||
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
|
||||
fun g => congrArg (· + c) g⟩
|
||||
@@ -93,6 +116,12 @@ theorem sub_eq_iff {a b c : M} : a - b = c ↔ a = c + b := by
|
||||
theorem sub_eq_zero_iff {a b : M} : a - b = 0 ↔ a = b := by
|
||||
simp [sub_eq_iff, zero_add]
|
||||
|
||||
theorem add_sub_cancel {a b : M} : a + b - b = a := by
|
||||
rw [sub_eq_add_neg, add_assoc, add_neg_cancel, add_zero]
|
||||
|
||||
theorem sub_add_cancel {a b : M} : a - b + b = a := by
|
||||
rw [sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero]
|
||||
|
||||
theorem neg_hmul (n : Int) (a : M) : (-n) * a = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← add_hmul, Int.add_left_neg, zero_hmul, neg_add_cancel]
|
||||
@@ -101,6 +130,12 @@ theorem hmul_neg (n : Int) (a : M) : n * (-a) = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← hmul_add, neg_add_cancel, neg_add_cancel, hmul_zero]
|
||||
|
||||
theorem hmul_sub (k : Int) (a b : M) : k * (a - b) = k * a - k * b := by
|
||||
rw [sub_eq_add_neg, hmul_add, hmul_neg, ← sub_eq_add_neg]
|
||||
|
||||
theorem sub_hmul (k₁ k₂ : Int) (a : M) : (k₁ - k₂) * a = k₁ * a - k₂ * a := by
|
||||
rw [Int.sub_eq_add_neg, add_hmul, neg_hmul, ← sub_eq_add_neg]
|
||||
|
||||
end IntModule
|
||||
|
||||
/--
|
||||
@@ -111,4 +146,17 @@ class NoNatZeroDivisors (α : Type u) [Zero α] [HMul Nat α α] where
|
||||
|
||||
export NoNatZeroDivisors (no_nat_zero_divisors)
|
||||
|
||||
instance [ToInt α (some lo) (some hi)] [IntModule α] [ToInt.Zero α (some lo) (some hi)] [ToInt.Add α (some lo) (some hi)] : ToInt.Neg α (some lo) (some hi) where
|
||||
toInt_neg x := by
|
||||
have := (ToInt.Add.toInt_add (-x) x).symm
|
||||
rw [IntModule.neg_add_cancel, ToInt.Zero.toInt_zero] at this
|
||||
rw [ToInt.wrap_eq_wrap_iff] at this
|
||||
simp at this
|
||||
rw [← ToInt.wrap_toInt]
|
||||
rw [ToInt.wrap_eq_wrap_iff]
|
||||
simpa
|
||||
|
||||
instance [ToInt α (some lo) (some hi)] [IntModule α] [ToInt.Add α (some lo) (some hi)] [ToInt.Neg α (some lo) (some hi)] : ToInt.Sub α (some lo) (some hi) :=
|
||||
ToInt.Sub.of_sub_eq_add_neg IntModule.sub_eq_add_neg
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -12,6 +12,7 @@ import Init.Classical
|
||||
import Init.ByCases
|
||||
import Init.Data.Int.Linear
|
||||
import Init.Data.Int.Pow
|
||||
import Init.Grind.Ring.Field
|
||||
|
||||
namespace Lean.Grind
|
||||
/-!
|
||||
@@ -177,15 +178,16 @@ init_grind_norm
|
||||
Nat.add_eq Nat.sub_eq Nat.mul_eq Nat.zero_eq Nat.le_eq
|
||||
Nat.div_zero Nat.mod_zero Nat.div_one Nat.mod_one
|
||||
Nat.sub_sub Nat.pow_zero Nat.pow_one Nat.sub_self
|
||||
Nat.one_pow
|
||||
-- Int
|
||||
Int.lt_eq
|
||||
Int.emod_neg Int.ediv_neg
|
||||
Int.ediv_zero Int.emod_zero
|
||||
Int.ediv_one Int.emod_one
|
||||
|
||||
Int.negSucc_eq
|
||||
natCast_eq natCast_div natCast_mod
|
||||
natCast_add natCast_mul
|
||||
|
||||
Int.one_pow
|
||||
Int.pow_zero Int.pow_one
|
||||
-- GT GE
|
||||
ge_eq gt_eq
|
||||
@@ -197,5 +199,7 @@ init_grind_norm
|
||||
-- Function composition
|
||||
Function.const_apply Function.comp_apply Function.const_comp
|
||||
Function.comp_const Function.true_comp Function.false_comp
|
||||
-- Field
|
||||
Field.div_eq_mul_inv Field.inv_zero Field.inv_inv Field.inv_one Field.inv_neg
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -11,3 +11,4 @@ import Init.Grind.Ordered.Module
|
||||
import Init.Grind.Ordered.Ring
|
||||
import Init.Grind.Ordered.Field
|
||||
import Init.Grind.Ordered.Int
|
||||
import Init.Grind.Ordered.Linarith
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Grind.CommRing.Field
|
||||
import Init.Grind.Ring.Field
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
namespace Lean.Grind
|
||||
@@ -185,4 +185,54 @@ theorem mul_le_mul_iff_of_neg_left {a b c : R} (h : c < 0) : c * a ≤ c * b ↔
|
||||
|
||||
end Field.IsOrdered
|
||||
|
||||
theorem Field.zero_lt_one [Field α] [LinearOrder α] [Ring.IsOrdered α] : (0 : α) < 1 := by
|
||||
cases LinearOrder.trichotomy (0:α) 1
|
||||
next => assumption
|
||||
next h =>
|
||||
cases h
|
||||
next => have := Field.zero_ne_one (α := α); contradiction
|
||||
next h =>
|
||||
have := Ring.IsOrdered.mul_pos_of_neg_of_neg h h
|
||||
simp [Semiring.one_mul] at this
|
||||
assumption
|
||||
|
||||
theorem Field.minus_one_lt_zero [Field α] [LinearOrder α] [Ring.IsOrdered α] : (-1 : α) < 0 := by
|
||||
have h := Field.zero_lt_one (α := α)
|
||||
have := IntModule.IsOrdered.add_lt_left h (-1)
|
||||
rw [Semiring.zero_add, Ring.add_neg_cancel] at this
|
||||
assumption
|
||||
|
||||
theorem ofNat_nonneg [Field α] [LinearOrder α] [Ring.IsOrdered α] (x : Nat) : (OfNat.ofNat x : α) ≥ 0 := by
|
||||
induction x
|
||||
next => simp [OfNat.ofNat, Zero.zero]; apply Preorder.le_refl
|
||||
next n ih =>
|
||||
have := Field.zero_lt_one (α := α)
|
||||
rw [Semiring.ofNat_succ]
|
||||
replace ih := IntModule.IsOrdered.add_le_left ih 1
|
||||
rw [Semiring.zero_add] at ih
|
||||
have := Preorder.lt_of_lt_of_le this ih
|
||||
exact Preorder.le_of_lt this
|
||||
|
||||
instance [Field α] [LinearOrder α] [Ring.IsOrdered α] : IsCharP α 0 where
|
||||
ofNat_eq_zero_iff := by
|
||||
intro x
|
||||
simp only [Nat.mod_zero]; constructor
|
||||
next =>
|
||||
intro h
|
||||
cases x
|
||||
next => rfl
|
||||
next x =>
|
||||
rw [Semiring.ofNat_succ] at h
|
||||
replace h := congrArg (· - 1) h; simp at h
|
||||
rw [Ring.sub_eq_add_neg, Semiring.add_assoc, Ring.add_neg_cancel,
|
||||
Ring.sub_eq_add_neg, Semiring.zero_add, Semiring.add_zero] at h
|
||||
have h₁ : (OfNat.ofNat x : α) < 0 := by
|
||||
have := Field.minus_one_lt_zero (α := α)
|
||||
rw [h]; assumption
|
||||
have h₂ := ofNat_nonneg (α := α) x
|
||||
have : (0 : α) < 0 := Preorder.lt_of_le_of_lt h₂ h₁
|
||||
simp
|
||||
exact (Preorder.lt_irrefl 0) this
|
||||
next => intro h; rw [OfNat.ofNat, h]; rfl
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Grind.Ordered.Ring
|
||||
import Init.Grind.CommRing.Int
|
||||
import Init.GrindInstances.Ring.Int
|
||||
import Init.Omega
|
||||
|
||||
/-!
|
||||
@@ -24,7 +24,7 @@ instance : Preorder Int where
|
||||
instance : IntModule.IsOrdered Int where
|
||||
neg_le_iff := by omega
|
||||
add_le_left := by omega
|
||||
hmul_pos k a ha := ⟨fun hk => Int.mul_pos hk ha, fun h => Int.pos_of_mul_pos_left h ha⟩
|
||||
hmul_pos_iff k a ha := ⟨fun h => Int.pos_of_mul_pos_left h ha, fun hk => Int.mul_pos hk ha⟩
|
||||
hmul_nonneg hk ha := Int.mul_nonneg hk ha
|
||||
|
||||
instance : Ring.IsOrdered Int where
|
||||
|
||||
564
src/Init/Grind/Ordered/Linarith.lean
Normal file
564
src/Init/Grind/Ordered/Linarith.lean
Normal file
@@ -0,0 +1,564 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
import Init.Grind.Ordered.Module
|
||||
import Init.Grind.Ordered.Ring
|
||||
import Init.Grind.Ring.Field
|
||||
import all Init.Data.Ord
|
||||
import all Init.Data.AC
|
||||
import Init.Data.RArray
|
||||
|
||||
/-!
|
||||
Support for the linear arithmetic module for `IntModule` in `grind`
|
||||
-/
|
||||
|
||||
namespace Lean.Grind.Linarith
|
||||
abbrev Var := Nat
|
||||
open IntModule
|
||||
|
||||
attribute [local simp] add_zero zero_add zero_hmul hmul_zero one_hmul
|
||||
|
||||
inductive Expr where
|
||||
| zero
|
||||
| var (i : Var)
|
||||
| add (a b : Expr)
|
||||
| sub (a b : Expr)
|
||||
| neg (a : Expr)
|
||||
| mul (k : Int) (a : Expr)
|
||||
deriving Inhabited, BEq
|
||||
|
||||
abbrev Context (α : Type u) := RArray α
|
||||
|
||||
def Var.denote {α} (ctx : Context α) (v : Var) : α :=
|
||||
ctx.get v
|
||||
|
||||
def Expr.denote {α} [IntModule α] (ctx : Context α) : Expr → α
|
||||
| zero => 0
|
||||
| .var v => v.denote ctx
|
||||
| .add a b => denote ctx a + denote ctx b
|
||||
| .sub a b => denote ctx a - denote ctx b
|
||||
| .mul k a => k * denote ctx a
|
||||
| .neg a => -denote ctx a
|
||||
|
||||
inductive Poly where
|
||||
| nil
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving BEq
|
||||
|
||||
def Poly.denote {α} [IntModule α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .nil => 0
|
||||
| .add k v p => k * v.denote ctx + denote ctx p
|
||||
|
||||
/--
|
||||
Similar to `Poly.denote`, but produces a denotation better for normalization.
|
||||
-/
|
||||
def Poly.denote' {α} [IntModule α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .nil => 0
|
||||
| .add 1 v p => go (v.denote ctx) p
|
||||
| .add k v p => go (k * v.denote ctx) p
|
||||
where
|
||||
go (r : α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .nil => r
|
||||
| .add 1 v p => go (r + v.denote ctx) p
|
||||
| .add k v p => go (r + k * v.denote ctx) p
|
||||
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [IntModule α] : Std.Associative (· + · : α → α → α) where
|
||||
assoc := IntModule.add_assoc
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [IntModule α] : Std.Commutative (· + · : α → α → α) where
|
||||
comm := IntModule.add_comm
|
||||
|
||||
theorem Poly.denote'_go_eq_denote {α} [IntModule α] (ctx : Context α) (p : Poly) (r : α) : denote'.go ctx r p = p.denote ctx + r := by
|
||||
induction r, p using denote'.go.induct ctx <;> simp [denote'.go, denote]
|
||||
next ih => rw [ih]; ac_rfl
|
||||
next ih => rw [ih]; ac_rfl
|
||||
|
||||
theorem Poly.denote'_eq_denote {α} [IntModule α] (ctx : Context α) (p : Poly) : p.denote' ctx = p.denote ctx := by
|
||||
unfold denote' <;> split <;> simp [denote, denote'_go_eq_denote] <;> ac_rfl
|
||||
|
||||
def Poly.coeff (p : Poly) (x : Var) : Int :=
|
||||
match p with
|
||||
| .add a y p => bif x == y then a else coeff p x
|
||||
| .nil => 0
|
||||
|
||||
def Poly.insert (k : Int) (v : Var) (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .nil => .add k v .nil
|
||||
| .add k' v' p =>
|
||||
bif Nat.blt v' v then
|
||||
.add k v <| .add k' v' p
|
||||
else bif Nat.beq v v' then
|
||||
if Int.add k k' == 0 then
|
||||
p
|
||||
else
|
||||
.add (Int.add k k') v' p
|
||||
else
|
||||
.add k' v' (insert k v p)
|
||||
|
||||
/-- Normalizes the given polynomial by fusing monomial and constants. -/
|
||||
def Poly.norm (p : Poly) : Poly :=
|
||||
match p with
|
||||
| .nil => .nil
|
||||
| .add k v p => (norm p).insert k v
|
||||
|
||||
def Poly.append (p₁ p₂ : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .nil => p₂
|
||||
| .add k x p₁ => .add k x (append p₁ p₂)
|
||||
|
||||
def Poly.combine' (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
|
||||
match fuel with
|
||||
| 0 => p₁.append p₂
|
||||
| fuel + 1 => match p₁, p₂ with
|
||||
| .nil, p₂ => p₂
|
||||
| p₁, .nil => p₁
|
||||
| .add a₁ x₁ p₁, .add a₂ x₂ p₂ =>
|
||||
bif Nat.beq x₁ x₂ then
|
||||
let a := a₁ + a₂
|
||||
bif a == 0 then
|
||||
combine' fuel p₁ p₂
|
||||
else
|
||||
.add a x₁ (combine' fuel p₁ p₂)
|
||||
else bif Nat.blt x₂ x₁ then
|
||||
.add a₁ x₁ (combine' fuel p₁ (.add a₂ x₂ p₂))
|
||||
else
|
||||
.add a₂ x₂ (combine' fuel (.add a₁ x₁ p₁) p₂)
|
||||
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
combine' 100000000 p₁ p₂
|
||||
|
||||
/-- Converts the given expression into a polynomial. -/
|
||||
def Expr.toPoly' (e : Expr) : Poly :=
|
||||
go 1 e .nil
|
||||
where
|
||||
go (coeff : Int) : Expr → (Poly → Poly)
|
||||
| .zero => id
|
||||
| .var v => (.add coeff v ·)
|
||||
| .add a b => go coeff a ∘ go coeff b
|
||||
| .sub a b => go coeff a ∘ go (-coeff) b
|
||||
| .mul k a => bif k == 0 then id else go (Int.mul coeff k) a
|
||||
| .neg a => go (-coeff) a
|
||||
|
||||
/-- Converts the given expression into a polynomial, and then normalizes it. -/
|
||||
def Expr.norm (e : Expr) : Poly :=
|
||||
e.toPoly'.norm
|
||||
|
||||
/--
|
||||
`p.mul k` multiplies all coefficients and constant of the polynomial `p` by `k`.
|
||||
-/
|
||||
def Poly.mul' (p : Poly) (k : Int) : Poly :=
|
||||
match p with
|
||||
| .nil => .nil
|
||||
| .add k' v p => .add (k*k') v (mul' p k)
|
||||
|
||||
def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
if k == 0 then
|
||||
.nil
|
||||
else
|
||||
p.mul' k
|
||||
|
||||
@[simp] theorem Poly.denote_mul {α} [IntModule α] (ctx : Context α) (p : Poly) (k : Int) : (p.mul k).denote ctx = k * p.denote ctx := by
|
||||
simp [mul]
|
||||
split
|
||||
next => simp [*, denote]
|
||||
next =>
|
||||
induction p <;> simp [mul', denote, *]
|
||||
rw [mul_hmul, hmul_add]
|
||||
|
||||
theorem Poly.denote_insert {α} [IntModule α] (ctx : Context α) (k : Int) (v : Var) (p : Poly) :
|
||||
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
|
||||
fun_induction p.insert k v <;> simp [denote]
|
||||
next => ac_rfl
|
||||
next h₁ h₂ h₃ =>
|
||||
simp at h₃; simp at h₂; subst h₂
|
||||
rw [add_comm, ← add_assoc, ← add_hmul, h₃, zero_hmul, zero_add]
|
||||
next h _ => simp at h; subst h; rw [add_hmul]; ac_rfl
|
||||
next ih => rw [ih]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denote_insert
|
||||
|
||||
theorem Poly.denote_norm {α} [IntModule α] (ctx : Context α) (p : Poly) : p.norm.denote ctx = p.denote ctx := by
|
||||
induction p <;> simp [denote, norm, add_comm, *]
|
||||
|
||||
attribute [local simp] Poly.denote_norm
|
||||
|
||||
theorem Poly.denote_append {α} [IntModule α] (ctx : Context α) (p₁ p₂ : Poly) : (p₁.append p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
induction p₁ <;> simp [append, denote, *]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denote_append
|
||||
|
||||
theorem Poly.denote_combine' {α} [IntModule α] (ctx : Context α) (fuel : Nat) (p₁ p₂ : Poly) : (p₁.combine' fuel p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
fun_induction p₁.combine' fuel p₂ <;>
|
||||
simp_all +zetaDelta [denote, ← Int.add_mul]
|
||||
next h _ =>
|
||||
rw [Int.add_comm] at h
|
||||
rw [add_left_comm, add_assoc, ← add_assoc, ← add_hmul, h, zero_hmul, zero_add]
|
||||
next => rw [add_hmul]; ac_rfl
|
||||
all_goals ac_rfl
|
||||
|
||||
theorem Poly.denote_combine {α} [IntModule α] (ctx : Context α) (p₁ p₂ : Poly) : (p₁.combine p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
simp [combine, denote_combine']
|
||||
|
||||
attribute [local simp] Poly.denote_combine
|
||||
|
||||
theorem Expr.denote_toPoly'_go {α} [IntModule α] {k p} (ctx : Context α) (e : Expr)
|
||||
: (toPoly'.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
|
||||
induction k, e using Expr.toPoly'.go.induct generalizing p <;> simp [toPoly'.go, denote, Poly.denote, *, hmul_add]
|
||||
next => ac_rfl
|
||||
next => rw [sub_eq_add_neg, neg_hmul, hmul_add, hmul_neg]; ac_rfl
|
||||
next h => simp at h; subst h; simp
|
||||
next ih => simp at ih; rw [ih, mul_hmul]
|
||||
next => rw [hmul_neg, neg_hmul]
|
||||
|
||||
theorem Expr.denote_norm {α} [IntModule α] (ctx : Context α) (e : Expr) : e.norm.denote ctx = e.denote ctx := by
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go, Poly.denote]
|
||||
|
||||
attribute [local simp] Expr.denote_norm
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next ih =>
|
||||
intro _ _ h
|
||||
exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
|
||||
attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
def Poly.leadCoeff (p : Poly) : Int :=
|
||||
match p with
|
||||
| .add a _ _ => a
|
||||
| _ => 1
|
||||
|
||||
open IntModule.IsOrdered
|
||||
|
||||
/-!
|
||||
Helper theorems for conflict resolution during model construction.
|
||||
-/
|
||||
|
||||
private theorem le_add_le {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
|
||||
(h₁ : a ≤ 0) (h₂ : b ≤ 0) : a + b ≤ 0 := by
|
||||
replace h₁ := add_le_left h₁ b; simp at h₁
|
||||
exact Preorder.le_trans h₁ h₂
|
||||
|
||||
private theorem le_add_lt {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
|
||||
(h₁ : a ≤ 0) (h₂ : b < 0) : a + b < 0 := by
|
||||
replace h₁ := add_le_left h₁ b; simp at h₁
|
||||
exact Preorder.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
private theorem lt_add_lt {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
|
||||
(h₁ : a < 0) (h₂ : b < 0) : a + b < 0 := by
|
||||
replace h₁ := add_lt_left h₁ b; simp at h₁
|
||||
exact Preorder.lt_trans h₁ h₂
|
||||
|
||||
private theorem coe_natAbs_nonneg (a : Int) : (a.natAbs : Int) ≥ 0 := by
|
||||
exact Int.natCast_nonneg a.natAbs
|
||||
|
||||
def le_le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let a₁ := p₁.leadCoeff.natAbs
|
||||
let a₂ := p₂.leadCoeff.natAbs
|
||||
p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
|
||||
|
||||
theorem le_le_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: le_le_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → p₃.denote' ctx ≤ 0 := by
|
||||
simp [le_le_combine_cert]; intro _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := hmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := hmul_nonpos (coe_natAbs_nonneg p₁.leadCoeff) h₂
|
||||
exact le_add_le h₁ h₂
|
||||
|
||||
def le_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let a₁ := p₁.leadCoeff.natAbs
|
||||
let a₂ := p₂.leadCoeff.natAbs
|
||||
a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
|
||||
|
||||
theorem le_lt_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: le_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [-Int.natAbs_pos, -Int.ofNat_pos, le_lt_combine_cert]; intro hp _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := hmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := hmul_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp
|
||||
exact le_add_lt h₁ h₂
|
||||
|
||||
def lt_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
let a₁ := p₁.leadCoeff.natAbs
|
||||
let a₂ := p₂.leadCoeff.natAbs
|
||||
a₂ > (0 : Int) && a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
|
||||
|
||||
theorem lt_lt_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: lt_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx < 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [-Int.natAbs_pos, -Int.ofNat_pos, lt_lt_combine_cert]; intro hp₁ hp₂ _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := hmul_neg_iff (↑p₂.leadCoeff.natAbs) h₁ |>.mpr hp₁
|
||||
replace h₂ := hmul_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp₂
|
||||
exact lt_add_lt h₁ h₂
|
||||
|
||||
def diseq_split_cert (p₁ p₂ : Poly) : Bool :=
|
||||
p₂ == p₁.mul (-1)
|
||||
|
||||
-- We need `LinearOrder` to use `trichotomy`
|
||||
theorem diseq_split {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: diseq_split_cert p₁ p₂ → p₁.denote' ctx ≠ 0 → p₁.denote' ctx < 0 ∨ p₂.denote' ctx < 0 := by
|
||||
simp [diseq_split_cert]; intro _ h₁; subst p₂; simp
|
||||
cases LinearOrder.trichotomy (p₁.denote ctx) 0
|
||||
next h => exact Or.inl h
|
||||
next h =>
|
||||
apply Or.inr
|
||||
simp [h₁] at h
|
||||
rw [← neg_pos_iff, neg_hmul, neg_neg, one_hmul]; assumption
|
||||
|
||||
theorem diseq_split_resolve {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: diseq_split_cert p₁ p₂ → p₁.denote' ctx ≠ 0 → ¬p₁.denote' ctx < 0 → p₂.denote' ctx < 0 := by
|
||||
intro h₁ h₂ h₃
|
||||
exact (diseq_split ctx p₁ p₂ h₁ h₂).resolve_left h₃
|
||||
|
||||
/-!
|
||||
Helper theorems for internalizing facts into the linear arithmetic procedure
|
||||
-/
|
||||
|
||||
def norm_cert (lhs rhs : Expr) (p : Poly) :=
|
||||
p == (lhs.sub rhs).norm
|
||||
|
||||
theorem eq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → lhs.denote ctx = rhs.denote ctx → p.denote' ctx = 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
|
||||
theorem le_of_eq {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → lhs.denote ctx = rhs.denote ctx → p.denote' ctx ≤ 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
apply Preorder.le_refl
|
||||
|
||||
theorem diseq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → lhs.denote ctx ≠ rhs.denote ctx → p.denote' ctx ≠ 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
intro h
|
||||
replace h := congrArg (rhs.denote ctx + ·) h; simp [sub_eq_add_neg] at h
|
||||
rw [add_left_comm, ← sub_eq_add_neg, sub_self, add_zero] at h
|
||||
contradiction
|
||||
|
||||
theorem le_norm {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → lhs.denote ctx ≤ rhs.denote ctx → p.denote' ctx ≤ 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
replace h₁ := add_le_left h₁ (-rhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
theorem lt_norm {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → lhs.denote ctx < rhs.denote ctx → p.denote' ctx < 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
replace h₁ := add_lt_left h₁ (-rhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
theorem not_le_norm {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert rhs lhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → p.denote' ctx < 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
replace h₁ := LinearOrder.lt_of_not_le h₁
|
||||
replace h₁ := add_lt_left h₁ (-lhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
theorem not_lt_norm {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert rhs lhs p → ¬ lhs.denote ctx < rhs.denote ctx → p.denote' ctx ≤ 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
|
||||
replace h₁ := LinearOrder.le_of_not_lt h₁
|
||||
replace h₁ := add_le_left h₁ (-lhs.denote ctx)
|
||||
simp [← sub_eq_add_neg, sub_self] at h₁
|
||||
assumption
|
||||
|
||||
-- If the module does not have a linear order, we can still put the expressions in polynomial forms
|
||||
|
||||
theorem not_le_norm' {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → ¬ p.denote' ctx ≤ 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]; intro h
|
||||
replace h := add_le_right (rhs.denote ctx) h
|
||||
rw [sub_eq_add_neg, add_left_comm, ← sub_eq_add_neg, sub_self] at h; simp at h
|
||||
contradiction
|
||||
|
||||
theorem not_lt_norm' {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
: norm_cert lhs rhs p → ¬ lhs.denote ctx < rhs.denote ctx → ¬ p.denote' ctx < 0 := by
|
||||
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]; intro h
|
||||
replace h := add_lt_right (rhs.denote ctx) h
|
||||
rw [sub_eq_add_neg, add_left_comm, ← sub_eq_add_neg, sub_self] at h; simp at h
|
||||
contradiction
|
||||
|
||||
/-!
|
||||
Equality detection
|
||||
-/
|
||||
def eq_of_le_ge_cert (p₁ p₂ : Poly) : Bool :=
|
||||
p₂ == p₁.mul (-1)
|
||||
|
||||
theorem eq_of_le_ge {α} [IntModule α] [PartialOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ : Poly) (p₂ : Poly)
|
||||
: eq_of_le_ge_cert p₁ p₂ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → p₁.denote' ctx = 0 := by
|
||||
simp [eq_of_le_ge_cert]
|
||||
intro; subst p₂; simp
|
||||
intro h₁ h₂
|
||||
replace h₂ := add_le_left h₂ (p₁.denote ctx)
|
||||
rw [add_comm, neg_hmul, one_hmul, ← sub_eq_add_neg, sub_self, zero_add] at h₂
|
||||
exact PartialOrder.le_antisymm h₁ h₂
|
||||
|
||||
/-!
|
||||
Helper theorems for closing the goal
|
||||
-/
|
||||
|
||||
theorem diseq_unsat {α} [IntModule α] (ctx : Context α) : (Poly.nil).denote ctx ≠ 0 → False := by
|
||||
simp [Poly.denote]
|
||||
|
||||
theorem lt_unsat {α} [IntModule α] [Preorder α] (ctx : Context α) : (Poly.nil).denote ctx < 0 → False := by
|
||||
simp [Poly.denote]; intro h
|
||||
have := Preorder.lt_iff_le_not_le.mp h
|
||||
simp at this
|
||||
|
||||
def zero_lt_one_cert (p : Poly) : Bool :=
|
||||
p == .add (-1) 0 .nil
|
||||
|
||||
theorem zero_lt_one {α} [Ring α] [Preorder α] [Ring.IsOrdered α] (ctx : Context α) (p : Poly)
|
||||
: zero_lt_one_cert p → (0 : Var).denote ctx = One.one → p.denote' ctx < 0 := by
|
||||
simp [zero_lt_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one, neg_hmul]
|
||||
rw [neg_lt_iff, neg_zero]; apply Ring.IsOrdered.zero_lt_one
|
||||
|
||||
def zero_ne_one_cert (p : Poly) : Bool :=
|
||||
p == .add 1 0 .nil
|
||||
|
||||
theorem zero_ne_one_of_ord_ring {α} [Ring α] [Preorder α] [Ring.IsOrdered α] (ctx : Context α) (p : Poly)
|
||||
: zero_ne_one_cert p → (0 : Var).denote ctx = One.one → p.denote' ctx ≠ 0 := by
|
||||
simp [zero_ne_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one]
|
||||
intro h; have := Ring.IsOrdered.zero_lt_one (R := α); simp [h, Preorder.lt_irrefl] at this
|
||||
|
||||
theorem zero_ne_one_of_field {α} [Field α] (ctx : Context α) (p : Poly)
|
||||
: zero_ne_one_cert p → (0 : Var).denote ctx = One.one → p.denote' ctx ≠ 0 := by
|
||||
simp [zero_ne_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one]
|
||||
intro h; have := Field.zero_ne_one (α := α); simp [h] at this
|
||||
|
||||
theorem zero_ne_one_of_char0 {α} [Ring α] [IsCharP α 0] (ctx : Context α) (p : Poly)
|
||||
: zero_ne_one_cert p → (0 : Var).denote ctx = One.one → p.denote' ctx ≠ 0 := by
|
||||
simp [zero_ne_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one]
|
||||
intro h; have := IsCharP.intCast_eq_zero_iff (α := α) 0 1; simp [Ring.intCast_one] at this
|
||||
contradiction
|
||||
|
||||
def zero_ne_one_of_charC_cert (c : Nat) (p : Poly) : Bool :=
|
||||
(c:Int) > 1 && p == .add 1 0 .nil
|
||||
|
||||
theorem zero_ne_one_of_charC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly)
|
||||
: zero_ne_one_of_charC_cert c p → (0 : Var).denote ctx = One.one → p.denote' ctx ≠ 0 := by
|
||||
simp [zero_ne_one_of_charC_cert]; intro hc _ h; subst p; simp [Poly.denote, h, One.one]
|
||||
intro h; have h' := IsCharP.intCast_eq_zero_iff (α := α) c 1; simp [Ring.intCast_one] at h'
|
||||
replace h' := h'.mp h
|
||||
have := Int.emod_eq_of_lt (by decide) hc
|
||||
simp [this] at h'
|
||||
|
||||
/-!
|
||||
Coefficient normalization
|
||||
-/
|
||||
|
||||
def eq_neg_cert (p₁ p₂ : Poly) :=
|
||||
p₂ == p₁.mul (-1)
|
||||
|
||||
theorem eq_neg {α} [IntModule α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: eq_neg_cert p₁ p₂ → p₁.denote' ctx = 0 → p₂.denote' ctx = 0 := by
|
||||
simp [eq_neg_cert]; intros; simp [*]
|
||||
|
||||
def eq_coeff_cert (p₁ p₂ : Poly) (k : Nat) :=
|
||||
k != 0 && p₁ == p₂.mul k
|
||||
|
||||
theorem eq_coeff {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
|
||||
: eq_coeff_cert p₁ p₂ k → p₁.denote' ctx = 0 → p₂.denote' ctx = 0 := by
|
||||
simp [eq_coeff_cert]; intro h _; subst p₁; simp [*]
|
||||
exact no_nat_zero_divisors k (p₂.denote ctx) h
|
||||
|
||||
def coeff_cert (p₁ p₂ : Poly) (k : Nat) :=
|
||||
k > 0 && p₁ == p₂.mul k
|
||||
|
||||
theorem le_coeff {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
|
||||
: coeff_cert p₁ p₂ k → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 := by
|
||||
simp [coeff_cert]; intro h _; subst p₁; simp
|
||||
have : ↑k > (0 : Int) := Int.natCast_pos.mpr h
|
||||
intro h₁; apply Classical.byContradiction
|
||||
intro h₂; replace h₂ := LinearOrder.lt_of_not_le h₂
|
||||
replace h₂ := IsOrdered.hmul_pos_iff (↑k) h₂ |>.mpr this
|
||||
exact Preorder.lt_irrefl 0 (Preorder.lt_of_lt_of_le h₂ h₁)
|
||||
|
||||
theorem lt_coeff {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
|
||||
: coeff_cert p₁ p₂ k → p₁.denote' ctx < 0 → p₂.denote' ctx < 0 := by
|
||||
simp [coeff_cert]; intro h _; subst p₁; simp
|
||||
have : ↑k > (0 : Int) := Int.natCast_pos.mpr h
|
||||
intro h₁; apply Classical.byContradiction
|
||||
intro h₂; replace h₂ := LinearOrder.le_of_not_lt h₂
|
||||
replace h₂ := IsOrdered.hmul_nonneg (Int.le_of_lt this) h₂
|
||||
exact Preorder.lt_irrefl 0 (Preorder.lt_of_le_of_lt h₂ h₁)
|
||||
|
||||
theorem diseq_neg {α} [IntModule α] (ctx : Context α) (p p' : Poly) : p' == p.mul (-1) → p.denote' ctx ≠ 0 → p'.denote' ctx ≠ 0 := by
|
||||
simp; intro _ _; subst p'; simp [neg_hmul]
|
||||
intro h; replace h := congrArg (- ·) h; simp [neg_neg, neg_zero] at h
|
||||
contradiction
|
||||
|
||||
/-!
|
||||
Substitution
|
||||
-/
|
||||
|
||||
def eq_diseq_subst_cert (k₁ k₂ : Int) (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
k₁.natAbs ≠ 0 && p₃ == (p₁.mul k₂ |>.combine (p₂.mul k₁))
|
||||
|
||||
theorem eq_diseq_subst {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context α) (k₁ k₂ : Int) (p₁ p₂ p₃ : Poly)
|
||||
: eq_diseq_subst_cert k₁ k₂ p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
|
||||
simp [eq_diseq_subst_cert, - Int.natAbs_eq_zero, -Int.natCast_eq_zero]; intro hne _ h₁ h₂; subst p₃
|
||||
simp [h₁, h₂]; intro h₃
|
||||
have : k₁.natAbs * Poly.denote ctx p₂ = 0 := by
|
||||
have : (k₁.natAbs : Int) * Poly.denote ctx p₂ = 0 := by
|
||||
cases Int.natAbs_eq_iff.mp (Eq.refl k₁.natAbs)
|
||||
next h => rw [← h]; assumption
|
||||
next h => replace h := congrArg (- ·) h; simp at h; rw [← h, IntModule.neg_hmul, h₃, IntModule.neg_zero]
|
||||
exact this
|
||||
have := no_nat_zero_divisors (k₁.natAbs) (p₂.denote ctx) hne this
|
||||
contradiction
|
||||
|
||||
def eq_diseq_subst1_cert (k : Int) (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
p₃ == (p₁.mul k |>.combine p₂)
|
||||
|
||||
/-
|
||||
Special case of `diseq_eq_subst` where leading coefficient `c₁` of `p₁` is `-k*c₂`, where
|
||||
`c₂` is the leading coefficient of `p₂`.
|
||||
-/
|
||||
theorem eq_diseq_subst1 {α} [IntModule α] (ctx : Context α) (k : Int) (p₁ p₂ p₃ : Poly)
|
||||
: eq_diseq_subst1_cert k p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
|
||||
simp [eq_diseq_subst1_cert]; intro _ h₁ h₂; subst p₃
|
||||
simp [h₁, h₂]
|
||||
|
||||
def eq_le_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
a ≥ 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
|
||||
|
||||
theorem eq_le_subst {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (x : Var) (p₁ p₂ p₃ : Poly)
|
||||
: eq_le_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≤ 0 → p₃.denote' ctx ≤ 0 := by
|
||||
simp [eq_le_subst_cert]; intro h _ h₁ h₂; subst p₃; simp [h₁]
|
||||
exact hmul_nonpos h h₂
|
||||
|
||||
def eq_lt_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
a > 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
|
||||
|
||||
theorem eq_lt_subst {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (x : Var) (p₁ p₂ p₃ : Poly)
|
||||
: eq_lt_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [eq_lt_subst_cert]; intro h _ h₁ h₂; subst p₃; simp [h₁]
|
||||
exact IsOrdered.hmul_neg_iff (p₁.coeff x) h₂ |>.mpr h
|
||||
|
||||
def eq_eq_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
let a := p₁.coeff x
|
||||
let b := p₂.coeff x
|
||||
p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
|
||||
|
||||
theorem eq_eq_subst {α} [IntModule α] (ctx : Context α) (x : Var) (p₁ p₂ p₃ : Poly)
|
||||
: eq_eq_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx = 0 → p₃.denote' ctx = 0 := by
|
||||
simp [eq_eq_subst_cert]; intro _ h₁ h₂; subst p₃; simp [h₁, h₂]
|
||||
|
||||
end Lean.Grind.Linarith
|
||||
@@ -12,12 +12,79 @@ import Init.Grind.Ordered.Order
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
class NatModule.IsOrdered (M : Type u) [Preorder M] [NatModule M] where
|
||||
add_le_left_iff : ∀ {a b : M} (c : M), a ≤ b ↔ a + c ≤ b + c
|
||||
hmul_lt_hmul_iff : ∀ (k : Nat) {a b : M}, a < b → (k * a < k * b ↔ 0 < k)
|
||||
hmul_le_hmul : ∀ {k : Nat} {a b : M}, a ≤ b → k * a ≤ k * b
|
||||
|
||||
class IntModule.IsOrdered (M : Type u) [Preorder M] [IntModule M] where
|
||||
neg_le_iff : ∀ a b : M, -a ≤ b ↔ -b ≤ a
|
||||
add_le_left : ∀ {a b : M}, a ≤ b → (c : M) → a + c ≤ b + c
|
||||
hmul_pos : ∀ (k : Int) {a : M}, 0 < a → (0 < k ↔ 0 < k * a)
|
||||
hmul_pos_iff : ∀ (k : Int) {a : M}, 0 < a → (0 < k * a ↔ 0 < k)
|
||||
hmul_nonneg : ∀ {k : Int} {a : M}, 0 ≤ k → 0 ≤ a → 0 ≤ k * a
|
||||
|
||||
namespace NatModule.IsOrdered
|
||||
|
||||
variable {M : Type u} [Preorder M] [NatModule M] [NatModule.IsOrdered M]
|
||||
|
||||
theorem add_le_right_iff {a b : M} (c : M) : a ≤ b ↔ c + a ≤ c + b := by
|
||||
rw [add_comm c a, add_comm c b, add_le_left_iff]
|
||||
|
||||
theorem add_le_left {a b : M} (h : a ≤ b) (c : M) : a + c ≤ b + c :=
|
||||
(add_le_left_iff c).mp h
|
||||
|
||||
theorem add_le_right {a b : M} (c : M) (h : a ≤ b) : c + a ≤ c + b :=
|
||||
(add_le_right_iff c).mp h
|
||||
|
||||
theorem add_lt_left {a b : M} (h : a < b) (c : M) : a + c < b + c := by
|
||||
simp only [Preorder.lt_iff_le_not_le] at h ⊢
|
||||
constructor
|
||||
· exact add_le_left h.1 _
|
||||
· intro w
|
||||
apply h.2
|
||||
exact (add_le_left_iff c).mpr w
|
||||
|
||||
theorem add_lt_right {a b : M} (c : M) (h : a < b) : c + a < c + b := by
|
||||
rw [add_comm c a, add_comm c b]
|
||||
exact add_lt_left h c
|
||||
|
||||
theorem add_lt_left_iff {a b : M} (c : M) : a < b ↔ a + c < b + c := by
|
||||
constructor
|
||||
· exact fun h => add_lt_left h c
|
||||
· intro w
|
||||
simp only [Preorder.lt_iff_le_not_le] at w ⊢
|
||||
constructor
|
||||
· exact (add_le_left_iff c).mpr w.1
|
||||
· intro h
|
||||
exact w.2 ((add_le_left_iff c).mp h)
|
||||
|
||||
theorem add_lt_right_iff {a b : M} (c : M) : a < b ↔ c + a < c + b := by
|
||||
rw [add_comm c a, add_comm c b, add_lt_left_iff]
|
||||
|
||||
theorem hmul_pos_iff {k : Nat} {a : M} (h : 0 < a) : 0 < k * a ↔ 0 < k:= by
|
||||
rw [← hmul_lt_hmul_iff k h, hmul_zero]
|
||||
|
||||
theorem hmul_nonneg {k : Nat} {a : M} (h : 0 ≤ a) : 0 ≤ k * a := by
|
||||
have := hmul_le_hmul (k := k) h
|
||||
rwa [hmul_zero] at this
|
||||
|
||||
theorem hmul_le_hmul_of_le_of_le_of_nonneg
|
||||
{k₁ k₂ : Nat} {x y : M} (hk : k₁ ≤ k₂) (h : x ≤ y) (w : 0 ≤ x) :
|
||||
k₁ * x ≤ k₂ * y := by
|
||||
apply Preorder.le_trans
|
||||
· change k₁ * x ≤ k₂ * x
|
||||
obtain ⟨k', rfl⟩ := Nat.exists_eq_add_of_le hk
|
||||
rw [add_hmul]
|
||||
conv => lhs; rw [← add_zero (k₁ * x)]
|
||||
rw [← add_le_right_iff]
|
||||
exact hmul_nonneg w
|
||||
· exact hmul_le_hmul h
|
||||
|
||||
theorem add_le_add {a b c d : M} (hab : a ≤ b) (hcd : c ≤ d) : a + c ≤ b + d :=
|
||||
Preorder.le_trans (add_le_right a hcd) (add_le_left hab d)
|
||||
|
||||
end NatModule.IsOrdered
|
||||
|
||||
namespace IntModule.IsOrdered
|
||||
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [IntModule.IsOrdered M]
|
||||
@@ -41,7 +108,7 @@ theorem neg_pos_iff {a : M} : 0 < -a ↔ a < 0 := by
|
||||
rw [lt_neg_iff, neg_zero]
|
||||
|
||||
theorem add_lt_left {a b : M} (h : a < b) (c : M) : a + c < b + c := by
|
||||
simp [Preorder.lt_iff_le_not_le] at h ⊢
|
||||
simp only [Preorder.lt_iff_le_not_le] at h ⊢
|
||||
constructor
|
||||
· exact add_le_left h.1 _
|
||||
· intro w
|
||||
@@ -58,12 +125,59 @@ theorem add_lt_right (a : M) {b c : M} (h : b < c) : a + b < a + c := by
|
||||
rw [add_comm a b, add_comm a c]
|
||||
exact add_lt_left h a
|
||||
|
||||
theorem hmul_neg (k : Int) {a : M} (h : a < 0) : 0 < k ↔ k * a < 0 := by
|
||||
simpa [IntModule.hmul_neg, neg_pos_iff] using hmul_pos k (neg_pos_iff.mpr h)
|
||||
theorem add_le_left_iff {a b : M} (c : M) : a ≤ b ↔ a + c ≤ b + c := by
|
||||
constructor
|
||||
· intro w
|
||||
exact add_le_left w c
|
||||
· intro w
|
||||
have := add_le_left w (-c)
|
||||
rwa [add_assoc, add_neg_cancel, add_zero, add_assoc, add_neg_cancel, add_zero] at this
|
||||
|
||||
theorem add_le_right_iff {a b : M} (c : M) : a ≤ b ↔ c + a ≤ c + b := by
|
||||
constructor
|
||||
· intro w
|
||||
exact add_le_right c w
|
||||
· intro w
|
||||
have := add_le_right (-c) w
|
||||
rwa [← add_assoc, neg_add_cancel, zero_add, ← add_assoc, neg_add_cancel, zero_add] at this
|
||||
|
||||
theorem add_lt_left_iff {a b : M} (c : M) : a < b ↔ a + c < b + c := by
|
||||
constructor
|
||||
· intro w
|
||||
exact add_lt_left w c
|
||||
· intro w
|
||||
have := add_lt_left w (-c)
|
||||
rwa [add_assoc, add_neg_cancel, add_zero, add_assoc, add_neg_cancel, add_zero] at this
|
||||
|
||||
theorem add_lt_right_iff {a b : M} (c : M) : a < b ↔ c + a < c + b := by
|
||||
constructor
|
||||
· intro w
|
||||
exact add_lt_right c w
|
||||
· intro w
|
||||
have := add_lt_right (-c) w
|
||||
rwa [← add_assoc, neg_add_cancel, zero_add, ← add_assoc, neg_add_cancel, zero_add] at this
|
||||
|
||||
theorem sub_nonneg_iff {a b : M} : 0 ≤ a - b ↔ b ≤ a := by
|
||||
rw [add_le_left_iff b, zero_add, sub_add_cancel]
|
||||
|
||||
theorem hmul_neg_iff (k : Int) {a : M} (h : a < 0) : k * a < 0 ↔ 0 < k := by
|
||||
simpa [IntModule.hmul_neg, neg_pos_iff] using hmul_pos_iff k (neg_pos_iff.mpr h)
|
||||
|
||||
theorem hmul_nonpos {k : Int} {a : M} (hk : 0 ≤ k) (ha : a ≤ 0) : k * a ≤ 0 := by
|
||||
simpa [IntModule.hmul_neg, neg_nonneg_iff] using hmul_nonneg hk (neg_nonneg_iff.mpr ha)
|
||||
|
||||
theorem hmul_le_hmul_of_le_of_le_of_nonneg_of_nonneg
|
||||
{k₁ k₂ : Int} {x y : M} (hk : k₁ ≤ k₂) (h : x ≤ y) (w : 0 ≤ k₁) (w' : 0 ≤ x) :
|
||||
k₁ * x ≤ k₂ * y := by
|
||||
apply Preorder.le_trans
|
||||
· have : 0 ≤ k₁ * (y - x) := hmul_nonneg w (sub_nonneg_iff.mpr h)
|
||||
rwa [IntModule.hmul_sub, sub_nonneg_iff] at this
|
||||
· have : 0 ≤ (k₂ - k₁) * y := hmul_nonneg (Int.sub_nonneg.mpr hk) (Preorder.le_trans w' h)
|
||||
rwa [IntModule.sub_hmul, sub_nonneg_iff] at this
|
||||
|
||||
theorem add_le_add {a b c d : M} (hab : a ≤ b) (hcd : c ≤ d) : a + c ≤ b + d :=
|
||||
Preorder.le_trans (add_le_right a hcd) (add_le_left hab d)
|
||||
|
||||
end IntModule.IsOrdered
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -91,6 +91,19 @@ theorem trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := by
|
||||
| inl h => right; right; exact h
|
||||
| inr h => right; left; exact h.symm
|
||||
|
||||
theorem le_of_not_lt {α} [LinearOrder α] {a b : α} (h : ¬ a < b) : b ≤ a := by
|
||||
cases LinearOrder.trichotomy a b
|
||||
next => contradiction
|
||||
next h => apply PartialOrder.le_iff_lt_or_eq.mpr; cases h <;> simp [*]
|
||||
|
||||
theorem lt_of_not_le {α} [LinearOrder α] {a b : α} (h : ¬ a ≤ b) : b < a := by
|
||||
cases LinearOrder.trichotomy a b
|
||||
next h₁ h₂ => have := Preorder.lt_iff_le_not_le.mp h₂; simp [h] at this
|
||||
next h =>
|
||||
cases h
|
||||
next h => subst a; exact False.elim <| h (Preorder.le_refl b)
|
||||
next => assumption
|
||||
|
||||
end LinearOrder
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user