mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-18 02:44:12 +00:00
Compare commits
244 Commits
change_arr
...
insertionS
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cce9ff119 | ||
|
|
6e41298f30 | ||
|
|
88e3a2b1ab | ||
|
|
b378fe98a7 | ||
|
|
5f1ff42a15 | ||
|
|
30d01f7a9a | ||
|
|
81b85d8e2f | ||
|
|
5982a6d230 | ||
|
|
cfc8c6ad8e | ||
|
|
8457fca519 | ||
|
|
ac1197ff59 | ||
|
|
609346f5e0 | ||
|
|
e3b05c13e1 | ||
|
|
04f80a1f9f | ||
|
|
0fc4ed91d1 | ||
|
|
7e9dd5668b | ||
|
|
66ebec97ca | ||
|
|
79f050b816 | ||
|
|
afd398678b | ||
|
|
7791ec7844 | ||
|
|
8f0d0995d6 | ||
|
|
e04e923b82 | ||
|
|
438a1dc989 | ||
|
|
af4a3f2251 | ||
|
|
7692343720 | ||
|
|
597ef8cfee | ||
|
|
321e148f51 | ||
|
|
ce692436f4 | ||
|
|
23bec25fce | ||
|
|
3d511a582a | ||
|
|
51015bf5c0 | ||
|
|
3ece36de9d | ||
|
|
54c48363ca | ||
|
|
0a22f8fa6f | ||
|
|
f70b7e5722 | ||
|
|
9a17919ef1 | ||
|
|
606aeddf06 | ||
|
|
0eca3bd55d | ||
|
|
43dfc2a25f | ||
|
|
935fcfb6ec | ||
|
|
20acc72a29 | ||
|
|
9221d9d4db | ||
|
|
c3948cba24 | ||
|
|
427dc66af3 | ||
|
|
1391f847bd | ||
|
|
85700f1fa4 | ||
|
|
5a23cefd80 | ||
|
|
5cfe1ca35b | ||
|
|
9052d3daef | ||
|
|
c1b887b1c1 | ||
|
|
90f2cb4226 | ||
|
|
62d869f267 | ||
|
|
4e885be96d | ||
|
|
29ff22c560 | ||
|
|
42e98bd3c9 | ||
|
|
884a9ea2ff | ||
|
|
2f5c7d0465 | ||
|
|
a5ffef7e13 | ||
|
|
442c3d5097 | ||
|
|
bf13b24692 | ||
|
|
51d1cc61d7 | ||
|
|
107a2e8b2e | ||
|
|
c4b0b94c91 | ||
|
|
ba3f2b3ecf | ||
|
|
4a69643858 | ||
|
|
b6a0d63612 | ||
|
|
5145030ff4 | ||
|
|
d3cb812fb6 | ||
|
|
e066c17a65 | ||
|
|
38cff08888 | ||
|
|
3388fc8d06 | ||
|
|
5adcd520fa | ||
|
|
1126407d9b | ||
|
|
a19ff61e15 | ||
|
|
6202461a21 | ||
|
|
ea221f3283 | ||
|
|
7c50d597c3 | ||
|
|
99031695bd | ||
|
|
b7248d5295 | ||
|
|
7f2e7e56d2 | ||
|
|
1fe66737ad | ||
|
|
765eb02279 | ||
|
|
a101377054 | ||
|
|
aca9929d84 | ||
|
|
19a701e5c9 | ||
|
|
fc4305ab15 | ||
|
|
9cf83706e7 | ||
|
|
459c6e2a46 | ||
|
|
72e952eadc | ||
|
|
56a80dec1b | ||
|
|
b894464191 | ||
|
|
b30903d1fc | ||
|
|
7fbe8e3b36 | ||
|
|
2fbc46641d | ||
|
|
17419aca7f | ||
|
|
f85c66789d | ||
|
|
c8b4f6b511 | ||
|
|
3c7555168d | ||
|
|
5eef3d27fb | ||
|
|
75d1504af2 | ||
|
|
a00cf6330f | ||
|
|
1f32477385 | ||
|
|
91c14c7ee9 | ||
|
|
69530afdf9 | ||
|
|
b7667c1604 | ||
|
|
d6f898001b | ||
|
|
a38566693b | ||
|
|
4bef3588b5 | ||
|
|
64538cf6e8 | ||
|
|
aadf3f1d2c | ||
|
|
95bf45ff8b | ||
|
|
2a02c121cf | ||
|
|
4600bb16fc | ||
|
|
7ccdfc30ff | ||
|
|
7f0bdefb6e | ||
|
|
799b2b6628 | ||
|
|
b8d6e44c4f | ||
|
|
5a99cb326c | ||
|
|
e10fac93a6 | ||
|
|
62ae320e1c | ||
|
|
98b1edfc1f | ||
|
|
ab162b3f52 | ||
|
|
b8a13ab755 | ||
|
|
405593ea28 | ||
|
|
24f305c0e3 | ||
|
|
5d553d6369 | ||
|
|
a449e3fdd6 | ||
|
|
764386734c | ||
|
|
7f1d7a595b | ||
|
|
f13e5ca852 | ||
|
|
ecbaeff24b | ||
|
|
691acde696 | ||
|
|
b1e0c1b594 | ||
|
|
93b4ec0351 | ||
|
|
f06fc30c0b | ||
|
|
64b35a8c19 | ||
|
|
688ee4c887 | ||
|
|
9a3dd615e0 | ||
|
|
7e6363dc05 | ||
|
|
a074bd9a2b | ||
|
|
498d41633b | ||
|
|
e0d7c3ac79 | ||
|
|
6a5b122b40 | ||
|
|
bf9ddf2c74 | ||
|
|
3f47871e73 | ||
|
|
85f25967ea | ||
|
|
8e1ddbc5aa | ||
|
|
e6e39f502f | ||
|
|
debb82bc20 | ||
|
|
9a85433477 | ||
|
|
4616c0ac3e | ||
|
|
e55b681774 | ||
|
|
63132105ba | ||
|
|
350b36411c | ||
|
|
1c30c76e72 | ||
|
|
d5adadc00e | ||
|
|
f08805e5c4 | ||
|
|
256b49bda9 | ||
|
|
28cf146d00 | ||
|
|
970261b1e1 | ||
|
|
6b811f8c92 | ||
|
|
f721f94045 | ||
|
|
86524d5c23 | ||
|
|
f18d9e04bc | ||
|
|
fa33423c84 | ||
|
|
1315266dd3 | ||
|
|
b1e52f1475 | ||
|
|
985600f448 | ||
|
|
ace6248e20 | ||
|
|
9f42368e1a | ||
|
|
a401368384 | ||
|
|
5e01e628b2 | ||
|
|
3a408e0e54 | ||
|
|
675d2d5a11 | ||
|
|
281c07ca97 | ||
|
|
004430b568 | ||
|
|
61f7dcb36b | ||
|
|
5c611f7814 | ||
|
|
722cb73019 | ||
|
|
258d3725e7 | ||
|
|
456e6d2b79 | ||
|
|
48e3d76173 | ||
|
|
78fe92507c | ||
|
|
811d8fb3c0 | ||
|
|
f55a9a71cb | ||
|
|
d12df6c2ad | ||
|
|
d1a99d8d45 | ||
|
|
c10e4c2256 | ||
|
|
e3420c08f1 | ||
|
|
4f7aa8c3c8 | ||
|
|
dac73c15c8 | ||
|
|
cb40ddad69 | ||
|
|
fc0529b020 | ||
|
|
837a67bedb | ||
|
|
85f2213d5a | ||
|
|
9b167e2051 | ||
|
|
1870c003d0 | ||
|
|
680177049f | ||
|
|
1b806c5535 | ||
|
|
9b18262567 | ||
|
|
d76d631856 | ||
|
|
17e6f3b3c2 | ||
|
|
5f7a40ae48 | ||
|
|
70435dfb5f | ||
|
|
59ee47ad44 | ||
|
|
ebc02fc6e8 | ||
|
|
05caf1bda9 | ||
|
|
b1dee4a42e | ||
|
|
a54226196d | ||
|
|
196b1e9250 | ||
|
|
345ecd20c9 | ||
|
|
7f0fe20315 | ||
|
|
1e98fd7f2d | ||
|
|
76d32cbd2a | ||
|
|
15139b6ef6 | ||
|
|
14c3d4b1a6 | ||
|
|
910b20fb2c | ||
|
|
4df71ed24f | ||
|
|
406da78fc6 | ||
|
|
5d2bd1e2e4 | ||
|
|
c31daece6c | ||
|
|
c157ddda11 | ||
|
|
c77b6a2c64 | ||
|
|
c6e4947f4a | ||
|
|
01814185a6 | ||
|
|
47d0060934 | ||
|
|
b1c2d851e5 | ||
|
|
970dc6f7aa | ||
|
|
8e2f92607f | ||
|
|
ee1fa6eeb7 | ||
|
|
9d2a017704 | ||
|
|
574b86c247 | ||
|
|
75602f7c29 | ||
|
|
0fd90c1283 | ||
|
|
128b049904 | ||
|
|
0e3f26e6df | ||
|
|
1148e6e142 | ||
|
|
02baaa42ff | ||
|
|
e573676db1 | ||
|
|
4dab6a108c | ||
|
|
a4d521cf96 | ||
|
|
99070bf304 | ||
|
|
93dd6f2b36 | ||
|
|
c61ced3f15 |
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,6 +5,10 @@
|
||||
* Include the link to your `RFC` or `bug` issue in the description.
|
||||
* If the issue does not already have approval from a developer, submit the PR as draft.
|
||||
* The PR title/description will become the commit message. Keep it up-to-date as the PR evolves.
|
||||
* For `feat/fix` PRs, the first paragraph starting with "This PR" must be present and will become a
|
||||
changelog entry unless the PR is labeled with `no-changelog`. If the PR does not have this label,
|
||||
it must instead be categorized with one of the `changelog-*` labels (which will be done by a
|
||||
reviewer for external PRs).
|
||||
* A toolchain of the form `leanprover/lean4-pr-releases:pr-release-NNNN` for Linux and M-series Macs will be generated upon build. To generate binaries for Windows and Intel-based Macs as well, write a comment containing `release-ci` on its own line.
|
||||
* If you rebase your PR onto `nightly-with-mathlib` then CI will test Mathlib against your PR.
|
||||
* You can manage the `awaiting-review`, `awaiting-author`, and `WIP` labels yourself, by writing a comment containing one of these labels on its own line.
|
||||
@@ -12,4 +16,6 @@
|
||||
|
||||
---
|
||||
|
||||
Closes #0000 (`RFC` or `bug` issue number fixed by this PR, if any)
|
||||
This PR <short changelog summary for feat/fix, see above>.
|
||||
|
||||
Closes <`RFC` or `bug` issue number fixed by this PR, if any>
|
||||
|
||||
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
commit-message:
|
||||
prefix: "chore: CI"
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -17,6 +17,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v1
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
pyflakes: false # we do not use python scripts
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -318,7 +318,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: 3.1.44
|
||||
actions-cache-folder: emsdk
|
||||
@@ -492,7 +492,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -536,7 +536,7 @@ jobs:
|
||||
echo -e "\n*Full commit log*\n" >> diff.md
|
||||
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
|
||||
- name: Release Nightly
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
24
.github/workflows/labels-from-comments.yml
vendored
24
.github/workflows/labels-from-comments.yml
vendored
@@ -1,7 +1,8 @@
|
||||
# This workflow allows any user to add one of the `awaiting-review`, `awaiting-author`, `WIP`,
|
||||
# or `release-ci` labels by commenting on the PR or issue.
|
||||
# `release-ci`, or a `changelog-XXX` label by commenting on the PR or issue.
|
||||
# If any labels from the set {`awaiting-review`, `awaiting-author`, `WIP`} are added, other labels
|
||||
# from that set are removed automatically at the same time.
|
||||
# Similarly, if any `changelog-XXX` label is added, other `changelog-YYY` labels are removed.
|
||||
|
||||
name: Label PR based on Comment
|
||||
|
||||
@@ -11,7 +12,7 @@ on:
|
||||
|
||||
jobs:
|
||||
update-label:
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci'))
|
||||
if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-review') || contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP') || contains(github.event.comment.body, 'release-ci') || contains(github.event.comment.body, 'changelog-'))
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -20,13 +21,14 @@ jobs:
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const commentLines = context.payload.comment.body.split('\r\n');
|
||||
|
||||
const awaitingReview = commentLines.includes('awaiting-review');
|
||||
const awaitingAuthor = commentLines.includes('awaiting-author');
|
||||
const wip = commentLines.includes('WIP');
|
||||
const releaseCI = commentLines.includes('release-ci');
|
||||
const changelogMatch = commentLines.find(line => line.startsWith('changelog-'));
|
||||
|
||||
if (awaitingReview || awaitingAuthor || wip) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'awaiting-review' }).catch(() => {});
|
||||
@@ -47,3 +49,19 @@ jobs:
|
||||
if (releaseCI) {
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['release-ci'] });
|
||||
}
|
||||
|
||||
if (changelogMatch) {
|
||||
const changelogLabel = changelogMatch.trim();
|
||||
const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({ owner, repo, issue_number });
|
||||
const changelogLabels = existingLabels.filter(label => label.name.startsWith('changelog-'));
|
||||
|
||||
// Remove all other changelog labels
|
||||
for (const label of changelogLabels) {
|
||||
if (label.name !== changelogLabel) {
|
||||
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label.name }).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new changelog label
|
||||
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: [changelogLabel] });
|
||||
}
|
||||
|
||||
10
.github/workflows/nix-ci.yml
vendored
10
.github/workflows/nix-ci.yml
vendored
@@ -110,14 +110,6 @@ jobs:
|
||||
# https://github.com/netlify/cli/issues/1809
|
||||
cp -r --dereference ./result ./dist
|
||||
if: matrix.name == 'Nix Linux'
|
||||
- name: Check manual for broken links
|
||||
id: lychee
|
||||
uses: lycheeverse/lychee-action@v1.9.0
|
||||
with:
|
||||
fail: false # report errors but do not block CI on temporary failures
|
||||
# gmplib.org consistently times out from GH actions
|
||||
# the GitHub token is to avoid rate limiting
|
||||
args: --base './dist' --no-progress --github-token ${{ secrets.GITHUB_TOKEN }} --exclude 'gmplib.org' './dist/**/*.html'
|
||||
- name: Rebuild Nix Store Cache
|
||||
run: |
|
||||
rm -rf nix-store-cache || true
|
||||
@@ -129,7 +121,7 @@ jobs:
|
||||
python3 -c 'import base64; print("alias="+base64.urlsafe_b64encode(bytes.fromhex("${{github.sha}}")).decode("utf-8").rstrip("="))' >> "$GITHUB_OUTPUT"
|
||||
echo "message=`git log -1 --pretty=format:"%s"`" >> "$GITHUB_OUTPUT"
|
||||
- name: Publish manual to Netlify
|
||||
uses: nwtgck/actions-netlify@v2.0
|
||||
uses: nwtgck/actions-netlify@v3.0
|
||||
id: publish-manual
|
||||
with:
|
||||
publish-dir: ./dist
|
||||
|
||||
25
.github/workflows/pr-body.yml
vendored
Normal file
25
.github/workflows/pr-body.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Check PR body for changelog convention
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited, labeled, converted_to_draft, ready_for_review]
|
||||
|
||||
jobs:
|
||||
check-pr-body:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR body
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { title, body, labels, draft } = context.payload.pull_request;
|
||||
if (!draft && /^(feat|fix):/.test(title) && !labels.some(label => label.name == "changelog-no")) {
|
||||
if (!labels.some(label => label.name.startsWith("changelog-"))) {
|
||||
core.setFailed('feat/fix PR must have a `changelog-*` label');
|
||||
}
|
||||
if (!/^This PR [^<]/.test(body)) {
|
||||
core.setFailed('feat/fix PR must have changelog summary starting with "This PR ..." as first line.');
|
||||
}
|
||||
}
|
||||
10
.github/workflows/pr-release.yml
vendored
10
.github/workflows/pr-release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v2 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v6 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Report release status
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
|
||||
- name: 'Setup jq'
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: dcarbone/install-jq-action@v1.0.1
|
||||
uses: dcarbone/install-jq-action@v2.1.0
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
|
||||
- name: Report mathlib base
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const description =
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 30
|
||||
|
||||
310
RELEASES.md
310
RELEASES.md
@@ -21,7 +21,315 @@ Release candidate, release notes will be copied from the branch `releases/v4.14.
|
||||
v4.13.0
|
||||
----------
|
||||
|
||||
Release candidate, release notes will be copied from the branch `releases/v4.13.0` once completed.
|
||||
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.12.0...v4.13.0
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* `structure` command
|
||||
* [#5511](https://github.com/leanprover/lean4/pull/5511) allows structure parents to be type synonyms.
|
||||
* [#5531](https://github.com/leanprover/lean4/pull/5531) allows default values for structure fields to be noncomputable.
|
||||
|
||||
* `rfl` and `apply_rfl` tactics
|
||||
* [#3714](https://github.com/leanprover/lean4/pull/3714), [#3718](https://github.com/leanprover/lean4/pull/3718) improve the `rfl` tactic and give better error messages.
|
||||
* [#3772](https://github.com/leanprover/lean4/pull/3772) makes `rfl` no longer use kernel defeq for ground terms.
|
||||
* [#5329](https://github.com/leanprover/lean4/pull/5329) tags `Iff.refl` with `@[refl]` (@Parcly-Taxel)
|
||||
* [#5359](https://github.com/leanprover/lean4/pull/5359) ensures that the `rfl` tactic tries `Iff.rfl` (@Parcly-Taxel)
|
||||
|
||||
* `unfold` tactic
|
||||
* [#4834](https://github.com/leanprover/lean4/pull/4834) let `unfold` do zeta-delta reduction of local definitions, incorporating functionality of the Mathlib `unfold_let` tactic.
|
||||
|
||||
* `omega` tactic
|
||||
* [#5382](https://github.com/leanprover/lean4/pull/5382) fixes spurious error in [#5315](https://github.com/leanprover/lean4/issues/5315)
|
||||
* [#5523](https://github.com/leanprover/lean4/pull/5523) supports `Int.toNat`
|
||||
|
||||
* `simp` tactic
|
||||
* [#5479](https://github.com/leanprover/lean4/pull/5479) lets `simp` apply rules with higher-order patterns.
|
||||
|
||||
* `induction` tactic
|
||||
* [#5494](https://github.com/leanprover/lean4/pull/5494) fixes `induction`’s "pre-tactic" block to always be indented, avoiding unintended uses of it.
|
||||
|
||||
* `ac_nf` tactic
|
||||
* [#5524](https://github.com/leanprover/lean4/pull/5524) adds `ac_nf`, a counterpart to `ac_rfl`, for normalizing expressions with respect to associativity and commutativity. Tests it with `BitVec` expressions.
|
||||
|
||||
* `bv_decide`
|
||||
* [#5211](https://github.com/leanprover/lean4/pull/5211) makes `extractLsb'` the primitive `bv_decide` understands, rather than `extractLsb` (@alexkeizer)
|
||||
* [#5365](https://github.com/leanprover/lean4/pull/5365) adds `bv_decide` diagnoses.
|
||||
* [#5375](https://github.com/leanprover/lean4/pull/5375) adds `bv_decide` normalization rules for `ofBool (a.getLsbD i)` and `ofBool a[i]` (@alexkeizer)
|
||||
* [#5423](https://github.com/leanprover/lean4/pull/5423) enhances the rewriting rules of `bv_decide`
|
||||
* [#5433](https://github.com/leanprover/lean4/pull/5433) presents the `bv_decide` counterexample at the API
|
||||
* [#5484](https://github.com/leanprover/lean4/pull/5484) handles `BitVec.ofNat` with `Nat` fvars in `bv_decide`
|
||||
* [#5506](https://github.com/leanprover/lean4/pull/5506), [#5507](https://github.com/leanprover/lean4/pull/5507) add `bv_normalize` rules.
|
||||
* [#5568](https://github.com/leanprover/lean4/pull/5568) generalize the `bv_normalize` pipeline to support more general preprocessing passes
|
||||
* [#5573](https://github.com/leanprover/lean4/pull/5573) gets `bv_normalize` up-to-date with the current `BitVec` rewrites
|
||||
* Cleanups: [#5408](https://github.com/leanprover/lean4/pull/5408), [#5493](https://github.com/leanprover/lean4/pull/5493), [#5578](https://github.com/leanprover/lean4/pull/5578)
|
||||
|
||||
|
||||
* Elaboration improvements
|
||||
* [#5266](https://github.com/leanprover/lean4/pull/5266) preserve order of overapplied arguments in `elab_as_elim` procedure.
|
||||
* [#5510](https://github.com/leanprover/lean4/pull/5510) generalizes `elab_as_elim` to allow arbitrary motive applications.
|
||||
* [#5283](https://github.com/leanprover/lean4/pull/5283), [#5512](https://github.com/leanprover/lean4/pull/5512) refine how named arguments suppress explicit arguments. Breaking change: some previously omitted explicit arguments may need explicit `_` arguments now.
|
||||
* [#5376](https://github.com/leanprover/lean4/pull/5376) modifies projection instance binder info for instances, making parameters that are instance implicit in the type be implicit.
|
||||
* [#5402](https://github.com/leanprover/lean4/pull/5402) localizes universe metavariable errors to `let` bindings and `fun` binders if possible. Makes "cannot synthesize metavariable" errors take precedence over unsolved universe level errors.
|
||||
* [#5419](https://github.com/leanprover/lean4/pull/5419) must not reduce `ite` in the discriminant of `match`-expression when reducibility setting is `.reducible`
|
||||
* [#5474](https://github.com/leanprover/lean4/pull/5474) have autoparams report parameter/field on failure
|
||||
* [#5530](https://github.com/leanprover/lean4/pull/5530) makes automatic instance names about types with hygienic names be hygienic.
|
||||
|
||||
* Deriving handlers
|
||||
* [#5432](https://github.com/leanprover/lean4/pull/5432) makes `Repr` deriving instance handle explicit type parameters
|
||||
|
||||
* Functional induction
|
||||
* [#5364](https://github.com/leanprover/lean4/pull/5364) adds more equalities in context, more careful cleanup.
|
||||
|
||||
* Linters
|
||||
* [#5335](https://github.com/leanprover/lean4/pull/5335) fixes the unused variables linter complaining about match/tactic combinations
|
||||
* [#5337](https://github.com/leanprover/lean4/pull/5337) fixes the unused variables linter complaining about some wildcard patterns
|
||||
|
||||
* Other fixes
|
||||
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
|
||||
|
||||
* Metaprogramming
|
||||
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
|
||||
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
|
||||
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
|
||||
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.
|
||||
* [#5587](https://github.com/leanprover/lean4/pull/5587) allows `MVarId.assertHypotheses` to set `BinderInfo` and `LocalDeclKind`.
|
||||
* [#5588](https://github.com/leanprover/lean4/pull/5588) adds `MVarId.tryClearMany'`, a variant of `MVarId.tryClearMany`.
|
||||
|
||||
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
|
||||
* [#5205](https://github.com/leanprover/lean4/pull/5205) decreases the latency of auto-completion in tactic blocks.
|
||||
* [#5237](https://github.com/leanprover/lean4/pull/5237) fixes symbol occurrence highlighting in VS Code not highlighting occurrences when moving the text cursor into the identifier from the right.
|
||||
* [#5257](https://github.com/leanprover/lean4/pull/5257) fixes several instances of incorrect auto-completions being reported.
|
||||
* [#5299](https://github.com/leanprover/lean4/pull/5299) allows auto-completion to report completions for global identifiers when the elaborator fails to provide context-specific auto-completions.
|
||||
* [#5312](https://github.com/leanprover/lean4/pull/5312) fixes the server breaking when changing whitespace after the module header.
|
||||
* [#5322](https://github.com/leanprover/lean4/pull/5322) fixes several instances of auto-completion reporting non-existent namespaces.
|
||||
* [#5428](https://github.com/leanprover/lean4/pull/5428) makes sure to always report some recent file range as progress when waiting for elaboration.
|
||||
|
||||
|
||||
### Pretty printing
|
||||
|
||||
* [#4979](https://github.com/leanprover/lean4/pull/4979) make pretty printer escape identifiers that are tokens.
|
||||
* [#5389](https://github.com/leanprover/lean4/pull/5389) makes formatter use the current token table.
|
||||
* [#5513](https://github.com/leanprover/lean4/pull/5513) use breakable instead of unbreakable whitespace when formatting tokens.
|
||||
|
||||
|
||||
### Library
|
||||
|
||||
* [#5222](https://github.com/leanprover/lean4/pull/5222) reduces allocations in `Json.compress`.
|
||||
* [#5231](https://github.com/leanprover/lean4/pull/5231) upstreams `Zero` and `NeZero`
|
||||
* [#5292](https://github.com/leanprover/lean4/pull/5292) refactors `Lean.Elab.Deriving.FromToJson` (@arthur-adjedj)
|
||||
* [#5415](https://github.com/leanprover/lean4/pull/5415) implements `Repr Empty` (@TomasPuverle)
|
||||
* [#5421](https://github.com/leanprover/lean4/pull/5421) implements `To/FromJSON Empty` (@TomasPuverle)
|
||||
|
||||
* Logic
|
||||
* [#5263](https://github.com/leanprover/lean4/pull/5263) allows simplifying `dite_not`/`decide_not` with only `Decidable (¬p)`.
|
||||
* [#5268](https://github.com/leanprover/lean4/pull/5268) fixes binders on `ite_eq_left_iff`
|
||||
* [#5284](https://github.com/leanprover/lean4/pull/5284) turns off `Inhabited (Sum α β)` instances
|
||||
* [#5355](https://github.com/leanprover/lean4/pull/5355) adds simp lemmas for `LawfulBEq`
|
||||
* [#5374](https://github.com/leanprover/lean4/pull/5374) add `Nonempty` instances for products, allowing more `partial` functions to elaborate successfully
|
||||
* [#5447](https://github.com/leanprover/lean4/pull/5447) updates Pi instance names
|
||||
* [#5454](https://github.com/leanprover/lean4/pull/5454) makes some instance arguments implicit
|
||||
* [#5456](https://github.com/leanprover/lean4/pull/5456) adds `heq_comm`
|
||||
* [#5529](https://github.com/leanprover/lean4/pull/5529) moves `@[simp]` from `exists_prop'` to `exists_prop`
|
||||
|
||||
* `Bool`
|
||||
* [#5228](https://github.com/leanprover/lean4/pull/5228) fills gaps in Bool lemmas
|
||||
* [#5332](https://github.com/leanprover/lean4/pull/5332) adds notation `^^` for Bool.xor
|
||||
* [#5351](https://github.com/leanprover/lean4/pull/5351) removes `_root_.and` (and or/not/xor) and instead exports/uses `Bool.and` (etc.).
|
||||
|
||||
* `BitVec`
|
||||
* [#5240](https://github.com/leanprover/lean4/pull/5240) removes BitVec simps with complicated RHS
|
||||
* [#5247](https://github.com/leanprover/lean4/pull/5247) `BitVec.getElem_zeroExtend`
|
||||
* [#5248](https://github.com/leanprover/lean4/pull/5248) simp lemmas for BitVec, improving confluence
|
||||
* [#5249](https://github.com/leanprover/lean4/pull/5249) removes `@[simp]` from some BitVec lemmas
|
||||
* [#5252](https://github.com/leanprover/lean4/pull/5252) changes `BitVec.intMin/Max` from abbrev to def
|
||||
* [#5278](https://github.com/leanprover/lean4/pull/5278) adds `BitVec.getElem_truncate` (@tobiasgrosser)
|
||||
* [#5281](https://github.com/leanprover/lean4/pull/5281) adds udiv/umod bitblasting for `bv_decide` (@bollu)
|
||||
* [#5297](https://github.com/leanprover/lean4/pull/5297) `BitVec` unsigned order theoretic results
|
||||
* [#5313](https://github.com/leanprover/lean4/pull/5313) adds more basic BitVec ordering theory for UInt
|
||||
* [#5314](https://github.com/leanprover/lean4/pull/5314) adds `toNat_sub_of_le` (@bollu)
|
||||
* [#5357](https://github.com/leanprover/lean4/pull/5357) adds `BitVec.truncate` lemmas
|
||||
* [#5358](https://github.com/leanprover/lean4/pull/5358) introduces `BitVec.setWidth` to unify zeroExtend and truncate (@tobiasgrosser)
|
||||
* [#5361](https://github.com/leanprover/lean4/pull/5361) some BitVec GetElem lemmas
|
||||
* [#5385](https://github.com/leanprover/lean4/pull/5385) adds `BitVec.ofBool_[and|or|xor]_ofBool` theorems (@tobiasgrosser)
|
||||
* [#5404](https://github.com/leanprover/lean4/pull/5404) more of `BitVec.getElem_*` (@tobiasgrosser)
|
||||
* [#5410](https://github.com/leanprover/lean4/pull/5410) BitVec analogues of `Nat.{mul_two, two_mul, mul_succ, succ_mul}` (@bollu)
|
||||
* [#5411](https://github.com/leanprover/lean4/pull/5411) `BitVec.toNat_{add,sub,mul_of_lt}` for BitVector non-overflow reasoning (@bollu)
|
||||
* [#5413](https://github.com/leanprover/lean4/pull/5413) adds `_self`, `_zero`, and `_allOnes` for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5416](https://github.com/leanprover/lean4/pull/5416) adds LawCommIdentity + IdempotentOp for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5418](https://github.com/leanprover/lean4/pull/5418) decidable quantifers for BitVec
|
||||
* [#5450](https://github.com/leanprover/lean4/pull/5450) adds `BitVec.toInt_[intMin|neg|neg_of_ne_intMin]` (@tobiasgrosser)
|
||||
* [#5459](https://github.com/leanprover/lean4/pull/5459) missing BitVec lemmas
|
||||
* [#5469](https://github.com/leanprover/lean4/pull/5469) adds `BitVec.[not_not, allOnes_shiftLeft_or_shiftLeft, allOnes_shiftLeft_and_shiftLeft]` (@luisacicolini)
|
||||
* [#5478](https://github.com/leanprover/lean4/pull/5478) adds `BitVec.(shiftLeft_add_distrib, shiftLeft_ushiftRight)` (@luisacicolini)
|
||||
* [#5487](https://github.com/leanprover/lean4/pull/5487) adds `sdiv_eq`, `smod_eq` to allow `sdiv`/`smod` bitblasting (@bollu)
|
||||
* [#5491](https://github.com/leanprover/lean4/pull/5491) adds `BitVec.toNat_[abs|sdiv|smod]` (@tobiasgrosser)
|
||||
* [#5492](https://github.com/leanprover/lean4/pull/5492) `BitVec.(not_sshiftRight, not_sshiftRight_not, getMsb_not, msb_not)` (@luisacicolini)
|
||||
* [#5499](https://github.com/leanprover/lean4/pull/5499) `BitVec.Lemmas` - drop non-terminal simps (@tobiasgrosser)
|
||||
* [#5505](https://github.com/leanprover/lean4/pull/5505) unsimps `BitVec.divRec_succ'`
|
||||
* [#5508](https://github.com/leanprover/lean4/pull/5508) adds `BitVec.getElem_[add|add_add_bool|mul|rotateLeft|rotateRight…` (@tobiasgrosser)
|
||||
* [#5554](https://github.com/leanprover/lean4/pull/5554) adds `Bitvec.[add, sub, mul]_eq_xor` and `width_one_cases` (@luisacicolini)
|
||||
|
||||
* `List`
|
||||
* [#5242](https://github.com/leanprover/lean4/pull/5242) improve naming for `List.mergeSort` lemmas
|
||||
* [#5302](https://github.com/leanprover/lean4/pull/5302) provide `mergeSort` comparator autoParam
|
||||
* [#5373](https://github.com/leanprover/lean4/pull/5373) fix name of `List.length_mergeSort`
|
||||
* [#5377](https://github.com/leanprover/lean4/pull/5377) upstream `map_mergeSort`
|
||||
* [#5378](https://github.com/leanprover/lean4/pull/5378) modify signature of lemmas about `mergeSort`
|
||||
* [#5245](https://github.com/leanprover/lean4/pull/5245) avoid importing `List.Basic` without List.Impl
|
||||
* [#5260](https://github.com/leanprover/lean4/pull/5260) review of List API
|
||||
* [#5264](https://github.com/leanprover/lean4/pull/5264) review of List API
|
||||
* [#5269](https://github.com/leanprover/lean4/pull/5269) remove HashMap's duplicated Pairwise and Sublist
|
||||
* [#5271](https://github.com/leanprover/lean4/pull/5271) remove @[simp] from `List.head_mem` and similar
|
||||
* [#5273](https://github.com/leanprover/lean4/pull/5273) lemmas about `List.attach`
|
||||
* [#5275](https://github.com/leanprover/lean4/pull/5275) reverse direction of `List.tail_map`
|
||||
* [#5277](https://github.com/leanprover/lean4/pull/5277) more `List.attach` lemmas
|
||||
* [#5285](https://github.com/leanprover/lean4/pull/5285) `List.count` lemmas
|
||||
* [#5287](https://github.com/leanprover/lean4/pull/5287) use boolean predicates in `List.filter`
|
||||
* [#5289](https://github.com/leanprover/lean4/pull/5289) `List.mem_ite_nil_left` and analogues
|
||||
* [#5293](https://github.com/leanprover/lean4/pull/5293) cleanup of `List.findIdx` / `List.take` lemmas
|
||||
* [#5294](https://github.com/leanprover/lean4/pull/5294) switch primes on `List.getElem_take`
|
||||
* [#5300](https://github.com/leanprover/lean4/pull/5300) more `List.findIdx` theorems
|
||||
* [#5310](https://github.com/leanprover/lean4/pull/5310) fix `List.all/any` lemmas
|
||||
* [#5311](https://github.com/leanprover/lean4/pull/5311) fix `List.countP` lemmas
|
||||
* [#5316](https://github.com/leanprover/lean4/pull/5316) `List.tail` lemma
|
||||
* [#5331](https://github.com/leanprover/lean4/pull/5331) fix implicitness of `List.getElem_mem`
|
||||
* [#5350](https://github.com/leanprover/lean4/pull/5350) `List.replicate` lemmas
|
||||
* [#5352](https://github.com/leanprover/lean4/pull/5352) `List.attachWith` lemmas
|
||||
* [#5353](https://github.com/leanprover/lean4/pull/5353) `List.head_mem_head?`
|
||||
* [#5360](https://github.com/leanprover/lean4/pull/5360) lemmas about `List.tail`
|
||||
* [#5391](https://github.com/leanprover/lean4/pull/5391) review of `List.erase` / `List.find` lemmas
|
||||
* [#5392](https://github.com/leanprover/lean4/pull/5392) `List.fold` / `attach` lemmas
|
||||
* [#5393](https://github.com/leanprover/lean4/pull/5393) `List.fold` relators
|
||||
* [#5394](https://github.com/leanprover/lean4/pull/5394) lemmas about `List.maximum?`
|
||||
* [#5403](https://github.com/leanprover/lean4/pull/5403) theorems about `List.toArray`
|
||||
* [#5405](https://github.com/leanprover/lean4/pull/5405) reverse direction of `List.set_map`
|
||||
* [#5448](https://github.com/leanprover/lean4/pull/5448) add lemmas about `List.IsPrefix` (@Command-Master)
|
||||
* [#5460](https://github.com/leanprover/lean4/pull/5460) missing `List.set_replicate_self`
|
||||
* [#5518](https://github.com/leanprover/lean4/pull/5518) rename `List.maximum?` to `max?`
|
||||
* [#5519](https://github.com/leanprover/lean4/pull/5519) upstream `List.fold` lemmas
|
||||
* [#5520](https://github.com/leanprover/lean4/pull/5520) restore `@[simp]` on `List.getElem_mem` etc.
|
||||
* [#5521](https://github.com/leanprover/lean4/pull/5521) List simp fixes
|
||||
* [#5550](https://github.com/leanprover/lean4/pull/5550) `List.unattach` and simp lemmas
|
||||
* [#5594](https://github.com/leanprover/lean4/pull/5594) induction-friendly `List.min?_cons`
|
||||
|
||||
* `Array`
|
||||
* [#5246](https://github.com/leanprover/lean4/pull/5246) cleanup imports of Array.Lemmas
|
||||
* [#5255](https://github.com/leanprover/lean4/pull/5255) split Init.Data.Array.Lemmas for better bootstrapping
|
||||
* [#5288](https://github.com/leanprover/lean4/pull/5288) rename `Array.data` to `Array.toList`
|
||||
* [#5303](https://github.com/leanprover/lean4/pull/5303) cleanup of `List.getElem_append` variants
|
||||
* [#5304](https://github.com/leanprover/lean4/pull/5304) `Array.not_mem_empty`
|
||||
* [#5400](https://github.com/leanprover/lean4/pull/5400) reorganization in Array/Basic
|
||||
* [#5420](https://github.com/leanprover/lean4/pull/5420) make `Array` functions either semireducible or use structural recursion
|
||||
* [#5422](https://github.com/leanprover/lean4/pull/5422) refactor `DecidableEq (Array α)`
|
||||
* [#5452](https://github.com/leanprover/lean4/pull/5452) refactor of Array
|
||||
* [#5458](https://github.com/leanprover/lean4/pull/5458) cleanup of Array docstrings after refactor
|
||||
* [#5461](https://github.com/leanprover/lean4/pull/5461) restore `@[simp]` on `Array.swapAt!_def`
|
||||
* [#5465](https://github.com/leanprover/lean4/pull/5465) improve Array GetElem lemmas
|
||||
* [#5466](https://github.com/leanprover/lean4/pull/5466) `Array.foldX` lemmas
|
||||
* [#5472](https://github.com/leanprover/lean4/pull/5472) @[simp] lemmas about `List.toArray`
|
||||
* [#5485](https://github.com/leanprover/lean4/pull/5485) reverse simp direction for `toArray_concat`
|
||||
* [#5514](https://github.com/leanprover/lean4/pull/5514) `Array.eraseReps`
|
||||
* [#5515](https://github.com/leanprover/lean4/pull/5515) upstream `Array.qsortOrd`
|
||||
* [#5516](https://github.com/leanprover/lean4/pull/5516) upstream `Subarray.empty`
|
||||
* [#5526](https://github.com/leanprover/lean4/pull/5526) fix name of `Array.length_toList`
|
||||
* [#5527](https://github.com/leanprover/lean4/pull/5527) reduce use of deprecated lemmas in Array
|
||||
* [#5534](https://github.com/leanprover/lean4/pull/5534) cleanup of Array GetElem lemmas
|
||||
* [#5536](https://github.com/leanprover/lean4/pull/5536) fix `Array.modify` lemmas
|
||||
* [#5551](https://github.com/leanprover/lean4/pull/5551) upstream `Array.flatten` lemmas
|
||||
* [#5552](https://github.com/leanprover/lean4/pull/5552) switch obvious cases of array "bang"`[]!` indexing to rely on hypothesis (@TomasPuverle)
|
||||
* [#5577](https://github.com/leanprover/lean4/pull/5577) add missing simp to `Array.size_feraseIdx`
|
||||
* [#5586](https://github.com/leanprover/lean4/pull/5586) `Array/Option.unattach`
|
||||
|
||||
* `Option`
|
||||
* [#5272](https://github.com/leanprover/lean4/pull/5272) remove @[simp] from `Option.pmap/pbind` and add simp lemmas
|
||||
* [#5307](https://github.com/leanprover/lean4/pull/5307) restoring Option simp confluence
|
||||
* [#5354](https://github.com/leanprover/lean4/pull/5354) remove @[simp] from `Option.bind_map`
|
||||
* [#5532](https://github.com/leanprover/lean4/pull/5532) `Option.attach`
|
||||
* [#5539](https://github.com/leanprover/lean4/pull/5539) fix explicitness of `Option.mem_toList`
|
||||
|
||||
* `Nat`
|
||||
* [#5241](https://github.com/leanprover/lean4/pull/5241) add @[simp] to `Nat.add_eq_zero_iff`
|
||||
* [#5261](https://github.com/leanprover/lean4/pull/5261) Nat bitwise lemmas
|
||||
* [#5262](https://github.com/leanprover/lean4/pull/5262) `Nat.testBit_add_one` should not be a global simp lemma
|
||||
* [#5267](https://github.com/leanprover/lean4/pull/5267) protect some Nat bitwise theorems
|
||||
* [#5305](https://github.com/leanprover/lean4/pull/5305) rename Nat bitwise lemmas
|
||||
* [#5306](https://github.com/leanprover/lean4/pull/5306) add `Nat.self_sub_mod` lemma
|
||||
* [#5503](https://github.com/leanprover/lean4/pull/5503) restore @[simp] to upstreamed `Nat.lt_off_iff`
|
||||
|
||||
* `Int`
|
||||
* [#5301](https://github.com/leanprover/lean4/pull/5301) rename `Int.div/mod` to `Int.tdiv/tmod`
|
||||
* [#5320](https://github.com/leanprover/lean4/pull/5320) add `ediv_nonneg_of_nonpos_of_nonpos` to DivModLemmas (@sakehl)
|
||||
|
||||
* `Fin`
|
||||
* [#5250](https://github.com/leanprover/lean4/pull/5250) missing lemma about `Fin.ofNat'`
|
||||
* [#5356](https://github.com/leanprover/lean4/pull/5356) `Fin.ofNat'` uses `NeZero`
|
||||
* [#5379](https://github.com/leanprover/lean4/pull/5379) remove some @[simp]s from Fin lemmas
|
||||
* [#5380](https://github.com/leanprover/lean4/pull/5380) missing Fin @[simp] lemmas
|
||||
|
||||
* `HashMap`
|
||||
* [#5244](https://github.com/leanprover/lean4/pull/5244) (`DHashMap`|`HashMap`|`HashSet`).(`getKey?`|`getKey`|`getKey!`|`getKeyD`)
|
||||
* [#5362](https://github.com/leanprover/lean4/pull/5362) remove the last use of `Lean.(HashSet|HashMap)`
|
||||
* [#5369](https://github.com/leanprover/lean4/pull/5369) `HashSet.ofArray`
|
||||
* [#5370](https://github.com/leanprover/lean4/pull/5370) `HashSet.partition`
|
||||
* [#5581](https://github.com/leanprover/lean4/pull/5581) `Singleton`/`Insert`/`Union` instances for `HashMap`/`Set`
|
||||
* [#5582](https://github.com/leanprover/lean4/pull/5582) `HashSet.all`/`any`
|
||||
* [#5590](https://github.com/leanprover/lean4/pull/5590) adding `Insert`/`Singleton`/`Union` instances for `HashMap`/`Set.Raw`
|
||||
* [#5591](https://github.com/leanprover/lean4/pull/5591) `HashSet.Raw.all/any`
|
||||
|
||||
* `Monads`
|
||||
* [#5463](https://github.com/leanprover/lean4/pull/5463) upstream some monad lemmas
|
||||
* [#5464](https://github.com/leanprover/lean4/pull/5464) adjust simp attributes on monad lemmas
|
||||
* [#5522](https://github.com/leanprover/lean4/pull/5522) more monadic simp lemmas
|
||||
|
||||
* Simp lemma cleanup
|
||||
* [#5251](https://github.com/leanprover/lean4/pull/5251) remove redundant simp annotations
|
||||
* [#5253](https://github.com/leanprover/lean4/pull/5253) remove Int simp lemmas that can't fire
|
||||
* [#5254](https://github.com/leanprover/lean4/pull/5254) variables appearing on both sides of an iff should be implicit
|
||||
* [#5381](https://github.com/leanprover/lean4/pull/5381) cleaning up redundant simp lemmas
|
||||
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
|
||||
* [#4685](https://github.com/leanprover/lean4/pull/4685) fixes a typo in the C `run_new_frontend` signature
|
||||
* [#4729](https://github.com/leanprover/lean4/pull/4729) has IR checker suggest using `noncomputable`
|
||||
* [#5143](https://github.com/leanprover/lean4/pull/5143) adds a shared library for Lake
|
||||
* [#5437](https://github.com/leanprover/lean4/pull/5437) removes (syntactically) duplicate imports (@euprunin)
|
||||
* [#5462](https://github.com/leanprover/lean4/pull/5462) updates `src/lake/lakefile.toml` to the adjusted Lake build process
|
||||
* [#5541](https://github.com/leanprover/lean4/pull/5541) removes new shared libs before build to better support Windows
|
||||
* [#5558](https://github.com/leanprover/lean4/pull/5558) make `lean.h` compile with MSVC (@kant2002)
|
||||
* [#5564](https://github.com/leanprover/lean4/pull/5564) removes non-conforming size-0 arrays (@eric-wieser)
|
||||
|
||||
|
||||
### Lake
|
||||
* Reservoir build cache. Lake will now attempt to fetch a pre-built copy of the package from Reservoir before building it. This is only enabled for packages in the leanprover or leanprover-community organizations on versions indexed by Reservoir. Users can force Lake to build packages from the source by passing --no-cache on the CLI or by setting the LAKE_NO_CACHE environment variable to true. [#5486](https://github.com/leanprover/lean4/pull/5486), [#5572](https://github.com/leanprover/lean4/pull/5572), [#5583](https://github.com/leanprover/lean4/pull/5583), [#5600](https://github.com/leanprover/lean4/pull/5600), [#5641](https://github.com/leanprover/lean4/pull/5641), [#5642](https://github.com/leanprover/lean4/pull/5642).
|
||||
* [#5504](https://github.com/leanprover/lean4/pull/5504) lake new and lake init now produce TOML configurations by default.
|
||||
* [#5878](https://github.com/leanprover/lean4/pull/5878) fixes a serious issue where Lake would delete path dependencies when attempting to cleanup a dependency required with an incorrect name.
|
||||
|
||||
* **Breaking changes**
|
||||
* [#5641](https://github.com/leanprover/lean4/pull/5641) A Lake build of target within a package will no longer build a package's dependencies package-level extra target dependencies. At the technical level, a package's extraDep facet no longer transitively builds its dependencies’ extraDep facets (which include their extraDepTargets).
|
||||
|
||||
### Documentation fixes
|
||||
|
||||
* [#3918](https://github.com/leanprover/lean4/pull/3918) `@[builtin_doc]` attribute (@digama0)
|
||||
* [#4305](https://github.com/leanprover/lean4/pull/4305) explains the borrow syntax (@eric-wieser)
|
||||
* [#5349](https://github.com/leanprover/lean4/pull/5349) adds documentation for `groupBy.loop` (@vihdzp)
|
||||
* [#5473](https://github.com/leanprover/lean4/pull/5473) fixes typo in `BitVec.mul` docstring (@llllvvuu)
|
||||
* [#5476](https://github.com/leanprover/lean4/pull/5476) fixes typos in `Lean.MetavarContext`
|
||||
* [#5481](https://github.com/leanprover/lean4/pull/5481) removes mention of `Lean.withSeconds` (@alexkeizer)
|
||||
* [#5497](https://github.com/leanprover/lean4/pull/5497) updates documentation and tests for `toUIntX` functions (@TomasPuverle)
|
||||
* [#5087](https://github.com/leanprover/lean4/pull/5087) mentions that `inferType` does not ensure type correctness
|
||||
* Many fixes to spelling across the doc-strings, (@euprunin): [#5425](https://github.com/leanprover/lean4/pull/5425) [#5426](https://github.com/leanprover/lean4/pull/5426) [#5427](https://github.com/leanprover/lean4/pull/5427) [#5430](https://github.com/leanprover/lean4/pull/5430) [#5431](https://github.com/leanprover/lean4/pull/5431) [#5434](https://github.com/leanprover/lean4/pull/5434) [#5435](https://github.com/leanprover/lean4/pull/5435) [#5436](https://github.com/leanprover/lean4/pull/5436) [#5438](https://github.com/leanprover/lean4/pull/5438) [#5439](https://github.com/leanprover/lean4/pull/5439) [#5440](https://github.com/leanprover/lean4/pull/5440) [#5599](https://github.com/leanprover/lean4/pull/5599)
|
||||
|
||||
### Changes to CI
|
||||
|
||||
* [#5343](https://github.com/leanprover/lean4/pull/5343) allows addition of `release-ci` label via comment (@thorimur)
|
||||
* [#5344](https://github.com/leanprover/lean4/pull/5344) sets check level correctly during workflow (@thorimur)
|
||||
* [#5444](https://github.com/leanprover/lean4/pull/5444) Mathlib's `lean-pr-testing-NNNN` branches should use Batteries' `lean-pr-testing-NNNN` branches
|
||||
* [#5489](https://github.com/leanprover/lean4/pull/5489) commit `lake-manifest.json` when updating `lean-pr-testing` branches
|
||||
* [#5490](https://github.com/leanprover/lean4/pull/5490) use separate secrets for commenting and branching in `pr-release.yml`
|
||||
|
||||
v4.12.0
|
||||
----------
|
||||
|
||||
@@ -103,10 +103,21 @@ your PR using rebase merge, bypassing the merge queue.
|
||||
As written above, changes in meta code in the current stage usually will only
|
||||
affect later stages. This is an issue in two specific cases.
|
||||
|
||||
* For the special case of *quotations*, it is desirable to have changes in builtin parsers affect them immediately: when the changes in the parser become active in the next stage, builtin macros implemented via quotations should generate syntax trees compatible with the new parser, and quotation patterns in builtin macros and elaborators should be able to match syntax created by the new parser and macros.
|
||||
Since quotations capture the syntax tree structure during execution of the current stage and turn it into code for the next stage, we need to run the current stage's builtin parsers in quotations via the interpreter for this to work.
|
||||
Caveats:
|
||||
* We activate this behavior by default when building stage 1 by setting `-Dinternal.parseQuotWithCurrentStage=true`.
|
||||
We force-disable it inside `macro/macro_rules/elab/elab_rules` via `suppressInsideQuot` as they are guaranteed not to run in the next stage and may need to be run in the current one, so the stage 0 parser is the correct one to use for them.
|
||||
It may be necessary to extend this disabling to functions that contain quotations and are (exclusively) used by one of the mentioned commands. A function using quotations should never be used by both builtin and non-builtin macros/elaborators. Example: https://github.com/leanprover/lean4/blob/f70b7e5722da6101572869d87832494e2f8534b7/src/Lean/Elab/Tactic/Config.lean#L118-L122
|
||||
* The parser needs to be reachable via an `import` statement, otherwise the version of the previous stage will silently be used.
|
||||
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading tokens is taken from the previous stage.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422R13
|
||||
|
||||
* For *non-builtin* meta code such as `notation`s or `macro`s in
|
||||
`Notation.lean`, we expect changes to affect the current file and all later
|
||||
files of the same stage immediately, just like outside the stdlib. To ensure
|
||||
this, we need to build the stage using `-Dinterpreter.prefer_native=false` -
|
||||
this, we build stage 1 using `-Dinterpreter.prefer_native=false` -
|
||||
otherwise, when executing a macro, the interpreter would notice that there is
|
||||
already a native symbol available for this function and run it instead of the
|
||||
new IR, but the symbol is from the previous stage!
|
||||
@@ -124,26 +135,11 @@ affect later stages. This is an issue in two specific cases.
|
||||
further stages (e.g. after an `update-stage0`) will then need to be compiled
|
||||
with the flag set to `false` again since they will expect the new signature.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
|
||||
When enabling `prefer_native`, we usually want to *disable* `parseQuotWithCurrentStage` as it would otherwise make quotations use the interpreter after all.
|
||||
However, there is a specific case where we want to set both options to `true`: when we make changes to a non-builtin parser like `simp` that has a builtin elaborator, we cannot have the new parser be active outside of quotations in stage 1 as the builtin elaborator from stage 0 would not understand them; on the other hand, we need quotations in e.g. the builtin `simp` elaborator to produce the new syntax in the next stage.
|
||||
As this issue usually affects only tactics, enabling `debug.byAsSorry` instead of `prefer_native` can be a simpler solution.
|
||||
|
||||
* For the special case of *quotations*, it is desirable to have changes in
|
||||
built-in parsers affect them immediately: when the changes in the parser
|
||||
become active in the next stage, macros implemented via quotations should
|
||||
generate syntax trees compatible with the new parser, and quotation patterns
|
||||
in macro and elaborators should be able to match syntax created by the new
|
||||
parser and macros. Since quotations capture the syntax tree structure during
|
||||
execution of the current stage and turn it into code for the next stage, we
|
||||
need to run the current stage's built-in parsers in quotation via the
|
||||
interpreter for this to work. Caveats:
|
||||
* Since interpreting full parsers is not nearly as cheap and we rarely change
|
||||
built-in syntax, this needs to be opted in using `-Dinternal.parseQuotWithCurrentStage=true`.
|
||||
* The parser needs to be reachable via an `import` statement, otherwise the
|
||||
version of the previous stage will silently be used.
|
||||
* Only the parser code (`Parser.fn`) is affected; all metadata such as leading
|
||||
tokens is taken from the previous stage.
|
||||
|
||||
For an example, see https://github.com/leanprover/lean4/commit/f9dcbbddc48ccab22c7674ba20c5f409823b4cc1#diff-371387aed38bb02bf7761084fd9460e4168ae16d1ffe5de041b47d3ad2d22422
|
||||
(from before the flag defaulted to `false`).
|
||||
For a `prefer_native` example, see https://github.com/leanprover/lean4/commit/da4c46370d85add64ef7ca5e7cc4638b62823fbb.
|
||||
|
||||
To modify either of these flags both for building and editing the stdlib, adjust
|
||||
the code in `stage0/src/stdlib_flags.h`. The flags will automatically be reset
|
||||
|
||||
@@ -12,17 +12,17 @@ Remark: this example is based on an example found in the Idris manual.
|
||||
Vectors
|
||||
--------
|
||||
|
||||
A `Vector` is a list of size `n` whose elements belong to a type `α`.
|
||||
A `Vec` is a list of size `n` whose elements belong to a type `α`.
|
||||
-/
|
||||
|
||||
inductive Vector (α : Type u) : Nat → Type u
|
||||
| nil : Vector α 0
|
||||
| cons : α → Vector α n → Vector α (n+1)
|
||||
inductive Vec (α : Type u) : Nat → Type u
|
||||
| nil : Vec α 0
|
||||
| cons : α → Vec α n → Vec α (n+1)
|
||||
|
||||
/-!
|
||||
We can overload the `List.cons` notation `::` and use it to create `Vector`s.
|
||||
We can overload the `List.cons` notation `::` and use it to create `Vec`s.
|
||||
-/
|
||||
infix:67 " :: " => Vector.cons
|
||||
infix:67 " :: " => Vec.cons
|
||||
|
||||
/-!
|
||||
Now, we define the types of our simple functional language.
|
||||
@@ -50,11 +50,11 @@ the builtin instance for `Add Int` as the solution.
|
||||
/-!
|
||||
Expressions are indexed by the types of the local variables, and the type of the expression itself.
|
||||
-/
|
||||
inductive HasType : Fin n → Vector Ty n → Ty → Type where
|
||||
inductive HasType : Fin n → Vec Ty n → Ty → Type where
|
||||
| stop : HasType 0 (ty :: ctx) ty
|
||||
| pop : HasType k ctx ty → HasType k.succ (u :: ctx) ty
|
||||
|
||||
inductive Expr : Vector Ty n → Ty → Type where
|
||||
inductive Expr : Vec Ty n → Ty → Type where
|
||||
| var : HasType i ctx ty → Expr ctx ty
|
||||
| val : Int → Expr ctx Ty.int
|
||||
| lam : Expr (a :: ctx) ty → Expr ctx (Ty.fn a ty)
|
||||
@@ -102,8 +102,8 @@ indexed over the types in scope. Since an environment is just another form of li
|
||||
to the vector of local variable types, we overload again the notation `::` so that we can use the usual list syntax.
|
||||
Given a proof that a variable is defined in the context, we can then produce a value from the environment.
|
||||
-/
|
||||
inductive Env : Vector Ty n → Type where
|
||||
| nil : Env Vector.nil
|
||||
inductive Env : Vec Ty n → Type where
|
||||
| nil : Env Vec.nil
|
||||
| cons : Ty.interp a → Env ctx → Env (a :: ctx)
|
||||
|
||||
infix:67 " :: " => Env.cons
|
||||
|
||||
@@ -82,9 +82,7 @@ theorem Expr.typeCheck_correct (h₁ : HasType e ty) (h₂ : e.typeCheck ≠ .un
|
||||
/-!
|
||||
Now, we prove that if `Expr.typeCheck e` returns `Maybe.unknown`, then forall `ty`, `HasType e ty` does not hold.
|
||||
The notation `e.typeCheck` is sugar for `Expr.typeCheck e`. Lean can infer this because we explicitly said that `e` has type `Expr`.
|
||||
The proof is by induction on `e` and case analysis. The tactic `rename_i` is used to rename "inaccessible" variables.
|
||||
We say a variable is inaccessible if it is introduced by a tactic (e.g., `cases`) or has been shadowed by another variable introduced
|
||||
by the user. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
|
||||
The proof is by induction on `e` and case analysis. Note that the tactic `simp [typeCheck]` is applied to all goal generated by the `induction` tactic, and closes
|
||||
the cases corresponding to the constructors `Expr.nat` and `Expr.bool`.
|
||||
-/
|
||||
theorem Expr.typeCheck_complete {e : Expr} : e.typeCheck = .unknown → ¬ HasType e ty := by
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](doc/dev/index.md).
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Quickstart](doc/quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -170,7 +170,7 @@ lib.warn "The Nix-based build is deprecated" rec {
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi' -j$NIX_BUILD_CORES
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
|
||||
@@ -64,7 +64,7 @@ fi
|
||||
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
|
||||
# but do not change sysroot so users can still link against system libs
|
||||
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
|
||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -lpthread -ldl -lrt -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
||||
# when not using the above flags, link GMP dynamically/as usual
|
||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -luv -lpthread -ldl -lrt -Wl,--no-as-needed'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
|
||||
@@ -17,6 +17,8 @@ set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description li
|
||||
set(LEAN_VERSION_STRING "${LEAN_VERSION_MAJOR}.${LEAN_VERSION_MINOR}.${LEAN_VERSION_PATCH}")
|
||||
if (LEAN_SPECIAL_VERSION_DESC)
|
||||
string(APPEND LEAN_VERSION_STRING "-${LEAN_SPECIAL_VERSION_DESC}")
|
||||
elseif (NOT LEAN_VERSION_IS_RELEASE)
|
||||
string(APPEND LEAN_VERSION_STRING "-pre")
|
||||
endif()
|
||||
|
||||
set(LEAN_PLATFORM_TARGET "" CACHE STRING "LLVM triple of the target platform")
|
||||
@@ -49,6 +51,8 @@ option(LLVM "LLVM" OFF)
|
||||
option(USE_GITHASH "GIT_HASH" ON)
|
||||
# When ON we install LICENSE files to CMAKE_INSTALL_PREFIX
|
||||
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
|
||||
# When ON we install a copy of cadical
|
||||
option(INSTALL_CADICAL "Install a copy of cadical" ON)
|
||||
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
|
||||
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
|
||||
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
|
||||
@@ -614,7 +618,7 @@ else()
|
||||
OUTPUT_NAME leancpp)
|
||||
endif()
|
||||
|
||||
if((${STAGE} GREATER 0) AND CADICAL)
|
||||
if((${STAGE} GREATER 0) AND CADICAL AND INSTALL_CADICAL)
|
||||
add_custom_target(copy-cadical
|
||||
COMMAND cmake -E copy_if_different "${CADICAL}" "${CMAKE_BINARY_DIR}/bin/cadical${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
add_dependencies(leancpp copy-cadical)
|
||||
@@ -736,7 +740,7 @@ file(COPY ${LEAN_SOURCE_DIR}/bin/leanmake DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
|
||||
|
||||
if (${STAGE} GREATER 0 AND CADICAL)
|
||||
if (${STAGE} GREATER 0 AND CADICAL AND INSTALL_CADICAL)
|
||||
install(PROGRAMS "${CADICAL}" DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -36,3 +36,4 @@ import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
|
||||
@@ -7,6 +7,7 @@ prelude
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Control.Except
|
||||
import Init.Control.StateRef
|
||||
import Init.Ext
|
||||
|
||||
open Function
|
||||
|
||||
@@ -14,7 +15,7 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@@ -105,7 +106,7 @@ instance : LawfulFunctor (Except ε) := inferInstance
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@@ -167,7 +168,7 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
|
||||
|
||||
namespace StateT
|
||||
|
||||
theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
@[ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
|
||||
@@ -861,16 +861,21 @@ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
|
||||
|
||||
/-! # Decidable -/
|
||||
|
||||
theorem decide_true_eq_true (h : Decidable True) : @decide True h = true :=
|
||||
@[simp] theorem decide_true (h : Decidable True) : @decide True h = true :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
| isFalse h => False.elim <| h ⟨⟩
|
||||
|
||||
theorem decide_false_eq_false (h : Decidable False) : @decide False h = false :=
|
||||
@[simp] theorem decide_false (h : Decidable False) : @decide False h = false :=
|
||||
match h with
|
||||
| isFalse _ => rfl
|
||||
| isTrue h => False.elim h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_true (since := "2024-11-05")] abbrev decide_true_eq_true := decide_true
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_false (since := "2024-11-05")] abbrev decide_false_eq_false := decide_false
|
||||
|
||||
/-- Similar to `decide`, but uses an explicit instance -/
|
||||
@[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool :=
|
||||
decide (h := d)
|
||||
@@ -1917,12 +1922,12 @@ represents an element of `Squash α` the same as `α` itself
|
||||
`Squash.lift` will extract a value in any subsingleton `β` from a function on `α`,
|
||||
while `Nonempty.rec` can only do the same when `β` is a proposition.
|
||||
-/
|
||||
def Squash (α : Type u) := Quot (fun (_ _ : α) => True)
|
||||
def Squash (α : Sort u) := Quot (fun (_ _ : α) => True)
|
||||
|
||||
/-- The canonical quotient map into `Squash α`. -/
|
||||
def Squash.mk {α : Type u} (x : α) : Squash α := Quot.mk _ x
|
||||
def Squash.mk {α : Sort u} (x : α) : Squash α := Quot.mk _ x
|
||||
|
||||
theorem Squash.ind {α : Type u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q :=
|
||||
theorem Squash.ind {α : Sort u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q :=
|
||||
Quot.ind h
|
||||
|
||||
/-- If `β` is a subsingleton, then a function `α → β` lifts to `Squash α → β`. -/
|
||||
|
||||
@@ -42,3 +42,5 @@ import Init.Data.PLift
|
||||
import Init.Data.Zero
|
||||
import Init.Data.NeZero
|
||||
import Init.Data.Function
|
||||
import Init.Data.RArray
|
||||
import Init.Data.Vector
|
||||
|
||||
@@ -17,3 +17,6 @@ import Init.Data.Array.TakeDrop
|
||||
import Init.Data.Array.Bootstrap
|
||||
import Init.Data.Array.GetLit
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Array.Set
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.Array.FinRange
|
||||
|
||||
@@ -10,6 +10,17 @@ import Init.Data.List.Attach
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
`O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`.
|
||||
|
||||
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
|
||||
-/
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) (l : Array α) (H : ∀ a ∈ l, P a) : Array β :=
|
||||
(l.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`Array {x // P x}` is the same as the input `Array α`.
|
||||
@@ -35,6 +46,10 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
l.toArray.attach = (l.attachWith (· ∈ l.toArray) (by simp)).toArray := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem _root_.List.pmap_toArray {l : List α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l.toArray, P a} :
|
||||
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toList_attachWith {l : Array α} {P : α → Prop} {H : ∀ x ∈ l, P x} :
|
||||
(l.attachWith P H).toList = l.toList.attachWith P (by simpa [mem_toList] using H) := by
|
||||
simp [attachWith]
|
||||
@@ -43,6 +58,387 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
l.attach.toList = l.toList.attachWith (· ∈ l) (by simp [mem_toList]) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toList_pmap {l : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l, P a} :
|
||||
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
|
||||
simp [pmap]
|
||||
|
||||
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||
@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : Array α) (H : ∀ a ∈ l, P a) :
|
||||
Array β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h'
|
||||
|
||||
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
|
||||
funext α β p f L h'
|
||||
cases L
|
||||
simp only [pmap, pmapImpl, List.attachWith_toArray, List.map_toArray, mk.injEq, List.map_attachWith]
|
||||
apply List.pmap_congr_left
|
||||
intro a m h₁ h₂
|
||||
congr
|
||||
|
||||
@[simp] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
|
||||
@[simp] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (l : Array α) (h : ∀ b ∈ l.push a, P b) :
|
||||
pmap f (l.push a) h =
|
||||
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
|
||||
@[simp] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #[], P x) : (#[] : Array α).attachWith P H = #[] := rfl
|
||||
|
||||
@[simp] theorem _root_.List.attachWith_mem_toArray {l : List α} :
|
||||
l.attachWith (fun x => x ∈ l.toArray) (fun x h => by simpa using h) =
|
||||
l.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
simp only [List.attachWith, List.attach, List.map_pmap]
|
||||
apply List.pmap_congr_left
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (l : Array α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) l H = map f l := by
|
||||
cases l; simp
|
||||
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (l : Array α) {H₁ H₂}
|
||||
(h : ∀ a ∈ l, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
|
||||
cases l
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (l H) :
|
||||
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
|
||||
cases l
|
||||
simp [List.map_pmap]
|
||||
|
||||
theorem pmap_map {p : β → Prop} (g : ∀ b, p b → γ) (f : α → β) (l H) :
|
||||
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
|
||||
cases l
|
||||
simp [List.pmap_map]
|
||||
|
||||
theorem attach_congr {l₁ l₂ : Array α} (h : l₁ = l₂) :
|
||||
l₁.attach = l₂.attach.map (fun x => ⟨x.1, h ▸ x.2⟩) := by
|
||||
subst h
|
||||
simp
|
||||
|
||||
theorem attachWith_congr {l₁ l₂ : Array α} (w : l₁ = l₂) {P : α → Prop} {H : ∀ x ∈ l₁, P x} :
|
||||
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w ▸ h) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_push {a : α} {l : Array α} :
|
||||
(l.push a).attach =
|
||||
(l.attach.map (fun ⟨x, h⟩ => ⟨x, mem_push_of_mem a h⟩)).push ⟨a, by simp⟩ := by
|
||||
cases l
|
||||
rw [attach_congr (List.push_toArray _ _)]
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_push {a : α} {l : Array α} {P : α → Prop} {H : ∀ x ∈ l.push a, P x} :
|
||||
(l.push a).attachWith P H =
|
||||
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push ⟨a, H a (by simp)⟩ := by
|
||||
cases l
|
||||
simp [attachWith_congr (List.push_toArray _ _)]
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
cases l
|
||||
simp [List.pmap_eq_map_attach]
|
||||
|
||||
theorem attach_map_coe (l : Array α) (f : α → β) :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
cases l
|
||||
simp [List.attach_map_coe]
|
||||
|
||||
theorem attach_map_val (l : Array α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
@[simp]
|
||||
theorem attach_map_subtype_val (l : Array α) : l.attach.map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_coe {p : α → Prop} (f : α → β) (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : Array α) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem mem_attach (l : Array α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).size = l.size := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem size_attach {L : Array α} : L.attach.size = L.size := by
|
||||
cases L; simp
|
||||
|
||||
@[simp]
|
||||
theorem size_attachWith {p : α → Prop} {l : Array α} {H} : (l.attachWith p H).size = l.size := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_empty_iff {p : α → Prop} {f : ∀ a, p a → β} {l H} : pmap f l H = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem pmap_ne_empty_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ #[] ↔ xs ≠ #[] := by
|
||||
cases xs; simp
|
||||
|
||||
theorem pmap_eq_self {l : Array α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
cases l; simp [List.pmap_eq_self]
|
||||
|
||||
@[simp]
|
||||
theorem attach_eq_empty_iff {l : Array α} : l.attach = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem attach_ne_empty_iff {l : Array α} : l.attach ≠ #[] ↔ l ≠ #[] := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem attachWith_eq_empty_iff {l : Array α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H = #[] ↔ l = #[] := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_ne_empty_iff {l : Array α} {P : α → Prop} {H : ∀ a ∈ l, P a} :
|
||||
l.attachWith P H ≠ #[] ↔ l ≠ #[] := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||
(hn : n < (pmap f l h).size) :
|
||||
(pmap f l h)[n] =
|
||||
f (l[n]'(@size_pmap _ _ p f l h ▸ hn))
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f l h ▸ hn))) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : Array α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : Array α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
theorem foldl_pmap (l : Array α) {P : α → Prop} (f : (a : α) → P a → β)
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
theorem foldr_pmap (l : Array α) {P : α → Prop} (f : (a : α) → P a → β)
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldl_subtype` below.
|
||||
-/
|
||||
theorem foldl_attach (l : Array α) (f : β → α → β) (b : β) :
|
||||
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
|
||||
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldr_subtype` below.
|
||||
-/
|
||||
theorem foldr_attach (l : Array α) (f : α → β → β) (b : β) :
|
||||
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.map_attach, size_toArray,
|
||||
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
theorem attach_map {l : Array α} (f : α → β) :
|
||||
(l.map f).attach = l.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem attachWith_map {l : Array α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ l.map f → P b} :
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases l
|
||||
ext
|
||||
· simp
|
||||
· simp only [List.map_toArray, List.attachWith_toArray, List.getElem_toArray,
|
||||
List.getElem_attachWith, List.getElem_map, Function.comp_apply]
|
||||
erw [List.getElem_attachWith] -- Why is `erw` needed here?
|
||||
|
||||
theorem map_attachWith {l : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f =
|
||||
l.pmap (fun a (h : a ∈ l ∧ P a) => f ⟨a, H _ h.1⟩) (fun a h => ⟨h, H a h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
|
||||
theorem map_attach {l : Array α} (f : { x // x ∈ l } → β) :
|
||||
l.attach.map f = l.pmap (fun a h => f ⟨a, h⟩) (fun _ => id) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem attach_filterMap {l : Array α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
cases l
|
||||
rw [attach_congr (List.filterMap_toArray f _)]
|
||||
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
|
||||
|
||||
theorem attach_filter {l : Array α} (p : α → Bool) :
|
||||
(l.filter p).attach = l.attach.filterMap
|
||||
fun x => if w : p x.1 then some ⟨x.1, mem_filter.mpr ⟨x.2, w⟩⟩ else none := by
|
||||
cases l
|
||||
rw [attach_congr (List.filter_toArray p _)]
|
||||
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
pmap (α := { x // x ∈ l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
|
||||
(fun a _ => H₁ a a.2) := by
|
||||
cases l
|
||||
simp [List.pmap_pmap, List.pmap_map]
|
||||
|
||||
@[simp] theorem pmap_append {p : ι → Prop} (f : ∀ a : ι, p a → α) (l₁ l₂ : Array ι)
|
||||
(h : ∀ a ∈ l₁ ++ l₂, p a) :
|
||||
(l₁ ++ l₂).pmap f h =
|
||||
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
|
||||
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ : Array α)
|
||||
(h₁ : ∀ a ∈ l₁, p a) (h₂ : ∀ a ∈ l₂, p a) :
|
||||
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
|
||||
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
|
||||
pmap_append f l₁ l₂ _
|
||||
|
||||
@[simp] theorem attach_append (xs ys : Array α) :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
cases xs
|
||||
cases ys
|
||||
rw [attach_congr (List.append_toArray _ _)]
|
||||
simp [List.attach_append, Function.comp_def]
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
induction xs <;> simp_all
|
||||
|
||||
theorem reverse_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_reverse (xs : Array α) :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr (List.reverse_toArray _)]
|
||||
simp
|
||||
|
||||
theorem reverse_attach (xs : Array α) :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).back? = xs.attach.back?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back?_eq_some h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem back?_attach {xs : Array α} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back?_eq_some h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`Array.unattach` is the (one-sided) inverse of `Array.attach`. It is a synonym for `Array.map Subtype.val`.
|
||||
@@ -83,7 +479,7 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
|
||||
|
||||
@[simp] theorem unattach_attach {l : Array α} : l.attach.unattach = l := by
|
||||
cases l
|
||||
simp
|
||||
simp only [List.attach_toArray, List.unattach_toArray, List.unattach_attachWith]
|
||||
|
||||
@[simp] theorem unattach_attachWith {p : α → Prop} {l : Array α}
|
||||
{H : ∀ a ∈ l, p a} :
|
||||
@@ -91,6 +487,15 @@ def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : Array { x // p x }} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem getElem_unattach
|
||||
{p : α → Prop} {l : Array { x // p x }} (i : Nat) (h : i < l.unattach.size) :
|
||||
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
|
||||
simp [unattach]
|
||||
|
||||
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -12,6 +12,8 @@ import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.GetElem
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.Array.Set
|
||||
|
||||
universe u v w
|
||||
|
||||
/-! ### Array literal syntax -/
|
||||
@@ -29,7 +31,8 @@ namespace Array
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp] theorem size_set (a : Array α) (i : Fin a.size) (v : α) : (set a i v).size = a.size :=
|
||||
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
||||
(set a i v h).size = a.size :=
|
||||
List.length_set ..
|
||||
|
||||
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
|
||||
@@ -141,7 +144,7 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
`fset` may be slightly slower than `uset`. -/
|
||||
@[extern "lean_array_uset"]
|
||||
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
|
||||
a.set ⟨i.toNat, h⟩ v
|
||||
a.set i.toNat v h
|
||||
|
||||
@[extern "lean_array_pop"]
|
||||
def pop (a : Array α) : Array α where
|
||||
@@ -163,14 +166,15 @@ This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_fswap"]
|
||||
def swap (a : Array α) (i j : @& Fin a.size) : Array α :=
|
||||
let v₁ := a.get i
|
||||
let v₂ := a.get j
|
||||
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
|
||||
let v₁ := a[i]
|
||||
let v₂ := a[j]
|
||||
let a' := a.set i v₂
|
||||
a'.set (size_set a i v₂ ▸ j) v₁
|
||||
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
|
||||
|
||||
@[simp] theorem size_swap (a : Array α) (i j : Fin a.size) : (a.swap i j).size = a.size := by
|
||||
show ((a.set i (a.get j)).set (size_set a i _ ▸ j) (a.get i)).size = a.size
|
||||
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
|
||||
show ((a.set i a[j]).set j a[i]
|
||||
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
|
||||
rw [size_set, size_set]
|
||||
|
||||
/--
|
||||
@@ -180,12 +184,14 @@ This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_swap"]
|
||||
def swap! (a : Array α) (i j : @& Nat) : Array α :=
|
||||
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
|
||||
if h₁ : i < a.size then
|
||||
if h₂ : j < a.size then swap a ⟨i, h₁⟩ ⟨j, h₂⟩
|
||||
if h₂ : j < a.size then swap a i j
|
||||
else a
|
||||
else a
|
||||
|
||||
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
|
||||
|
||||
/-! ### GetElem instance for `USize`, backed by `uget` -/
|
||||
|
||||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
@@ -230,7 +236,7 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (mkEmpty n) where
|
||||
|
||||
/-- The array `#[0, 1, ..., n - 1]`. -/
|
||||
def range (n : Nat) : Array Nat :=
|
||||
n.fold (flip Array.push) (mkEmpty n)
|
||||
ofFn fun (i : Fin n) => i
|
||||
|
||||
def singleton (v : α) : Array α :=
|
||||
mkArray 1 v
|
||||
@@ -244,17 +250,17 @@ def get? (a : Array α) (i : Nat) : Option α :=
|
||||
if h : i < a.size then some a[i] else none
|
||||
|
||||
def back? (a : Array α) : Option α :=
|
||||
a.get? (a.size - 1)
|
||||
a[a.size - 1]?
|
||||
|
||||
@[inline] def swapAt (a : Array α) (i : Fin a.size) (v : α) : α × Array α :=
|
||||
let e := a.get i
|
||||
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
|
||||
let e := a[i]
|
||||
let a := a.set i v
|
||||
(e, a)
|
||||
|
||||
@[inline]
|
||||
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
if h : i < a.size then
|
||||
swapAt a ⟨i, h⟩ v
|
||||
swapAt a i v
|
||||
else
|
||||
have : Inhabited (α × Array α) := ⟨(v, a)⟩
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
@@ -271,24 +277,22 @@ def take (a : Array α) (n : Nat) : Array α :=
|
||||
@[inline]
|
||||
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||||
if h : i < a.size then
|
||||
let idx : Fin a.size := ⟨i, h⟩
|
||||
let v := a.get idx
|
||||
let v := a[i]
|
||||
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
|
||||
-- Note: we assume that arrays have a uniform representation irrespective
|
||||
-- of the element type, and that it is valid to store `box(0)` in any array.
|
||||
let a' := a.set idx (unsafeCast ())
|
||||
let a' := a.set i (unsafeCast ())
|
||||
let v ← f v
|
||||
pure <| a'.set (size_set a .. ▸ idx) v
|
||||
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
|
||||
else
|
||||
pure a
|
||||
|
||||
@[implemented_by modifyMUnsafe]
|
||||
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||||
if h : i < a.size then
|
||||
let idx := ⟨i, h⟩
|
||||
let v := a.get idx
|
||||
let v := a[i]
|
||||
let v ← f v
|
||||
pure <| a.set idx v
|
||||
pure <| a.set i v
|
||||
else
|
||||
pure a
|
||||
|
||||
@@ -441,6 +445,8 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
map 0 (mkEmpty as.size)
|
||||
|
||||
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
|
||||
|
||||
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
|
||||
@[inline]
|
||||
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
@@ -453,15 +459,15 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
rw [← inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
|
||||
apply Nat.le_add_right
|
||||
have : i + (j + 1) = as.size := by rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
|
||||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get ⟨j, j_lt⟩)))
|
||||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get j j_lt)))
|
||||
map as.size 0 rfl (mkEmpty as.size)
|
||||
|
||||
@[inline]
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : Nat → α → m β) : m (Array β) :=
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β) :=
|
||||
as.mapFinIdxM fun i a => f i a
|
||||
|
||||
@[inline]
|
||||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : α → m (Option β)) : m (Option β) := do
|
||||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) := do
|
||||
for a in as do
|
||||
match (← f a) with
|
||||
| some b => return b
|
||||
@@ -469,14 +475,14 @@ def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as
|
||||
return none
|
||||
|
||||
@[inline]
|
||||
def findM? {α : Type} {m : Type → Type} [Monad m] (as : Array α) (p : α → m Bool) : m (Option α) := do
|
||||
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
||||
for a in as do
|
||||
if (← p a) then
|
||||
return a
|
||||
return none
|
||||
|
||||
@[inline]
|
||||
def findIdxM? [Monad m] (as : Array α) (p : α → m Bool) : m (Option Nat) := do
|
||||
def findIdxM? [Monad m] (p : α → m Bool) (as : Array α) : m (Option Nat) := do
|
||||
let mut i := 0
|
||||
for a in as do
|
||||
if (← p a) then
|
||||
@@ -528,7 +534,7 @@ def allM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as :
|
||||
return !(← as.anyM (start := start) (stop := stop) fun v => return !(← p v))
|
||||
|
||||
@[inline]
|
||||
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (f : α → m (Option β)) : m (Option β) :=
|
||||
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) :=
|
||||
let rec @[specialize] find : (i : Nat) → i ≤ as.size → m (Option β)
|
||||
| 0, _ => pure none
|
||||
| i+1, h => do
|
||||
@@ -542,7 +548,7 @@ def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
find as.size (Nat.le_refl _)
|
||||
|
||||
@[inline]
|
||||
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (as : Array α) (p : α → m Bool) : m (Option α) :=
|
||||
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) :=
|
||||
as.findSomeRevM? fun a => return if (← p a) then some a else none
|
||||
|
||||
@[inline]
|
||||
@@ -571,7 +577,7 @@ def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size →
|
||||
Id.run <| as.mapFinIdxM f
|
||||
|
||||
@[inline]
|
||||
def mapIdx {α : Type u} {β : Type v} (as : Array α) (f : Nat → α → β) : Array β :=
|
||||
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapIdxM f
|
||||
|
||||
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
|
||||
@@ -579,29 +585,29 @@ def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
||||
arr.mapIdx fun i a => (a, i)
|
||||
|
||||
@[inline]
|
||||
def find? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
|
||||
def find? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findM? p
|
||||
|
||||
@[inline]
|
||||
def findSome? {α : Type u} {β : Type v} (as : Array α) (f : α → Option β) : Option β :=
|
||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeM? f
|
||||
|
||||
@[inline]
|
||||
def findSome! {α : Type u} {β : Type v} [Inhabited β] (a : Array α) (f : α → Option β) : β :=
|
||||
match findSome? a f with
|
||||
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α → Option β) (a : Array α) : β :=
|
||||
match a.findSome? f with
|
||||
| some b => b
|
||||
| none => panic! "failed to find element"
|
||||
|
||||
@[inline]
|
||||
def findSomeRev? {α : Type u} {β : Type v} (as : Array α) (f : α → Option β) : Option β :=
|
||||
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeRevM? f
|
||||
|
||||
@[inline]
|
||||
def findRev? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
|
||||
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findRevM? p
|
||||
|
||||
@[inline]
|
||||
def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
|
||||
def findIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option Nat :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (j : Nat) :=
|
||||
if h : j < as.size then
|
||||
@@ -610,14 +616,20 @@ def findIdx? {α : Type u} (as : Array α) (p : α → Bool) : Option Nat :=
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||||
a.findIdx? fun a => a == v
|
||||
@[inline]
|
||||
def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (j : Nat) :=
|
||||
if h : j < as.size then
|
||||
if p as[j] then some ⟨j, h⟩ else loop (j + 1)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
loop 0
|
||||
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
|
||||
if h : i < a.size then
|
||||
let idx : Fin a.size := ⟨i, h⟩;
|
||||
if a.get idx == v then some idx
|
||||
if a[i] == v then some ⟨i, h⟩
|
||||
else indexOfAux a v (i+1)
|
||||
else none
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
@@ -625,6 +637,10 @@ decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
|
||||
indexOfAux a v 0
|
||||
|
||||
@[deprecated indexOf? (since := "2024-11-20")]
|
||||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||||
a.findIdx? fun a => a == v
|
||||
|
||||
@[inline]
|
||||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.anyM p start stop
|
||||
@@ -733,7 +749,7 @@ where
|
||||
loop (as : Array α) (i : Nat) (j : Fin as.size) :=
|
||||
if h : i < j then
|
||||
have := termination h
|
||||
let as := as.swap ⟨i, Nat.lt_trans h j.2⟩ j
|
||||
let as := as.swap i j (Nat.lt_trans h j.2)
|
||||
have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
|
||||
loop as (i+1) ⟨j-1, this⟩
|
||||
else
|
||||
@@ -742,7 +758,7 @@ where
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def popWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
if h : as.size > 0 then
|
||||
if p (as.get ⟨as.size - 1, Nat.sub_lt h (by decide)⟩) then
|
||||
if p (as[as.size - 1]'(Nat.sub_lt h (by decide))) then
|
||||
popWhile p as.pop
|
||||
else
|
||||
as
|
||||
@@ -754,7 +770,7 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
go (i : Nat) (r : Array α) : Array α :=
|
||||
if h : i < as.size then
|
||||
let a := as.get ⟨i, h⟩
|
||||
let a := as[i]
|
||||
if p a then
|
||||
go (i+1) (r.push a)
|
||||
else
|
||||
@@ -764,49 +780,63 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
go 0 #[]
|
||||
|
||||
/-- Remove the element at a given index from an array without bounds checks, using a `Fin` index.
|
||||
/--
|
||||
Remove the element at a given index from an array without a runtime bounds checks,
|
||||
using a `Nat` index and a tactic-provided bound.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
|
||||
if h : i.val + 1 < a.size then
|
||||
let a' := a.swap ⟨i.val + 1, h⟩ i
|
||||
let i' : Fin a'.size := ⟨i.val + 1, by simp [a', h]⟩
|
||||
a'.feraseIdx i'
|
||||
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
|
||||
if h' : i + 1 < a.size then
|
||||
let a' := a.swap (i + 1) i
|
||||
a'.eraseIdx (i + 1) (by simp [a', h'])
|
||||
else
|
||||
a.pop
|
||||
termination_by a.size - i.val
|
||||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ i.isLt
|
||||
termination_by a.size - i
|
||||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
|
||||
-- This is required in `Lean.Data.PersistentHashMap`.
|
||||
@[simp] theorem size_feraseIdx (a : Array α) (i : Fin a.size) : (a.feraseIdx i).size = a.size - 1 := by
|
||||
induction a, i using Array.feraseIdx.induct with
|
||||
| @case1 a i h a' _ ih =>
|
||||
unfold feraseIdx
|
||||
simp [h, a', ih]
|
||||
| case2 a i h =>
|
||||
unfold feraseIdx
|
||||
simp [h]
|
||||
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
|
||||
induction a, i, h using Array.eraseIdx.induct with
|
||||
| @case1 a i h h' a' ih =>
|
||||
unfold eraseIdx
|
||||
simp [h', a', ih]
|
||||
| case2 a i h h' =>
|
||||
unfold eraseIdx
|
||||
simp [h']
|
||||
|
||||
/-- Remove the element at a given index from an array, or do nothing if the index is out of bounds.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`.-/
|
||||
def eraseIdx (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.feraseIdx ⟨i, h⟩ else a
|
||||
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.eraseIdx i h else a
|
||||
|
||||
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all elements at positions greater than `i`. -/
|
||||
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
|
||||
|
||||
def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
match as.indexOf? a with
|
||||
| none => as
|
||||
| some i => as.feraseIdx i
|
||||
| some i => as.eraseIdx i
|
||||
|
||||
/-- Erase the first element that satisfies the predicate `p`. -/
|
||||
def eraseP (as : Array α) (p : α → Bool) : Array α :=
|
||||
match as.findIdx? p with
|
||||
| none => as
|
||||
| some i => as.eraseIdxIfInBounds i
|
||||
|
||||
/-- Insert element `a` at position `i`. -/
|
||||
@[inline] def insertAt (as : Array α) (i : Fin (as.size + 1)) (a : α) : Array α :=
|
||||
@[inline] def insertIdx (as : Array α) (i : Nat) (a : α) (_ : i ≤ as.size := by get_elem_tactic) : Array α :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
loop (as : Array α) (j : Fin as.size) :=
|
||||
if i.1 < j then
|
||||
let j' := ⟨j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2⟩
|
||||
if i < j then
|
||||
let j' : Fin as.size := ⟨j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2⟩
|
||||
let as := as.swap j' j
|
||||
loop as ⟨j', by rw [size_swap]; exact j'.2⟩
|
||||
else
|
||||
@@ -816,12 +846,23 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
let as := as.push a
|
||||
loop as ⟨j, size_push .. ▸ j.lt_succ_self⟩
|
||||
|
||||
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
|
||||
|
||||
/-- Insert element `a` at position `i`. Panics if `i` is not `i ≤ as.size`. -/
|
||||
def insertAt! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertAt as ⟨i, Nat.lt_succ_of_le h⟩ a
|
||||
insertIdx as i a
|
||||
else panic! "invalid index"
|
||||
|
||||
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
|
||||
|
||||
/-- Insert element `a` at position `i`, or do nothing if `as.size < i`. -/
|
||||
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertIdx as i a
|
||||
else
|
||||
as
|
||||
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool :=
|
||||
if h : i < as.size then
|
||||
@@ -845,12 +886,12 @@ def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
|
||||
false
|
||||
|
||||
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
def zipWithAux (f : α → β → γ) (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) : Array γ :=
|
||||
def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ :=
|
||||
if h : i < as.size then
|
||||
let a := as[i]
|
||||
if h : i < bs.size then
|
||||
let b := bs[i]
|
||||
zipWithAux f as bs (i+1) <| cs.push <| f a b
|
||||
zipWithAux as bs f (i+1) <| cs.push <| f a b
|
||||
else
|
||||
cs
|
||||
else
|
||||
@@ -858,14 +899,27 @@ def zipWithAux (f : α → β → γ) (as : Array α) (bs : Array β) (i : Nat)
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : Array γ :=
|
||||
zipWithAux f as bs 0 #[]
|
||||
zipWithAux as bs f 0 #[]
|
||||
|
||||
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
|
||||
zipWith as bs Prod.mk
|
||||
|
||||
def zipWithAll (as : Array α) (bs : Array β) (f : Option α → Option β → γ) : Array γ :=
|
||||
go as bs 0 #[]
|
||||
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
|
||||
if i < max as.size bs.size then
|
||||
let a := as[i]?
|
||||
let b := bs[i]?
|
||||
go as bs (i+1) (cs.push (f a b))
|
||||
else
|
||||
cs
|
||||
termination_by max as.size bs.size - i
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
def unzip (as : Array (α × β)) : Array α × Array β :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
|
||||
|
||||
@[deprecated partition (since := "2024-11-06")]
|
||||
def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) a =>
|
||||
if p a then (as.push a, bs) else (as, bs.push a)
|
||||
|
||||
@@ -60,7 +60,7 @@ where
|
||||
if ptrEq a b then
|
||||
go (i+1) as
|
||||
else
|
||||
go (i+1) (as.set ⟨i, h⟩ b)
|
||||
go (i+1) (as.set i b h)
|
||||
else
|
||||
return as
|
||||
|
||||
|
||||
@@ -5,59 +5,64 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Omega
|
||||
universe u v
|
||||
|
||||
-- TODO: CLEANUP
|
||||
|
||||
namespace Array
|
||||
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
|
||||
-- TODO: remove `partial` using well-founded recursion
|
||||
|
||||
@[specialize] partial def binSearchAux {α : Type u} {β : Type v} [Inhabited β] (lt : α → α → Bool) (found : Option α → β) (as : Array α) (k : α) : Nat → Nat → β
|
||||
| lo, hi =>
|
||||
if lo <= hi then
|
||||
let _ := Inhabited.mk k
|
||||
let m := (lo + hi)/2
|
||||
let a := as.get! m
|
||||
if lt a k then binSearchAux lt found as k (m+1) hi
|
||||
else if lt k a then
|
||||
if m == 0 then found none
|
||||
else binSearchAux lt found as k lo (m-1)
|
||||
else found (some a)
|
||||
else found none
|
||||
@[specialize] def binSearchAux {α : Type u} {β : Type v} (lt : α → α → Bool) (found : Option α → β) (as : Array α) (k : α) :
|
||||
(lo : Fin (as.size + 1)) → (hi : Fin as.size) → (lo.1 ≤ hi.1) → β
|
||||
| lo, hi, h =>
|
||||
let m := (lo.1 + hi.1)/2
|
||||
let a := as[m]
|
||||
if lt a k then
|
||||
if h' : m + 1 ≤ hi.1 then
|
||||
binSearchAux lt found as k ⟨m+1, by omega⟩ hi h'
|
||||
else found none
|
||||
else if lt k a then
|
||||
if h' : m = 0 ∨ m - 1 < lo.1 then found none
|
||||
else binSearchAux lt found as k lo ⟨m-1, by omega⟩ (by simp; omega)
|
||||
else found (some a)
|
||||
termination_by lo hi => hi.1 - lo.1
|
||||
|
||||
@[inline] def binSearch {α : Type} (as : Array α) (k : α) (lt : α → α → Bool) (lo := 0) (hi := as.size - 1) : Option α :=
|
||||
if lo < as.size then
|
||||
if h : lo < as.size then
|
||||
let hi := if hi < as.size then hi else as.size - 1
|
||||
binSearchAux lt id as k lo hi
|
||||
if w : lo ≤ hi then
|
||||
binSearchAux lt id as k ⟨lo, by omega⟩ ⟨hi, by simp [hi]; split <;> omega⟩ (by simp [hi]; omega)
|
||||
else
|
||||
none
|
||||
else
|
||||
none
|
||||
|
||||
@[inline] def binSearchContains {α : Type} (as : Array α) (k : α) (lt : α → α → Bool) (lo := 0) (hi := as.size - 1) : Bool :=
|
||||
if lo < as.size then
|
||||
if h : lo < as.size then
|
||||
let hi := if hi < as.size then hi else as.size - 1
|
||||
binSearchAux lt Option.isSome as k lo hi
|
||||
if w : lo ≤ hi then
|
||||
binSearchAux lt Option.isSome as k ⟨lo, by omega⟩ ⟨hi, by simp [hi]; split <;> omega⟩ (by simp [hi]; omega)
|
||||
else
|
||||
false
|
||||
else
|
||||
false
|
||||
|
||||
@[specialize] private partial def binInsertAux {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
@[specialize] private def binInsertAux {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
(lt : α → α → Bool)
|
||||
(merge : α → m α)
|
||||
(add : Unit → m α)
|
||||
(as : Array α)
|
||||
(k : α) : Nat → Nat → m (Array α)
|
||||
| lo, hi =>
|
||||
let _ := Inhabited.mk k
|
||||
-- as[lo] < k < as[hi]
|
||||
let mid := (lo + hi)/2
|
||||
let midVal := as.get! mid
|
||||
if lt midVal k then
|
||||
if mid == lo then do let v ← add (); pure <| as.insertAt! (lo+1) v
|
||||
else binInsertAux lt merge add as k mid hi
|
||||
else if lt k midVal then
|
||||
binInsertAux lt merge add as k lo mid
|
||||
(k : α) : (lo : Fin as.size) → (hi : Fin as.size) → (lo.1 ≤ hi.1) → (lt as[lo] k) → m (Array α)
|
||||
| lo, hi, h, w =>
|
||||
let mid := (lo.1 + hi.1)/2
|
||||
let midVal := as[mid]
|
||||
if w₁ : lt midVal k then
|
||||
if h' : mid = lo then do let v ← add (); pure <| as.insertIdx (lo+1) v
|
||||
else binInsertAux lt merge add as k ⟨mid, by omega⟩ hi (by simp; omega) w₁
|
||||
else if w₂ : lt k midVal then
|
||||
have : mid ≠ lo := fun z => by simp [midVal, z] at w₁; simp_all
|
||||
binInsertAux lt merge add as k lo ⟨mid, by omega⟩ (by simp; omega) w
|
||||
else do
|
||||
as.modifyM mid <| fun v => merge v
|
||||
termination_by lo hi => hi.1 - lo.1
|
||||
|
||||
@[specialize] def binInsertM {α : Type u} {m : Type u → Type v} [Monad m]
|
||||
(lt : α → α → Bool)
|
||||
@@ -65,13 +70,12 @@ namespace Array
|
||||
(add : Unit → m α)
|
||||
(as : Array α)
|
||||
(k : α) : m (Array α) :=
|
||||
let _ := Inhabited.mk k
|
||||
if as.isEmpty then do let v ← add (); pure <| as.push v
|
||||
else if lt k (as.get! 0) then do let v ← add (); pure <| as.insertAt! 0 v
|
||||
else if !lt (as.get! 0) k then as.modifyM 0 <| merge
|
||||
else if lt as.back! k then do let v ← add (); pure <| as.push v
|
||||
else if !lt k as.back! then as.modifyM (as.size - 1) <| merge
|
||||
else binInsertAux lt merge add as k 0 (as.size - 1)
|
||||
if h : as.size = 0 then do let v ← add (); pure <| as.push v
|
||||
else if lt k as[0] then do let v ← add (); pure <| as.insertIdx 0 v
|
||||
else if h' : !lt as[0] k then as.modifyM 0 <| merge
|
||||
else if lt as[as.size - 1] k then do let v ← add (); pure <| as.push v
|
||||
else if !lt k as[as.size - 1] then as.modifyM (as.size - 1) <| merge
|
||||
else binInsertAux lt merge add as k ⟨0, by omega⟩ ⟨as.size - 1, by omega⟩ (by simp) (by simpa using h')
|
||||
|
||||
@[inline] def binInsert {α : Type u} (lt : α → α → Bool) (as : Array α) (k : α) : Array α :=
|
||||
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k
|
||||
|
||||
@@ -15,26 +15,26 @@ This file contains some theorems about `Array` and `List` needed for `Init.Data.
|
||||
|
||||
namespace Array
|
||||
|
||||
theorem foldlM_eq_foldlM_toList.aux [Monad m]
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
||||
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.toList.drop j).foldlM f b := by
|
||||
unfold foldlM.loop
|
||||
split; split
|
||||
· cases Nat.not_le_of_gt ‹_› (Nat.zero_add _ ▸ H)
|
||||
· rename_i i; rw [Nat.succ_add] at H
|
||||
simp [foldlM_eq_foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (occs := .pos [2]) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||
simp [foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (occs := [2]) [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
@[simp] theorem foldlM_toList [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
arr.foldlM f init = arr.toList.foldlM f init := by
|
||||
simp [foldlM, foldlM_eq_foldlM_toList.aux]
|
||||
arr.toList.foldlM f init = arr.foldlM f init := by
|
||||
simp [foldlM, foldlM_toList.aux]
|
||||
|
||||
theorem foldl_eq_foldl_toList (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.toList.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_eq_foldlM_toList ..
|
||||
@[simp] theorem foldl_toList (f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.toList.foldl f init = arr.foldl f init :=
|
||||
List.foldl_eq_foldlM .. ▸ foldlM_toList ..
|
||||
|
||||
theorem foldrM_eq_reverse_foldlM_toList.aux [Monad m]
|
||||
(f : α → β → m β) (arr : Array α) (init : β) (i h) :
|
||||
@@ -51,23 +51,23 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
|
||||
match arr, this with | _, .inl rfl => rfl | arr, .inr h => ?_
|
||||
simp [foldrM, h, ← foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
|
||||
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
@[simp] theorem foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.toList.foldrM f init := by
|
||||
arr.toList.foldrM f init = arr.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_toList, List.foldlM_reverse]
|
||||
|
||||
theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.toList.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_eq_foldrM_toList ..
|
||||
@[simp] theorem foldr_toList (f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.toList.foldr f init = arr.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_toList ..
|
||||
|
||||
@[simp] theorem push_toList (arr : Array α) (a : α) : (arr.push a).toList = arr.toList ++ [a] := by
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[simp] theorem toListAppend_eq (arr : Array α) (l) : arr.toListAppend l = arr.toList ++ l := by
|
||||
simp [toListAppend, foldr_eq_foldr_toList]
|
||||
simp [toListAppend, ← foldr_toList]
|
||||
|
||||
@[simp] theorem toListImpl_eq (arr : Array α) : arr.toListImpl = arr.toList := by
|
||||
simp [toListImpl, foldr_eq_foldr_toList]
|
||||
simp [toListImpl, ← foldr_toList]
|
||||
|
||||
@[simp] theorem pop_toList (arr : Array α) : arr.pop.toList = arr.toList.dropLast := rfl
|
||||
|
||||
@@ -76,9 +76,20 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
|
||||
@[simp] theorem toList_append (arr arr' : Array α) :
|
||||
(arr ++ arr').toList = arr.toList ++ arr'.toList := by
|
||||
rw [← append_eq_append]; unfold Array.append
|
||||
rw [foldl_eq_foldl_toList]
|
||||
rw [← foldl_toList]
|
||||
induction arr'.toList generalizing arr <;> simp [*]
|
||||
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
@[simp] theorem appendList_eq_append
|
||||
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
|
||||
|
||||
@@ -87,20 +98,44 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
|
||||
rw [← appendList_eq_append]; unfold Array.appendList
|
||||
induction l generalizing arr <;> simp [*]
|
||||
|
||||
@[deprecated foldlM_eq_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldlM_eq_foldlM_data := @foldlM_eq_foldlM_toList
|
||||
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
(f : α → β → m β) (init : β) (arr : Array α) :
|
||||
arr.foldrM f init = arr.toList.foldrM f init := by
|
||||
simp
|
||||
|
||||
@[deprecated foldl_eq_foldl_toList (since := "2024-09-09")]
|
||||
abbrev foldl_eq_foldl_data := @foldl_eq_foldl_toList
|
||||
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
arr.foldlM f init = arr.toList.foldlM f init:= by
|
||||
simp
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldr_toList`." (since := "2024-11-13")]
|
||||
theorem foldr_eq_foldr_toList
|
||||
(f : α → β → β) (init : β) (arr : Array α) :
|
||||
arr.foldr f init = arr.toList.foldr f init := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldl_toList`." (since := "2024-11-13")]
|
||||
theorem foldl_eq_foldl_toList
|
||||
(f : β → α → β) (init : β) (arr : Array α) :
|
||||
arr.foldl f init = arr.toList.foldl f init:= by
|
||||
simp
|
||||
|
||||
@[deprecated foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldlM_eq_foldlM_data := @foldlM_toList
|
||||
|
||||
@[deprecated foldl_toList (since := "2024-09-09")]
|
||||
abbrev foldl_eq_foldl_data := @foldl_toList
|
||||
|
||||
@[deprecated foldrM_eq_reverse_foldlM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_reverse_foldlM_data := @foldrM_eq_reverse_foldlM_toList
|
||||
|
||||
@[deprecated foldrM_eq_foldrM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_foldrM_data := @foldrM_eq_foldrM_toList
|
||||
@[deprecated foldrM_toList (since := "2024-09-09")]
|
||||
abbrev foldrM_eq_foldrM_data := @foldrM_toList
|
||||
|
||||
@[deprecated foldr_eq_foldr_toList (since := "2024-09-09")]
|
||||
abbrev foldr_eq_foldr_data := @foldr_eq_foldr_toList
|
||||
@[deprecated foldr_toList (since := "2024-09-09")]
|
||||
abbrev foldr_eq_foldr_data := @foldr_toList
|
||||
|
||||
@[deprecated push_toList (since := "2024-09-09")]
|
||||
abbrev push_data := @push_toList
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.BEq
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.ByCases
|
||||
|
||||
|
||||
14
src/Init/Data/Array/FinRange.lean
Normal file
14
src/Init/Data/Array/FinRange.lean
Normal file
@@ -0,0 +1,14 @@
|
||||
/-
|
||||
Copyright (c) 2024 François G. Dorais. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
namespace Array
|
||||
|
||||
/-- `finRange n` is the array of all elements of `Fin n` in order. -/
|
||||
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
|
||||
|
||||
end Array
|
||||
281
src/Init/Data/Array/Find.lean
Normal file
281
src/Init/Data/Array/Find.lean
Normal file
@@ -0,0 +1,281 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Find
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.findSome?`, `Array.find?`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp] theorem findSomeRev?_push_of_isSome (l : Array α) (h : (f a).isSome) : (l.push a).findSomeRev? f = f a := by
|
||||
cases l; simp_all
|
||||
|
||||
@[simp] theorem findSomeRev?_push_of_isNone (l : Array α) (h : (f a).isNone) : (l.push a).findSomeRev? f = l.findSomeRev? f := by
|
||||
cases l; simp_all
|
||||
|
||||
theorem exists_of_findSome?_eq_some {f : α → Option β} {l : Array α} (w : l.findSome? f = some b) :
|
||||
∃ a, a ∈ l ∧ f a = b := by
|
||||
cases l; simp_all [List.exists_of_findSome?_eq_some]
|
||||
|
||||
@[simp] theorem findSome?_eq_none_iff : findSome? p l = none ↔ ∀ x ∈ l, p x = none := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem findSome?_isSome_iff {f : α → Option β} {l : Array α} :
|
||||
(l.findSome? f).isSome ↔ ∃ x, x ∈ l ∧ (f x).isSome := by
|
||||
cases l; simp
|
||||
|
||||
theorem findSome?_eq_some_iff {f : α → Option β} {l : Array α} {b : β} :
|
||||
l.findSome? f = some b ↔ ∃ (l₁ : Array α) (a : α) (l₂ : Array α), l = l₁.push a ++ l₂ ∧ f a = some b ∧ ∀ x ∈ l₁, f x = none := by
|
||||
cases l
|
||||
simp only [List.findSome?_toArray, List.findSome?_eq_some_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, a, l₂, rfl, h₁, h₂⟩
|
||||
exact ⟨l₁.toArray, a, l₂.toArray, by simp_all⟩
|
||||
· rintro ⟨l₁, a, l₂, h₀, h₁, h₂⟩
|
||||
exact ⟨l₁.toList, a, l₂.toList, by simpa using congrArg toList h₀, h₁, by simpa⟩
|
||||
|
||||
@[simp] theorem findSome?_guard (l : Array α) : findSome? (Option.guard fun x => p x) l = find? p l := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem getElem?_zero_filterMap (f : α → Option β) (l : Array α) : (l.filterMap f)[0]? = l.findSome? f := by
|
||||
cases l; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filterMap (f : α → Option β) (l : Array α) (h) :
|
||||
(l.filterMap f)[0] = (l.findSome? f).get (by cases l; simpa [List.length_filterMap_eq_countP] using h) := by
|
||||
cases l; simp [← List.head_eq_getElem, ← getElem?_zero_filterMap]
|
||||
|
||||
@[simp] theorem back?_filterMap (f : α → Option β) (l : Array α) : (l.filterMap f).back? = l.findSomeRev? f := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem back!_filterMap [Inhabited β] (f : α → Option β) (l : Array α) :
|
||||
(l.filterMap f).back! = (l.findSomeRev? f).getD default := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem map_findSome? (f : α → Option β) (g : β → γ) (l : Array α) :
|
||||
(l.findSome? f).map g = l.findSome? (Option.map g ∘ f) := by
|
||||
cases l; simp
|
||||
|
||||
theorem findSome?_map (f : β → γ) (l : Array β) : findSome? p (l.map f) = l.findSome? (p ∘ f) := by
|
||||
cases l; simp [List.findSome?_map]
|
||||
|
||||
theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (l₁.findSome? f).or (l₂.findSome? f) := by
|
||||
cases l₁; cases l₂; simp [List.findSome?_append]
|
||||
|
||||
theorem getElem?_zero_flatten (L : Array (Array α)) :
|
||||
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
|
||||
cases L using array_array_induction
|
||||
simp [← List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
|
||||
(L.findSome? fun l => l[0]?).isSome := by
|
||||
cases L using array_array_induction
|
||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
||||
List.findSome?_isSome_iff, List.isSome_getElem?]
|
||||
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
|
||||
Nat.sum_pos_iff_exists_pos, List.mem_map] at h
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
exact ⟨xs, m, by simpa using h⟩
|
||||
|
||||
theorem getElem_zero_flatten {L : Array (Array α)} (h) :
|
||||
(flatten L)[0] = (L.findSome? fun l => l[0]?).get (getElem_zero_flatten.proof h) := by
|
||||
have t := getElem?_zero_flatten L
|
||||
simp [getElem?_eq_getElem, h] at t
|
||||
simp [← t]
|
||||
|
||||
theorem back?_flatten {L : Array (Array α)} :
|
||||
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
|
||||
cases L using array_array_induction
|
||||
simp [List.getLast?_flatten, ← List.map_reverse, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@[simp] theorem findSome?_mkArray_of_pos (h : 0 < n) : findSome? f (mkArray n a) = f a := by
|
||||
simp [findSome?_mkArray, Nat.ne_of_gt h]
|
||||
|
||||
-- Argument is unused, but used to decide whether `simp` should unfold.
|
||||
@[simp] theorem findSome?_mkArray_of_isSome (_ : (f a).isSome) :
|
||||
findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
simp [findSome?_mkArray]
|
||||
|
||||
@[simp] theorem findSome?_mkArray_of_isNone (h : (f a).isNone) :
|
||||
findSome? f (mkArray n a) = none := by
|
||||
rw [Option.isNone_iff_eq_none] at h
|
||||
simp [findSome?_mkArray, h]
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp] theorem find?_singleton (a : α) (p : α → Bool) :
|
||||
#[a].find? p = if p a then some a else none := by
|
||||
simp [singleton_eq_toArray_singleton]
|
||||
|
||||
@[simp] theorem findRev?_push_of_pos (l : Array α) (h : p a) :
|
||||
findRev? p (l.push a) = some a := by
|
||||
cases l; simp [h]
|
||||
|
||||
@[simp] theorem findRev?_cons_of_neg (l : Array α) (h : ¬p a) :
|
||||
findRev? p (l.push a) = findRev? p l := by
|
||||
cases l; simp [h]
|
||||
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
cases l; simp
|
||||
|
||||
theorem find?_eq_some_iff_append {xs : Array α} :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ (as bs : Array α), xs = as.push b ++ bs ∧ ∀ a ∈ as, !p a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.find?_toArray, List.find?_eq_some_iff_append, Bool.not_eq_eq_eq_not,
|
||||
Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ⟨⟨x, rfl⟩, h⟩⟩
|
||||
exact ⟨as.toArray, ⟨x.toArray, by simp⟩ , by simpa using h⟩
|
||||
· rintro ⟨as, ⟨⟨x, h'⟩, h⟩⟩
|
||||
exact ⟨as.toList, ⟨x.toList, by simpa using congrArg Array.toList h'⟩,
|
||||
by simpa using h⟩
|
||||
|
||||
@[simp]
|
||||
theorem find?_push_eq_some {xs : Array α} :
|
||||
(xs.push a).find? p = some b ↔ xs.find? p = some b ∨ (xs.find? p = none ∧ (p a ∧ a = b)) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_some {xs : Array α} (h : find? p xs = some a) : p a := by
|
||||
cases xs
|
||||
simp at h
|
||||
exact List.find?_some h
|
||||
|
||||
theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ xs := by
|
||||
cases xs
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
@[simp] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem getElem?_zero_filter (p : α → Bool) (l : Array α) :
|
||||
(l.filter p)[0]? = l.find? p := by
|
||||
cases l; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getElem_zero_filter (p : α → Bool) (l : Array α) (h) :
|
||||
(l.filter p)[0] =
|
||||
(l.find? p).get (by cases l; simpa [← List.countP_eq_length_filter] using h) := by
|
||||
cases l
|
||||
simp [List.getElem_zero_eq_head]
|
||||
|
||||
@[simp] theorem back?_filter (p : α → Bool) (l : Array α) : (l.filter p).back? = l.findRev? p := by
|
||||
cases l; simp
|
||||
|
||||
@[simp] theorem back!_filter [Inhabited α] (p : α → Bool) (l : Array α) :
|
||||
(l.filter p).back! = (l.findRev? p).get! := by
|
||||
cases l; simp [Option.get!_eq_getD]
|
||||
|
||||
@[simp] theorem find?_filterMap (xs : Array α) (f : α → Option β) (p : β → Bool) :
|
||||
(xs.filterMap f).find? p = (xs.find? (fun a => (f a).any p)).bind f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_map (f : β → α) (xs : Array β) :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem find?_append {l₁ l₂ : Array α} :
|
||||
(l₁ ++ l₂).find? p = (l₁.find? p).or (l₂.find? p) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α → Bool) :
|
||||
xs.flatten.find? p = xs.findSome? (·.find? p) := by
|
||||
cases xs using array_array_induction
|
||||
simp [List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem find?_flatten_eq_none {xs : Array (Array α)} {p : α → Bool} :
|
||||
xs.flatten.find? p = none ↔ ∀ ys ∈ xs, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
|
||||
Moreover, no earlier array in `xs` has an element satisfying `p`.
|
||||
-/
|
||||
theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α → Bool} {a : α} :
|
||||
xs.flatten.find? p = some a ↔
|
||||
p a ∧ ∃ (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
|
||||
xs = as.push (ys.push a ++ zs) ++ bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
cases xs using array_array_induction
|
||||
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ys, ⟨⟨zs, bs, rfl⟩, h₁, h₂⟩⟩
|
||||
exact ⟨as.toArray.map List.toArray, ys.toArray,
|
||||
⟨zs.toArray, bs.toArray.map List.toArray, by simp⟩, by simpa using h₁, by simpa using h₂⟩
|
||||
· rintro ⟨as, ys, ⟨⟨zs, bs, h⟩, h₁, h₂⟩⟩
|
||||
replace h := congrArg (·.map Array.toList) (congrArg Array.toList h)
|
||||
simp [Function.comp_def] at h
|
||||
exact ⟨as.toList.map Array.toList, ys.toList,
|
||||
⟨zs.toList, bs.toList.map Array.toList, by simpa using h⟩,
|
||||
by simpa using h₁, by simpa using h₂⟩
|
||||
|
||||
@[simp] theorem find?_flatMap (xs : Array α) (f : α → Array β) (p : β → Bool) :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
simp [List.find?_flatMap, Array.flatMap_toArray]
|
||||
|
||||
theorem find?_flatMap_eq_none {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
simp
|
||||
|
||||
theorem find?_mkArray :
|
||||
find? p (mkArray n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_length_pos (h : 0 < n) :
|
||||
find? p (mkArray n a) = if p a then some a else none := by
|
||||
simp [find?_mkArray, Nat.ne_of_gt h]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_pos (h : p a) :
|
||||
find? p (mkArray n a) = if n = 0 then none else some a := by
|
||||
simp [find?_mkArray, h]
|
||||
|
||||
@[simp] theorem find?_mkArray_of_neg (h : ¬ p a) : find? p (mkArray n a) = none := by
|
||||
simp [find?_mkArray, h]
|
||||
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_mkArray_eq_none {n : Nat} {a : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [mkArray_eq_toArray_replicate, List.find?_replicate_eq_none, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[simp] theorem find?_mkArray_eq_some {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(mkArray n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
|
||||
@[simp] theorem get_find?_mkArray (n : Nat) (a : α) (p : α → Bool) (h) :
|
||||
((mkArray n a).find? p).get h = a := by
|
||||
simp [mkArray_eq_toArray_replicate]
|
||||
|
||||
theorem find?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Array α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (p : β → Bool) :
|
||||
(xs.pmap f H).find? p = (xs.attach.find? (fun ⟨a, m⟩ => p (f a (H a m)))).map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
simp only [pmap_eq_map_attach, find?_map]
|
||||
rfl
|
||||
|
||||
end Array
|
||||
@@ -41,6 +41,6 @@ where
|
||||
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) ▸ h₂) :=
|
||||
rfl
|
||||
go (i : Nat) (hi : i ≤ as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.get_drop_eq_drop, *]
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -5,24 +5,91 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Fold
|
||||
import Init.Data.Vector.Lemmas
|
||||
|
||||
@[inline] def Array.insertionSort (a : Array α) (lt : α → α → Bool) : Array α :=
|
||||
traverse a 0 a.size
|
||||
where
|
||||
@[specialize] traverse (a : Array α) (i : Nat) (fuel : Nat) : Array α :=
|
||||
match fuel with
|
||||
| 0 => a
|
||||
| fuel+1 =>
|
||||
if h : i < a.size then
|
||||
traverse (swapLoop a i h) (i+1) fuel
|
||||
else
|
||||
a
|
||||
@[specialize] swapLoop (a : Array α) (j : Nat) (h : j < a.size) : Array α :=
|
||||
match (generalizing := false) he:j with -- using `generalizing` because we don't want to refine the type of `h`
|
||||
| 0 => a
|
||||
| j'+1 =>
|
||||
have h' : j' < a.size := by subst j; exact Nat.lt_trans (Nat.lt_succ_self _) h
|
||||
if lt a[j] a[j'] then
|
||||
swapLoop (a.swap ⟨j, h⟩ ⟨j', h'⟩) j' (by rw [size_swap]; assumption; done)
|
||||
else
|
||||
a
|
||||
namespace Vector
|
||||
|
||||
/-- Swap the `i`-th element repeatedly to the left, while the element to its left is not `lt` it. -/
|
||||
@[specialize, inline] def swapLeftWhileLT {n} (a : Vector α n) (i : Nat) (h : i < n)
|
||||
(lt : α → α → Bool := by exact (· < ·)) : Vector α n :=
|
||||
match h' : i with
|
||||
| 0 => a
|
||||
| i'+1 =>
|
||||
if lt a[i] a[i'] then
|
||||
swapLeftWhileLT (a.swap i' i) i' (by omega) lt
|
||||
else
|
||||
a
|
||||
|
||||
end Vector
|
||||
|
||||
open Vector
|
||||
namespace Array
|
||||
|
||||
/-- Sort an array in place using insertion sort. -/
|
||||
@[inline] def insertionSort (a : Array α) (lt : α → α → Bool := by exact (· < ·)) : Array α :=
|
||||
a.size.fold (init := ⟨a, rfl⟩) (fun i h acc => swapLeftWhileLT acc i h lt) |>.toArray
|
||||
|
||||
/-- Insert an element into an array, after the last element which is not `lt` the inserted element. -/
|
||||
def orderedInsert (a : Array α) (x : α) (lt : α → α → Bool := by exact (· < ·)) : Array α :=
|
||||
swapLeftWhileLT ⟨a.push x, rfl⟩ a.size (by simp) lt |>.toArray
|
||||
|
||||
end Array
|
||||
|
||||
/-! ### Verification -/
|
||||
|
||||
namespace Vector
|
||||
|
||||
theorem swapLeftWhileLT_push {n} (a : Vector α n) (x : α) (j : Nat) (h : j < n) :
|
||||
swapLeftWhileLT (a.push x) j (by omega) lt = (swapLeftWhileLT a j h lt).push x := by
|
||||
induction j generalizing a with
|
||||
| zero => simp [swapLeftWhileLT]
|
||||
| succ j ih =>
|
||||
simp [swapLeftWhileLT]
|
||||
split <;> rename_i h
|
||||
· rw [Vector.getElem_push_lt (by omega), Vector.getElem_push_lt (by omega)] at h
|
||||
rw [← Vector.push_swap, ih, if_pos h]
|
||||
· rw [Vector.getElem_push_lt (by omega), Vector.getElem_push_lt (by omega)] at h
|
||||
rw [if_neg h]
|
||||
|
||||
theorem swapLeftWhileLT_cast {n m} (a : Vector α n) (j : Nat) (h : j < n) (h' : n = m) :
|
||||
swapLeftWhileLT (a.cast h') j (by omega) lt = (swapLeftWhileLT a j h lt).cast h' := by
|
||||
subst h'
|
||||
simp
|
||||
|
||||
end Vector
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem size_insertionSort (a : Array α) : (a.insertionSort lt).size = a.size := by
|
||||
simp [insertionSort]
|
||||
|
||||
private theorem insertionSort_push' (a : Array α) (x : α) :
|
||||
(a.push x).insertionSort lt =
|
||||
(swapLeftWhileLT ⟨(a.insertionSort lt).push x, rfl⟩ a.size (by simp) lt).toArray := by
|
||||
rw [insertionSort, Nat.fold_congr (size_push a x), Nat.fold]
|
||||
have : (a.size.fold (fun i h acc => swapLeftWhileLT acc i (by simp; omega) lt) ⟨a.push x, rfl⟩) =
|
||||
((a.size.fold (fun i h acc => swapLeftWhileLT acc i h lt) ⟨a, rfl⟩).push x).cast (by simp) := by
|
||||
rw [Vector.eq_cast_iff]
|
||||
simp only [Nat.fold_eq_finRange_foldl]
|
||||
rw [← List.foldl_hom (fun a => (Vector.push x a)) _ (fun v ⟨i, h⟩ => swapLeftWhileLT v i (by omega) lt)]
|
||||
rw [Vector.push_mk]
|
||||
rw [← List.foldl_hom (Vector.cast _) _ (fun v ⟨i, h⟩ => swapLeftWhileLT v i (by omega) lt)]
|
||||
· simp
|
||||
· intro v i
|
||||
simp only
|
||||
rw [swapLeftWhileLT_cast]
|
||||
· simp [swapLeftWhileLT_push]
|
||||
rw [this]
|
||||
simp only [Nat.lt_add_one, swapLeftWhileLT_cast, Vector.toArray_cast]
|
||||
unfold insertionSort
|
||||
simp only [Vector.push]
|
||||
congr
|
||||
all_goals simp
|
||||
|
||||
theorem insertionSort_push (a : Array α) (x : α) :
|
||||
(a.push x).insertionSort lt = (a.insertionSort lt).orderedInsert x lt := by
|
||||
rw [insertionSort_push', orderedInsert]
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -66,35 +66,35 @@ theorem mapFinIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
theorem mapIdx_induction (as : Array α) (f : Nat → α → β)
|
||||
theorem mapIdx_induction (f : Nat → α → β) (as : Array α)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
motive as.size ∧ ∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
mapFinIdx_induction as (fun i a => f i a) motive h0 p hs
|
||||
|
||||
theorem mapIdx_spec (as : Array α) (f : Nat → α → β)
|
||||
theorem mapIdx_spec (f : Nat → α → β) (as : Array α)
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx (a : Array α) (f : Nat → α → β) : (a.mapIdx f).size = a.size :=
|
||||
@[simp] theorem size_mapIdx (f : Nat → α → β) (as : Array α) : (as.mapIdx f).size = as.size :=
|
||||
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem getElem_mapIdx (a : Array α) (f : Nat → α → β) (i : Nat)
|
||||
(h : i < (mapIdx a f).size) :
|
||||
(a.mapIdx f)[i] = f i (a[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i (by simp_all)
|
||||
@[simp] theorem getElem_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat)
|
||||
(h : i < (as.mapIdx f).size) :
|
||||
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i as[i]) fun _ => rfl).2 i (by simp_all)
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (a : Array α) (f : Nat → α → β) (i : Nat) :
|
||||
(a.mapIdx f)[i]? =
|
||||
a[i]?.map (f i) := by
|
||||
@[simp] theorem getElem?_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat) :
|
||||
(as.mapIdx f)[i]? =
|
||||
as[i]?.map (f i) := by
|
||||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
|
||||
@[simp] theorem toList_mapIdx (a : Array α) (f : Nat → α → β) :
|
||||
(a.mapIdx f).toList = a.toList.mapIdx (fun i a => f i a) := by
|
||||
@[simp] theorem toList_mapIdx (f : Nat → α → β) (as : Array α) :
|
||||
(as.mapIdx f).toList = as.toList.mapIdx (fun i a => f i a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
end Array
|
||||
@@ -105,7 +105,7 @@ namespace List
|
||||
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_toArray (l : List α) (f : Nat → α → β) :
|
||||
@[simp] theorem mapIdx_toArray (f : Nat → α → β) (l : List α) :
|
||||
l.toArray.mapIdx f = (l.mapIdx f).toArray := by
|
||||
ext <;> simp
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a <
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
|
||||
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) : sizeOf (as.get i h) < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
||||
simpa using Nat.lt_trans (List.sizeOf_get _ ⟨i, h⟩) (by simp_arith)
|
||||
|
||||
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
|
||||
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _
|
||||
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _ h
|
||||
|
||||
/-- This tactic, added to the `decreasing_trivial` toolbox, proves that
|
||||
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions
|
||||
|
||||
159
src/Init/Data/Array/Monadic.lean
Normal file
159
src/Init/Data/Array/Monadic.lean
Normal file
@@ -0,0 +1,159 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.List.Monadic
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.forIn'` and `Array.forIn`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ## Monadic operations -/
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] (f : α → m β) (l : Array α) :
|
||||
mapM f l = l.foldlM (fun acc a => return (acc.push (← f a))) #[] := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.mapM_toArray, bind_pure_comp, size_toArray, List.foldlM_toArray']
|
||||
rw [List.mapM_eq_reverse_foldlM_cons]
|
||||
simp only [bind_pure_comp, Functor.map_map]
|
||||
suffices ∀ (k), (fun a => a.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) k l =
|
||||
List.foldlM (fun acc a => acc.push <$> f a) k.reverse.toArray l by
|
||||
exact this []
|
||||
intro k
|
||||
induction l generalizing k with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
simp [ih, List.foldlM_cons]
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : Array β₁) (init : α) :
|
||||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||||
cases l
|
||||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : Array β₁)
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
cases l
|
||||
rw [List.map_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_map]
|
||||
|
||||
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : Array α) (init : γ) :
|
||||
(l.filterMap f).foldlM g init =
|
||||
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
|
||||
cases l
|
||||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_filterMap]
|
||||
rfl
|
||||
|
||||
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : Array α) (init : γ) :
|
||||
(l.filterMap f).foldrM g init =
|
||||
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
|
||||
cases l
|
||||
rw [List.filterMap_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_filterMap]
|
||||
rfl
|
||||
|
||||
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : Array α) (init : β) :
|
||||
(l.filter p).foldlM g init =
|
||||
l.foldlM (fun x y => if p y then g x y else pure x) init := by
|
||||
cases l
|
||||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_filter]
|
||||
|
||||
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : Array α) (init : β) :
|
||||
(l.filter p).foldrM g init =
|
||||
l.foldrM (fun x y => if p x then g x y else pure y) init := by
|
||||
cases l
|
||||
rw [List.filter_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldrM_filter]
|
||||
|
||||
/-! ### forIn' -/
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
|
||||
forIn' l init f = ForInStep.value <$>
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => match b with
|
||||
| .yield b => f a m b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
cases l
|
||||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp only [List.forIn'_toArray, List.forIn'_eq_foldlM, List.attachWith_mem_toArray, size_toArray,
|
||||
List.length_map, List.length_attach, List.foldlM_toArray', List.foldlM_map]
|
||||
congr
|
||||
|
||||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||||
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
|
||||
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => g a m b <$> f a m b) init := by
|
||||
cases l
|
||||
rw [List.attach_toArray] -- Why doesn't this fire via `simp`?
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' l init (fun a m b => pure (.yield (f a m b))) =
|
||||
pure (f := m) (l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init) := by
|
||||
cases l
|
||||
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
(l : Array α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
/--
|
||||
We can express a for loop over an array as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
-/
|
||||
theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(f : α → β → m (ForInStep β)) (init : β) (l : Array α) :
|
||||
forIn l init f = ForInStep.value <$>
|
||||
l.foldlM (fun b a => match b with
|
||||
| .yield b => f a b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
cases l
|
||||
simp only [List.forIn_toArray, List.forIn_eq_foldlM, size_toArray, List.foldlM_toArray']
|
||||
congr
|
||||
|
||||
/-- We can express a for loop over an array which always yields as a fold. -/
|
||||
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
|
||||
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
l.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
cases l
|
||||
simp [List.foldlM_map]
|
||||
|
||||
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : Array α) (f : α → β → β) (init : β) :
|
||||
forIn l init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (l.foldl (fun b a => f a b) init) := by
|
||||
cases l
|
||||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
(l : Array α) (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init := by
|
||||
cases l
|
||||
simp [List.foldl_map]
|
||||
|
||||
end Array
|
||||
@@ -13,19 +13,19 @@ namespace Array
|
||||
def qpartition (as : Array α) (lt : α → α → Bool) (lo hi : Nat) : Nat × Array α :=
|
||||
if h : as.size = 0 then (0, as) else have : Inhabited α := ⟨as[0]'(by revert h; cases as.size <;> simp)⟩ -- TODO: remove
|
||||
let mid := (lo + hi) / 2
|
||||
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
|
||||
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
|
||||
let as := if lt (as.get! mid) (as.get! hi) then as.swap! mid hi else as
|
||||
let as := if lt (as.get! mid) (as.get! lo) then as.swapIfInBounds lo mid else as
|
||||
let as := if lt (as.get! hi) (as.get! lo) then as.swapIfInBounds lo hi else as
|
||||
let as := if lt (as.get! mid) (as.get! hi) then as.swapIfInBounds mid hi else as
|
||||
let pivot := as.get! hi
|
||||
let rec loop (as : Array α) (i j : Nat) :=
|
||||
if h : j < hi then
|
||||
if lt (as.get! j) pivot then
|
||||
let as := as.swap! i j
|
||||
let as := as.swapIfInBounds i j
|
||||
loop as (i+1) (j+1)
|
||||
else
|
||||
loop as i (j+1)
|
||||
else
|
||||
let as := as.swap! i hi
|
||||
let as := as.swapIfInBounds i hi
|
||||
(i, as)
|
||||
termination_by hi - j
|
||||
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
41
src/Init/Data/Array/Set.lean
Normal file
41
src/Init/Data/Array/Set.lean
Normal file
@@ -0,0 +1,41 @@
|
||||
/-
|
||||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Tactics
|
||||
|
||||
|
||||
/--
|
||||
Set an element in an array, using a proof that the index is in bounds.
|
||||
(This proof can usually be omitted, and will be synthesized automatically.)
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_fset"]
|
||||
def Array.set (a : Array α) (i : @& Nat) (v : α) (h : i < a.size := by get_elem_tactic) :
|
||||
Array α where
|
||||
toList := a.toList.set i v
|
||||
|
||||
/--
|
||||
Set an element in an array, or do nothing if the index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[inline] def Array.setIfInBounds (a : Array α) (i : Nat) (v : α) : Array α :=
|
||||
dite (LT.lt i a.size) (fun h => a.set i v h) (fun _ => a)
|
||||
|
||||
@[deprecated Array.setIfInBounds (since := "2024-11-24")] abbrev Array.setD := @Array.setIfInBounds
|
||||
|
||||
/--
|
||||
Set an element in an array, or panic if the index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that `a` has a reference
|
||||
count of 1 when called.
|
||||
-/
|
||||
@[extern "lean_array_set"]
|
||||
def Array.set! (a : Array α) (i : @& Nat) (v : α) : Array α :=
|
||||
Array.setIfInBounds a i v
|
||||
@@ -15,15 +15,6 @@ structure Subarray (α : Type u) where
|
||||
start_le_stop : start ≤ stop
|
||||
stop_le_array_size : stop ≤ array.size
|
||||
|
||||
@[deprecated Subarray.array (since := "2024-04-13")]
|
||||
abbrev Subarray.as (s : Subarray α) : Array α := s.array
|
||||
|
||||
@[deprecated Subarray.start_le_stop (since := "2024-04-13")]
|
||||
theorem Subarray.h₁ (s : Subarray α) : s.start ≤ s.stop := s.start_le_stop
|
||||
|
||||
@[deprecated Subarray.stop_le_array_size (since := "2024-04-13")]
|
||||
theorem Subarray.h₂ (s : Subarray α) : s.stop ≤ s.array.size := s.stop_le_array_size
|
||||
|
||||
namespace Subarray
|
||||
|
||||
def size (s : Subarray α) : Nat :=
|
||||
@@ -48,7 +39,7 @@ instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
||||
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
||||
if h : i < s.size then s[i] else v₀
|
||||
|
||||
abbrev get! [Inhabited α] (s : Subarray α) (i : Nat) : α :=
|
||||
getD s i default
|
||||
|
||||
@@ -23,16 +23,13 @@ def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α)
|
||||
let ⟨i', isLt⟩ := i
|
||||
have := s.start_le_stop
|
||||
have := s.stop_le_array_size
|
||||
have : i' ≤ s.stop - s.start := Nat.lt_succ.mp isLt
|
||||
have : s.start + i' ≤ s.stop := by omega
|
||||
have : s.start + i' ≤ s.array.size := by omega
|
||||
have : s.start + i' ≤ s.stop := by
|
||||
simp only [size] at isLt
|
||||
omega
|
||||
let pre := {s with
|
||||
stop := s.start + i',
|
||||
start_le_stop := by omega,
|
||||
stop_le_array_size := by assumption
|
||||
stop_le_array_size := by omega
|
||||
}
|
||||
let post := {s with
|
||||
start := s.start + i'
|
||||
@@ -48,9 +45,7 @@ def drop (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
array := arr.array
|
||||
start := min (arr.start + i) arr.stop
|
||||
stop := arr.stop
|
||||
start_le_stop := by
|
||||
rw [Nat.min_def]
|
||||
split <;> simp only [Nat.le_refl, *]
|
||||
start_le_stop := by omega
|
||||
stop_le_array_size := arr.stop_le_array_size
|
||||
|
||||
/--
|
||||
@@ -63,9 +58,7 @@ def take (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
stop := min (arr.start + i) arr.stop
|
||||
start_le_stop := by
|
||||
have := arr.start_le_stop
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
omega
|
||||
stop_le_array_size := by
|
||||
have := arr.stop_le_array_size
|
||||
rw [Nat.min_def]
|
||||
split <;> omega
|
||||
omega
|
||||
|
||||
@@ -29,9 +29,6 @@ section Nat
|
||||
|
||||
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||
|
||||
@[deprecated isLt (since := "2024-03-12")]
|
||||
theorem toNat_lt (x : BitVec n) : x.toNat < 2^n := x.isLt
|
||||
|
||||
/-- Theorem for normalizing the bit vector literal representation. -/
|
||||
-- TODO: This needs more usage data to assess which direction the simp should go.
|
||||
@[simp, bv_toNat] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
|
||||
|
||||
@@ -76,7 +76,7 @@ to prove the correctness of the circuit that is built by `bv_decide`.
|
||||
def blastMul (aig : AIG BVBit) (input : AIG.BinaryRefVec aig w) : AIG.RefVecEntry BVBit w
|
||||
theorem denote_blastMul (aig : AIG BVBit) (lhs rhs : BitVec w) (assign : Assignment) :
|
||||
...
|
||||
⟦(blastMul aig input).aig, (blastMul aig input).vec.get idx hidx, assign.toAIGAssignment⟧
|
||||
⟦(blastMul aig input).aig, (blastMul aig input).vec[idx], assign.toAIGAssignment⟧
|
||||
=
|
||||
(lhs * rhs).getLsbD idx
|
||||
```
|
||||
@@ -180,7 +180,7 @@ theorem carry_succ_one (i : Nat) (x : BitVec w) (h : 0 < w) :
|
||||
| zero => simp [carry_succ, h]
|
||||
| succ i ih =>
|
||||
rw [carry_succ, ih]
|
||||
simp only [getLsbD_one, add_one_ne_zero, decide_False, Bool.and_false, atLeastTwo_false_mid]
|
||||
simp only [getLsbD_one, add_one_ne_zero, decide_false, Bool.and_false, atLeastTwo_false_mid]
|
||||
cases hx : x.getLsbD (i+1)
|
||||
case false =>
|
||||
have : ∃ j ≤ i + 1, x.getLsbD j = false :=
|
||||
@@ -249,7 +249,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
|
||||
[ Nat.testBit_mod_two_pow,
|
||||
Nat.testBit_mul_two_pow_add_eq,
|
||||
i_lt,
|
||||
decide_True,
|
||||
decide_true,
|
||||
Bool.true_and,
|
||||
Nat.add_assoc,
|
||||
Nat.add_left_comm (_%_) (_ * _) _,
|
||||
@@ -346,6 +346,10 @@ theorem getMsbD_sub {i : Nat} {i_lt : i < w} {x y : BitVec w} :
|
||||
· rfl
|
||||
· omega
|
||||
|
||||
theorem getElem_sub {i : Nat} {x y : BitVec w} (h : i < w) :
|
||||
(x - y)[i] = (x[i] ^^ ((~~~y + 1#w)[i] ^^ carry i x (~~~y + 1#w) false)) := by
|
||||
simp [← getLsbD_eq_getElem, getLsbD_sub, h]
|
||||
|
||||
theorem msb_sub {x y: BitVec w} :
|
||||
(x - y).msb
|
||||
= (x.msb ^^ ((~~~y + 1#w).msb ^^ carry (w - 1 - 0) x (~~~y + 1#w) false)) := by
|
||||
@@ -392,7 +396,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
by_cases hi : i < w
|
||||
· rw [getLsbD_add hi]
|
||||
have : 0 < w := by omega
|
||||
simp only [getLsbD_not, hi, decide_True, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
_root_.true_and, not_eq_eq_eq_not]
|
||||
cases i with
|
||||
| zero =>
|
||||
@@ -401,15 +405,19 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
simp [hi, carry_zero]
|
||||
| succ =>
|
||||
rw [carry_succ_one _ _ (by omega), ← Bool.xor_not, ← decide_not]
|
||||
simp only [add_one_ne_zero, decide_False, getLsbD_not, and_eq_true, decide_eq_true_eq,
|
||||
simp only [add_one_ne_zero, decide_false, getLsbD_not, and_eq_true, decide_eq_true_eq,
|
||||
not_eq_eq_eq_not, Bool.not_true, false_bne, not_exists, _root_.not_and, not_eq_true,
|
||||
bne_left_inj, decide_eq_decide]
|
||||
bne_right_inj, decide_eq_decide]
|
||||
constructor
|
||||
· rintro h j hj; exact And.right <| h j (by omega)
|
||||
· rintro h j hj; exact ⟨by omega, h j (by omega)⟩
|
||||
· have h_ge : w ≤ i := by omega
|
||||
simp [getLsbD_ge _ _ h_ge, h_ge, hi]
|
||||
|
||||
theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
(-x)[i] = (x[i] ^^ decide (∃ j < i, x.getLsbD j = true)) := by
|
||||
simp [← getLsbD_eq_getElem, getLsbD_neg, h]
|
||||
|
||||
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
getMsbD (-x) i =
|
||||
(getMsbD x i ^^ decide (∃ j < w, i < j ∧ getMsbD x j = true)) := by
|
||||
@@ -419,7 +427,7 @@ theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
simp [hi]; omega
|
||||
case pos =>
|
||||
have h₁ : w - 1 - i < w := by omega
|
||||
simp only [hi, decide_True, h₁, Bool.true_and, Bool.bne_left_inj, decide_eq_decide]
|
||||
simp only [hi, decide_true, h₁, Bool.true_and, Bool.bne_right_inj, decide_eq_decide]
|
||||
constructor
|
||||
· rintro ⟨j, hj, h⟩
|
||||
refine ⟨w - 1 - j, by omega, by omega, by omega, _root_.cast ?_ h⟩
|
||||
@@ -455,7 +463,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
apply hmin
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and]
|
||||
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
case succ => exact getMsbD_x _ hi (by omega)
|
||||
@@ -476,7 +484,7 @@ theorem msb_abs {w : Nat} {x : BitVec w} :
|
||||
by_cases h₀ : 0 < w
|
||||
· by_cases h₁ : x = intMin w
|
||||
· simp [h₁, msb_intMin]
|
||||
· simp only [neg_eq, h₁, decide_False]
|
||||
· simp only [neg_eq, h₁, decide_false]
|
||||
by_cases h₂ : x.msb
|
||||
· simp [h₂, msb_neg]
|
||||
and_intros
|
||||
@@ -566,18 +574,18 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
||||
rw [add_eq_or_of_and_eq_zero]
|
||||
· ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
· simp only [getLsbD_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
|
||||
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
||||
by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
· have hik'' : ¬ (k < i) := by omega
|
||||
simp [hik', hik'']
|
||||
· ext k
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and,
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and,
|
||||
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
|
||||
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
|
||||
|
||||
@@ -1092,8 +1100,8 @@ def sshiftRightRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :
|
||||
|
||||
@[simp]
|
||||
theorem sshiftRightRec_zero_eq (x : BitVec w₁) (y : BitVec w₂) :
|
||||
sshiftRightRec x y 0 = x.sshiftRight' (y &&& 1#w₂) := by
|
||||
simp only [sshiftRightRec, twoPow_zero]
|
||||
sshiftRightRec x y 0 = x.sshiftRight' (y &&& twoPow w₂ 0) := by
|
||||
simp only [sshiftRightRec]
|
||||
|
||||
@[simp]
|
||||
theorem sshiftRightRec_succ_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :
|
||||
|
||||
@@ -65,7 +65,7 @@ theorem iunfoldr_getLsbD' {f : Fin w → α → α × Bool} (state : Nat → α)
|
||||
intro
|
||||
apply And.intro
|
||||
· intro i
|
||||
have := Fin.size_pos i
|
||||
have := Fin.pos i
|
||||
contradiction
|
||||
· rfl
|
||||
case step =>
|
||||
|
||||
@@ -123,7 +123,7 @@ theorem getMsbD_eq_getLsbD (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i <
|
||||
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 <;>
|
||||
simp only [h₁, h₂] <;> simp only [decide_True, decide_False, Bool.false_and, Bool.and_false, Bool.true_and, Bool.and_true]
|
||||
simp only [h₁, h₂] <;> simp only [decide_true, decide_false, Bool.false_and, Bool.and_false, Bool.true_and, Bool.and_true]
|
||||
· congr
|
||||
omega
|
||||
all_goals
|
||||
@@ -269,6 +269,10 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
|
||||
getLsbD (x#'lt) i = x.testBit i := by
|
||||
simp [getLsbD, BitVec.ofNatLt]
|
||||
|
||||
@[simp] theorem getMsbD_ofNatLt {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := by
|
||||
simp [getMsbD, getLsbD]
|
||||
|
||||
@[simp, bv_toNat] theorem toNat_ofNat (x w : Nat) : (BitVec.ofNat w x).toNat = x % 2^w := by
|
||||
simp [BitVec.toNat, BitVec.ofNat, Fin.ofNat']
|
||||
|
||||
@@ -386,7 +390,7 @@ theorem msb_eq_getLsbD_last (x : BitVec w) :
|
||||
· simp [Nat.div_eq_of_lt h, h]
|
||||
· simp only [h]
|
||||
rw [Nat.div_eq_sub_div (Nat.two_pow_pos w) h, Nat.div_eq_of_lt]
|
||||
· decide
|
||||
· simp
|
||||
· omega
|
||||
|
||||
@[bv_toNat] theorem getLsbD_succ_last (x : BitVec (w + 1)) :
|
||||
@@ -512,6 +516,31 @@ theorem eq_zero_or_eq_one (a : BitVec 1) : a = 0#1 ∨ a = 1#1 := by
|
||||
subst h
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem toInt_zero {w : Nat} : (0#w).toInt = 0 := by
|
||||
simp [BitVec.toInt, show 0 < 2^w by exact Nat.two_pow_pos w]
|
||||
|
||||
/-! ### slt -/
|
||||
|
||||
/--
|
||||
A bitvector, when interpreted as an integer, is less than zero iff
|
||||
its most significant bit is true.
|
||||
-/
|
||||
theorem slt_zero_iff_msb_cond (x : BitVec w) : x.slt 0#w ↔ x.msb = true := by
|
||||
have := toInt_eq_msb_cond x
|
||||
constructor
|
||||
· intros h
|
||||
apply Classical.byContradiction
|
||||
intros hmsb
|
||||
simp only [Bool.not_eq_true] at hmsb
|
||||
simp only [hmsb, Bool.false_eq_true, ↓reduceIte] at this
|
||||
simp only [BitVec.slt, toInt_zero, decide_eq_true_eq] at h
|
||||
omega /- Can't have `x.toInt` which is equal to `x.toNat` be strictly less than zero -/
|
||||
· intros h
|
||||
simp only [h, ↓reduceIte] at this
|
||||
simp [BitVec.slt, this]
|
||||
omega
|
||||
|
||||
/-! ### setWidth, zeroExtend and truncate -/
|
||||
|
||||
@[simp]
|
||||
@@ -536,6 +565,10 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
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]
|
||||
|
||||
theorem setWidth'_eq {x : BitVec w} (h : w ≤ v) : x.setWidth' h = x.setWidth v := by
|
||||
apply eq_of_toNat_eq
|
||||
rw [toNat_setWidth, toNat_setWidth']
|
||||
@@ -633,7 +666,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
@[simp] theorem setWidth_setWidth_of_le (x : BitVec w) (h : k ≤ l) :
|
||||
(x.setWidth l).setWidth k = x.setWidth k := by
|
||||
ext i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and]
|
||||
have p := lt_of_getLsbD (x := x) (i := i)
|
||||
revert p
|
||||
cases getLsbD x i <;> simp; omega
|
||||
@@ -663,7 +696,7 @@ theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||
theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
(BitVec.ofNat v 1).setWidth w = BitVec.ofNat w 1 := by
|
||||
ext ⟨i, hilt⟩
|
||||
simp only [getLsbD_setWidth, hilt, decide_True, getLsbD_ofNat, Bool.true_and,
|
||||
simp only [getLsbD_setWidth, hilt, decide_true, getLsbD_ofNat, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||
intros hi₁
|
||||
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
||||
@@ -730,14 +763,18 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
@[simp] theorem getLsbD_allOnes : (allOnes v).getLsbD i = decide (i < v) := by
|
||||
simp [allOnes]
|
||||
|
||||
@[simp] theorem getMsbD_allOnes : (allOnes v).getMsbD i = decide (i < v) := by
|
||||
simp [allOnes]
|
||||
omega
|
||||
|
||||
@[simp] theorem getElem_allOnes (i : Nat) (h : i < v) : (allOnes v)[i] = true := by
|
||||
simp [getElem_eq_testBit_toNat, h]
|
||||
|
||||
@[simp] theorem ofFin_add_rev (x : Fin (2^n)) : ofFin (x + x.rev) = allOnes n := by
|
||||
ext
|
||||
simp only [Fin.rev, getLsbD_ofFin, getLsbD_allOnes, Fin.is_lt, decide_True]
|
||||
simp only [Fin.rev, getLsbD_ofFin, getLsbD_allOnes, Fin.is_lt, decide_true]
|
||||
rw [Fin.add_def]
|
||||
simp only [Nat.testBit_mod_two_pow, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [Nat.testBit_mod_two_pow, Fin.is_lt, decide_true, Bool.true_and]
|
||||
have h : (x : Nat) + (2 ^ n - (x + 1)) = 2 ^ n - 1 := by omega
|
||||
rw [h, Nat.testBit_two_pow_sub_one]
|
||||
simp
|
||||
@@ -747,6 +784,12 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
@[simp] theorem toNat_or (x y : BitVec v) :
|
||||
BitVec.toNat (x ||| y) = BitVec.toNat x ||| BitVec.toNat y := rfl
|
||||
|
||||
@[simp] theorem toInt_or (x y : BitVec w) :
|
||||
BitVec.toInt (x ||| y) = Int.bmod (BitVec.toNat x ||| BitVec.toNat y) (2^w) := by
|
||||
rw_mod_cast [Int.bmod_def, BitVec.toInt, toNat_or, Nat.mod_eq_of_lt
|
||||
(Nat.or_lt_two_pow (BitVec.isLt x) (BitVec.isLt y))]
|
||||
omega
|
||||
|
||||
@[simp] theorem toFin_or (x y : BitVec v) :
|
||||
BitVec.toFin (x ||| y) = BitVec.toFin x ||| BitVec.toFin y := by
|
||||
apply Fin.eq_of_val_eq
|
||||
@@ -814,6 +857,12 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
||||
@[simp] theorem toNat_and (x y : BitVec v) :
|
||||
BitVec.toNat (x &&& y) = BitVec.toNat x &&& BitVec.toNat y := rfl
|
||||
|
||||
@[simp] theorem toInt_and (x y : BitVec w) :
|
||||
BitVec.toInt (x &&& y) = Int.bmod (BitVec.toNat x &&& BitVec.toNat y) (2^w) := by
|
||||
rw_mod_cast [Int.bmod_def, BitVec.toInt, toNat_and, Nat.mod_eq_of_lt
|
||||
(Nat.and_lt_two_pow x.toNat (BitVec.isLt y))]
|
||||
omega
|
||||
|
||||
@[simp] theorem toFin_and (x y : BitVec v) :
|
||||
BitVec.toFin (x &&& y) = BitVec.toFin x &&& BitVec.toFin y := by
|
||||
apply Fin.eq_of_val_eq
|
||||
@@ -881,6 +930,12 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) wher
|
||||
@[simp] theorem toNat_xor (x y : BitVec v) :
|
||||
BitVec.toNat (x ^^^ y) = BitVec.toNat x ^^^ BitVec.toNat y := rfl
|
||||
|
||||
@[simp] theorem toInt_xor (x y : BitVec w) :
|
||||
BitVec.toInt (x ^^^ y) = Int.bmod (BitVec.toNat x ^^^ BitVec.toNat y) (2^w) := by
|
||||
rw_mod_cast [Int.bmod_def, BitVec.toInt, toNat_xor, Nat.mod_eq_of_lt
|
||||
(Nat.xor_lt_two_pow (BitVec.isLt x) (BitVec.isLt y))]
|
||||
omega
|
||||
|
||||
@[simp] theorem toFin_xor (x y : BitVec v) :
|
||||
BitVec.toFin (x ^^^ y) = BitVec.toFin x ^^^ BitVec.toFin y := by
|
||||
apply Fin.eq_of_val_eq
|
||||
@@ -958,6 +1013,13 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
_ ≤ 2 ^ i := Nat.pow_le_pow_of_le_right Nat.zero_lt_two w
|
||||
· simp
|
||||
|
||||
@[simp] theorem toInt_not {x : BitVec w} :
|
||||
(~~~x).toInt = Int.bmod (2^w - 1 - x.toNat) (2^w) := by
|
||||
rw_mod_cast [BitVec.toInt, BitVec.toNat_not, Int.bmod_def]
|
||||
simp [show ((2^w : Nat) : Int) - 1 - x.toNat = ((2^w - 1 - x.toNat) : Nat) by omega]
|
||||
rw_mod_cast [Nat.mod_eq_of_lt (by omega)]
|
||||
omega
|
||||
|
||||
@[simp] theorem ofInt_negSucc_eq_not_ofNat {w n : Nat} :
|
||||
BitVec.ofInt w (Int.negSucc n) = ~~~.ofNat w n := by
|
||||
simp only [BitVec.ofInt, Int.toNat, Int.ofNat_eq_coe, toNat_eq, toNat_ofNatLt, toNat_not,
|
||||
@@ -982,6 +1044,10 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
@[simp] theorem getLsbD_not {x : BitVec v} : (~~~x).getLsbD i = (decide (i < v) && ! x.getLsbD i) := by
|
||||
by_cases h' : i < v <;> simp_all [not_def]
|
||||
|
||||
@[simp] theorem getMsbD_not {x : BitVec v} :
|
||||
(~~~x).getMsbD i = (decide (i < v) && ! x.getMsbD i) := by
|
||||
by_cases h' : i < v <;> simp_all [not_def]
|
||||
|
||||
@[simp] theorem getElem_not {x : BitVec w} {i : Nat} (h : i < w) : (~~~x)[i] = !x[i] := by
|
||||
simp only [getElem_eq_testBit_toNat, toNat_not]
|
||||
rw [← Nat.sub_add_eq, Nat.add_comm 1]
|
||||
@@ -1089,21 +1155,21 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
|
||||
theorem shiftLeft_xor_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ^^^ y) <<< n = (x <<< n) ^^^ (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_xor]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_xor]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
theorem shiftLeft_and_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x &&& y) <<< n = (x <<< n) &&& (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_and]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_and]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ||| y) <<< n = (x <<< n) ||| (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
@@ -1114,9 +1180,9 @@ theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
· subst h; simp
|
||||
have t : w - 1 - k < w := by omega
|
||||
simp only [t]
|
||||
simp only [decide_True, Nat.sub_sub, Bool.true_and, Nat.add_assoc]
|
||||
simp only [decide_true, Nat.sub_sub, Bool.true_and, Nat.add_assoc]
|
||||
by_cases h₁ : k < w <;> by_cases h₂ : w - (1 + k) < i <;> by_cases h₃ : k + i < w
|
||||
<;> simp only [h₁, h₂, h₃, decide_False, h₂, decide_True, Bool.not_true, Bool.false_and, Bool.and_self,
|
||||
<;> simp only [h₁, h₂, h₃, decide_false, h₂, decide_true, Bool.not_true, Bool.false_and, Bool.and_self,
|
||||
Bool.true_and, Bool.false_eq, Bool.false_and, Bool.not_false]
|
||||
<;> (first | apply getLsbD_ge | apply Eq.symm; apply getLsbD_ge)
|
||||
<;> omega
|
||||
@@ -1160,7 +1226,7 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
theorem shiftLeft_add {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
x <<< (n + m) = (x <<< n) <<< m := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and]
|
||||
rw [show i - (n + m) = (i - m - n) by omega]
|
||||
cases h₂ : decide (i < m) <;>
|
||||
cases h₃ : decide (i - m < w) <;>
|
||||
@@ -1258,7 +1324,8 @@ theorem getMsbD_ushiftRight {x : BitVec w} {i n : Nat} :
|
||||
· simp [getLsbD_ge, show w ≤ (n + (w - 1 - i)) by omega]
|
||||
omega
|
||||
· by_cases h₁ : i < w
|
||||
· simp only [h, ushiftRight_eq, getLsbD_ushiftRight, show i - n < w by omega]
|
||||
· simp only [h, decide_false, Bool.not_false, show i - n < w by omega, decide_true,
|
||||
Bool.true_and]
|
||||
congr
|
||||
omega
|
||||
· simp [h, h₁]
|
||||
@@ -1327,17 +1394,17 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
|
||||
rcases hmsb : x.msb with rfl | rfl
|
||||
· simp only [sshiftRight_eq_of_msb_false hmsb, getLsbD_ushiftRight, Bool.if_false_right]
|
||||
by_cases hi : i ≥ w
|
||||
· simp only [hi, decide_True, Bool.not_true, Bool.false_and]
|
||||
· simp only [hi, decide_true, Bool.not_true, Bool.false_and]
|
||||
apply getLsbD_ge
|
||||
omega
|
||||
· simp only [hi, decide_False, Bool.not_false, Bool.true_and, Bool.iff_and_self,
|
||||
· simp only [hi, decide_false, Bool.not_false, Bool.true_and, Bool.iff_and_self,
|
||||
decide_eq_true_eq]
|
||||
intros hlsb
|
||||
apply BitVec.lt_of_getLsbD hlsb
|
||||
· by_cases hi : i ≥ w
|
||||
· simp [hi]
|
||||
· simp only [sshiftRight_eq_of_msb_true hmsb, getLsbD_not, getLsbD_ushiftRight, Bool.not_and,
|
||||
Bool.not_not, hi, decide_False, Bool.not_false, Bool.if_true_right, Bool.true_and,
|
||||
Bool.not_not, hi, decide_false, Bool.not_false, Bool.if_true_right, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, Bool.or_eq_true, Bool.not_eq_true', decide_eq_false_iff_not,
|
||||
Nat.not_lt, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -1382,7 +1449,7 @@ theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
||||
rw [msb_eq_getLsbD_last, getLsbD_sshiftRight, msb_eq_getLsbD_last]
|
||||
by_cases hw₀ : w = 0
|
||||
· simp [hw₀]
|
||||
· simp only [show ¬(w ≤ w - 1) by omega, decide_False, Bool.not_false, Bool.true_and,
|
||||
· simp only [show ¬(w ≤ w - 1) by omega, decide_false, Bool.not_false, Bool.true_and,
|
||||
ite_eq_right_iff]
|
||||
intros h
|
||||
simp [show n = 0 by omega]
|
||||
@@ -1401,7 +1468,7 @@ theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||
simp only [getLsbD_sshiftRight, Nat.add_assoc]
|
||||
by_cases h₁ : w ≤ (i : Nat)
|
||||
· simp [h₁]
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : n + ↑i < w
|
||||
· simp [h₂]
|
||||
· simp only [h₂, ↓reduceIte]
|
||||
@@ -1413,7 +1480,7 @@ theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||
theorem not_sshiftRight {b : BitVec w} :
|
||||
~~~b.sshiftRight n = (~~~b).sshiftRight n := by
|
||||
ext i
|
||||
simp only [getLsbD_not, Fin.is_lt, decide_True, getLsbD_sshiftRight, Bool.not_and, Bool.not_not,
|
||||
simp only [getLsbD_not, Fin.is_lt, decide_true, getLsbD_sshiftRight, Bool.not_and, Bool.not_not,
|
||||
Bool.true_and, msb_not]
|
||||
by_cases h : w ≤ i
|
||||
<;> by_cases h' : n + i < w
|
||||
@@ -1431,15 +1498,15 @@ theorem getMsbD_sshiftRight {x : BitVec w} {i n : Nat} :
|
||||
getMsbD (x.sshiftRight n) i = (decide (i < w) && if i < n then x.msb else getMsbD x (i - n)) := by
|
||||
simp only [getMsbD, BitVec.getLsbD_sshiftRight]
|
||||
by_cases h : i < w
|
||||
· simp only [h, decide_True, Bool.true_and]
|
||||
· simp only [h, decide_true, Bool.true_and]
|
||||
by_cases h₁ : w ≤ w - 1 - i
|
||||
· simp [h₁]
|
||||
omega
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : i < n
|
||||
· simp only [h₂, ↓reduceIte, ite_eq_right_iff]
|
||||
omega
|
||||
· simp only [show i - n < w by omega, h₂, ↓reduceIte, decide_True, Bool.true_and]
|
||||
· simp only [show i - n < w by omega, h₂, ↓reduceIte, decide_true, Bool.true_and]
|
||||
by_cases h₄ : n + (w - 1 - i) < w <;> (simp only [h₄, ↓reduceIte]; congr; omega)
|
||||
· simp [h]
|
||||
|
||||
@@ -1454,20 +1521,26 @@ theorem getLsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
|
||||
(!decide (w ≤ i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
|
||||
simp only [BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_sshiftRight' {x y : BitVec w} {i : Nat} (h : i < w) :
|
||||
(x.sshiftRight' y)[i] =
|
||||
(!decide (w ≤ i) && if y.toNat + i < w then x.getLsbD (y.toNat + i) else x.msb) := by
|
||||
simp only [← getLsbD_eq_getElem, BitVec.sshiftRight', BitVec.getLsbD_sshiftRight]
|
||||
|
||||
@[simp]
|
||||
theorem getMsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
|
||||
(x.sshiftRight y.toNat).getMsbD i = (decide (i < w) && if i < y.toNat then x.msb else x.getMsbD (i - y.toNat)) := by
|
||||
simp only [BitVec.sshiftRight', getMsbD, BitVec.getLsbD_sshiftRight]
|
||||
by_cases h : i < w
|
||||
· simp only [h, decide_True, Bool.true_and]
|
||||
· simp only [h, decide_true, Bool.true_and]
|
||||
by_cases h₁ : w ≤ w - 1 - i
|
||||
· simp [h₁]
|
||||
omega
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : i < y.toNat
|
||||
· simp only [h₂, ↓reduceIte, ite_eq_right_iff]
|
||||
omega
|
||||
· simp only [show i - y.toNat < w by omega, h₂, ↓reduceIte, decide_True, Bool.true_and]
|
||||
· simp only [show i - y.toNat < w by omega, h₂, ↓reduceIte, decide_true, Bool.true_and]
|
||||
by_cases h₄ : y.toNat + (w - 1 - i) < w <;> (simp only [h₄, ↓reduceIte]; congr; omega)
|
||||
· simp [h]
|
||||
|
||||
@@ -1492,11 +1565,11 @@ theorem signExtend_eq_not_setWidth_not_of_msb_false {x : BitVec w} {v : Nat} (hm
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
by_cases hv : i < v
|
||||
· simp only [signExtend, getLsbD, getLsbD_setWidth, hv, decide_True, Bool.true_and, toNat_ofInt,
|
||||
· simp only [signExtend, getLsbD, getLsbD_setWidth, hv, decide_true, Bool.true_and, toNat_ofInt,
|
||||
BitVec.toInt_eq_msb_cond, hmsb, ↓reduceIte, reduceCtorEq]
|
||||
rw [Int.ofNat_mod_ofNat, Int.toNat_ofNat, Nat.testBit_mod_two_pow]
|
||||
simp [BitVec.testBit_toNat]
|
||||
· simp only [getLsbD_setWidth, hv, decide_False, Bool.false_and]
|
||||
· simp only [getLsbD_setWidth, hv, decide_false, Bool.false_and]
|
||||
apply getLsbD_ge
|
||||
omega
|
||||
|
||||
@@ -1538,7 +1611,7 @@ theorem getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
|
||||
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w):
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_True, Bool.true_and, getLsbD_setWidth,
|
||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_true, Bool.true_and, getLsbD_setWidth,
|
||||
ite_eq_left_iff, Nat.not_lt]
|
||||
omega
|
||||
|
||||
@@ -1546,6 +1619,82 @@ theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w):
|
||||
theorem signExtend_eq (x : BitVec w) : x.signExtend w = x := by
|
||||
rw [signExtend_eq_setWidth_of_lt _ (Nat.le_refl _), setWidth_eq]
|
||||
|
||||
/-- Sign extending to a larger bitwidth depends on the msb.
|
||||
If the msb is false, then the result equals the original value.
|
||||
If the msb is true, then we add a value of `(2^v - 2^w)`, which arises from the sign extension. -/
|
||||
private theorem toNat_signExtend_of_le (x : BitVec w) {v : Nat} (hv : w ≤ v) :
|
||||
(x.signExtend v).toNat = x.toNat + if x.msb then 2^v - 2^w else 0 := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
intro i
|
||||
have ⟨k, hk⟩ := Nat.exists_eq_add_of_le hv
|
||||
rw [hk, testBit_toNat, getLsbD_signExtend, Nat.pow_add, ← Nat.mul_sub_one, Nat.add_comm (x.toNat)]
|
||||
by_cases hx : x.msb
|
||||
· simp only [hx, Bool.if_true_right, ↓reduceIte,
|
||||
Nat.testBit_mul_pow_two_add _ x.isLt,
|
||||
testBit_toNat, Nat.testBit_two_pow_sub_one]
|
||||
-- Case analysis on i being in the intervals [0..w), [w..w + k), [w+k..∞)
|
||||
have hi : i < w ∨ (w ≤ i ∧ i < w + k) ∨ w + k ≤ i := by omega
|
||||
rcases hi with hi | hi | hi
|
||||
· simp [hi]; omega
|
||||
· simp [hi]; omega
|
||||
· simp [hi, show ¬ (i < w + k) by omega, show ¬ (i < w) by omega]
|
||||
omega
|
||||
· simp only [hx, Bool.if_false_right,
|
||||
Bool.false_eq_true, ↓reduceIte, Nat.zero_add, testBit_toNat]
|
||||
have hi : i < w ∨ (w ≤ i ∧ i < w + k) ∨ w + k ≤ i := by omega
|
||||
rcases hi with hi | hi | hi
|
||||
· simp [hi]; omega
|
||||
· simp [hi]
|
||||
· simp [hi, show ¬ (i < w + k) by omega, show ¬ (i < w) by omega, getLsbD_ge x i (by omega)]
|
||||
|
||||
/-- Sign extending to a larger bitwidth depends on the msb.
|
||||
If the msb is false, then the result equals the original value.
|
||||
If the msb is true, then we add a value of `(2^v - 2^w)`, which arises from the sign extension. -/
|
||||
theorem toNat_signExtend (x : BitVec w) {v : Nat} :
|
||||
(x.signExtend v).toNat = (x.setWidth v).toNat + if x.msb then 2^v - 2^w else 0 := by
|
||||
by_cases h : v ≤ w
|
||||
· have : 2^v ≤ 2^w := Nat.pow_le_pow_of_le_right Nat.two_pos h
|
||||
simp [signExtend_eq_setWidth_of_lt x h, toNat_setWidth, Nat.sub_eq_zero_of_le this]
|
||||
· have : 2^w ≤ 2^v := Nat.pow_le_pow_of_le_right Nat.two_pos (by omega)
|
||||
rw [toNat_signExtend_of_le x (by omega), toNat_setWidth, Nat.mod_eq_of_lt (by omega)]
|
||||
|
||||
/-
|
||||
If the current width `w` is smaller than the extended width `v`,
|
||||
then the value when interpreted as an integer does not change.
|
||||
-/
|
||||
theorem toInt_signExtend_of_lt {x : BitVec w} (hv : w < v):
|
||||
(x.signExtend v).toInt = x.toInt := by
|
||||
simp only [toInt_eq_msb_cond, toNat_signExtend]
|
||||
have : (x.signExtend v).msb = x.msb := by
|
||||
rw [msb_eq_getLsbD_last, getLsbD_eq_getElem (Nat.sub_one_lt_of_lt hv)]
|
||||
simp [getElem_signExtend, Nat.le_sub_one_of_lt hv]
|
||||
have H : 2^w ≤ 2^v := Nat.pow_le_pow_of_le_right (by omega) (by omega)
|
||||
simp only [this, toNat_setWidth, Int.natCast_add, Int.ofNat_emod, Int.natCast_mul]
|
||||
by_cases h : x.msb
|
||||
<;> norm_cast
|
||||
<;> simp [h, Nat.mod_eq_of_lt (Nat.lt_of_lt_of_le x.isLt H)]
|
||||
omega
|
||||
|
||||
/-
|
||||
If the current width `w` is larger than the extended width `v`,
|
||||
then the value when interpreted as an integer is truncated,
|
||||
and we compute a modulo by `2^v`.
|
||||
-/
|
||||
theorem toInt_signExtend_of_le {x : BitVec w} (hv : v ≤ w) :
|
||||
(x.signExtend v).toInt = Int.bmod x.toNat (2^v) := by
|
||||
simp [signExtend_eq_setWidth_of_lt _ hv]
|
||||
|
||||
/-
|
||||
Interpreting the sign extension of `(x : BitVec w)` to width `v`
|
||||
computes `x % 2^v` (where `%` is the balanced mod).
|
||||
-/
|
||||
theorem toInt_signExtend (x : BitVec w) :
|
||||
(x.signExtend v).toInt = Int.bmod x.toNat (2^(min v w)) := by
|
||||
by_cases hv : v ≤ w
|
||||
· simp [toInt_signExtend_of_le hv, Nat.min_eq_left hv]
|
||||
· simp only [Nat.not_le] at hv
|
||||
rw [toInt_signExtend_of_lt hv, Nat.min_eq_right (by omega), toInt_eq_toNat_bmod]
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
theorem append_def (x : BitVec v) (y : BitVec w) :
|
||||
@@ -1622,7 +1771,7 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
||||
(x ++ y).setWidth k = if h : k ≤ v then y.setWidth k else (x.setWidth (k - v) ++ y).cast (by omega) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_append, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, Bool.true_and]
|
||||
split
|
||||
· have t : i < v := by omega
|
||||
simp [t]
|
||||
@@ -1634,7 +1783,7 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
||||
@[simp] theorem setWidth_append_of_eq {x : BitVec v} {y : BitVec w} (h : w' = w) : setWidth (v' + w') (x ++ y) = setWidth v' x ++ setWidth w' y := by
|
||||
subst h
|
||||
ext i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_append, cond_eq_if,
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, cond_eq_if,
|
||||
decide_eq_true_eq, Bool.true_and, setWidth_eq]
|
||||
split
|
||||
· simp_all
|
||||
@@ -1705,13 +1854,13 @@ theorem shiftRight_shiftRight {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
|
||||
theorem getLsbD_rev (x : BitVec w) (i : Fin w) :
|
||||
x.getLsbD i.rev = x.getMsbD i := by
|
||||
simp only [getLsbD, Fin.val_rev, getMsbD, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD, Fin.val_rev, getMsbD, Fin.is_lt, decide_true, Bool.true_and]
|
||||
congr 1
|
||||
omega
|
||||
|
||||
theorem getElem_rev {x : BitVec w} {i : Fin w}:
|
||||
x[i.rev] = x.getMsbD i := by
|
||||
simp only [Fin.getElem_fin, Fin.val_rev, getMsbD, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [Fin.getElem_fin, Fin.val_rev, getMsbD, Fin.is_lt, decide_true, Bool.true_and]
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@@ -1741,7 +1890,7 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
|
||||
· 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,
|
||||
· 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_ge, Bool.or_false, ↓reduceIte]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
@@ -1756,7 +1905,7 @@ theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||||
· 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,
|
||||
· 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_ge, Bool.or_false, ↓reduceIte]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
@@ -1776,7 +1925,7 @@ theorem setWidth_succ (x : BitVec w) :
|
||||
setWidth (i+1) x = cons (getLsbD x i) (setWidth i x) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro j
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_true, Bool.true_and]
|
||||
if j_eq : j.val = i then
|
||||
simp [j_eq]
|
||||
else
|
||||
@@ -1884,7 +2033,7 @@ theorem getLsbD_shiftConcat_eq_decide (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
||||
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
||||
ext i
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_true, Bool.true_and]
|
||||
split
|
||||
· simp [*]
|
||||
· congr 1; omega
|
||||
@@ -1925,7 +2074,7 @@ theorem getMsbD_concat {i w : Nat} {b : Bool} {x : BitVec w} :
|
||||
· simp [h₀]
|
||||
· by_cases h₁ : i < w
|
||||
· simp [h₀, h₁, show ¬ w - i = 0 by omega, show i < w + 1 by omega, Nat.sub_sub, Nat.add_comm]
|
||||
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_False, Bool.false_and,
|
||||
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_false, Bool.false_and,
|
||||
Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
intro
|
||||
omega
|
||||
@@ -1933,10 +2082,10 @@ theorem getMsbD_concat {i w : Nat} {b : Bool} {x : BitVec w} :
|
||||
@[simp]
|
||||
theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
||||
(x.concat b).msb = if 0 < w then x.msb else b := by
|
||||
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_True, Nat.add_one_sub_one,
|
||||
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
|
||||
Nat.sub_zero, Bool.true_and]
|
||||
by_cases h₀ : 0 < w
|
||||
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_True,
|
||||
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_true,
|
||||
Bool.true_and, ite_eq_right_iff]
|
||||
intro
|
||||
omega
|
||||
@@ -2026,9 +2175,9 @@ theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toN
|
||||
|
||||
@[simp] theorem toFin_sub (x y : BitVec n) : (x - y).toFin = toFin x - toFin y := rfl
|
||||
|
||||
@[simp] theorem ofFin_sub (x : Fin (2^n)) (y : BitVec n) : .ofFin x - y = .ofFin (x - y.toFin) :=
|
||||
theorem ofFin_sub (x : Fin (2^n)) (y : BitVec n) : .ofFin x - y = .ofFin (x - y.toFin) :=
|
||||
rfl
|
||||
@[simp] theorem sub_ofFin (x : BitVec n) (y : Fin (2^n)) : x - .ofFin y = .ofFin (x.toFin - y) :=
|
||||
theorem sub_ofFin (x : BitVec n) (y : Fin (2^n)) : x - .ofFin y = .ofFin (x.toFin - y) :=
|
||||
rfl
|
||||
|
||||
-- Remark: we don't use `[simp]` here because simproc` subsumes it for literals.
|
||||
@@ -2375,6 +2524,9 @@ theorem umod_eq_and {x y : BitVec 1} : x % y = x &&& (~~~y) := by
|
||||
theorem smtUDiv_eq (x y : BitVec w) : smtUDiv x y = if y = 0#w then allOnes w else x / y := by
|
||||
simp [smtUDiv]
|
||||
|
||||
@[simp]
|
||||
theorem smtUDiv_zero {x : BitVec n} : x.smtUDiv 0#n = allOnes n := rfl
|
||||
|
||||
/-! ### sdiv -/
|
||||
|
||||
/-- Equation theorem for `sdiv` in terms of `udiv`. -/
|
||||
@@ -2442,6 +2594,10 @@ theorem smtSDiv_eq (x y : BitVec w) : smtSDiv x y =
|
||||
rw [BitVec.smtSDiv]
|
||||
rcases x.msb <;> rcases y.msb <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem smtSDiv_zero {x : BitVec n} : x.smtSDiv 0#n = if x.slt 0#n then 1#n else (allOnes n) := by
|
||||
rcases hx : x.msb <;> simp [smtSDiv, slt_zero_iff_msb_cond x, hx, ← negOne_eq_allOnes]
|
||||
|
||||
/-! ### srem -/
|
||||
|
||||
theorem srem_eq (x y : BitVec w) : srem x y =
|
||||
@@ -2506,7 +2662,7 @@ theorem smod_zero {x : BitVec n} : x.smod 0#n = x := by
|
||||
@[simp] theorem getElem_ofBoolListBE (h : i < bs.length) :
|
||||
(ofBoolListBE bs)[i] = bs[bs.length - 1 - i] := by
|
||||
rw [← getLsbD_eq_getElem, getLsbD_ofBoolListBE]
|
||||
simp only [h, decide_True, List.getD_eq_getElem?_getD, Bool.true_and]
|
||||
simp only [h, decide_true, List.getD_eq_getElem?_getD, Bool.true_and]
|
||||
rw [List.getElem?_eq_getElem (by omega)]
|
||||
simp
|
||||
|
||||
@@ -2578,7 +2734,7 @@ theorem getLsbD_rotateLeftAux_of_geq {x : BitVec w} {r : Nat} {i : Nat} (hi : i
|
||||
apply getLsbD_ge
|
||||
omega
|
||||
|
||||
/-- When `r < w`, we give a formula for `(x.rotateRight r).getLsbD i`. -/
|
||||
/-- When `r < w`, we give a formula for `(x.rotateLeft r).getLsbD i`. -/
|
||||
theorem getLsbD_rotateLeft_of_le {x : BitVec w} {r i : Nat} (hr: r < w) :
|
||||
(x.rotateLeft r).getLsbD i =
|
||||
cond (i < r)
|
||||
@@ -2605,6 +2761,64 @@ theorem getElem_rotateLeft {x : BitVec w} {r i : Nat} (h : i < w) :
|
||||
if h' : i < r % w then x[(w - (r % w) + i)] else x[i - (r % w)] := by
|
||||
simp [← BitVec.getLsbD_eq_getElem, h]
|
||||
|
||||
theorem getMsbD_rotateLeftAux_of_lt {x : BitVec w} {r : Nat} {i : Nat} (hi : i < w - r) :
|
||||
(x.rotateLeftAux r).getMsbD i = x.getMsbD (r + i) := by
|
||||
rw [rotateLeftAux, getMsbD_or]
|
||||
simp [show i < w - r by omega, Nat.add_comm]
|
||||
|
||||
theorem getMsbD_rotateLeftAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i ≥ w - r) :
|
||||
(x.rotateLeftAux r).getMsbD i = (decide (i < w) && x.getMsbD (i - (w - r))) := by
|
||||
simp [rotateLeftAux, getMsbD_or, show i + r ≥ w by omega, show ¬i < w - r by omega]
|
||||
|
||||
/--
|
||||
If a number `w * n ≤ i < w * (n + 1)`, then `i - w * n` equals `i % w`.
|
||||
This is true by subtracting `w * n` from the inequality, giving
|
||||
`0 ≤ i - w * n < w`, which uniquely identifies `i % w`.
|
||||
-/
|
||||
private theorem Nat.sub_mul_eq_mod_of_lt_of_le (hlo : w * n ≤ i) (hhi : i < w * (n + 1)) :
|
||||
i - w * n = i % w := by
|
||||
rw [Nat.mod_def]
|
||||
congr
|
||||
symm
|
||||
apply Nat.div_eq_of_lt_le
|
||||
(by rw [Nat.mul_comm]; omega)
|
||||
(by rw [Nat.mul_comm]; omega)
|
||||
|
||||
/-- When `r < w`, we give a formula for `(x.rotateLeft r).getMsbD i`. -/
|
||||
theorem getMsbD_rotateLeft_of_lt {n w : Nat} {x : BitVec w} (hi : r < w):
|
||||
(x.rotateLeft r).getMsbD n = (decide (n < w) && x.getMsbD ((r + n) % w)) := by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· rw [BitVec.rotateLeft_eq_rotateLeftAux_of_lt (by omega)]
|
||||
by_cases h : n < (w + 1) - r
|
||||
· simp [getMsbD_rotateLeftAux_of_lt h, Nat.mod_eq_of_lt, show r + n < (w + 1) by omega, show n < w + 1 by omega]
|
||||
· simp [getMsbD_rotateLeftAux_of_ge <| Nat.ge_of_not_lt h]
|
||||
by_cases h₁ : n < w + 1
|
||||
· simp only [h₁, decide_true, Bool.true_and]
|
||||
have h₂ : (r + n) < 2 * (w + 1) := by omega
|
||||
congr 1
|
||||
rw [← Nat.sub_mul_eq_mod_of_lt_of_le (n := 1) (by omega) (by omega), Nat.mul_one]
|
||||
omega
|
||||
· simp [h₁]
|
||||
|
||||
theorem getMsbD_rotateLeft {r n w : Nat} {x : BitVec w} :
|
||||
(x.rotateLeft r).getMsbD n = (decide (n < w) && x.getMsbD ((r + n) % w)) := by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· by_cases h : r < w
|
||||
· rw [getMsbD_rotateLeft_of_lt (by omega)]
|
||||
· rw [← rotateLeft_mod_eq_rotateLeft, getMsbD_rotateLeft_of_lt (by apply Nat.mod_lt; simp)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem msb_rotateLeft {m w : Nat} {x : BitVec w} :
|
||||
(x.rotateLeft m).msb = x.getMsbD (m % w) := by
|
||||
simp only [BitVec.msb, getMsbD_rotateLeft]
|
||||
by_cases h : w = 0
|
||||
· simp [h]
|
||||
· simp
|
||||
omega
|
||||
|
||||
/-! ## Rotate Right -/
|
||||
|
||||
/--
|
||||
@@ -2666,7 +2880,7 @@ theorem rotateRight_mod_eq_rotateRight {x : BitVec w} {r : Nat} :
|
||||
simp only [rotateRight, Nat.mod_mod]
|
||||
|
||||
/-- When `r < w`, we give a formula for `(x.rotateRight r).getLsb i`. -/
|
||||
theorem getLsbD_rotateRight_of_le {x : BitVec w} {r i : Nat} (hr: r < w) :
|
||||
theorem getLsbD_rotateRight_of_lt {x : BitVec w} {r i : Nat} (hr: r < w) :
|
||||
(x.rotateRight r).getLsbD i =
|
||||
cond (i < w - r)
|
||||
(x.getLsbD (r + i))
|
||||
@@ -2684,7 +2898,7 @@ theorem getLsbD_rotateRight {x : BitVec w} {r i : Nat} :
|
||||
(decide (i < w) && x.getLsbD (i - (w - (r % w)))) := by
|
||||
rcases w with ⟨rfl, w⟩
|
||||
· simp
|
||||
· rw [← rotateRight_mod_eq_rotateRight, getLsbD_rotateRight_of_le (Nat.mod_lt _ (by omega))]
|
||||
· rw [← rotateRight_mod_eq_rotateRight, getLsbD_rotateRight_of_lt (Nat.mod_lt _ (by omega))]
|
||||
|
||||
@[simp]
|
||||
theorem getElem_rotateRight {x : BitVec w} {r i : Nat} (h : i < w) :
|
||||
@@ -2692,8 +2906,61 @@ theorem getElem_rotateRight {x : BitVec w} {r i : Nat} (h : i < w) :
|
||||
simp only [← BitVec.getLsbD_eq_getElem]
|
||||
simp [getLsbD_rotateRight, h]
|
||||
|
||||
theorem getMsbD_rotateRightAux_of_lt {x : BitVec w} {r : Nat} {i : Nat} (hi : i < r) :
|
||||
(x.rotateRightAux r).getMsbD i = x.getMsbD (i + (w - r)) := by
|
||||
rw [rotateRightAux, getMsbD_or, getMsbD_ushiftRight]
|
||||
simp [show i < r by omega]
|
||||
|
||||
theorem getMsbD_rotateRightAux_of_ge {x : BitVec w} {r : Nat} {i : Nat} (hi : i ≥ r) :
|
||||
(x.rotateRightAux r).getMsbD i = (decide (i < w) && x.getMsbD (i - r)) := by
|
||||
simp [rotateRightAux, show ¬ i < r by omega, show i + (w - r) ≥ w by omega]
|
||||
|
||||
/-- When `m < w`, we give a formula for `(x.rotateLeft m).getMsbD i`. -/
|
||||
@[simp]
|
||||
theorem getMsbD_rotateRight_of_lt {w n m : Nat} {x : BitVec w} (hr : m < w):
|
||||
(x.rotateRight m).getMsbD n = (decide (n < w) && (if (n < m % w)
|
||||
then x.getMsbD ((w + n - m % w) % w) else x.getMsbD (n - m % w))):= by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· rw [rotateRight_eq_rotateRightAux_of_lt (by omega)]
|
||||
by_cases h : n < m
|
||||
· simp only [getMsbD_rotateRightAux_of_lt h, show n < w + 1 by omega, decide_true,
|
||||
show m % (w + 1) = m by rw [Nat.mod_eq_of_lt hr], h, ↓reduceIte,
|
||||
show (w + 1 + n - m) < (w + 1) by omega, Nat.mod_eq_of_lt, Bool.true_and]
|
||||
congr 1
|
||||
omega
|
||||
· simp [h, getMsbD_rotateRightAux_of_ge <| Nat.ge_of_not_lt h]
|
||||
by_cases h₁ : n < w + 1
|
||||
· simp [h, h₁, decide_true, Bool.true_and, Nat.mod_eq_of_lt hr]
|
||||
· simp [h₁]
|
||||
|
||||
@[simp]
|
||||
theorem getMsbD_rotateRight {w n m : Nat} {x : BitVec w} :
|
||||
(x.rotateRight m).getMsbD n = (decide (n < w) && (if (n < m % w)
|
||||
then x.getMsbD ((w + n - m % w) % w) else x.getMsbD (n - m % w))):= by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· by_cases h₀ : m < w
|
||||
· rw [getMsbD_rotateRight_of_lt (by omega)]
|
||||
· rw [← rotateRight_mod_eq_rotateRight, getMsbD_rotateRight_of_lt (by apply Nat.mod_lt; simp)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem msb_rotateRight {r w : Nat} {x : BitVec w} :
|
||||
(x.rotateRight r).msb = x.getMsbD ((w - r % w) % w) := by
|
||||
simp only [BitVec.msb, getMsbD_rotateRight]
|
||||
by_cases h₀ : 0 < w
|
||||
· simp only [h₀, decide_true, Nat.add_zero, Nat.zero_le, Nat.sub_eq_zero_of_le, Bool.true_and,
|
||||
ite_eq_left_iff, Nat.not_lt, Nat.le_zero_eq]
|
||||
intro h₁
|
||||
simp [h₁]
|
||||
· simp [show w = 0 by omega]
|
||||
|
||||
/- ## twoPow -/
|
||||
|
||||
theorem twoPow_eq (w : Nat) (i : Nat) : twoPow w i = 1#w <<< i := by
|
||||
dsimp [twoPow]
|
||||
|
||||
@[simp, bv_toNat]
|
||||
theorem toNat_twoPow (w : Nat) (i : Nat) : (twoPow w i).toNat = 2^i % 2^w := by
|
||||
rcases w with rfl | w
|
||||
@@ -2708,7 +2975,7 @@ theorem getLsbD_twoPow (i j : Nat) : (twoPow w i).getLsbD j = ((i < w) && (i = j
|
||||
· simp
|
||||
· simp only [twoPow, getLsbD_shiftLeft, getLsbD_ofNat]
|
||||
by_cases hj : j < i
|
||||
· simp only [hj, decide_True, Bool.not_true, Bool.and_false, Bool.false_and, Bool.false_eq,
|
||||
· simp only [hj, decide_true, Bool.not_true, Bool.and_false, Bool.false_and, Bool.false_eq,
|
||||
Bool.and_eq_false_imp, decide_eq_true_eq, decide_eq_false_iff_not]
|
||||
omega
|
||||
· by_cases hi : Nat.testBit 1 (j - i)
|
||||
@@ -2771,7 +3038,15 @@ theorem twoPow_zero {w : Nat} : twoPow w 0 = 1#w := by
|
||||
theorem shiftLeft_eq_mul_twoPow (x : BitVec w) (n : Nat) :
|
||||
x <<< n = x * (BitVec.twoPow w n) := by
|
||||
ext i
|
||||
simp [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, mul_twoPow_eq_shiftLeft]
|
||||
simp [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, mul_twoPow_eq_shiftLeft]
|
||||
|
||||
/--
|
||||
The unsigned division of `x` by `2^k` equals shifting `x` right by `k`,
|
||||
when `k` is less than the bitwidth `w`.
|
||||
-/
|
||||
theorem udiv_twoPow_eq_of_lt {w : Nat} {x : BitVec w} {k : Nat} (hk : k < w) : x / (twoPow w k) = x >>> k := by
|
||||
have : 2^k < 2^w := Nat.pow_lt_pow_of_lt (by decide) hk
|
||||
simp [bv_toNat, Nat.shiftRight_eq_div_pow, Nat.mod_eq_of_lt this]
|
||||
|
||||
/- ### cons -/
|
||||
|
||||
@@ -2799,7 +3074,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
@@ -2815,7 +3090,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) ||| (twoPow w i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
@@ -2825,7 +3100,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
||||
theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||
(x &&& 1#w) = setWidth w (ofBool (x.getLsbD 0)) := by
|
||||
ext i
|
||||
simp only [getLsbD_and, getLsbD_one, getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_ofBool,
|
||||
simp only [getLsbD_and, getLsbD_one, getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_ofBool,
|
||||
Bool.true_and]
|
||||
by_cases h : ((i : Nat) = 0) <;> simp [h] <;> omega
|
||||
|
||||
@@ -2839,20 +3114,6 @@ theorem replicate_succ_eq {x : BitVec w} :
|
||||
(x ++ replicate n x).cast (by rw [Nat.mul_succ]; omega) := by
|
||||
simp [replicate]
|
||||
|
||||
/--
|
||||
If a number `w * n ≤ i < w * (n + 1)`, then `i - w * n` equals `i % w`.
|
||||
This is true by subtracting `w * n` from the inequality, giving
|
||||
`0 ≤ i - w * n < w`, which uniquely identifies `i % w`.
|
||||
-/
|
||||
private theorem Nat.sub_mul_eq_mod_of_lt_of_le (hlo : w * n ≤ i) (hhi : i < w * (n + 1)) :
|
||||
i - w * n = i % w := by
|
||||
rw [Nat.mod_def]
|
||||
congr
|
||||
symm
|
||||
apply Nat.div_eq_of_lt_le
|
||||
(by rw [Nat.mul_comm]; omega)
|
||||
(by rw [Nat.mul_comm]; omega)
|
||||
|
||||
@[simp]
|
||||
theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
||||
(x.replicate n).getLsbD i =
|
||||
@@ -2862,13 +3123,13 @@ theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
||||
case succ n ih =>
|
||||
simp only [replicate_succ_eq, getLsbD_cast, getLsbD_append]
|
||||
by_cases hi : i < w * (n + 1)
|
||||
· simp only [hi, decide_True, Bool.true_and]
|
||||
· simp only [hi, decide_true, Bool.true_and]
|
||||
by_cases hi' : i < w * n
|
||||
· simp [hi', ih]
|
||||
· simp only [hi', decide_False, cond_false]
|
||||
· simp only [hi', decide_false, cond_false]
|
||||
rw [Nat.sub_mul_eq_mod_of_lt_of_le] <;> omega
|
||||
· rw [Nat.mul_succ] at hi ⊢
|
||||
simp only [show ¬i < w * n by omega, decide_False, cond_false, hi, Bool.false_and]
|
||||
simp only [show ¬i < w * n by omega, decide_false, cond_false, hi, Bool.false_and]
|
||||
apply BitVec.getLsbD_ge (x := x) (i := i - w * n) (ge := by omega)
|
||||
|
||||
@[simp]
|
||||
@@ -2929,7 +3190,7 @@ theorem toInt_intMin_le (x : BitVec w) :
|
||||
apply Int.le_bmod (by omega)
|
||||
|
||||
theorem intMin_sle (x : BitVec w) : (intMin w).sle x := by
|
||||
simp only [BitVec.sle, toInt_intMin_le x, decide_True]
|
||||
simp only [BitVec.sle, toInt_intMin_le x, decide_true]
|
||||
|
||||
@[simp]
|
||||
theorem neg_intMin {w : Nat} : -intMin w = intMin w := by
|
||||
@@ -2958,6 +3219,11 @@ theorem toInt_neg_of_ne_intMin {x : BitVec w} (rs : x ≠ intMin w) :
|
||||
have := @Nat.two_pow_pred_mul_two w (by omega)
|
||||
split <;> split <;> omega
|
||||
|
||||
theorem toInt_neg_eq_ite {x : BitVec w} :
|
||||
(-x).toInt = if x = intMin w then x.toInt else -(x.toInt) := by
|
||||
by_cases hx : x = intMin w <;>
|
||||
simp [hx, neg_intMin, toInt_neg_of_ne_intMin]
|
||||
|
||||
theorem msb_intMin {w : Nat} : (intMin w).msb = decide (0 < w) := by
|
||||
simp only [msb_eq_decide, toNat_intMin, decide_eq_decide]
|
||||
by_cases h : 0 < w <;> simp_all
|
||||
@@ -3080,13 +3346,84 @@ theorem toNat_abs {x : BitVec w} : x.abs.toNat = if x.msb then 2^w - x.toNat els
|
||||
· simp [h]
|
||||
|
||||
theorem getLsbD_abs {i : Nat} {x : BitVec w} :
|
||||
getLsbD x.abs i = if x.msb then getLsbD (-x) i else getLsbD x i := by
|
||||
getLsbD x.abs i = if x.msb then getLsbD (-x) i else getLsbD x i := by
|
||||
by_cases h : x.msb <;> simp [BitVec.abs, h]
|
||||
|
||||
theorem getElem_abs {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
x.abs[i] = if x.msb then (-x)[i] else x[i] := by
|
||||
by_cases h : x.msb <;> simp [BitVec.abs, h]
|
||||
|
||||
theorem getMsbD_abs {i : Nat} {x : BitVec w} :
|
||||
getMsbD (x.abs) i = if x.msb then getMsbD (-x) i else getMsbD x i := by
|
||||
by_cases h : x.msb <;> simp [BitVec.abs, h]
|
||||
|
||||
/-
|
||||
The absolute value of `x : BitVec w` is naively a case split on the sign of `x`.
|
||||
However, recall that when `x = intMin w`, `-x = x`.
|
||||
Thus, the full value of `abs x` is computed by the case split:
|
||||
- If `x : BitVec w` is `intMin`, then its absolute value is also `intMin w`, and
|
||||
thus `toInt` will equal `intMin.toInt`.
|
||||
- Otherwise, if `x` is negative, then `x.abs.toInt = (-x).toInt`.
|
||||
- If `x` is positive, then it is equal to `x.abs.toInt = x.toInt`.
|
||||
-/
|
||||
theorem toInt_abs_eq_ite {x : BitVec w} :
|
||||
x.abs.toInt =
|
||||
if x = intMin w then (intMin w).toInt
|
||||
else if x.msb then -x.toInt
|
||||
else x.toInt := by
|
||||
by_cases hx : x = intMin w
|
||||
· simp [hx]
|
||||
· simp [hx]
|
||||
by_cases hx₂ : x.msb
|
||||
· simp [hx₂, abs_eq, toInt_neg_of_ne_intMin hx]
|
||||
· simp [hx₂, abs_eq]
|
||||
|
||||
|
||||
|
||||
/-
|
||||
The absolute value of `x : BitVec w` is a case split on the sign of `x`, when `x ≠ intMin w`.
|
||||
This is a variant of `toInt_abs_eq_ite`.
|
||||
-/
|
||||
theorem toInt_abs_eq_ite_of_ne_intMin {x : BitVec w} (hx : x ≠ intMin w) :
|
||||
x.abs.toInt = if x.msb then -x.toInt else x.toInt := by
|
||||
simp [toInt_abs_eq_ite, hx]
|
||||
|
||||
|
||||
/--
|
||||
The absolute value of `x : BitVec w`, interpreted as an integer, is a case split:
|
||||
- When `x = intMin w`, then `x.abs = intMin w`
|
||||
- Otherwise, `x.abs.toInt` equals the absolute value (`x.toInt.natAbs`).
|
||||
|
||||
This is a simpler version of `BitVec.toInt_abs_eq_ite`, which hides a case split on `x.msb`.
|
||||
-/
|
||||
theorem toInt_abs_eq_natAbs {x : BitVec w} : x.abs.toInt =
|
||||
if x = intMin w then (intMin w).toInt else x.toInt.natAbs := by
|
||||
rw [toInt_abs_eq_ite]
|
||||
by_cases hx : x = intMin w
|
||||
· simp [hx]
|
||||
· simp [hx]
|
||||
by_cases h : x.msb
|
||||
· simp only [h, ↓reduceIte]
|
||||
have : x.toInt < 0 := by
|
||||
rw [toInt_neg_iff]
|
||||
have := msb_eq_true_iff_two_mul_ge.mp h
|
||||
omega
|
||||
omega
|
||||
· simp only [h, Bool.false_eq_true, ↓reduceIte]
|
||||
have : 0 ≤ x.toInt := by
|
||||
rw [toInt_pos_iff]
|
||||
exact msb_eq_false_iff_two_mul_lt.mp (by simp [h])
|
||||
omega
|
||||
|
||||
/-
|
||||
The absolute value of `(x : BitVec w)`, when interpreted as an integer,
|
||||
is the absolute value of `x.toInt` when `(x ≠ intMin)`.
|
||||
-/
|
||||
theorem toInt_abs_eq_natAbs_of_ne_intMin {x : BitVec w} (hx : x ≠ intMin w) :
|
||||
x.abs.toInt = x.toInt.natAbs := by
|
||||
simp [toInt_abs_eq_natAbs, hx]
|
||||
|
||||
|
||||
/-! ### Decidable quantifiers -/
|
||||
|
||||
theorem forall_zero_iff {P : BitVec 0 → Prop} :
|
||||
|
||||
@@ -238,8 +238,8 @@ theorem not_bne_not : ∀ (x y : Bool), ((!x) != (!y)) = (x != y) := by simp
|
||||
@[simp] theorem bne_assoc : ∀ (x y z : Bool), ((x != y) != z) = (x != (y != z)) := by decide
|
||||
instance : Std.Associative (· != ·) := ⟨bne_assoc⟩
|
||||
|
||||
@[simp] theorem bne_left_inj : ∀ {x y z : Bool}, (x != y) = (x != z) ↔ y = z := by decide
|
||||
@[simp] theorem bne_right_inj : ∀ {x y z : Bool}, (x != z) = (y != z) ↔ x = y := by decide
|
||||
@[simp] theorem bne_right_inj : ∀ {x y z : Bool}, (x != y) = (x != z) ↔ y = z := by decide
|
||||
@[simp] theorem bne_left_inj : ∀ {x y z : Bool}, (x != z) = (y != z) ↔ x = y := by decide
|
||||
|
||||
theorem eq_not_of_ne : ∀ {x y : Bool}, x ≠ y → x = !y := by decide
|
||||
|
||||
@@ -295,9 +295,9 @@ theorem xor_right_comm : ∀ (x y z : Bool), ((x ^^ y) ^^ z) = ((x ^^ z) ^^ y) :
|
||||
|
||||
theorem xor_assoc : ∀ (x y z : Bool), ((x ^^ y) ^^ z) = (x ^^ (y ^^ z)) := bne_assoc
|
||||
|
||||
theorem xor_left_inj : ∀ {x y z : Bool}, (x ^^ y) = (x ^^ z) ↔ y = z := bne_left_inj
|
||||
theorem xor_right_inj : ∀ {x y z : Bool}, (x ^^ y) = (x ^^ z) ↔ y = z := bne_right_inj
|
||||
|
||||
theorem xor_right_inj : ∀ {x y z : Bool}, (x ^^ z) = (y ^^ z) ↔ x = y := bne_right_inj
|
||||
theorem xor_left_inj : ∀ {x y z : Bool}, (x ^^ z) = (y ^^ z) ↔ x = y := bne_left_inj
|
||||
|
||||
/-! ### le/lt -/
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ def usize (a : @& ByteArray) : USize :=
|
||||
a.size.toUSize
|
||||
|
||||
@[extern "lean_byte_array_uget"]
|
||||
def uget : (a : @& ByteArray) → (i : USize) → i.toNat < a.size → UInt8
|
||||
def uget : (a : @& ByteArray) → (i : USize) → (h : i.toNat < a.size := by get_elem_tactic) → UInt8
|
||||
| ⟨bs⟩, i, h => bs[i]
|
||||
|
||||
@[extern "lean_byte_array_get"]
|
||||
@@ -50,11 +50,11 @@ def get! : (@& ByteArray) → (@& Nat) → UInt8
|
||||
| ⟨bs⟩, i => bs.get! i
|
||||
|
||||
@[extern "lean_byte_array_fget"]
|
||||
def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
|
||||
| ⟨bs⟩, i => bs.get i
|
||||
def get : (a : @& ByteArray) → (i : @& Nat) → (h : i < a.size := by get_elem_tactic) → UInt8
|
||||
| ⟨bs⟩, i, _ => bs[i]
|
||||
|
||||
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
getElem xs i h := xs.get i
|
||||
|
||||
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
@@ -64,11 +64,11 @@ def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
||||
|
||||
@[extern "lean_byte_array_fset"]
|
||||
def set : (a : ByteArray) → (@& Fin a.size) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set i b⟩
|
||||
def set : (a : ByteArray) → (i : @& Nat) → UInt8 → (h : i < a.size := by get_elem_tactic) → ByteArray
|
||||
| ⟨bs⟩, i, b, h => ⟨bs.set i b h⟩
|
||||
|
||||
@[extern "lean_byte_array_uset"]
|
||||
def uset : (a : ByteArray) → (i : USize) → UInt8 → i.toNat < a.size → ByteArray
|
||||
def uset : (a : ByteArray) → (i : USize) → UInt8 → (h : i.toNat < a.size := by get_elem_tactic) → ByteArray
|
||||
| ⟨bs⟩, i, v, h => ⟨bs.uset i v h⟩
|
||||
|
||||
@[extern "lean_byte_array_hash"]
|
||||
@@ -108,8 +108,18 @@ def toList (bs : ByteArray) : List UInt8 :=
|
||||
|
||||
@[inline] def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
||||
let rec @[specialize] loop (i : Nat) :=
|
||||
if i < a.size then
|
||||
if p (a.get! i) then some i else loop (i+1)
|
||||
if h : i < a.size then
|
||||
if p a[i] then some i else loop (i+1)
|
||||
else
|
||||
none
|
||||
termination_by a.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
loop start
|
||||
|
||||
@[inline] def findFinIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option (Fin a.size) :=
|
||||
let rec @[specialize] loop (i : Nat) :=
|
||||
if h : i < a.size then
|
||||
if p a[i] then some ⟨i, h⟩ else loop (i+1)
|
||||
else
|
||||
none
|
||||
termination_by a.size - i
|
||||
@@ -144,7 +154,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteAr
|
||||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||||
match (← f (as.get ⟨as.size - 1 - i, this⟩) b) with
|
||||
match (← f as[as.size - 1 - i] b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
@@ -178,7 +188,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
|
||||
match i with
|
||||
| 0 => pure b
|
||||
| i'+1 =>
|
||||
loop i' (j+1) (← f b (as.get ⟨j, Nat.lt_of_lt_of_le hlt h⟩))
|
||||
loop i' (j+1) (← f b as[j])
|
||||
else
|
||||
pure b
|
||||
loop (stop - start) start init
|
||||
|
||||
@@ -165,6 +165,7 @@ theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
|
||||
theorem val_lt_of_le (i : Fin b) (h : b ≤ n) : i.val < n :=
|
||||
Nat.lt_of_lt_of_le i.isLt h
|
||||
|
||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||
protected theorem pos (i : Fin n) : 0 < n :=
|
||||
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
|
||||
|
||||
|
||||
@@ -13,17 +13,17 @@ namespace Fin
|
||||
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
|
||||
@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where
|
||||
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
|
||||
loop (x : α) (i : Nat) : α :=
|
||||
@[semireducible] loop (x : α) (i : Nat) : α :=
|
||||
if h : i < n then loop (f x ⟨i, h⟩) (i+1) else x
|
||||
termination_by n - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
/-- Folds over `Fin n` from the right: `foldr 3 f x = f 0 (f 1 (f 2 x))`. -/
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop ⟨n, Nat.le_refl n⟩ init where
|
||||
@[inline] def foldr (n) (f : Fin n → α → α) (init : α) : α := loop n (Nat.le_refl n) init where
|
||||
/-- Inner loop for `Fin.foldr`. `Fin.foldr.loop n f i x = f 0 (f ... (f (i-1) x))` -/
|
||||
loop : {i // i ≤ n} → α → α
|
||||
| ⟨0, _⟩, x => x
|
||||
| ⟨i+1, h⟩, x => loop ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x)
|
||||
loop : (i : _) → i ≤ n → α → α
|
||||
| 0, _, x => x
|
||||
| i+1, h, x => loop i (Nat.le_of_lt h) (f ⟨i, h⟩ x)
|
||||
termination_by structural i => i
|
||||
|
||||
/--
|
||||
Folds a monadic function over `Fin n` from left to right:
|
||||
@@ -176,17 +176,19 @@ theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
|
||||
/-! ### foldr -/
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f ⟨0, Nat.zero_le _⟩ x = x := by
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop_succ (f : Fin n → α → α) (x) (h : i < n) :
|
||||
foldr.loop n f ⟨i+1, h⟩ x = foldr.loop n f ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x) := by
|
||||
foldr.loop n f (i+1) h x = foldr.loop n f i (Nat.le_of_lt h) (f ⟨i, h⟩ x) := by
|
||||
rw [foldr.loop]
|
||||
|
||||
theorem foldr_loop (f : Fin (n+1) → α → α) (x) (h : i+1 ≤ n+1) :
|
||||
foldr.loop (n+1) f ⟨i+1, h⟩ x =
|
||||
f 0 (foldr.loop n (fun j => f j.succ) ⟨i, Nat.le_of_succ_le_succ h⟩ x) := by
|
||||
induction i generalizing x <;> simp [foldr_loop_zero, foldr_loop_succ, *]
|
||||
foldr.loop (n+1) f (i+1) h x =
|
||||
f 0 (foldr.loop n (fun j => f j.succ) i (Nat.le_of_succ_le_succ h) x) := by
|
||||
induction i generalizing x with
|
||||
| zero => simp [foldr_loop_succ, foldr_loop_zero]
|
||||
| succ i ih => rw [foldr_loop_succ, ih]; rfl
|
||||
|
||||
@[simp] theorem foldr_zero (f : Fin 0 → α → α) (x) : foldr 0 f x = x :=
|
||||
foldr_loop_zero ..
|
||||
|
||||
@@ -13,17 +13,19 @@ import Init.Omega
|
||||
|
||||
namespace Fin
|
||||
|
||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||
theorem size_pos (i : Fin n) : 0 < n := Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
|
||||
@[deprecated Fin.pos (since := "2024-11-11")]
|
||||
theorem size_pos (i : Fin n) : 0 < n := i.pos
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.size_pos
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@[deprecated pos' (since := "2024-11-11")] abbrev size_pos' := @pos'
|
||||
|
||||
@[simp] theorem is_lt (a : Fin n) : (a : Nat) < n := a.2
|
||||
|
||||
@@ -240,7 +242,7 @@ theorem fin_one_eq_zero (a : Fin 1) : a = 0 := Subsingleton.elim a 0
|
||||
rw [eq_comm]
|
||||
simp
|
||||
|
||||
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem add_def (a b : Fin n) : a + b = Fin.mk ((a + b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem val_add (a b : Fin n) : (a + b).val = (a.val + b.val) % n := rfl
|
||||
|
||||
@@ -640,7 +642,7 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 ≤ ↑i) : (subNat 1 i h).succ = i := by
|
||||
@[simp] theorem subNat_one_succ (i : Fin (n + 1)) (h : 1 ≤ (i : Nat)) : (subNat 1 i h).succ = i := by
|
||||
ext
|
||||
simp
|
||||
omega
|
||||
|
||||
@@ -31,7 +31,7 @@ opaque floatSpec : FloatSpec := {
|
||||
structure Float where
|
||||
val : floatSpec.float
|
||||
|
||||
instance : Inhabited Float := ⟨{ val := floatSpec.val }⟩
|
||||
instance : Nonempty Float := ⟨{ val := floatSpec.val }⟩
|
||||
|
||||
@[extern "lean_float_add"] opaque Float.add : Float → Float → Float
|
||||
@[extern "lean_float_sub"] opaque Float.sub : Float → Float → Float
|
||||
@@ -47,6 +47,25 @@ def Float.lt : Float → Float → Prop := fun a b =>
|
||||
def Float.le : Float → Float → Prop := fun a b =>
|
||||
floatSpec.le a.val b.val
|
||||
|
||||
/--
|
||||
Raw transmutation from `UInt64`.
|
||||
|
||||
Floats and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
-/
|
||||
@[extern "lean_float_of_bits"] opaque Float.ofBits : UInt64 → Float
|
||||
|
||||
/--
|
||||
Raw transmutation to `UInt64`.
|
||||
|
||||
Floats and UInts have the same endianness on all supported platforms.
|
||||
IEEE 754 very precisely specifies the bit layout of floats.
|
||||
|
||||
Note that this function is distinct from `Float.toUInt64`, which attempts
|
||||
to preserve the numeric value, and not the bitwise value.
|
||||
-/
|
||||
@[extern "lean_float_to_bits"] opaque Float.toBits : Float → UInt64
|
||||
|
||||
instance : Add Float := ⟨Float.add⟩
|
||||
instance : Sub Float := ⟨Float.sub⟩
|
||||
instance : Mul Float := ⟨Float.mul⟩
|
||||
@@ -117,6 +136,9 @@ instance : ToString Float where
|
||||
|
||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
||||
|
||||
instance : Inhabited Float where
|
||||
default := UInt64.toFloat 0
|
||||
|
||||
instance : Repr Float where
|
||||
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
|
||||
| ⟨ds⟩, i, h => ds[i]
|
||||
|
||||
@[extern "lean_float_array_fget"]
|
||||
def get : (ds : @& FloatArray) → (@& Fin ds.size) → Float
|
||||
| ⟨ds⟩, i => ds.get i
|
||||
def get : (ds : @& FloatArray) → (i : @& Nat) → (h : i < ds.size := by get_elem_tactic) → Float
|
||||
| ⟨ds⟩, i, h => ds.get i h
|
||||
|
||||
@[extern "lean_float_array_get"]
|
||||
def get! : (@& FloatArray) → (@& Nat) → Float
|
||||
@@ -55,23 +55,23 @@ def get! : (@& FloatArray) → (@& Nat) → Float
|
||||
|
||||
def get? (ds : FloatArray) (i : Nat) : Option Float :=
|
||||
if h : i < ds.size then
|
||||
ds.get ⟨i, h⟩
|
||||
some (ds.get i h)
|
||||
else
|
||||
none
|
||||
|
||||
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
getElem xs i h := xs.get i h
|
||||
|
||||
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
@[extern "lean_float_array_uset"]
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → (h : i.toNat < a.size := by get_elem_tactic) → FloatArray
|
||||
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
||||
|
||||
@[extern "lean_float_array_fset"]
|
||||
def set : (ds : FloatArray) → (@& Fin ds.size) → Float → FloatArray
|
||||
| ⟨ds⟩, i, d => ⟨ds.set i d⟩
|
||||
def set : (ds : FloatArray) → (i : @& Nat) → Float → (h : i < ds.size := by get_elem_tactic) → FloatArray
|
||||
| ⟨ds⟩, i, d, h => ⟨ds.set i d h⟩
|
||||
|
||||
@[extern "lean_float_array_set"]
|
||||
def set! : FloatArray → (@& Nat) → Float → FloatArray
|
||||
@@ -83,7 +83,7 @@ def isEmpty (s : FloatArray) : Bool :=
|
||||
partial def toList (ds : FloatArray) : List Float :=
|
||||
let rec loop (i r) :=
|
||||
if h : i < ds.size then
|
||||
loop (i+1) (ds.get ⟨i, h⟩ :: r)
|
||||
loop (i+1) (ds[i] :: r)
|
||||
else
|
||||
r.reverse
|
||||
loop 0 []
|
||||
@@ -115,7 +115,7 @@ protected def forIn {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatA
|
||||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||||
match (← f (as.get ⟨as.size - 1 - i, this⟩) b) with
|
||||
match (← f as[as.size - 1 - i] b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||||
loop as.size (Nat.le_refl _) b
|
||||
@@ -149,7 +149,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → Float →
|
||||
match i with
|
||||
| 0 => pure b
|
||||
| i'+1 =>
|
||||
loop i' (j+1) (← f b (as.get ⟨j, Nat.lt_of_lt_of_le hlt h⟩))
|
||||
loop i' (j+1) (← f b (as[j]'(Nat.lt_of_lt_of_le hlt h)))
|
||||
else
|
||||
pure b
|
||||
loop (stop - start) start init
|
||||
|
||||
@@ -329,22 +329,22 @@ theorem toNat_sub (m n : Nat) : toNat (m - n) = m - n := by
|
||||
/- ## add/sub injectivity -/
|
||||
|
||||
@[simp]
|
||||
protected theorem add_right_inj {i j : Int} (k : Int) : (i + k = j + k) ↔ i = j := by
|
||||
protected theorem add_left_inj {i j : Int} (k : Int) : (i + k = j + k) ↔ i = j := by
|
||||
apply Iff.intro
|
||||
· intro p
|
||||
rw [←Int.add_sub_cancel i k, ←Int.add_sub_cancel j k, p]
|
||||
· exact congrArg (· + k)
|
||||
|
||||
@[simp]
|
||||
protected theorem add_left_inj {i j : Int} (k : Int) : (k + i = k + j) ↔ i = j := by
|
||||
protected theorem add_right_inj {i j : Int} (k : Int) : (k + i = k + j) ↔ i = j := by
|
||||
simp [Int.add_comm k]
|
||||
|
||||
@[simp]
|
||||
protected theorem sub_left_inj {i j : Int} (k : Int) : (k - i = k - j) ↔ i = j := by
|
||||
protected theorem sub_right_inj {i j : Int} (k : Int) : (k - i = k - j) ↔ i = j := by
|
||||
simp [Int.sub_eq_add_neg, Int.neg_inj]
|
||||
|
||||
@[simp]
|
||||
protected theorem sub_right_inj {i j : Int} (k : Int) : (i - k = j - k) ↔ i = j := by
|
||||
protected theorem sub_left_inj {i j : Int} (k : Int) : (i - k = j - k) ↔ i = j := by
|
||||
simp [Int.sub_eq_add_neg]
|
||||
|
||||
/- ## Ring properties -/
|
||||
|
||||
@@ -26,3 +26,4 @@ import Init.Data.List.Sort
|
||||
import Init.Data.List.ToArray
|
||||
import Init.Data.List.MapIdx
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace List
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`. -/
|
||||
@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
| [], _ => []
|
||||
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
|
||||
|
||||
@@ -46,6 +46,11 @@ Unsafe implementation of `attachWith`, taking advantage of the fact that the rep
|
||||
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
|
||||
exact go L h'
|
||||
|
||||
@[simp] theorem pmap_nil {P : α → Prop} (f : ∀ a, P a → β) : pmap f [] (by simp) = [] := rfl
|
||||
|
||||
@[simp] theorem pmap_cons {P : α → Prop} (f : ∀ a, P a → β) (a : α) (l : List α) (h : ∀ b ∈ a :: l, P b) :
|
||||
pmap f (a :: l) h = f a (forall_mem_cons.1 h).1 :: pmap f l (forall_mem_cons.1 h).2 := rfl
|
||||
|
||||
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||
|
||||
@[simp] theorem attachWith_nil : ([] : List α).attachWith P H = [] := rfl
|
||||
@@ -148,7 +153,7 @@ theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h :
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : length (pmap f l H) = length l := by
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
· rfl
|
||||
· simp only [*, pmap, length]
|
||||
@@ -169,6 +174,13 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ [] ↔ xs ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem pmap_eq_self {l : List α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
rw [pmap_eq_map_attach]
|
||||
conv => lhs; rhs; rw [← attach_map_subtype_val l]
|
||||
rw [map_inj_left]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem attach_eq_nil_iff {l : List α} : l.attach = [] ↔ l = [] :=
|
||||
pmap_eq_nil_iff
|
||||
@@ -192,7 +204,7 @@ theorem attachWith_ne_nil_iff {l : List α} {P : α → Prop} {H : ∀ a ∈ l,
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (getElem?_mem H) := by
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons hd tl hl =>
|
||||
@@ -208,7 +220,7 @@ theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
|
||||
· simp_all
|
||||
|
||||
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (get?_mem H) := by
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
|
||||
simp only [get?_eq_getElem?]
|
||||
simp [getElem?_pmap, h]
|
||||
|
||||
@@ -231,18 +243,18 @@ theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h :
|
||||
(hn : n < (pmap f l h).length) :
|
||||
get (pmap f l h) ⟨n, hn⟩ =
|
||||
f (get l ⟨n, @length_pmap _ _ p f l h ▸ hn⟩)
|
||||
(h _ (get_mem l n (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
(h _ (getElem_mem (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (getElem?_mem a)) :=
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : List α} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => getElem?_mem a) :=
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
@@ -326,6 +338,7 @@ This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldl_subtype` below.
|
||||
-/
|
||||
theorem foldl_attach (l : List α) (f : β → α → β) (b : β) :
|
||||
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
|
||||
@@ -341,6 +354,7 @@ This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldr_subtype` below.
|
||||
-/
|
||||
theorem foldr_attach (l : List α) (f : α → β → β) (b : β) :
|
||||
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
|
||||
@@ -445,16 +459,16 @@ theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ :
|
||||
pmap_append f l₁ l₂ _
|
||||
|
||||
@[simp] theorem attach_append (xs ys : List α) :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_right xs h⟩ := by
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_left ys h⟩) ++
|
||||
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_right xs h⟩ := by
|
||||
simp only [attach, attachWith, pmap, map_pmap, pmap_append]
|
||||
congr 1 <;>
|
||||
exact pmap_congr_left _ fun _ _ _ _ => rfl
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs ys : List α}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_of_mem_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_of_mem_right xs h)) := by
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp only [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
@@ -591,6 +605,15 @@ def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) := l.map (
|
||||
| nil => simp
|
||||
| cons a l ih => simp [ih, Function.comp_def]
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : List { x // p x }} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem getElem_unattach
|
||||
{p : α → Prop} {l : List { x // p x }} (i : Nat) (h : i < l.unattach.length) :
|
||||
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
|
||||
simp [unattach]
|
||||
|
||||
/-! ### Recognizing higher order functions on subtypes using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -38,7 +38,7 @@ The operations are organized as follow:
|
||||
* Sublists: `take`, `drop`, `takeWhile`, `dropWhile`, `partition`, `dropLast`,
|
||||
`isPrefixOf`, `isPrefixOf?`, `isSuffixOf`, `isSuffixOf?`, `Subset`, `Sublist`,
|
||||
`rotateLeft` and `rotateRight`.
|
||||
* Manipulating elements: `replace`, `insert`, `modify`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Manipulating elements: `replace`, `modify`, `insert`, `insertIdx`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Finding elements: `find?`, `findSome?`, `findIdx`, `indexOf`, `findIdx?`, `indexOf?`,
|
||||
`countP`, `count`, and `lookup`.
|
||||
* Logic: `any`, `all`, `or`, and `and`.
|
||||
@@ -231,7 +231,7 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
|
||||
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
|
||||
|
||||
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
|
||||
@[deprecated (since := "2024-06-07")] abbrev ext := @ext_get?
|
||||
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
@@ -551,7 +551,7 @@ theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux a
|
||||
/-! ### flatten -/
|
||||
|
||||
/--
|
||||
`O(|flatten L|)`. `join L` concatenates all the lists in `L` into one list.
|
||||
`O(|flatten L|)`. `flatten L` concatenates all the lists in `L` into one list.
|
||||
* `flatten [[a], [], [b, c], [d, e, f]] = [a, b, c, d, e, f]`
|
||||
-/
|
||||
def flatten : List (List α) → List α
|
||||
@@ -682,7 +682,7 @@ theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
/-- `notElem a l` is `!(elem a l)`. -/
|
||||
@[deprecated (since := "2024-06-15")]
|
||||
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
|
||||
def notElem [BEq α] (a : α) (as : List α) : Bool :=
|
||||
!(as.elem a)
|
||||
|
||||
@@ -726,13 +726,13 @@ theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h :
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)
|
||||
|
||||
theorem mem_append_of_mem_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs := by
|
||||
theorem mem_append_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs := by
|
||||
intro h
|
||||
induction h with
|
||||
| head => apply Mem.head
|
||||
| tail => apply Mem.tail; assumption
|
||||
|
||||
theorem mem_append_of_mem_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs := by
|
||||
theorem mem_append_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs := by
|
||||
intro h
|
||||
induction as with
|
||||
| nil => simp [h]
|
||||
@@ -1113,12 +1113,6 @@ theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
/-! ### insert -/
|
||||
|
||||
/-- Inserts an element into a list without duplication. -/
|
||||
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
|
||||
if l.elem a then l else a :: l
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
/--
|
||||
@@ -1148,6 +1142,21 @@ Apply `f` to the nth element of the list, if it exists, replacing that element w
|
||||
def modify (f : α → α) : Nat → List α → List α :=
|
||||
modifyTailIdx (modifyHead f)
|
||||
|
||||
/-! ### insert -/
|
||||
|
||||
/-- Inserts an element into a list without duplication. -/
|
||||
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
|
||||
if l.elem a then l else a :: l
|
||||
|
||||
/--
|
||||
`insertIdx n a l` inserts `a` into the list `l` after the first `n` elements of `l`
|
||||
```
|
||||
insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
|
||||
```
|
||||
-/
|
||||
def insertIdx (n : Nat) (a : α) : List α → List α :=
|
||||
modifyTailIdx (cons a) n
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/--
|
||||
@@ -1418,10 +1427,10 @@ def zipWithAll (f : Option α → Option β → γ) : List α → List β → Li
|
||||
| a :: as, [] => (a :: as).map fun a => f (some a) none
|
||||
| a :: as, b :: bs => f a b :: zipWithAll f as bs
|
||||
|
||||
@[simp] theorem zipWithAll_nil_right :
|
||||
@[simp] theorem zipWithAll_nil :
|
||||
zipWithAll f as [] = as.map fun a => f (some a) none := by
|
||||
cases as <;> rfl
|
||||
@[simp] theorem zipWithAll_nil_left :
|
||||
@[simp] theorem nil_zipWithAll :
|
||||
zipWithAll f [] bs = bs.map fun b => f none (some b) := rfl
|
||||
@[simp] theorem zipWithAll_cons_cons :
|
||||
zipWithAll f (a :: as) (b :: bs) = f (some a) (some b) :: zipWithAll f as bs := rfl
|
||||
|
||||
@@ -5,6 +5,8 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Control.Lawful
|
||||
import Init.Data.List.Basic
|
||||
|
||||
namespace List
|
||||
@@ -207,6 +209,16 @@ def findM? {m : Type → Type u} [Monad m] {α : Type} (p : α → m Bool) : Lis
|
||||
| true => pure (some a)
|
||||
| false => findM? p as
|
||||
|
||||
@[simp]
|
||||
theorem findM?_id (p : α → Bool) (as : List α) : findM? (m := Id) p as = as.find? p := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, find?]
|
||||
cases p a with
|
||||
| true => rfl
|
||||
| false => rw [ih]; rfl
|
||||
|
||||
@[specialize]
|
||||
def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (Option β)) : List α → m (Option β)
|
||||
| [] => pure none
|
||||
@@ -215,6 +227,28 @@ def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
||||
| some b => pure (some b)
|
||||
| none => findSomeM? f as
|
||||
|
||||
@[simp]
|
||||
theorem findSomeM?_id (f : α → Option β) (as : List α) : findSomeM? (m := Id) f as = as.findSome? f := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findSomeM?, findSome?]
|
||||
cases f a with
|
||||
| some b => rfl
|
||||
| none => rw [ih]; rfl
|
||||
|
||||
theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
as.findM? p = as.findSomeM? fun a => return if (← p a) then some a else none := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, findSomeM?]
|
||||
simp [ih]
|
||||
congr
|
||||
apply funext
|
||||
intro b
|
||||
cases b <;> simp
|
||||
|
||||
@[inline] protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : List α) (init : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop : (as' : List α) → (b : β) → Exists (fun bs => bs ++ as' = as) → m β
|
||||
| [], b, _ => pure b
|
||||
@@ -222,7 +256,7 @@ def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
||||
have : a ∈ as := by
|
||||
have ⟨bs, h⟩ := h
|
||||
subst h
|
||||
exact mem_append_of_mem_right _ (Mem.head ..)
|
||||
exact mem_append_right _ (Mem.head ..)
|
||||
match (← f a this b) with
|
||||
| ForInStep.done b => pure b
|
||||
| ForInStep.yield b =>
|
||||
|
||||
48
src/Init/Data/List/FinRange.lean
Normal file
48
src/Init/Data/List/FinRange.lean
Normal file
@@ -0,0 +1,48 @@
|
||||
/-
|
||||
Copyright (c) 2024 François G. Dorais. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: François G. Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.OfFn
|
||||
|
||||
namespace List
|
||||
|
||||
/-- `finRange n` lists all elements of `Fin n` in order -/
|
||||
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp] theorem length_finRange (n) : (List.finRange n).length = n := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem getElem_finRange (i : Nat) (h : i < (List.finRange n).length) :
|
||||
(finRange n)[i] = Fin.cast (length_finRange n) ⟨i, h⟩ := by
|
||||
simp [List.finRange]
|
||||
|
||||
@[simp] theorem finRange_zero : finRange 0 = [] := by simp [finRange, ofFn]
|
||||
|
||||
theorem finRange_succ (n) : finRange (n+1) = 0 :: (finRange n).map Fin.succ := by
|
||||
apply List.ext_getElem; simp; intro i; cases i <;> simp
|
||||
|
||||
theorem finRange_succ_last (n) :
|
||||
finRange (n+1) = (finRange n).map Fin.castSucc ++ [Fin.last n] := by
|
||||
apply List.ext_getElem
|
||||
· simp
|
||||
· intros
|
||||
simp only [List.finRange, List.getElem_ofFn, getElem_append, length_map, length_ofFn,
|
||||
getElem_map, Fin.castSucc_mk, getElem_singleton]
|
||||
split
|
||||
· rfl
|
||||
· next h => exact Fin.eq_last_of_not_lt h
|
||||
|
||||
theorem finRange_reverse (n) : (finRange n).reverse = (finRange n).map Fin.rev := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
conv => lhs; rw [finRange_succ_last]
|
||||
conv => rhs; rw [finRange_succ]
|
||||
rw [reverse_append, reverse_cons, reverse_nil, nil_append, singleton_append, ← map_reverse,
|
||||
map_cons, ih, map_map, map_map]
|
||||
congr; funext
|
||||
simp [Fin.rev_succ]
|
||||
|
||||
end List
|
||||
@@ -10,7 +10,8 @@ import Init.Data.List.Sublist
|
||||
import Init.Data.List.Range
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, and `List.indexOf`.
|
||||
Lemmas about `List.findSome?`, `List.find?`, `List.findIdx`, `List.findIdx?`, `List.indexOf`,
|
||||
and `List.lookup`.
|
||||
-/
|
||||
|
||||
namespace List
|
||||
@@ -95,22 +96,22 @@ theorem findSome?_eq_some_iff {f : α → Option β} {l : List α} {b : β} :
|
||||
· simp only [Option.guard_eq_none] at h
|
||||
simp [ih, h]
|
||||
|
||||
@[simp] theorem filterMap_head? (f : α → Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
|
||||
@[simp] theorem head?_filterMap (f : α → Option β) (l : List α) : (l.filterMap f).head? = l.findSome? f := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [filterMap_cons, findSome?_cons]
|
||||
split <;> simp [*]
|
||||
|
||||
@[simp] theorem filterMap_head (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
@[simp] theorem head_filterMap (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).head h = (l.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem filterMap_getLast? (f : α → Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
@[simp] theorem getLast?_filterMap (f : α → Option β) (l : List α) : (l.filterMap f).getLast? = l.reverse.findSome? f := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filterMap_reverse]
|
||||
|
||||
@[simp] theorem filterMap_getLast (f : α → Option β) (l : List α) (h) :
|
||||
@[simp] theorem getLast_filterMap (f : α → Option β) (l : List α) (h) :
|
||||
(l.filterMap f).getLast h = (l.reverse.findSome? f).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast_eq_some]
|
||||
|
||||
@@ -206,7 +207,8 @@ theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
induction l <;> simp [find?_cons]; split <;> simp [*]
|
||||
|
||||
theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
theorem find?_eq_some_iff_append :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
@@ -242,6 +244,9 @@ theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b
|
||||
cases h₁
|
||||
simp
|
||||
|
||||
@[deprecated find?_eq_some_iff_append (since := "2024-11-06")]
|
||||
abbrev find?_eq_some := @find?_eq_some_iff_append
|
||||
|
||||
@[simp]
|
||||
theorem find?_cons_eq_some : (a :: xs).find? p = some b ↔ (p a ∧ a = b) ∨ (!p a ∧ xs.find? p = some b) := by
|
||||
rw [find?_cons]
|
||||
@@ -287,18 +292,18 @@ theorem get_find?_mem (xs : List α) (p : α → Bool) (h) : (xs.find? p).get h
|
||||
· simp only [find?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem filter_head? (p : α → Bool) (l : List α) : (l.filter p).head? = l.find? p := by
|
||||
rw [← filterMap_eq_filter, filterMap_head?, findSome?_guard]
|
||||
@[simp] theorem head?_filter (p : α → Bool) (l : List α) : (l.filter p).head? = l.find? p := by
|
||||
rw [← filterMap_eq_filter, head?_filterMap, findSome?_guard]
|
||||
|
||||
@[simp] theorem filter_head (p : α → Bool) (l : List α) (h) :
|
||||
@[simp] theorem head_filter (p : α → Bool) (l : List α) (h) :
|
||||
(l.filter p).head h = (l.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [head_eq_iff_head?_eq_some]
|
||||
|
||||
@[simp] theorem filter_getLast? (p : α → Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
@[simp] theorem getLast?_filter (p : α → Bool) (l : List α) : (l.filter p).getLast? = l.reverse.find? p := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [← filter_reverse]
|
||||
|
||||
@[simp] theorem filter_getLast (p : α → Bool) (l : List α) (h) :
|
||||
@[simp] theorem getLast_filter (p : α → Bool) (l : List α) (h) :
|
||||
(l.filter p).getLast h = (l.reverse.find? p).get (by simp_all [Option.isSome_iff_ne_none]) := by
|
||||
simp [getLast_eq_iff_getLast_eq_some]
|
||||
|
||||
@@ -347,7 +352,7 @@ theorem find?_flatten_eq_some {xs : List (List α)} {p : α → Bool} {a : α} :
|
||||
xs.flatten.find? p = some a ↔
|
||||
p a ∧ ∃ as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
constructor
|
||||
· rintro ⟨h, ⟨ys, zs, h₁, h₂⟩⟩
|
||||
refine ⟨h, ?_⟩
|
||||
|
||||
@@ -38,7 +38,7 @@ The following operations were already given `@[csimp]` replacements in `Init/Dat
|
||||
|
||||
The following operations are given `@[csimp]` replacements below:
|
||||
`set`, `filterMap`, `foldr`, `append`, `bind`, `join`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `insertIdx`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`enumFrom`, and `intercalate`.
|
||||
|
||||
-/
|
||||
@@ -91,7 +91,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_toList, -Array.size_toArray]
|
||||
funext α β f init l; simp [foldrTR, ← Array.foldr_toList, -Array.size_toArray]
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
@@ -215,6 +215,23 @@ theorem modifyTR_go_eq : ∀ l n, modifyTR.go f l n acc = acc.toList ++ modify f
|
||||
@[csimp] theorem modify_eq_modifyTR : @modify = @modifyTR := by
|
||||
funext α f n l; simp [modifyTR, modifyTR_go_eq]
|
||||
|
||||
/-! ### insertIdx -/
|
||||
|
||||
/-- Tail-recursive version of `insertIdx`. -/
|
||||
@[inline] def insertIdxTR (n : Nat) (a : α) (l : List α) : List α := go n l #[] where
|
||||
/-- Auxiliary for `insertIdxTR`: `insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l`. -/
|
||||
go : Nat → List α → Array α → List α
|
||||
| 0, l, acc => acc.toListAppend (a :: l)
|
||||
| _, [], acc => acc.toList
|
||||
| n+1, a :: l, acc => go n l (acc.push a)
|
||||
|
||||
theorem insertIdxTR_go_eq : ∀ n l, insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l
|
||||
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
|
||||
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
|
||||
|
||||
@[csimp] theorem insertIdx_eq_insertIdxTR : @insertIdx = @insertIdxTR := by
|
||||
funext α f n l; simp [insertIdxTR, insertIdxTR_go_eq]
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/-- Tail recursive version of `List.erase`. -/
|
||||
@@ -314,7 +331,7 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [enumFrom, f]
|
||||
rw [Array.foldr_eq_foldr_toList]
|
||||
rw [← Array.foldr_toList]
|
||||
simp [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
|
||||
@@ -101,7 +101,7 @@ theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (c
|
||||
theorem cons_inj_right (a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l' :=
|
||||
⟨tail_eq_of_cons_eq, congrArg _⟩
|
||||
|
||||
@[deprecated (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
|
||||
@[deprecated cons_inj_right (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
|
||||
|
||||
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l' :=
|
||||
List.cons.injEq .. ▸ .rfl
|
||||
@@ -171,7 +171,7 @@ theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
|
||||
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
|
||||
(a :: as).get i.succ = as.get i := rfl
|
||||
|
||||
@[deprecated (since := "2024-07-09")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-07-09")]
|
||||
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
|
||||
|
||||
theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos.mp h)
|
||||
@@ -372,6 +372,17 @@ theorem getElem?_concat_length (l : List α) (a : α) : (l ++ [a])[l.length]? =
|
||||
@[deprecated getElem?_concat_length (since := "2024-06-12")]
|
||||
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
|
||||
|
||||
@[simp] theorem isSome_getElem? {l : List α} {n : Nat} : l[n]?.isSome ↔ n < l.length := by
|
||||
by_cases h : n < l.length
|
||||
· simp_all
|
||||
· simp [h]
|
||||
simp_all
|
||||
|
||||
@[simp] theorem isNone_getElem? {l : List α} {n : Nat} : l[n]?.isNone ↔ l.length ≤ n := by
|
||||
by_cases h : n < l.length
|
||||
· simp_all
|
||||
· simp [h]
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp] theorem not_mem_nil (a : α) : ¬ a ∈ [] := nofun
|
||||
@@ -383,9 +394,9 @@ theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = s
|
||||
theorem mem_cons_self (a : α) (l : List α) : a ∈ a :: l := .head ..
|
||||
|
||||
theorem mem_concat_self (xs : List α) (a : α) : a ∈ xs ++ [a] :=
|
||||
mem_append_of_mem_right xs (mem_cons_self a _)
|
||||
mem_append_right xs (mem_cons_self a _)
|
||||
|
||||
theorem mem_append_cons_self : a ∈ xs ++ a :: ys := mem_append_of_mem_right _ (mem_cons_self _ _)
|
||||
theorem mem_append_cons_self : a ∈ xs ++ a :: ys := mem_append_right _ (mem_cons_self _ _)
|
||||
|
||||
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
∃ as bs, xs = as ++ a :: bs ∧ a ∉ as := by
|
||||
@@ -492,16 +503,20 @@ theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n : Nat, l[n]? = s
|
||||
theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a :=
|
||||
let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩
|
||||
|
||||
theorem get_mem : ∀ (l : List α) n h, get l ⟨n, h⟩ ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (get_mem l ..)
|
||||
theorem get_mem : ∀ (l : List α) n, get l n ∈ l
|
||||
| _ :: _, ⟨0, _⟩ => .head ..
|
||||
| _ :: l, ⟨_+1, _⟩ => .tail _ (get_mem l ..)
|
||||
|
||||
theorem getElem?_mem {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||
theorem mem_of_getElem? {l : List α} {n : Nat} {a : α} (e : l[n]? = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
||||
|
||||
theorem get?_mem {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
|
||||
@[deprecated mem_of_getElem? (since := "2024-09-06")] abbrev getElem?_mem := @mem_of_getElem?
|
||||
|
||||
theorem mem_of_get? {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := get?_eq_some.1 e; e ▸ get_mem ..
|
||||
|
||||
@[deprecated mem_of_get? (since := "2024-09-06")] abbrev get?_mem := @mem_of_get?
|
||||
|
||||
theorem mem_iff_getElem {a} {l : List α} : a ∈ l ↔ ∃ (n : Nat) (h : n < l.length), l[n]'h = a :=
|
||||
⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
|
||||
|
||||
@@ -776,6 +791,24 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {n : Nat} {a b : α}, a ∈ l.s
|
||||
· intro a
|
||||
simp
|
||||
|
||||
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
|
||||
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
|
||||
match l₁, l₂ with
|
||||
| [], [] => rfl
|
||||
| [], _ :: _ => by simp [beq_nil_iff] at h
|
||||
| _ :: _, [] => by simp [nil_beq_iff] at h
|
||||
| a :: l₁, b :: l₂ => by
|
||||
simp at h
|
||||
simpa [Nat.add_one_inj]using length_eq_of_beq h.2
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
protected theorem lt_irrefl [LT α] (lt_irrefl : ∀ x : α, ¬x < x) (l : List α) : ¬l < l := by
|
||||
@@ -841,6 +874,12 @@ theorem foldr_eq_foldrM (f : α → β → β) (b) (l : List α) :
|
||||
l.foldr f b = l.foldrM (m := Id) f b := by
|
||||
induction l <;> simp [*, foldr]
|
||||
|
||||
@[simp] theorem id_run_foldlM (f : β → α → Id β) (b) (l : List α) :
|
||||
Id.run (l.foldlM f b) = l.foldl f b := (foldl_eq_foldlM f b l).symm
|
||||
|
||||
@[simp] theorem id_run_foldrM (f : α → β → Id β) (b) (l : List α) :
|
||||
Id.run (l.foldrM f b) = l.foldr f b := (foldr_eq_foldrM f b l).symm
|
||||
|
||||
/-! ### foldl and foldr -/
|
||||
|
||||
@[simp] theorem foldr_cons_eq_append (l : List α) : l.foldr cons l' = l ++ l' := by
|
||||
@@ -863,14 +902,30 @@ theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α
|
||||
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldl_filterMap (f : α → Option β) (g : γ → β → γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldl_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldr_filterMap (f : α → Option β) (g : β → γ → γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldr_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldl_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldr_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
@@ -983,6 +1038,21 @@ theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} (r : β →
|
||||
· simp
|
||||
· exact ih h fun a m c c' h => h' _ (by simp_all) _ _ h
|
||||
|
||||
@[simp] theorem foldl_add_const (l : List α) (a b : Nat) :
|
||||
l.foldl (fun x _ => x + a) b = b + a * l.length := by
|
||||
induction l generalizing b with
|
||||
| nil => simp
|
||||
| cons y l ih =>
|
||||
simp only [foldl_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc,
|
||||
Nat.add_comm a]
|
||||
|
||||
@[simp] theorem foldr_add_const (l : List α) (a b : Nat) :
|
||||
l.foldr (fun _ x => x + a) b = b + a * l.length := by
|
||||
induction l generalizing b with
|
||||
| nil => simp
|
||||
| cons y l ih =>
|
||||
simp only [foldr_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc]
|
||||
|
||||
/-! ### getLast -/
|
||||
|
||||
theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
||||
@@ -994,6 +1064,10 @@ theorem getLast_eq_getElem : ∀ (l : List α) (h : l ≠ []),
|
||||
| _ :: _ :: _, _ => by
|
||||
simp [getLast, get, Nat.succ_sub_succ, getLast_eq_getElem]
|
||||
|
||||
theorem getElem_length_sub_one_eq_getLast (l : List α) (h) :
|
||||
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
|
||||
rw [← getLast_eq_getElem]
|
||||
|
||||
@[deprecated getLast_eq_getElem (since := "2024-07-15")]
|
||||
theorem getLast_eq_get (l : List α) (h : l ≠ []) :
|
||||
getLast l h = l.get ⟨l.length - 1, by
|
||||
@@ -1014,7 +1088,7 @@ theorem getLast_eq_getLastD (a l h) : @getLast α (a::l) h = getLastD l a := by
|
||||
|
||||
@[simp] theorem getLast_singleton (a h) : @getLast α [a] h = a := rfl
|
||||
|
||||
theorem getLast!_cons [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
|
||||
simp [getLast!, getLast_eq_getLastD]
|
||||
|
||||
@[simp] theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
|
||||
@@ -1078,7 +1152,12 @@ theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by
|
||||
|
||||
/-! ### getLast! -/
|
||||
|
||||
@[simp] theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
|
||||
@[simp] theorem getLast!_eq_getLast?_getD [Inhabited α] {l : List α} : getLast! l = (getLast? l).getD default := by
|
||||
cases l with
|
||||
| nil => simp [getLast!_nil]
|
||||
| cons _ _ => simp [getLast!, getLast?_eq_getLast]
|
||||
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
@@ -1113,6 +1192,11 @@ theorem head_eq_getElem (l : List α) (h : l ≠ []) : head l h = l[0]'(length_p
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem getElem_zero_eq_head (l : List α) (h) : l[0] = head l (by simpa [length_pos] using h) := by
|
||||
cases l with
|
||||
| nil => simp at h
|
||||
| cons _ _ => simp
|
||||
|
||||
theorem head_eq_iff_head?_eq_some {xs : List α} (h) : xs.head h = a ↔ xs.head? = some a := by
|
||||
cases xs with
|
||||
| nil => simp at h
|
||||
@@ -1457,6 +1541,22 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
|
||||
| [] => rfl
|
||||
| a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter _ l]
|
||||
|
||||
theorem foldl_filter (p : α → Bool) (f : β → α → β) (l : List α) (init : β) :
|
||||
(l.filter p).foldl f init = l.foldl (fun x y => if p y then f x y else x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldl_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem foldr_filter (p : α → Bool) (f : α → β → β) (l : List α) (init : β) :
|
||||
(l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldr_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem filter_map (f : β → α) (l : List β) : filter p (map f l) = map f (filter (p ∘ f) l) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -1724,7 +1824,7 @@ theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {n : Nat} (hn :
|
||||
l₂[n] = (l₁ ++ l₂)[n + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hn _) := by
|
||||
rw [getElem_append_right] <;> simp [*, le_add_left]
|
||||
|
||||
@[deprecated (since := "2024-06-12")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_append_right_aux {l₁ l₂ : List α} {n : Nat}
|
||||
(h₁ : l₁.length ≤ n) (h₂ : n < (l₁ ++ l₂).length) : n - l₁.length < l₂.length := by
|
||||
rw [length_append] at h₂
|
||||
@@ -1741,7 +1841,7 @@ theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.l
|
||||
rw [← getElem?_eq_getElem, eq, getElem?_append_right (h ▸ Nat.le_refl _), h]
|
||||
simp
|
||||
|
||||
@[deprecated (since := "2024-06-12")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_of_append_proof {l : List α}
|
||||
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = n) : n < length l := eq ▸ h ▸ by simp_arith
|
||||
|
||||
@@ -1925,11 +2025,8 @@ theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t
|
||||
theorem mem_append_eq (a : α) (s t : List α) : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
theorem mem_append_left {a : α} {l₁ : List α} (l₂ : List α) (h : a ∈ l₁) : a ∈ l₁ ++ l₂ :=
|
||||
mem_append.2 (Or.inl h)
|
||||
|
||||
theorem mem_append_right {a : α} (l₁ : List α) {l₂ : List α} (h : a ∈ l₂) : a ∈ l₁ ++ l₂ :=
|
||||
mem_append.2 (Or.inr h)
|
||||
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
|
||||
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
|
||||
|
||||
theorem mem_iff_append {a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t :=
|
||||
⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩
|
||||
@@ -2343,7 +2440,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
|
||||
@[simp] theorem getElem_replicate (a : α) {n : Nat} {m} (h : m < (replicate n a).length) :
|
||||
(replicate n a)[m] = a :=
|
||||
eq_of_mem_replicate (get_mem _ _ _)
|
||||
eq_of_mem_replicate (getElem_mem _)
|
||||
|
||||
@[deprecated getElem_replicate (since := "2024-06-12")]
|
||||
theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := by
|
||||
@@ -2700,6 +2797,12 @@ theorem flatMap_reverse {β} (l : List α) (f : α → List β) : (l.reverse.fla
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
theorem foldl_eq_foldr_reverse (l : List α) (f : β → α → β) (b) :
|
||||
l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
|
||||
|
||||
theorem foldr_eq_foldl_reverse (l : List α) (f : α → β → β) (b) :
|
||||
l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
|
||||
|
||||
@[simp] theorem reverse_replicate (n) (a : α) : reverse (replicate n a) = replicate n a :=
|
||||
eq_replicate_iff.2
|
||||
⟨by rw [length_reverse, length_replicate],
|
||||
@@ -2843,6 +2946,10 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ ∃ a' ∈ l, a == a' := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.contains a ↔ a ∈ l := by
|
||||
simp
|
||||
|
||||
/-! ## Sublists -/
|
||||
|
||||
/-! ### partition
|
||||
@@ -3250,10 +3357,10 @@ theorem any_eq_not_all_not (l : List α) (p : α → Bool) : l.any p = !l.all (!
|
||||
theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!p .) := by
|
||||
simp only [not_any_eq_all_not, Bool.not_not]
|
||||
|
||||
@[simp] theorem any_map {l : List α} {p : α → Bool} : (l.map f).any p = l.any (p ∘ f) := by
|
||||
@[simp] theorem any_map {l : List α} {p : β → Bool} : (l.map f).any p = l.any (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
@[simp] theorem all_map {l : List α} {p : α → Bool} : (l.map f).all p = l.all (p ∘ f) := by
|
||||
@[simp] theorem all_map {l : List α} {p : β → Bool} : (l.map f).all p = l.all (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
@[simp] theorem any_filter {l : List α} {p q : α → Bool} :
|
||||
|
||||
@@ -86,6 +86,42 @@ theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
theorem foldlM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldlM g init =
|
||||
l.foldlM (fun x y => match f y with | some b => g x b | none => pure x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldlM_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldrM_filterMap [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : List α) (init : γ) :
|
||||
(l.filterMap f).foldrM g init =
|
||||
l.foldrM (fun x y => match f x with | some b => g b y | none => pure y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filterMap_cons, foldrM_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldlM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : List α) (init : β) :
|
||||
(l.filter p).foldlM g init =
|
||||
l.foldlM (fun x y => if p y then g x y else pure x) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldlM_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
theorem foldrM_filter [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : List α) (init : β) :
|
||||
(l.filter p).foldrM g init =
|
||||
l.foldrM (fun x y => if p x then g x y else pure y) init := by
|
||||
induction l generalizing init with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp only [filter_cons, foldrM_cons]
|
||||
split <;> simp [ih]
|
||||
|
||||
/-! ### forM -/
|
||||
|
||||
-- We use `List.forM` as the simp normal form, rather that `ForM.forM`.
|
||||
@@ -172,8 +208,8 @@ in which whenever we reach `.done b` we keep that value through the rest of the
|
||||
theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
|
||||
forIn' l init f = ForInStep.value <$>
|
||||
l.attach.foldlM (fun b a => match b with
|
||||
| .yield b => f a.1 a.2 b
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => match b with
|
||||
| .yield b => f a m b
|
||||
| .done b => pure (.done b)) (ForInStep.yield init) := by
|
||||
induction l generalizing init with
|
||||
| nil => simp
|
||||
@@ -198,6 +234,31 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
| .yield b =>
|
||||
simp [ih, List.foldlM_map]
|
||||
|
||||
/-- We can express a for loop over a list which always yields as a fold. -/
|
||||
@[simp] theorem forIn'_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
|
||||
forIn' l init (fun a m b => (fun c => .yield (g a m b c)) <$> f a m b) =
|
||||
l.attach.foldlM (fun b ⟨a, m⟩ => g a m b <$> f a m b) init := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
theorem forIn'_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' l init (fun a m b => pure (.yield (f a m b))) =
|
||||
pure (f := m) (l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init) := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
(l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
simp only [forIn'_eq_foldlM]
|
||||
generalize l.attach = l'
|
||||
induction l' generalizing init <;> simp_all
|
||||
|
||||
/--
|
||||
We can express a for loop over a list as a fold,
|
||||
in which whenever we reach `.done b` we keep that value through the rest of the fold.
|
||||
@@ -224,6 +285,28 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
| .yield b =>
|
||||
simp [ih]
|
||||
|
||||
/-- We can express a for loop over a list which always yields as a fold. -/
|
||||
@[simp] theorem forIn_yield_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
|
||||
forIn l init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
l.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
(l : List α) (f : α → β → β) (init : β) :
|
||||
forIn l init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (l.foldl (fun b a => f a b) init) := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
(l : List α) (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init := by
|
||||
simp only [forIn_eq_foldlM]
|
||||
induction l generalizing init <;> simp_all
|
||||
|
||||
/-! ### allM -/
|
||||
|
||||
theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
|
||||
@@ -14,3 +14,4 @@ import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Nat.Find
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.Data.List.Nat.Modify
|
||||
import Init.Data.List.Nat.InsertIdx
|
||||
|
||||
@@ -9,7 +9,7 @@ import Init.Data.List.Basic
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ### isEqv-/
|
||||
/-! ### isEqv -/
|
||||
|
||||
theorem isEqv_eq_decide (a b : List α) (r) :
|
||||
isEqv a b r = if h : a.length = b.length then
|
||||
|
||||
@@ -64,3 +64,82 @@ theorem getElem_eraseIdx_of_ge (l : List α) (i : Nat) (j : Nat) (h : j < (l.era
|
||||
(l.eraseIdx i)[j] = l[j + 1]'(by rw [length_eraseIdx] at h; split at h <;> omega) := by
|
||||
rw [getElem_eraseIdx, dif_neg]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_eq {l : List α} {i : Nat} {a : α} :
|
||||
(l.set i a).eraseIdx i = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx, getElem_eraseIdx]
|
||||
split <;>
|
||||
· rw [getElem_set_ne]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_lt {l : List α} {i : Nat} {j : Nat} {a : α} (h : j < i) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set (i - 1) a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· split
|
||||
· omega
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i - 1 ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set i a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{l : List α} {i : Nat} (h : i + 1 < l.length) :
|
||||
(l.eraseIdx (i + 1)).set i l[i + 1] = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp only [length_set, length_eraseIdx, h, ↓reduceIte]
|
||||
rw [if_pos]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
simp [getElem_set, getElem_eraseIdx]
|
||||
split
|
||||
· split
|
||||
· omega
|
||||
· simp_all
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : ¬ n < i := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem eraseIdx_length_sub_one (l : List α) :
|
||||
(l.eraseIdx (l.length - 1)) = l.dropLast := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx_of_lt, getElem_dropLast]
|
||||
simp_all
|
||||
|
||||
end List
|
||||
|
||||
@@ -9,6 +9,32 @@ import Init.Data.List.Find
|
||||
|
||||
namespace List
|
||||
|
||||
open Nat
|
||||
|
||||
theorem find?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {b : α} :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ i h, xs[i] = b ∧ ∀ j : Nat, (hj : j < i) → !p xs[j] := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ⟨bs, rfl⟩, h⟩
|
||||
refine ⟨as.length, ⟨?_, ?_, ?_⟩⟩
|
||||
· simp only [length_append, length_cons]
|
||||
refine Nat.lt_add_of_pos_right (zero_lt_succ bs.length)
|
||||
· rw [getElem_append_right (Nat.le_refl as.length)]
|
||||
simp
|
||||
· intro j h'
|
||||
rw [getElem_append_left h']
|
||||
exact h _ (getElem_mem h')
|
||||
· rintro ⟨i, h, rfl, h'⟩
|
||||
refine ⟨xs.take i, ⟨xs.drop (i+1), ?_⟩, ?_⟩
|
||||
· rw [getElem_cons_drop, take_append_drop]
|
||||
· intro a m
|
||||
rw [mem_take_iff_getElem] at m
|
||||
obtain ⟨j, h, rfl⟩ := m
|
||||
apply h'
|
||||
omega
|
||||
|
||||
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {p q : α → Bool} (w : ∀ x ∈ xs, p x → q x) {i : Nat}
|
||||
(h : xs.findIdx? p = some i) : ∃ j, j ≤ i ∧ xs.findIdx? q = some j := by
|
||||
simp only [findIdx?_eq_findSome?_enum] at h
|
||||
|
||||
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
@@ -0,0 +1,242 @@
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Nat.Modify
|
||||
|
||||
/-!
|
||||
# insertIdx
|
||||
|
||||
Proves various lemmas about `List.insertIdx`.
|
||||
-/
|
||||
|
||||
open Function
|
||||
|
||||
open Nat
|
||||
|
||||
namespace List
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type u}
|
||||
|
||||
section InsertIdx
|
||||
|
||||
variable {a : α}
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_zero (s : List α) (x : α) : insertIdx 0 x s = x :: s :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_nil (n : Nat) (a : α) : insertIdx (n + 1) a [] = [] :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : Nat) :
|
||||
insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s :=
|
||||
rfl
|
||||
|
||||
theorem length_insertIdx : ∀ n as, (insertIdx n a as).length = if n ≤ as.length then as.length + 1 else as.length
|
||||
| 0, _ => by simp
|
||||
| n + 1, [] => by simp
|
||||
| n + 1, a :: as => by
|
||||
simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_le_add_iff_right]
|
||||
split <;> rfl
|
||||
|
||||
theorem length_insertIdx_of_le_length (h : n ≤ length as) : length (insertIdx n a as) = length as + 1 := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge :
|
||||
∀ n m as,
|
||||
n < length as → n ≤ m → insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n
|
||||
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
|
||||
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
|
||||
| 0, _ + 1, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_eraseIdx_of_le :
|
||||
∀ n m as,
|
||||
n < length as → m ≤ n → insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1)
|
||||
| _, 0, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_comm (a b : α) :
|
||||
∀ (i j : Nat) (l : List α) (_ : i ≤ j) (_ : j ≤ length l),
|
||||
(l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a
|
||||
| 0, j, l => by simp [insertIdx]
|
||||
| _ + 1, 0, _ => fun h => (Nat.not_lt_zero _ h).elim
|
||||
| i + 1, j + 1, [] => by simp
|
||||
| i + 1, j + 1, c :: l => fun h₀ h₁ => by
|
||||
simp only [insertIdx_succ_cons, cons.injEq, true_and]
|
||||
exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁)
|
||||
|
||||
theorem mem_insertIdx {a b : α} :
|
||||
∀ {n : Nat} {l : List α} (_ : n ≤ l.length), a ∈ l.insertIdx n b ↔ a = b ∨ a ∈ l
|
||||
| 0, as, _ => by simp
|
||||
| _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim
|
||||
| n + 1, a' :: as, h => by
|
||||
rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h),
|
||||
← or_assoc, @or_comm (a = a'), or_assoc, mem_cons]
|
||||
|
||||
theorem insertIdx_of_length_lt (l : List α) (x : α) (n : Nat) (h : l.length < n) :
|
||||
insertIdx n x l = l := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp
|
||||
| cons x l ih =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp only [Nat.succ_lt_succ_iff, length] at h
|
||||
simpa using ih _ h
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l = l ++ [x] := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih => simpa using ih
|
||||
|
||||
theorem length_le_length_insertIdx (l : List α) (x : α) (n : Nat) :
|
||||
l.length ≤ (insertIdx n x l).length := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem length_insertIdx_le_succ (l : List α) (x : α) (n : Nat) :
|
||||
(insertIdx n x l).length ≤ l.length + 1 := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (hn : k < n)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction n generalizing k l with
|
||||
| zero => simp at hn
|
||||
| succ n ih =>
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons _ _=>
|
||||
cases k
|
||||
· simp [get]
|
||||
· rw [Nat.succ_lt_succ_iff] at hn
|
||||
simpa using ih hn _
|
||||
|
||||
@[simp]
|
||||
theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[n] = x := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
simp [length_insertIdx] at hn
|
||||
split at hn
|
||||
· simp_all
|
||||
· omega
|
||||
| cons _ _ ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
|
||||
simpa using ih hn
|
||||
|
||||
theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1 ≤ k)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction l generalizing n k with
|
||||
| nil =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero, length_singleton, lt_one_iff] at hk
|
||||
omega
|
||||
| succ n => simp at hk
|
||||
| cons _ _ ih =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero] at hk
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
| succ n =>
|
||||
cases k with
|
||||
| zero => simp
|
||||
| succ k =>
|
||||
simp only [insertIdx_succ_cons, getElem_cons_succ]
|
||||
rw [ih (by omega)]
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] =
|
||||
if h₁ : k < n then
|
||||
l[k]'(by simp [length_insertIdx] at h; split at h <;> omega)
|
||||
else
|
||||
if h₂ : k = n then
|
||||
x
|
||||
else
|
||||
l[k-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem_insertIdx_of_lt h₁]
|
||||
· split <;> rename_i h₂
|
||||
· subst h₂
|
||||
rw [getElem_insertIdx_self h]
|
||||
· rw [getElem_insertIdx_of_ge (by omega)]
|
||||
|
||||
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
|
||||
(insertIdx n x l)[k]? =
|
||||
if k < n then
|
||||
l[k]?
|
||||
else
|
||||
if k = n then
|
||||
if k ≤ l.length then some x else none
|
||||
else
|
||||
l[k-1]? := by
|
||||
rw [getElem?_def]
|
||||
split <;> rename_i h
|
||||
· rw [getElem_insertIdx h]
|
||||
simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_def, dif_pos]
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_pos]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_def]
|
||||
simp only [Option.some_eq_dite_none_right, exists_prop, and_true]
|
||||
split at h <;> omega
|
||||
· simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_neg]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
|
||||
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (h : k < n) :
|
||||
(insertIdx n x l)[k]? = l[k]? := by
|
||||
rw [getElem?_insertIdx, if_pos h]
|
||||
|
||||
theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
|
||||
(insertIdx n x l)[n]? = if n ≤ l.length then some x else none := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega)]
|
||||
simp
|
||||
|
||||
theorem getElem?_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (h : n + 1 ≤ k) :
|
||||
(insertIdx n x l)[k]? = l[k - 1]? := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
|
||||
|
||||
end InsertIdx
|
||||
|
||||
end List
|
||||
@@ -110,6 +110,25 @@ theorem exists_of_modifyTailIdx (f : List α → List α) {n} {l : List α} (h :
|
||||
⟨_, _, (take_append_drop n l).symm, length_take_of_le h⟩
|
||||
⟨_, _, eq, hl, hl ▸ eq ▸ modifyTailIdx_add (n := 0) ..⟩
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx {f g : List α → List α} (m : Nat) :
|
||||
∀ (n) (l : List α),
|
||||
(l.modifyTailIdx f n).modifyTailIdx g (m + n) =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g m) n
|
||||
| 0, _ => rfl
|
||||
| _ + 1, [] => rfl
|
||||
| n + 1, a :: l => congrArg (List.cons a) (modifyTailIdx_modifyTailIdx m n l)
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : Nat) (l : List α)
|
||||
(h : n ≤ m) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g m =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g (m - n)) n := by
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨m, rfl⟩
|
||||
rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel]
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_self {f g : List α → List α} (n : Nat) (l : List α) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g ∘ f) n := by
|
||||
rw [modifyTailIdx_modifyTailIdx_le n n l (Nat.le_refl n), Nat.sub_self]; rfl
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem modify_nil (f : α → α) (n) : [].modify f n = [] := by cases n <;> rfl
|
||||
|
||||
@@ -108,7 +108,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
simp only [range'_eq_append_iff, eq_comm (a := i :: _), range'_eq_cons_iff]
|
||||
@@ -282,7 +282,7 @@ theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
|
||||
@@ -52,4 +52,29 @@ protected theorem getElem?_ofFn (f : Fin n → α) (i) : (ofFn f)[i]? = if h : i
|
||||
rw [dif_neg] <;>
|
||||
simpa using h
|
||||
|
||||
/-- `ofFn` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
theorem ofFn_zero (f : Fin 0 → α) : ofFn f = [] :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by contradiction)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_succ {n} (f : Fin (n + 1) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by
|
||||
cases i
|
||||
· simp
|
||||
· simp)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
theorem head_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn _ ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
List.getElem_ofFn]
|
||||
|
||||
theorem getLast_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
|
||||
|
||||
end List
|
||||
|
||||
@@ -114,6 +114,14 @@ theorem Perm.length_eq {l₁ l₂ : List α} (p : l₁ ~ l₂) : length l₁ = l
|
||||
| swap => rfl
|
||||
| trans _ _ ih₁ ih₂ => simp only [ih₁, ih₂]
|
||||
|
||||
theorem Perm.contains_eq [BEq α] {l₁ l₂ : List α} (h : l₁ ~ l₂) {a : α} :
|
||||
l₁.contains a = l₂.contains a := by
|
||||
induction h with
|
||||
| nil => rfl
|
||||
| cons => simp_all
|
||||
| swap => simp only [contains_cons, ← Bool.or_assoc, Bool.or_comm]
|
||||
| trans => simp_all
|
||||
|
||||
theorem Perm.eq_nil {l : List α} (p : l ~ []) : l = [] := eq_nil_of_length_eq_zero p.length_eq
|
||||
|
||||
theorem Perm.nil_eq {l : List α} (p : [] ~ l) : [] = l := p.symm.eq_nil.symm
|
||||
|
||||
@@ -293,7 +293,7 @@ theorem sorted_mergeSort
|
||||
apply sorted_mergeSort trans total
|
||||
termination_by l => l.length
|
||||
|
||||
@[deprecated (since := "2024-09-02")] abbrev mergeSort_sorted := @sorted_mergeSort
|
||||
@[deprecated sorted_mergeSort (since := "2024-09-02")] abbrev mergeSort_sorted := @sorted_mergeSort
|
||||
|
||||
/--
|
||||
If the input list is already sorted, then `mergeSort` does not change the list.
|
||||
@@ -429,7 +429,8 @@ theorem sublist_mergeSort
|
||||
((fun w => Sublist.of_sublist_append_right w h') fun b m₁ m₃ =>
|
||||
(Bool.eq_not_self true).mp ((rel_of_pairwise_cons hc m₁).symm.trans (h₃ b m₃))))
|
||||
|
||||
@[deprecated (since := "2024-09-02")] abbrev mergeSort_stable := @sublist_mergeSort
|
||||
@[deprecated sublist_mergeSort (since := "2024-09-02")]
|
||||
abbrev mergeSort_stable := @sublist_mergeSort
|
||||
|
||||
/--
|
||||
Another statement of stability of merge sort.
|
||||
@@ -442,7 +443,8 @@ theorem pair_sublist_mergeSort
|
||||
(hab : le a b) (h : [a, b] <+ l) : [a, b] <+ mergeSort l le :=
|
||||
sublist_mergeSort trans total (pairwise_pair.mpr hab) h
|
||||
|
||||
@[deprecated (since := "2024-09-02")] abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
|
||||
@[deprecated pair_sublist_mergeSort(since := "2024-09-02")]
|
||||
abbrev mergeSort_stable_pair := @pair_sublist_mergeSort
|
||||
|
||||
theorem map_merge {f : α → β} {r : α → α → Bool} {s : β → β → Bool} {l l' : List α}
|
||||
(hl : ∀ a ∈ l, ∀ b ∈ l', r a b = s (f a) (f b)) :
|
||||
|
||||
@@ -417,7 +417,7 @@ theorem Sublist.of_sublist_append_left (w : ∀ a, a ∈ l → a ∉ l₂) (h :
|
||||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||||
have : l₂' = [] := by
|
||||
rw [eq_nil_iff_forall_not_mem]
|
||||
exact fun x m => w x (mem_append_of_mem_right l₁' m) (h₂.mem m)
|
||||
exact fun x m => w x (mem_append_right l₁' m) (h₂.mem m)
|
||||
simp_all
|
||||
|
||||
theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h : l <+ l₁ ++ l₂) : l <+ l₂ := by
|
||||
@@ -425,7 +425,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
|
||||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||||
have : l₁' = [] := by
|
||||
rw [eq_nil_iff_forall_not_mem]
|
||||
exact fun x m => w x (mem_append_of_mem_left l₂' m) (h₁.mem m)
|
||||
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
|
||||
simp_all
|
||||
|
||||
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
|
||||
@@ -835,7 +835,7 @@ theorem isPrefix_iff : l₁ <+: l₂ ↔ ∀ i (h : i < l₁.length), l₂[i]? =
|
||||
simpa using ⟨0, by simp⟩
|
||||
| cons b l₂ =>
|
||||
simp only [cons_append, cons_prefix_cons, ih]
|
||||
rw (occs := .pos [2]) [← Nat.and_forall_add_one]
|
||||
rw (occs := [2]) [← Nat.and_forall_add_one]
|
||||
simp [Nat.succ_lt_succ_iff, eq_comm]
|
||||
|
||||
theorem isPrefix_iff_getElem {l₁ l₂ : List α} :
|
||||
|
||||
@@ -190,7 +190,7 @@ theorem set_drop {l : List α} {n m : Nat} {a : α} :
|
||||
theorem take_concat_get (l : List α) (i : Nat) (h : i < l.length) :
|
||||
(l.take i).concat l[i] = l.take (i+1) :=
|
||||
Eq.symm <| (append_left_inj _).1 <| (take_append_drop (i+1) l).trans <| by
|
||||
rw [concat_eq_append, append_assoc, singleton_append, get_drop_eq_drop, take_append_drop]
|
||||
rw [concat_eq_append, append_assoc, singleton_append, getElem_cons_drop_succ_eq_drop, take_append_drop]
|
||||
|
||||
@[deprecated take_succ_cons (since := "2024-07-25")]
|
||||
theorem take_cons_succ : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
@@ -224,7 +224,7 @@ theorem take_succ {l : List α} {n : Nat} : l.take (n + 1) = l.take n ++ l[n]?.t
|
||||
· simp only [take, Option.toList, getElem?_cons_zero, nil_append]
|
||||
· simp only [take, hl, getElem?_cons_succ, cons_append]
|
||||
|
||||
@[deprecated (since := "2024-07-25")]
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-07-25")]
|
||||
theorem drop_sizeOf_le [SizeOf α] (l : List α) (n : Nat) : sizeOf (l.drop n) ≤ sizeOf l := by
|
||||
induction l generalizing n with
|
||||
| nil => rw [drop_nil]; apply Nat.le_refl
|
||||
|
||||
@@ -20,3 +20,4 @@ import Init.Data.Nat.Mod
|
||||
import Init.Data.Nat.Lcm
|
||||
import Init.Data.Nat.Compare
|
||||
import Init.Data.Nat.Simproc
|
||||
import Init.Data.Nat.Fold
|
||||
|
||||
@@ -35,52 +35,6 @@ Used as the default `Nat` eliminator by the `cases` tactic. -/
|
||||
protected abbrev casesAuxOn {motive : Nat → Sort u} (t : Nat) (zero : motive 0) (succ : (n : Nat) → motive (n + 1)) : motive t :=
|
||||
Nat.casesOn t zero succ
|
||||
|
||||
/--
|
||||
`Nat.fold` evaluates `f` on the numbers up to `n` exclusive, in increasing order:
|
||||
* `Nat.fold f 3 init = init |> f 0 |> f 1 |> f 2`
|
||||
-/
|
||||
@[specialize] def fold {α : Type u} (f : Nat → α → α) : (n : Nat) → (init : α) → α
|
||||
| 0, a => a
|
||||
| succ n, a => f n (fold f n a)
|
||||
|
||||
/-- Tail-recursive version of `Nat.fold`. -/
|
||||
@[inline] def foldTR {α : Type u} (f : Nat → α → α) (n : Nat) (init : α) : α :=
|
||||
let rec @[specialize] loop
|
||||
| 0, a => a
|
||||
| succ m, a => loop m (f (n - succ m) a)
|
||||
loop n init
|
||||
|
||||
/--
|
||||
`Nat.foldRev` evaluates `f` on the numbers up to `n` exclusive, in decreasing order:
|
||||
* `Nat.foldRev f 3 init = f 0 <| f 1 <| f 2 <| init`
|
||||
-/
|
||||
@[specialize] def foldRev {α : Type u} (f : Nat → α → α) : (n : Nat) → (init : α) → α
|
||||
| 0, a => a
|
||||
| succ n, a => foldRev f n (f n a)
|
||||
|
||||
/-- `any f n = true` iff there is `i in [0, n-1]` s.t. `f i = true` -/
|
||||
@[specialize] def any (f : Nat → Bool) : Nat → Bool
|
||||
| 0 => false
|
||||
| succ n => any f n || f n
|
||||
|
||||
/-- Tail-recursive version of `Nat.any`. -/
|
||||
@[inline] def anyTR (f : Nat → Bool) (n : Nat) : Bool :=
|
||||
let rec @[specialize] loop : Nat → Bool
|
||||
| 0 => false
|
||||
| succ m => f (n - succ m) || loop m
|
||||
loop n
|
||||
|
||||
/-- `all f n = true` iff every `i in [0, n-1]` satisfies `f i = true` -/
|
||||
@[specialize] def all (f : Nat → Bool) : Nat → Bool
|
||||
| 0 => true
|
||||
| succ n => all f n && f n
|
||||
|
||||
/-- Tail-recursive version of `Nat.all`. -/
|
||||
@[inline] def allTR (f : Nat → Bool) (n : Nat) : Bool :=
|
||||
let rec @[specialize] loop : Nat → Bool
|
||||
| 0 => true
|
||||
| succ m => f (n - succ m) && loop m
|
||||
loop n
|
||||
|
||||
/--
|
||||
`Nat.repeat f n a` is `f^(n) a`; that is, it iterates `f` `n` times on `a`.
|
||||
@@ -835,7 +789,7 @@ theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
|
||||
pred_lt (not_eq_zero_of_lt h)
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
|
||||
@[deprecated pred_lt_of_lt (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
|
||||
|
||||
theorem sub_one_lt_of_lt {n m : Nat} (h : m < n) : n - 1 < n :=
|
||||
sub_one_lt (not_eq_zero_of_lt h)
|
||||
@@ -1121,7 +1075,7 @@ theorem pred_mul (n m : Nat) : pred n * m = n * m - m := by
|
||||
| succ n => rw [Nat.pred_succ, succ_mul, Nat.add_sub_cancel]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
|
||||
@[deprecated pred_mul (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
|
||||
|
||||
protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
|
||||
cases n with
|
||||
@@ -1133,7 +1087,7 @@ theorem mul_pred (n m : Nat) : n * pred m = n * m - n := by
|
||||
rw [Nat.mul_comm, pred_mul, Nat.mul_comm]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
|
||||
@[deprecated mul_pred (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
|
||||
|
||||
theorem mul_sub_one (n m : Nat) : n * (m - 1) = n * m - n := by
|
||||
rw [Nat.mul_comm, Nat.sub_one_mul , Nat.mul_comm]
|
||||
@@ -1158,33 +1112,6 @@ theorem not_lt_eq (a b : Nat) : (¬ (a < b)) = (b ≤ a) :=
|
||||
theorem not_gt_eq (a b : Nat) : (¬ (a > b)) = (a ≤ b) :=
|
||||
not_lt_eq b a
|
||||
|
||||
/-! # csimp theorems -/
|
||||
|
||||
@[csimp] theorem fold_eq_foldTR : @fold = @foldTR :=
|
||||
funext fun α => funext fun f => funext fun n => funext fun init =>
|
||||
let rec go : ∀ m n, foldTR.loop f (m + n) m (fold f n init) = fold f (m + n) init
|
||||
| 0, n => by simp [foldTR.loop]
|
||||
| succ m, n => by rw [foldTR.loop, add_sub_self_left, succ_add]; exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
@[csimp] theorem any_eq_anyTR : @any = @anyTR :=
|
||||
funext fun f => funext fun n =>
|
||||
let rec go : ∀ m n, (any f n || anyTR.loop f (m + n) m) = any f (m + n)
|
||||
| 0, n => by simp [anyTR.loop]
|
||||
| succ m, n => by
|
||||
rw [anyTR.loop, add_sub_self_left, ← Bool.or_assoc, succ_add]
|
||||
exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
@[csimp] theorem all_eq_allTR : @all = @allTR :=
|
||||
funext fun f => funext fun n =>
|
||||
let rec go : ∀ m n, (all f n && allTR.loop f (m + n) m) = all f (m + n)
|
||||
| 0, n => by simp [allTR.loop]
|
||||
| succ m, n => by
|
||||
rw [allTR.loop, add_sub_self_left, ← Bool.and_assoc, succ_add]
|
||||
exact go m (succ n)
|
||||
(go n 0).symm
|
||||
|
||||
@[csimp] theorem repeat_eq_repeatTR : @repeat = @repeatTR :=
|
||||
funext fun α => funext fun f => funext fun n => funext fun init =>
|
||||
let rec go : ∀ m n, repeatTR.loop f m (repeat f n init) = repeat f (m + n) init
|
||||
@@ -1193,31 +1120,3 @@ theorem not_gt_eq (a b : Nat) : (¬ (a > b)) = (a ≤ b) :=
|
||||
(go n 0).symm
|
||||
|
||||
end Nat
|
||||
|
||||
namespace Prod
|
||||
|
||||
/--
|
||||
`(start, stop).foldI f a` evaluates `f` on all the numbers
|
||||
from `start` (inclusive) to `stop` (exclusive) in increasing order:
|
||||
* `(5, 8).foldI f init = init |> f 5 |> f 6 |> f 7`
|
||||
-/
|
||||
@[inline] def foldI {α : Type u} (f : Nat → α → α) (i : Nat × Nat) (a : α) : α :=
|
||||
Nat.foldTR.loop f i.2 (i.2 - i.1) a
|
||||
|
||||
/--
|
||||
`(start, stop).anyI f a` returns true if `f` is true for some natural number
|
||||
from `start` (inclusive) to `stop` (exclusive):
|
||||
* `(5, 8).anyI f = f 5 || f 6 || f 7`
|
||||
-/
|
||||
@[inline] def anyI (f : Nat → Bool) (i : Nat × Nat) : Bool :=
|
||||
Nat.anyTR.loop f i.2 (i.2 - i.1)
|
||||
|
||||
/--
|
||||
`(start, stop).allI f a` returns true if `f` is true for all natural numbers
|
||||
from `start` (inclusive) to `stop` (exclusive):
|
||||
* `(5, 8).anyI f = f 5 && f 6 && f 7`
|
||||
-/
|
||||
@[inline] def allI (f : Nat → Bool) (i : Nat × Nat) : Bool :=
|
||||
Nat.allTR.loop f i.2 (i.2 - i.1)
|
||||
|
||||
end Prod
|
||||
|
||||
@@ -357,7 +357,7 @@ theorem testBit_two_pow_of_ne {n m : Nat} (hm : n ≠ m) : testBit (2 ^ n) m = f
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
rw [mod_eq_of_lt (a := 1) (Nat.one_lt_two_pow (by omega)), mod_two_eq_one_iff_testBit_zero, testBit_two_pow_sub_one ]
|
||||
simp only [zero_lt_succ, decide_True]
|
||||
simp only [zero_lt_succ, decide_true]
|
||||
|
||||
@[simp] theorem mod_two_pos_mod_two_eq_one : x % 2 ^ j % 2 = 1 ↔ (0 < j) ∧ x % 2 = 1 := by
|
||||
rw [mod_two_eq_one_iff_testBit_zero, testBit_mod_two_pow]
|
||||
|
||||
@@ -6,50 +6,51 @@ Author: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Control.Basic
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Omega
|
||||
|
||||
namespace Nat
|
||||
universe u v
|
||||
|
||||
@[inline] def forM {m} [Monad m] (n : Nat) (f : Nat → m Unit) : m Unit :=
|
||||
let rec @[specialize] loop
|
||||
| 0 => pure ()
|
||||
| i+1 => do f (n-i-1); loop i
|
||||
loop n
|
||||
@[inline] def forM {m} [Monad m] (n : Nat) (f : (i : Nat) → i < n → m Unit) : m Unit :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → m Unit
|
||||
| 0, _ => pure ()
|
||||
| i+1, h => do f (n-i-1) (by omega); loop i (Nat.le_of_succ_le h)
|
||||
loop n (by simp)
|
||||
|
||||
@[inline] def forRevM {m} [Monad m] (n : Nat) (f : Nat → m Unit) : m Unit :=
|
||||
let rec @[specialize] loop
|
||||
| 0 => pure ()
|
||||
| i+1 => do f i; loop i
|
||||
loop n
|
||||
@[inline] def forRevM {m} [Monad m] (n : Nat) (f : (i : Nat) → i < n → m Unit) : m Unit :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → m Unit
|
||||
| 0, _ => pure ()
|
||||
| i+1, h => do f i (by omega); loop i (Nat.le_of_succ_le h)
|
||||
loop n (by simp)
|
||||
|
||||
@[inline] def foldM {α : Type u} {m : Type u → Type v} [Monad m] (f : Nat → α → m α) (init : α) (n : Nat) : m α :=
|
||||
let rec @[specialize] loop
|
||||
| 0, a => pure a
|
||||
| i+1, a => f (n-i-1) a >>= loop i
|
||||
loop n init
|
||||
@[inline] def foldM {α : Type u} {m : Type u → Type v} [Monad m] (n : Nat) (f : (i : Nat) → i < n → α → m α) (init : α) : m α :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → α → m α
|
||||
| 0, h, a => pure a
|
||||
| i+1, h, a => f (n-i-1) (by omega) a >>= loop i (Nat.le_of_succ_le h)
|
||||
loop n (by omega) init
|
||||
|
||||
@[inline] def foldRevM {α : Type u} {m : Type u → Type v} [Monad m] (f : Nat → α → m α) (init : α) (n : Nat) : m α :=
|
||||
let rec @[specialize] loop
|
||||
| 0, a => pure a
|
||||
| i+1, a => f i a >>= loop i
|
||||
loop n init
|
||||
@[inline] def foldRevM {α : Type u} {m : Type u → Type v} [Monad m] (n : Nat) (f : (i : Nat) → i < n → α → m α) (init : α) : m α :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → α → m α
|
||||
| 0, h, a => pure a
|
||||
| i+1, h, a => f i (by omega) a >>= loop i (Nat.le_of_succ_le h)
|
||||
loop n (by omega) init
|
||||
|
||||
@[inline] def allM {m} [Monad m] (n : Nat) (p : Nat → m Bool) : m Bool :=
|
||||
let rec @[specialize] loop
|
||||
| 0 => pure true
|
||||
| i+1 => do
|
||||
match (← p (n-i-1)) with
|
||||
| true => loop i
|
||||
@[inline] def allM {m} [Monad m] (n : Nat) (p : (i : Nat) → i < n → m Bool) : m Bool :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → m Bool
|
||||
| 0, _ => pure true
|
||||
| i+1 , h => do
|
||||
match (← p (n-i-1) (by omega)) with
|
||||
| true => loop i (by omega)
|
||||
| false => pure false
|
||||
loop n
|
||||
loop n (by simp)
|
||||
|
||||
@[inline] def anyM {m} [Monad m] (n : Nat) (p : Nat → m Bool) : m Bool :=
|
||||
let rec @[specialize] loop
|
||||
| 0 => pure false
|
||||
| i+1 => do
|
||||
match (← p (n-i-1)) with
|
||||
@[inline] def anyM {m} [Monad m] (n : Nat) (p : (i : Nat) → i < n → m Bool) : m Bool :=
|
||||
let rec @[specialize] loop : ∀ i, i ≤ n → m Bool
|
||||
| 0, _ => pure false
|
||||
| i+1, h => do
|
||||
match (← p (n-i-1) (by omega)) with
|
||||
| true => pure true
|
||||
| false => loop i
|
||||
loop n
|
||||
| false => loop i (Nat.le_of_succ_le h)
|
||||
loop n (by simp)
|
||||
|
||||
end Nat
|
||||
|
||||
@@ -92,7 +92,7 @@ protected theorem div_mul_cancel {n m : Nat} (H : n ∣ m) : m / n * n = m := by
|
||||
rw [Nat.mul_comm, Nat.mul_div_cancel' H]
|
||||
|
||||
@[simp] theorem mod_mod_of_dvd (a : Nat) (h : c ∣ b) : a % b % c = a % c := by
|
||||
rw (occs := .pos [2]) [← mod_add_div a b]
|
||||
rw (occs := [2]) [← mod_add_div a b]
|
||||
have ⟨x, h⟩ := h
|
||||
subst h
|
||||
rw [Nat.mul_assoc, add_mul_mod_self_left]
|
||||
|
||||
217
src/Init/Data/Nat/Fold.lean
Normal file
217
src/Init/Data/Nat/Fold.lean
Normal file
@@ -0,0 +1,217 @@
|
||||
/-
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Floris van Doorn, Leonardo de Moura, Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Omega
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
universe u
|
||||
|
||||
namespace Nat
|
||||
|
||||
/--
|
||||
`Nat.fold` evaluates `f` on the numbers up to `n` exclusive, in increasing order:
|
||||
* `Nat.fold f 3 init = init |> f 0 |> f 1 |> f 2`
|
||||
-/
|
||||
@[specialize] def fold {α : Type u} : (n : Nat) → (f : (i : Nat) → i < n → α → α) → (init : α) → α
|
||||
| 0, f, a => a
|
||||
| succ n, f, a => f n (by omega) (fold n (fun i h => f i (by omega)) a)
|
||||
|
||||
/-- Tail-recursive version of `Nat.fold`. -/
|
||||
@[inline] def foldTR {α : Type u} (n : Nat) (f : (i : Nat) → i < n → α → α) (init : α) : α :=
|
||||
let rec @[specialize] loop : ∀ j, j ≤ n → α → α
|
||||
| 0, h, a => a
|
||||
| succ m, h, a => loop m (by omega) (f (n - succ m) (by omega) a)
|
||||
loop n (by omega) init
|
||||
|
||||
/--
|
||||
`Nat.foldRev` evaluates `f` on the numbers up to `n` exclusive, in decreasing order:
|
||||
* `Nat.foldRev f 3 init = f 0 <| f 1 <| f 2 <| init`
|
||||
-/
|
||||
@[specialize] def foldRev {α : Type u} : (n : Nat) → (f : (i : Nat) → i < n → α → α) → (init : α) → α
|
||||
| 0, f, a => a
|
||||
| succ n, f, a => foldRev n (fun i h => f i (by omega)) (f n (by omega) a)
|
||||
|
||||
/-- `any f n = true` iff there is `i in [0, n-1]` s.t. `f i = true` -/
|
||||
@[specialize] def any : (n : Nat) → (f : (i : Nat) → i < n → Bool) → Bool
|
||||
| 0, f => false
|
||||
| succ n, f => any n (fun i h => f i (by omega)) || f n (by omega)
|
||||
|
||||
/-- Tail-recursive version of `Nat.any`. -/
|
||||
@[inline] def anyTR (n : Nat) (f : (i : Nat) → i < n → Bool) : Bool :=
|
||||
let rec @[specialize] loop : (i : Nat) → i ≤ n → Bool
|
||||
| 0, h => false
|
||||
| succ m, h => f (n - succ m) (by omega) || loop m (by omega)
|
||||
loop n (by omega)
|
||||
|
||||
/-- `all f n = true` iff every `i in [0, n-1]` satisfies `f i = true` -/
|
||||
@[specialize] def all : (n : Nat) → (f : (i : Nat) → i < n → Bool) → Bool
|
||||
| 0, f => true
|
||||
| succ n, f => all n (fun i h => f i (by omega)) && f n (by omega)
|
||||
|
||||
/-- Tail-recursive version of `Nat.all`. -/
|
||||
@[inline] def allTR (n : Nat) (f : (i : Nat) → i < n → Bool) : Bool :=
|
||||
let rec @[specialize] loop : (i : Nat) → i ≤ n → Bool
|
||||
| 0, h => true
|
||||
| succ m, h => f (n - succ m) (by omega) && loop m (by omega)
|
||||
loop n (by omega)
|
||||
|
||||
/-! # csimp theorems -/
|
||||
|
||||
theorem fold_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
(f : (i : Nat) → i < n → α → α) (init : α) :
|
||||
fold n f init = fold m (fun i h => f i (by omega)) init := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem foldTR_loop_congr {α : Type u} {n m : Nat} (w : n = m)
|
||||
(f : (i : Nat) → i < n → α → α) (j : Nat) (h : j ≤ n) (init : α) :
|
||||
foldTR.loop n f j h init = foldTR.loop m (fun i h => f i (by omega)) j (by omega) init := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
@[csimp] theorem fold_eq_foldTR : @fold = @foldTR :=
|
||||
funext fun α => funext fun n => funext fun f => funext fun init =>
|
||||
let rec go : ∀ m n f, fold (m + n) f init = foldTR.loop (m + n) f m (by omega) (fold n (fun i h => f i (by omega)) init)
|
||||
| 0, n, f => by
|
||||
simp only [foldTR.loop]
|
||||
have t : 0 + n = n := by omega
|
||||
rw [fold_congr t]
|
||||
| succ m, n, f => by
|
||||
have t : (m + 1) + n = m + (n + 1) := by omega
|
||||
rw [foldTR.loop]
|
||||
simp only [succ_eq_add_one, Nat.add_sub_cancel]
|
||||
rw [fold_congr t, foldTR_loop_congr t, go, fold]
|
||||
congr
|
||||
omega
|
||||
go n 0 f
|
||||
|
||||
theorem any_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : any n f = any m (fun i h => f i (by omega)) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem anyTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) :
|
||||
anyTR.loop n f j h = anyTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
@[csimp] theorem any_eq_anyTR : @any = @anyTR :=
|
||||
funext fun n => funext fun f =>
|
||||
let rec go : ∀ m n f, any (m + n) f = (any n (fun i h => f i (by omega)) || anyTR.loop (m + n) f m (by omega))
|
||||
| 0, n, f => by
|
||||
simp [anyTR.loop]
|
||||
have t : 0 + n = n := by omega
|
||||
rw [any_congr t]
|
||||
| succ m, n, f => by
|
||||
have t : (m + 1) + n = m + (n + 1) := by omega
|
||||
rw [anyTR.loop]
|
||||
simp only [succ_eq_add_one]
|
||||
rw [any_congr t, anyTR_loop_congr t, go, any, Bool.or_assoc]
|
||||
congr
|
||||
omega
|
||||
go n 0 f
|
||||
|
||||
theorem all_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) : all n f = all m (fun i h => f i (by omega)) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
theorem allTR_loop_congr {n m : Nat} (w : n = m) (f : (i : Nat) → i < n → Bool) (j : Nat) (h : j ≤ n) : allTR.loop n f j h = allTR.loop m (fun i h => f i (by omega)) j (by omega) := by
|
||||
subst m
|
||||
rfl
|
||||
|
||||
@[csimp] theorem all_eq_allTR : @all = @allTR :=
|
||||
funext fun n => funext fun f =>
|
||||
let rec go : ∀ m n f, all (m + n) f = (all n (fun i h => f i (by omega)) && allTR.loop (m + n) f m (by omega))
|
||||
| 0, n, f => by
|
||||
simp [allTR.loop]
|
||||
have t : 0 + n = n := by omega
|
||||
rw [all_congr t]
|
||||
| succ m, n, f => by
|
||||
have t : (m + 1) + n = m + (n + 1) := by omega
|
||||
rw [allTR.loop]
|
||||
simp only [succ_eq_add_one]
|
||||
rw [all_congr t, allTR_loop_congr t, go, all, Bool.and_assoc]
|
||||
congr
|
||||
omega
|
||||
go n 0 f
|
||||
|
||||
@[simp] theorem fold_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
fold 0 f init = init := by simp [fold]
|
||||
|
||||
@[simp] theorem fold_succ {α : Type u} (n : Nat) (f : (i : Nat) → i < n + 1 → α → α) (init : α) :
|
||||
fold (n + 1) f init = f n (by omega) (fold n (fun i h => f i (by omega)) init) := by simp [fold]
|
||||
|
||||
theorem fold_eq_finRange_foldl {α : Type u} (n : Nat) (f : (i : Nat) → i < n → α → α) (init : α) :
|
||||
fold n f init = (List.finRange n).foldl (fun acc ⟨i, h⟩ => f i h acc) init := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp [ih, List.finRange_succ_last, List.foldl_map]
|
||||
|
||||
@[simp] theorem foldRev_zero {α : Type u} (f : (i : Nat) → i < 0 → α → α) (init : α) :
|
||||
foldRev 0 f init = init := by simp [foldRev]
|
||||
|
||||
@[simp] theorem foldRev_succ {α : Type u} (n : Nat) (f : (i : Nat) → i < n + 1 → α → α) (init : α) :
|
||||
foldRev (n + 1) f init = foldRev n (fun i h => f i (by omega)) (f n (by omega) init) := by
|
||||
simp [foldRev]
|
||||
|
||||
theorem foldRev_eq_finRange_foldr {α : Type u} (n : Nat) (f : (i : Nat) → i < n → α → α) (init : α) :
|
||||
foldRev n f init = (List.finRange n).foldr (fun ⟨i, h⟩ acc => f i h acc) init := by
|
||||
induction n generalizing init with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.foldr_map]
|
||||
|
||||
@[simp] theorem any_zero {f : (i : Nat) → i < 0 → Bool} : any 0 f = false := by simp [any]
|
||||
|
||||
@[simp] theorem any_succ {n : Nat} (f : (i : Nat) → i < n + 1 → Bool) :
|
||||
any (n + 1) f = (any n (fun i h => f i (by omega)) || f n (by omega)) := by simp [any]
|
||||
|
||||
theorem any_eq_finRange_any {n : Nat} (f : (i : Nat) → i < n → Bool) :
|
||||
any n f = (List.finRange n).any (fun ⟨i, h⟩ => f i h) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.any_map, Function.comp_def]
|
||||
|
||||
@[simp] theorem all_zero {f : (i : Nat) → i < 0 → Bool} : all 0 f = true := by simp [all]
|
||||
|
||||
@[simp] theorem all_succ {n : Nat} (f : (i : Nat) → i < n + 1 → Bool) :
|
||||
all (n + 1) f = (all n (fun i h => f i (by omega)) && f n (by omega)) := by simp [all]
|
||||
|
||||
theorem all_eq_finRange_all {n : Nat} (f : (i : Nat) → i < n → Bool) :
|
||||
all n f = (List.finRange n).all (fun ⟨i, h⟩ => f i h) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ih, List.finRange_succ_last, List.all_map, Function.comp_def]
|
||||
|
||||
end Nat
|
||||
|
||||
namespace Prod
|
||||
|
||||
/--
|
||||
`(start, stop).foldI f a` evaluates `f` on all the numbers
|
||||
from `start` (inclusive) to `stop` (exclusive) in increasing order:
|
||||
* `(5, 8).foldI f init = init |> f 5 |> f 6 |> f 7`
|
||||
-/
|
||||
@[inline] def foldI {α : Type u} (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → α → α) (a : α) : α :=
|
||||
(i.2 - i.1).fold (fun j _ => f (i.1 + j) (by omega) (by omega)) a
|
||||
|
||||
/--
|
||||
`(start, stop).anyI f a` returns true if `f` is true for some natural number
|
||||
from `start` (inclusive) to `stop` (exclusive):
|
||||
* `(5, 8).anyI f = f 5 || f 6 || f 7`
|
||||
-/
|
||||
@[inline] def anyI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
(i.2 - i.1).any (fun j _ => f (i.1 + j) (by omega) (by omega))
|
||||
|
||||
/--
|
||||
`(start, stop).allI f a` returns true if `f` is true for all natural numbers
|
||||
from `start` (inclusive) to `stop` (exclusive):
|
||||
* `(5, 8).anyI f = f 5 && f 6 && f 7`
|
||||
-/
|
||||
@[inline] def allI (i : Nat × Nat) (f : (j : Nat) → i.1 ≤ j → j < i.2 → Bool) : Bool :=
|
||||
(i.2 - i.1).all (fun j _ => f (i.1 + j) (by omega) (by omega))
|
||||
|
||||
end Prod
|
||||
@@ -651,8 +651,8 @@ theorem sub_mul_mod {x k n : Nat} (h₁ : n*k ≤ x) : (x - n*k) % n = x % n :=
|
||||
| .inr npos => Nat.mod_eq_of_lt (mod_lt _ npos)
|
||||
|
||||
theorem mul_mod (a b n : Nat) : a * b % n = (a % n) * (b % n) % n := by
|
||||
rw (occs := .pos [1]) [← mod_add_div a n]
|
||||
rw (occs := .pos [1]) [← mod_add_div b n]
|
||||
rw (occs := [1]) [← mod_add_div a n]
|
||||
rw (occs := [1]) [← mod_add_div b n]
|
||||
rw [Nat.add_mul, Nat.mul_add, Nat.mul_add,
|
||||
Nat.mul_assoc, Nat.mul_assoc, ← Nat.mul_add n, add_mul_mod_self_left,
|
||||
Nat.mul_comm _ (n * (b / n)), Nat.mul_assoc, add_mul_mod_self_left]
|
||||
@@ -679,6 +679,10 @@ theorem add_mod (a b n : Nat) : (a + b) % n = ((a % n) + (b % n)) % n := by
|
||||
@[simp] theorem mod_mul_mod {a b c : Nat} : (a % c * b) % c = a * b % c := by
|
||||
rw [mul_mod, mod_mod, ← mul_mod]
|
||||
|
||||
theorem mod_eq_sub (x w : Nat) : x % w = x - w * (x / w) := by
|
||||
conv => rhs; congr; rw [← mod_add_div x w]
|
||||
simp
|
||||
|
||||
/-! ### pow -/
|
||||
|
||||
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
|
||||
@@ -846,6 +850,18 @@ protected theorem pow_lt_pow_iff_pow_mul_le_pow {a n m : Nat} (h : 1 < a) :
|
||||
rw [←Nat.pow_add_one, Nat.pow_le_pow_iff_right (by omega), Nat.pow_lt_pow_iff_right (by omega)]
|
||||
omega
|
||||
|
||||
protected theorem lt_pow_self {n a : Nat} (h : 1 < a) : n < a ^ n := by
|
||||
induction n with
|
||||
| zero => exact Nat.zero_lt_one
|
||||
| succ _ ih => exact Nat.lt_of_lt_of_le (Nat.add_lt_add_right ih 1) (Nat.pow_lt_pow_succ h)
|
||||
|
||||
protected theorem lt_two_pow_self : n < 2 ^ n :=
|
||||
Nat.lt_pow_self Nat.one_lt_two
|
||||
|
||||
@[simp]
|
||||
protected theorem mod_two_pow_self : n % 2 ^ n = n :=
|
||||
Nat.mod_eq_of_lt Nat.lt_two_pow_self
|
||||
|
||||
@[simp]
|
||||
theorem two_pow_pred_mul_two (h : 0 < w) :
|
||||
2 ^ (w - 1) * 2 = 2 ^ w := by
|
||||
@@ -1029,3 +1045,12 @@ instance decidableExistsLT [h : DecidablePred p] : DecidablePred fun n => ∃ m
|
||||
instance decidableExistsLE [DecidablePred p] : DecidablePred fun n => ∃ m : Nat, m ≤ n ∧ p m :=
|
||||
fun n => decidable_of_iff (∃ m, m < n + 1 ∧ p m)
|
||||
(exists_congr fun _ => and_congr_left' Nat.lt_succ_iff)
|
||||
|
||||
/-! ### 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
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp [← ih]
|
||||
omega
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.ByCases
|
||||
import Init.Data.Prod
|
||||
import Init.Data.RArray
|
||||
|
||||
namespace Nat.Linear
|
||||
|
||||
@@ -15,7 +16,7 @@ namespace Nat.Linear
|
||||
|
||||
abbrev Var := Nat
|
||||
|
||||
abbrev Context := List Nat
|
||||
abbrev Context := Lean.RArray Nat
|
||||
|
||||
/--
|
||||
When encoding polynomials. We use `fixedVar` for encoding numerals.
|
||||
@@ -23,12 +24,7 @@ abbrev Context := List Nat
|
||||
def fixedVar := 100000000 -- Any big number should work here
|
||||
|
||||
def Var.denote (ctx : Context) (v : Var) : Nat :=
|
||||
bif v == fixedVar then 1 else go ctx v
|
||||
where
|
||||
go : List Nat → Nat → Nat
|
||||
| [], _ => 0
|
||||
| a::_, 0 => a
|
||||
| _::as, i+1 => go as i
|
||||
bif v == fixedVar then 1 else ctx.get v
|
||||
|
||||
inductive Expr where
|
||||
| num (v : Nat)
|
||||
@@ -52,25 +48,23 @@ def Poly.denote (ctx : Context) (p : Poly) : Nat :=
|
||||
| [] => 0
|
||||
| (k, v) :: p => Nat.add (Nat.mul k (v.denote ctx)) (denote ctx p)
|
||||
|
||||
def Poly.insertSorted (k : Nat) (v : Var) (p : Poly) : Poly :=
|
||||
def Poly.insert (k : Nat) (v : Var) (p : Poly) : Poly :=
|
||||
match p with
|
||||
| [] => [(k, v)]
|
||||
| (k', v') :: p => bif Nat.blt v v' then (k, v) :: (k', v') :: p else (k', v') :: insertSorted k v p
|
||||
| (k', v') :: p =>
|
||||
bif Nat.blt v v' then
|
||||
(k, v) :: (k', v') :: p
|
||||
else bif Nat.beq v v' then
|
||||
(k + k', v') :: p
|
||||
else
|
||||
(k', v') :: insert k v p
|
||||
|
||||
def Poly.sort (p : Poly) : Poly :=
|
||||
let rec go (p : Poly) (r : Poly) : Poly :=
|
||||
def Poly.norm (p : Poly) : Poly := go p []
|
||||
where
|
||||
go (p : Poly) (r : Poly) : Poly :=
|
||||
match p with
|
||||
| [] => r
|
||||
| (k, v) :: p => go p (r.insertSorted k v)
|
||||
go p []
|
||||
|
||||
def Poly.fuse (p : Poly) : Poly :=
|
||||
match p with
|
||||
| [] => []
|
||||
| (k, v) :: p =>
|
||||
match fuse p with
|
||||
| [] => [(k, v)]
|
||||
| (k', v') :: p' => bif v == v' then (Nat.add k k', v)::p' else (k, v) :: (k', v') :: p'
|
||||
| (k, v) :: p => go p (r.insert k v)
|
||||
|
||||
def Poly.mul (k : Nat) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
@@ -146,15 +140,17 @@ def Poly.combineAux (fuel : Nat) (p₁ p₂ : Poly) : Poly :=
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
combineAux hugeFuel p₁ p₂
|
||||
|
||||
def Expr.toPoly : Expr → Poly
|
||||
| Expr.num k => bif k == 0 then [] else [ (k, fixedVar) ]
|
||||
| Expr.var i => [(1, i)]
|
||||
| Expr.add a b => a.toPoly ++ b.toPoly
|
||||
| Expr.mulL k a => a.toPoly.mul k
|
||||
| Expr.mulR a k => a.toPoly.mul k
|
||||
|
||||
def Poly.norm (p : Poly) : Poly :=
|
||||
p.sort.fuse
|
||||
def Expr.toPoly (e : Expr) :=
|
||||
go 1 e []
|
||||
where
|
||||
-- Implementation note: This assembles the result using difference lists
|
||||
-- to avoid `++` on lists.
|
||||
go (coeff : Nat) : Expr → (Poly → Poly)
|
||||
| Expr.num k => bif k == 0 then id else ((coeff * k, fixedVar) :: ·)
|
||||
| Expr.var i => ((coeff, i) :: ·)
|
||||
| Expr.add a b => go coeff a ∘ go coeff b
|
||||
| Expr.mulL k a
|
||||
| Expr.mulR a k => bif k == 0 then id else go (coeff * k) a
|
||||
|
||||
def Expr.toNormPoly (e : Expr) : Poly :=
|
||||
e.toPoly.norm
|
||||
@@ -201,7 +197,7 @@ def PolyCnstr.denote (ctx : Context) (c : PolyCnstr) : Prop :=
|
||||
Poly.denote_le ctx (c.lhs, c.rhs)
|
||||
|
||||
def PolyCnstr.norm (c : PolyCnstr) : PolyCnstr :=
|
||||
let (lhs, rhs) := Poly.cancel c.lhs.sort.fuse c.rhs.sort.fuse
|
||||
let (lhs, rhs) := Poly.cancel c.lhs.norm c.rhs.norm
|
||||
{ eq := c.eq, lhs, rhs }
|
||||
|
||||
def PolyCnstr.isUnsat (c : PolyCnstr) : Bool :=
|
||||
@@ -268,24 +264,32 @@ def PolyCnstr.toExpr (c : PolyCnstr) : ExprCnstr :=
|
||||
{ c with lhs := c.lhs.toExpr, rhs := c.rhs.toExpr }
|
||||
|
||||
attribute [local simp] Nat.add_comm Nat.add_assoc Nat.add_left_comm Nat.right_distrib Nat.left_distrib Nat.mul_assoc Nat.mul_comm
|
||||
attribute [local simp] Poly.denote Expr.denote Poly.insertSorted Poly.sort Poly.sort.go Poly.fuse Poly.cancelAux
|
||||
attribute [local simp] Poly.denote Expr.denote Poly.insert Poly.norm Poly.norm.go Poly.cancelAux
|
||||
attribute [local simp] Poly.mul Poly.mul.go
|
||||
|
||||
theorem Poly.denote_insertSorted (ctx : Context) (k : Nat) (v : Var) (p : Poly) : (p.insertSorted k v).denote ctx = p.denote ctx + k * v.denote ctx := by
|
||||
theorem Poly.denote_insert (ctx : Context) (k : Nat) (v : Var) (p : Poly) :
|
||||
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
|
||||
match p with
|
||||
| [] => simp
|
||||
| (k', v') :: p => by_cases h : Nat.blt v v' <;> simp [h, denote_insertSorted]
|
||||
| (k', v') :: p =>
|
||||
by_cases h₁ : Nat.blt v v'
|
||||
· simp [h₁]
|
||||
· by_cases h₂ : Nat.beq v v'
|
||||
· simp only [insert, h₁, h₂, cond_false, cond_true]
|
||||
simp [Nat.eq_of_beq_eq_true h₂]
|
||||
· simp only [insert, h₁, h₂, cond_false, cond_true]
|
||||
simp [denote_insert]
|
||||
|
||||
attribute [local simp] Poly.denote_insertSorted
|
||||
attribute [local simp] Poly.denote_insert
|
||||
|
||||
theorem Poly.denote_sort_go (ctx : Context) (p : Poly) (r : Poly) : (sort.go p r).denote ctx = p.denote ctx + r.denote ctx := by
|
||||
theorem Poly.denote_norm_go (ctx : Context) (p : Poly) (r : Poly) : (norm.go p r).denote ctx = p.denote ctx + r.denote ctx := by
|
||||
match p with
|
||||
| [] => simp
|
||||
| (k, v):: p => simp [denote_sort_go]
|
||||
| (k, v):: p => simp [denote_norm_go]
|
||||
|
||||
attribute [local simp] Poly.denote_sort_go
|
||||
attribute [local simp] Poly.denote_norm_go
|
||||
|
||||
theorem Poly.denote_sort (ctx : Context) (m : Poly) : m.sort.denote ctx = m.denote ctx := by
|
||||
theorem Poly.denote_sort (ctx : Context) (m : Poly) : m.norm.denote ctx = m.denote ctx := by
|
||||
simp
|
||||
|
||||
attribute [local simp] Poly.denote_sort
|
||||
@@ -316,18 +320,6 @@ theorem Poly.denote_reverse (ctx : Context) (p : Poly) : denote ctx (List.revers
|
||||
|
||||
attribute [local simp] Poly.denote_reverse
|
||||
|
||||
theorem Poly.denote_fuse (ctx : Context) (p : Poly) : p.fuse.denote ctx = p.denote ctx := by
|
||||
match p with
|
||||
| [] => rfl
|
||||
| (k, v) :: p =>
|
||||
have ih := denote_fuse ctx p
|
||||
simp
|
||||
split
|
||||
case _ h => simp [← ih, h]
|
||||
case _ k' v' p' h => by_cases he : v == v' <;> simp [he, ← ih, h]; rw [eq_of_beq he]
|
||||
|
||||
attribute [local simp] Poly.denote_fuse
|
||||
|
||||
theorem Poly.denote_mul (ctx : Context) (k : Nat) (p : Poly) : (p.mul k).denote ctx = k * p.denote ctx := by
|
||||
simp
|
||||
by_cases h : k == 0 <;> simp [h]; simp [eq_of_beq h]
|
||||
@@ -516,13 +508,25 @@ theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p
|
||||
|
||||
attribute [local simp] Poly.denote_combine
|
||||
|
||||
theorem Expr.denote_toPoly_go (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 with
|
||||
| case1 k k' =>
|
||||
simp only [toPoly.go]
|
||||
by_cases h : k' == 0
|
||||
· simp [h, eq_of_beq h]
|
||||
· simp [h, Var.denote]
|
||||
| case2 k i => simp [toPoly.go]
|
||||
| case3 k a b iha ihb => simp [toPoly.go, iha, ihb]
|
||||
| case4 k k' a ih
|
||||
| case5 k a k' ih =>
|
||||
simp only [toPoly.go, denote, mul_eq]
|
||||
by_cases h : k' == 0
|
||||
· simp [h, eq_of_beq h]
|
||||
· simp [h, cond_false, ih, Nat.mul_assoc]
|
||||
|
||||
theorem Expr.denote_toPoly (ctx : Context) (e : Expr) : e.toPoly.denote ctx = e.denote ctx := by
|
||||
induction e with
|
||||
| num k => by_cases h : k == 0 <;> simp [toPoly, h, Var.denote]; simp [eq_of_beq h]
|
||||
| var i => simp [toPoly]
|
||||
| add a b iha ihb => simp [toPoly, iha, ihb]
|
||||
| mulL k a ih => simp [toPoly, ih, -Poly.mul]
|
||||
| mulR k a ih => simp [toPoly, ih, -Poly.mul]
|
||||
simp [toPoly, Expr.denote_toPoly_go]
|
||||
|
||||
attribute [local simp] Expr.denote_toPoly
|
||||
|
||||
@@ -554,8 +558,8 @@ theorem ExprCnstr.denote_toPoly (ctx : Context) (c : ExprCnstr) : c.toPoly.denot
|
||||
cases c; rename_i eq lhs rhs
|
||||
simp [ExprCnstr.denote, PolyCnstr.denote, ExprCnstr.toPoly];
|
||||
by_cases h : eq = true <;> simp [h]
|
||||
· simp [Poly.denote_eq, Expr.toPoly]
|
||||
· simp [Poly.denote_le, Expr.toPoly]
|
||||
· simp [Poly.denote_eq]
|
||||
· simp [Poly.denote_le]
|
||||
|
||||
attribute [local simp] ExprCnstr.denote_toPoly
|
||||
|
||||
|
||||
@@ -16,22 +16,22 @@ def getM [Alternative m] : Option α → m α
|
||||
| none => failure
|
||||
| some a => pure a
|
||||
|
||||
@[deprecated getM (since := "2024-04-17")]
|
||||
-- `[Monad m]` is not needed here.
|
||||
def toMonad [Monad m] [Alternative m] : Option α → m α := getM
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@[inline] def isSome : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[deprecated isSome (since := "2024-04-17"), inline] def toBool : Option α → Bool := isSome
|
||||
@[simp] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp] theorem isSome_some : isSome (some a) = true := rfl
|
||||
|
||||
/-- Returns `true` on `none` and `false` on `some x`. -/
|
||||
@[inline] def isNone : Option α → Bool
|
||||
| some _ => false
|
||||
| none => true
|
||||
|
||||
@[simp] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp] theorem isNone_some : isNone (some a) = false := rfl
|
||||
|
||||
/--
|
||||
`x?.isEqSome y` is equivalent to `x? == some y`, but avoids an allocation.
|
||||
-/
|
||||
@@ -134,6 +134,10 @@ def merge (fn : α → α → α) : Option α → Option α → Option α
|
||||
@[inline] def get {α : Type u} : (o : Option α) → isSome o → α
|
||||
| some x, _ => x
|
||||
|
||||
@[simp] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
| some _, _ => rfl
|
||||
@[simp] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
|
||||
/-- `guard p a` returns `some a` if `p a` holds, otherwise `none`. -/
|
||||
@[inline] def guard (p : α → Prop) [DecidablePred p] (a : α) : Option α :=
|
||||
if p a then some a else none
|
||||
|
||||
@@ -36,11 +36,6 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
|
||||
|
||||
theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
|
||||
@[simp] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
| some _, _ => rfl
|
||||
|
||||
@[simp] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
|
||||
theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.getD y) = x := by
|
||||
cases x; {contradiction}; rw [getD_some]
|
||||
|
||||
@@ -60,7 +55,9 @@ theorem get_eq_getD {fallback : α} : (o : Option α) → {h : o.isSome} → o.g
|
||||
theorem some_get! [Inhabited α] : (o : Option α) → o.isSome → some (o.get!) = o
|
||||
| some _, _ => rfl
|
||||
|
||||
theorem get!_eq_getD_default [Inhabited α] (o : Option α) : o.get! = o.getD default := rfl
|
||||
theorem get!_eq_getD [Inhabited α] (o : Option α) : o.get! = o.getD default := rfl
|
||||
|
||||
@[deprecated get!_eq_getD (since := "2024-11-18")] abbrev get!_eq_getD_default := @get!_eq_getD
|
||||
|
||||
theorem mem_unique {o : Option α} {a b : α} (ha : a ∈ o) (hb : b ∈ o) : a = b :=
|
||||
some.inj <| ha ▸ hb
|
||||
@@ -73,19 +70,11 @@ theorem mem_unique {o : Option α} {a b : α} (ha : a ∈ o) (hb : b ∈ o) : a
|
||||
theorem eq_none_iff_forall_not_mem : o = none ↔ ∀ a, a ∉ o :=
|
||||
⟨fun e a h => by rw [e] at h; (cases h), fun h => ext <| by simp; exact h⟩
|
||||
|
||||
@[simp] theorem isSome_none : @isSome α none = false := rfl
|
||||
|
||||
@[simp] theorem isSome_some : isSome (some a) = true := rfl
|
||||
|
||||
theorem isSome_iff_exists : isSome x ↔ ∃ a, x = some a := by cases x <;> simp [isSome]
|
||||
|
||||
theorem isSome_eq_isSome : (isSome x = isSome y) ↔ (x = none ↔ y = none) := by
|
||||
cases x <;> cases y <;> simp
|
||||
|
||||
@[simp] theorem isNone_none : @isNone α none = true := rfl
|
||||
|
||||
@[simp] theorem isNone_some : isNone (some a) = false := rfl
|
||||
|
||||
@[simp] theorem not_isSome : isSome a = false ↔ a.isNone = true := by
|
||||
cases a <;> simp
|
||||
|
||||
@@ -374,9 +363,15 @@ end choice
|
||||
|
||||
-- See `Init.Data.Option.List` for lemmas about `toList`.
|
||||
|
||||
@[simp] theorem or_some : (some a).or o = some a := rfl
|
||||
@[simp] theorem some_or : (some a).or o = some a := rfl
|
||||
@[simp] theorem none_or : none.or o = o := rfl
|
||||
|
||||
@[deprecated some_or (since := "2024-11-03")] theorem or_some : (some a).or o = some a := rfl
|
||||
|
||||
/-- This will be renamed to `or_some` once the existing deprecated lemma is removed. -/
|
||||
@[simp] theorem or_some' {o : Option α} : o.or (some a) = o.getD a := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
cases o <;> rfl
|
||||
|
||||
|
||||
69
src/Init/Data/RArray.lean
Normal file
69
src/Init/Data/RArray.lean
Normal file
@@ -0,0 +1,69 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.PropLemmas
|
||||
|
||||
namespace Lean
|
||||
|
||||
/--
|
||||
A `RArray` can model `Fin n → α` or `Array α`, but is optimized for a fast kernel-reducible `get`
|
||||
operation.
|
||||
|
||||
The primary intended use case is the “denote” function of a typical proof by reflection proof, where
|
||||
only the `get` operation is necessary. It is not suitable as a general-purpose data structure.
|
||||
|
||||
There is no well-formedness invariant attached to this data structure, to keep it concise; it's
|
||||
semantics is given through `RArray.get`. In that way one can also view an `RArray` as a decision
|
||||
tree implementing `Nat → α`.
|
||||
|
||||
See `RArray.ofFn` and `RArray.ofArray` in module `Lean.Data.RArray` for functions that construct an
|
||||
`RArray`.
|
||||
|
||||
It is not universe-polymorphic. ; smaller proof objects and no complication with the `ToExpr` type
|
||||
class.
|
||||
-/
|
||||
inductive RArray (α : Type) : Type where
|
||||
| leaf : α → RArray α
|
||||
| branch : Nat → RArray α → RArray α → RArray α
|
||||
|
||||
variable {α : Type}
|
||||
|
||||
/-- The crucial operation, written with very little abstractional overhead -/
|
||||
noncomputable def RArray.get (a : RArray α) (n : Nat) : α :=
|
||||
RArray.rec (fun x => x) (fun p _ _ l r => (Nat.ble p n).rec l r) a
|
||||
|
||||
private theorem RArray.get_eq_def (a : RArray α) (n : Nat) :
|
||||
a.get n = match a with
|
||||
| .leaf x => x
|
||||
| .branch p l r => (Nat.ble p n).rec (l.get n) (r.get n) := by
|
||||
conv => lhs; unfold RArray.get
|
||||
split <;> rfl
|
||||
|
||||
/-- `RArray.get`, implemented conventionally -/
|
||||
def RArray.getImpl (a : RArray α) (n : Nat) : α :=
|
||||
match a with
|
||||
| .leaf x => x
|
||||
| .branch p l r => if n < p then l.getImpl n else r.getImpl n
|
||||
|
||||
@[csimp]
|
||||
theorem RArray.get_eq_getImpl : @RArray.get = @RArray.getImpl := by
|
||||
funext α a n
|
||||
induction a with
|
||||
| leaf _ => rfl
|
||||
| branch p l r ihl ihr =>
|
||||
rw [RArray.getImpl, RArray.get_eq_def]
|
||||
simp only [ihl, ihr, ← Nat.not_le, ← Nat.ble_eq, ite_not]
|
||||
cases hnp : Nat.ble p n <;> rfl
|
||||
|
||||
instance : GetElem (RArray α) Nat α (fun _ _ => True) where
|
||||
getElem a n _ := a.get n
|
||||
|
||||
def RArray.size : RArray α → Nat
|
||||
| leaf _ => 1
|
||||
| branch _ l r => l.size + r.size
|
||||
|
||||
end Lean
|
||||
@@ -113,10 +113,10 @@ initialize IO.stdGenRef : IO.Ref StdGen ←
|
||||
let seed := UInt64.toNat (ByteArray.toUInt64LE! (← IO.getRandomBytes 8))
|
||||
IO.mkRef (mkStdGen seed)
|
||||
|
||||
def IO.setRandSeed (n : Nat) : IO Unit :=
|
||||
def IO.setRandSeed (n : Nat) : BaseIO Unit :=
|
||||
IO.stdGenRef.set (mkStdGen n)
|
||||
|
||||
def IO.rand (lo hi : Nat) : IO Nat := do
|
||||
def IO.rand (lo hi : Nat) : BaseIO Nat := do
|
||||
let gen ← IO.stdGenRef.get
|
||||
let (r, gen) := randNat gen lo hi
|
||||
IO.stdGenRef.set gen
|
||||
|
||||
@@ -162,7 +162,7 @@ private def reprArray : Array String := Id.run do
|
||||
List.range 128 |>.map (·.toUSize.repr) |> Array.mk
|
||||
|
||||
private def reprFast (n : Nat) : String :=
|
||||
if h : n < 128 then Nat.reprArray.get ⟨n, h⟩ else
|
||||
if h : n < 128 then Nat.reprArray.get n h else
|
||||
if h : n < USize.size then (USize.ofNatCore n h).repr
|
||||
else (toDigits 10 n).asString
|
||||
|
||||
|
||||
@@ -22,6 +22,48 @@ structure Int8 where
|
||||
-/
|
||||
toUInt8 : UInt8
|
||||
|
||||
/--
|
||||
The type of signed 16-bit integers. This type has special support in the
|
||||
compiler to make it actually 16 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int16 where
|
||||
/--
|
||||
Obtain the `UInt16` that is 2's complement equivalent to the `Int16`.
|
||||
-/
|
||||
toUInt16 : UInt16
|
||||
|
||||
/--
|
||||
The type of signed 32-bit integers. This type has special support in the
|
||||
compiler to make it actually 32 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int32 where
|
||||
/--
|
||||
Obtain the `UInt32` that is 2's complement equivalent to the `Int32`.
|
||||
-/
|
||||
toUInt32 : UInt32
|
||||
|
||||
/--
|
||||
The type of signed 64-bit integers. This type has special support in the
|
||||
compiler to make it actually 64 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int64 where
|
||||
/--
|
||||
Obtain the `UInt64` that is 2's complement equivalent to the `Int64`.
|
||||
-/
|
||||
toUInt64 : UInt64
|
||||
|
||||
/--
|
||||
A `ISize` is a signed integer with the size of a word for the platform's architecture.
|
||||
|
||||
For example, if running on a 32-bit machine, ISize is equivalent to `Int32`.
|
||||
Or on a 64-bit machine, `Int64`.
|
||||
-/
|
||||
structure ISize where
|
||||
/--
|
||||
Obtain the `USize` that is 2's complement equivalent to the `ISize`.
|
||||
-/
|
||||
toUSize : USize
|
||||
|
||||
/-- The size of type `Int8`, that is, `2^8 = 256`. -/
|
||||
abbrev Int8.size : Nat := 256
|
||||
|
||||
@@ -32,12 +74,16 @@ Obtain the `BitVec` that contains the 2's complement representation of the `Int8
|
||||
|
||||
@[extern "lean_int8_of_int"]
|
||||
def Int8.ofInt (i : @& Int) : Int8 := ⟨⟨BitVec.ofInt 8 i⟩⟩
|
||||
@[extern "lean_int8_of_int"]
|
||||
@[extern "lean_int8_of_nat"]
|
||||
def Int8.ofNat (n : @& Nat) : Int8 := ⟨⟨BitVec.ofNat 8 n⟩⟩
|
||||
abbrev Int.toInt8 := Int8.ofInt
|
||||
abbrev Nat.toInt8 := Int8.ofNat
|
||||
@[extern "lean_int8_to_int"]
|
||||
def Int8.toInt (i : Int8) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int8.toNat (i : Int8) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int8_neg"]
|
||||
def Int8.neg (i : Int8) : Int8 := ⟨⟨-i.toBitVec⟩⟩
|
||||
@@ -58,7 +104,7 @@ def Int8.mul (a b : Int8) : Int8 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_div"]
|
||||
def Int8.div (a b : Int8) : Int8 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_mod"]
|
||||
def Int8.mod (a b : Int8) : Int8 := ⟨⟨BitVec.smod a.toBitVec b.toBitVec⟩⟩
|
||||
def Int8.mod (a b : Int8) : Int8 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_land"]
|
||||
def Int8.land (a b : Int8) : Int8 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_lor"]
|
||||
@@ -66,9 +112,9 @@ def Int8.lor (a b : Int8) : Int8 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_xor"]
|
||||
def Int8.xor (a b : Int8) : Int8 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_shift_left"]
|
||||
def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (mod b 8).toBitVec⟩⟩
|
||||
def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 8)⟩⟩
|
||||
@[extern "lean_int8_shift_right"]
|
||||
def Int8.shiftRight (a b : Int8) : Int8 := ⟨⟨BitVec.sshiftRight' a.toBitVec (mod b 8).toBitVec⟩⟩
|
||||
def Int8.shiftRight (a b : Int8) : Int8 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 8)⟩⟩
|
||||
@[extern "lean_int8_complement"]
|
||||
def Int8.complement (a : Int8) : Int8 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@@ -102,6 +148,9 @@ instance : ShiftLeft Int8 := ⟨Int8.shiftLeft⟩
|
||||
instance : ShiftRight Int8 := ⟨Int8.shiftRight⟩
|
||||
instance : DecidableEq Int8 := Int8.decEq
|
||||
|
||||
@[extern "lean_bool_to_int8"]
|
||||
def Bool.toInt8 (b : Bool) : Int8 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_int8_dec_lt"]
|
||||
def Int8.decLt (a b : Int8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
@@ -114,3 +163,441 @@ instance (a b : Int8) : Decidable (a < b) := Int8.decLt a b
|
||||
instance (a b : Int8) : Decidable (a ≤ b) := Int8.decLe a b
|
||||
instance : Max Int8 := maxOfLe
|
||||
instance : Min Int8 := minOfLe
|
||||
|
||||
/-- The size of type `Int16`, that is, `2^16 = 65536`. -/
|
||||
abbrev Int16.size : Nat := 65536
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int16`.
|
||||
-/
|
||||
@[inline] def Int16.toBitVec (x : Int16) : BitVec 16 := x.toUInt16.toBitVec
|
||||
|
||||
@[extern "lean_int16_of_int"]
|
||||
def Int16.ofInt (i : @& Int) : Int16 := ⟨⟨BitVec.ofInt 16 i⟩⟩
|
||||
@[extern "lean_int16_of_nat"]
|
||||
def Int16.ofNat (n : @& Nat) : Int16 := ⟨⟨BitVec.ofNat 16 n⟩⟩
|
||||
abbrev Int.toInt16 := Int16.ofInt
|
||||
abbrev Nat.toInt16 := Int16.ofNat
|
||||
@[extern "lean_int16_to_int"]
|
||||
def Int16.toInt (i : Int16) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int16.toNat (i : Int16) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int16_to_int8"]
|
||||
def Int16.toInt8 (a : Int16) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int8_to_int16"]
|
||||
def Int8.toInt16 (a : Int8) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int16_neg"]
|
||||
def Int16.neg (i : Int16) : Int16 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int16 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int16 n := ⟨Int16.ofNat n⟩
|
||||
instance : Neg Int16 where
|
||||
neg := Int16.neg
|
||||
|
||||
@[extern "lean_int16_add"]
|
||||
def Int16.add (a b : Int16) : Int16 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_sub"]
|
||||
def Int16.sub (a b : Int16) : Int16 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_mul"]
|
||||
def Int16.mul (a b : Int16) : Int16 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_div"]
|
||||
def Int16.div (a b : Int16) : Int16 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_mod"]
|
||||
def Int16.mod (a b : Int16) : Int16 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_land"]
|
||||
def Int16.land (a b : Int16) : Int16 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_lor"]
|
||||
def Int16.lor (a b : Int16) : Int16 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_xor"]
|
||||
def Int16.xor (a b : Int16) : Int16 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_shift_left"]
|
||||
def Int16.shiftLeft (a b : Int16) : Int16 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 16)⟩⟩
|
||||
@[extern "lean_int16_shift_right"]
|
||||
def Int16.shiftRight (a b : Int16) : Int16 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 16)⟩⟩
|
||||
@[extern "lean_int16_complement"]
|
||||
def Int16.complement (a : Int16) : Int16 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int16_dec_eq"]
|
||||
def Int16.decEq (a b : Int16) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int16.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int16.lt (a b : Int16) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int16.le (a b : Int16) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int16 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int16 := ⟨Int16.add⟩
|
||||
instance : Sub Int16 := ⟨Int16.sub⟩
|
||||
instance : Mul Int16 := ⟨Int16.mul⟩
|
||||
instance : Mod Int16 := ⟨Int16.mod⟩
|
||||
instance : Div Int16 := ⟨Int16.div⟩
|
||||
instance : LT Int16 := ⟨Int16.lt⟩
|
||||
instance : LE Int16 := ⟨Int16.le⟩
|
||||
instance : Complement Int16 := ⟨Int16.complement⟩
|
||||
instance : AndOp Int16 := ⟨Int16.land⟩
|
||||
instance : OrOp Int16 := ⟨Int16.lor⟩
|
||||
instance : Xor Int16 := ⟨Int16.xor⟩
|
||||
instance : ShiftLeft Int16 := ⟨Int16.shiftLeft⟩
|
||||
instance : ShiftRight Int16 := ⟨Int16.shiftRight⟩
|
||||
instance : DecidableEq Int16 := Int16.decEq
|
||||
|
||||
@[extern "lean_bool_to_int16"]
|
||||
def Bool.toInt16 (b : Bool) : Int16 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_int16_dec_lt"]
|
||||
def Int16.decLt (a b : Int16) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int16_dec_le"]
|
||||
def Int16.decLe (a b : Int16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int16) : Decidable (a < b) := Int16.decLt a b
|
||||
instance (a b : Int16) : Decidable (a ≤ b) := Int16.decLe a b
|
||||
instance : Max Int16 := maxOfLe
|
||||
instance : Min Int16 := minOfLe
|
||||
|
||||
/-- The size of type `Int32`, that is, `2^32 = 4294967296`. -/
|
||||
abbrev Int32.size : Nat := 4294967296
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int32`.
|
||||
-/
|
||||
@[inline] def Int32.toBitVec (x : Int32) : BitVec 32 := x.toUInt32.toBitVec
|
||||
|
||||
@[extern "lean_int32_of_int"]
|
||||
def Int32.ofInt (i : @& Int) : Int32 := ⟨⟨BitVec.ofInt 32 i⟩⟩
|
||||
@[extern "lean_int32_of_nat"]
|
||||
def Int32.ofNat (n : @& Nat) : Int32 := ⟨⟨BitVec.ofNat 32 n⟩⟩
|
||||
abbrev Int.toInt32 := Int32.ofInt
|
||||
abbrev Nat.toInt32 := Int32.ofNat
|
||||
@[extern "lean_int32_to_int"]
|
||||
def Int32.toInt (i : Int32) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int32.toNat (i : Int32) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int32_to_int8"]
|
||||
def Int32.toInt8 (a : Int32) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int32_to_int16"]
|
||||
def Int32.toInt16 (a : Int32) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int8_to_int32"]
|
||||
def Int8.toInt32 (a : Int8) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int16_to_int32"]
|
||||
def Int16.toInt32 (a : Int16) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int32_neg"]
|
||||
def Int32.neg (i : Int32) : Int32 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int32 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int32 n := ⟨Int32.ofNat n⟩
|
||||
instance : Neg Int32 where
|
||||
neg := Int32.neg
|
||||
|
||||
@[extern "lean_int32_add"]
|
||||
def Int32.add (a b : Int32) : Int32 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_sub"]
|
||||
def Int32.sub (a b : Int32) : Int32 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_mul"]
|
||||
def Int32.mul (a b : Int32) : Int32 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_div"]
|
||||
def Int32.div (a b : Int32) : Int32 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_mod"]
|
||||
def Int32.mod (a b : Int32) : Int32 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_land"]
|
||||
def Int32.land (a b : Int32) : Int32 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_lor"]
|
||||
def Int32.lor (a b : Int32) : Int32 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_xor"]
|
||||
def Int32.xor (a b : Int32) : Int32 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_shift_left"]
|
||||
def Int32.shiftLeft (a b : Int32) : Int32 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 32)⟩⟩
|
||||
@[extern "lean_int32_shift_right"]
|
||||
def Int32.shiftRight (a b : Int32) : Int32 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 32)⟩⟩
|
||||
@[extern "lean_int32_complement"]
|
||||
def Int32.complement (a : Int32) : Int32 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int32_dec_eq"]
|
||||
def Int32.decEq (a b : Int32) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int32.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int32.lt (a b : Int32) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int32.le (a b : Int32) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int32 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int32 := ⟨Int32.add⟩
|
||||
instance : Sub Int32 := ⟨Int32.sub⟩
|
||||
instance : Mul Int32 := ⟨Int32.mul⟩
|
||||
instance : Mod Int32 := ⟨Int32.mod⟩
|
||||
instance : Div Int32 := ⟨Int32.div⟩
|
||||
instance : LT Int32 := ⟨Int32.lt⟩
|
||||
instance : LE Int32 := ⟨Int32.le⟩
|
||||
instance : Complement Int32 := ⟨Int32.complement⟩
|
||||
instance : AndOp Int32 := ⟨Int32.land⟩
|
||||
instance : OrOp Int32 := ⟨Int32.lor⟩
|
||||
instance : Xor Int32 := ⟨Int32.xor⟩
|
||||
instance : ShiftLeft Int32 := ⟨Int32.shiftLeft⟩
|
||||
instance : ShiftRight Int32 := ⟨Int32.shiftRight⟩
|
||||
instance : DecidableEq Int32 := Int32.decEq
|
||||
|
||||
@[extern "lean_bool_to_int32"]
|
||||
def Bool.toInt32 (b : Bool) : Int32 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_int32_dec_lt"]
|
||||
def Int32.decLt (a b : Int32) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int32_dec_le"]
|
||||
def Int32.decLe (a b : Int32) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int32) : Decidable (a < b) := Int32.decLt a b
|
||||
instance (a b : Int32) : Decidable (a ≤ b) := Int32.decLe a b
|
||||
instance : Max Int32 := maxOfLe
|
||||
instance : Min Int32 := minOfLe
|
||||
|
||||
/-- The size of type `Int64`, that is, `2^64 = 18446744073709551616`. -/
|
||||
abbrev Int64.size : Nat := 18446744073709551616
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int64`.
|
||||
-/
|
||||
@[inline] def Int64.toBitVec (x : Int64) : BitVec 64 := x.toUInt64.toBitVec
|
||||
|
||||
@[extern "lean_int64_of_int"]
|
||||
def Int64.ofInt (i : @& Int) : Int64 := ⟨⟨BitVec.ofInt 64 i⟩⟩
|
||||
@[extern "lean_int64_of_nat"]
|
||||
def Int64.ofNat (n : @& Nat) : Int64 := ⟨⟨BitVec.ofNat 64 n⟩⟩
|
||||
abbrev Int.toInt64 := Int64.ofInt
|
||||
abbrev Nat.toInt64 := Int64.ofNat
|
||||
@[extern "lean_int64_to_int_sint"]
|
||||
def Int64.toInt (i : Int64) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int64.toNat (i : Int64) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int64_to_int8"]
|
||||
def Int64.toInt8 (a : Int64) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int64_to_int16"]
|
||||
def Int64.toInt16 (a : Int64) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int64_to_int32"]
|
||||
def Int64.toInt32 (a : Int64) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int8_to_int64"]
|
||||
def Int8.toInt64 (a : Int8) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int16_to_int64"]
|
||||
def Int16.toInt64 (a : Int16) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int32_to_int64"]
|
||||
def Int32.toInt64 (a : Int32) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int64_neg"]
|
||||
def Int64.neg (i : Int64) : Int64 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int64 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int64 n := ⟨Int64.ofNat n⟩
|
||||
instance : Neg Int64 where
|
||||
neg := Int64.neg
|
||||
|
||||
@[extern "lean_int64_add"]
|
||||
def Int64.add (a b : Int64) : Int64 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_sub"]
|
||||
def Int64.sub (a b : Int64) : Int64 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_mul"]
|
||||
def Int64.mul (a b : Int64) : Int64 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_div"]
|
||||
def Int64.div (a b : Int64) : Int64 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_mod"]
|
||||
def Int64.mod (a b : Int64) : Int64 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_land"]
|
||||
def Int64.land (a b : Int64) : Int64 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_lor"]
|
||||
def Int64.lor (a b : Int64) : Int64 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_xor"]
|
||||
def Int64.xor (a b : Int64) : Int64 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_shift_left"]
|
||||
def Int64.shiftLeft (a b : Int64) : Int64 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 64)⟩⟩
|
||||
@[extern "lean_int64_shift_right"]
|
||||
def Int64.shiftRight (a b : Int64) : Int64 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 64)⟩⟩
|
||||
@[extern "lean_int64_complement"]
|
||||
def Int64.complement (a : Int64) : Int64 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int64_dec_eq"]
|
||||
def Int64.decEq (a b : Int64) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int64.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int64.lt (a b : Int64) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int64.le (a b : Int64) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int64 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int64 := ⟨Int64.add⟩
|
||||
instance : Sub Int64 := ⟨Int64.sub⟩
|
||||
instance : Mul Int64 := ⟨Int64.mul⟩
|
||||
instance : Mod Int64 := ⟨Int64.mod⟩
|
||||
instance : Div Int64 := ⟨Int64.div⟩
|
||||
instance : LT Int64 := ⟨Int64.lt⟩
|
||||
instance : LE Int64 := ⟨Int64.le⟩
|
||||
instance : Complement Int64 := ⟨Int64.complement⟩
|
||||
instance : AndOp Int64 := ⟨Int64.land⟩
|
||||
instance : OrOp Int64 := ⟨Int64.lor⟩
|
||||
instance : Xor Int64 := ⟨Int64.xor⟩
|
||||
instance : ShiftLeft Int64 := ⟨Int64.shiftLeft⟩
|
||||
instance : ShiftRight Int64 := ⟨Int64.shiftRight⟩
|
||||
instance : DecidableEq Int64 := Int64.decEq
|
||||
|
||||
@[extern "lean_bool_to_int64"]
|
||||
def Bool.toInt64 (b : Bool) : Int64 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_int64_dec_lt"]
|
||||
def Int64.decLt (a b : Int64) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int64_dec_le"]
|
||||
def Int64.decLe (a b : Int64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int64) : Decidable (a < b) := Int64.decLt a b
|
||||
instance (a b : Int64) : Decidable (a ≤ b) := Int64.decLe a b
|
||||
instance : Max Int64 := maxOfLe
|
||||
instance : Min Int64 := minOfLe
|
||||
|
||||
/-- The size of type `ISize`, that is, `2^System.Platform.numBits`. -/
|
||||
abbrev ISize.size : Nat := 2^System.Platform.numBits
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `ISize`.
|
||||
-/
|
||||
@[inline] def ISize.toBitVec (x : ISize) : BitVec System.Platform.numBits := x.toUSize.toBitVec
|
||||
|
||||
@[extern "lean_isize_of_int"]
|
||||
def ISize.ofInt (i : @& Int) : ISize := ⟨⟨BitVec.ofInt System.Platform.numBits i⟩⟩
|
||||
@[extern "lean_isize_of_nat"]
|
||||
def ISize.ofNat (n : @& Nat) : ISize := ⟨⟨BitVec.ofNat System.Platform.numBits n⟩⟩
|
||||
abbrev Int.toISize := ISize.ofInt
|
||||
abbrev Nat.toISize := ISize.ofNat
|
||||
@[extern "lean_isize_to_int"]
|
||||
def ISize.toInt (i : ISize) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def ISize.toNat (i : ISize) : Nat := i.toInt.toNat
|
||||
@[extern "lean_isize_to_int32"]
|
||||
def ISize.toInt32 (a : ISize) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
/--
|
||||
Upcast `ISize` to `Int64`. This function is losless as `ISize` is either `Int32` or `Int64`.
|
||||
-/
|
||||
@[extern "lean_isize_to_int64"]
|
||||
def ISize.toInt64 (a : ISize) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
/--
|
||||
Upcast `Int32` to `ISize`. This function is losless as `ISize` is either `Int32` or `Int64`.
|
||||
-/
|
||||
@[extern "lean_int32_to_isize"]
|
||||
def Int32.toISize (a : Int32) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
|
||||
@[extern "lean_int64_to_isize"]
|
||||
def Int64.toISize (a : Int64) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
|
||||
@[extern "lean_isize_neg"]
|
||||
def ISize.neg (i : ISize) : ISize := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString ISize where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat ISize n := ⟨ISize.ofNat n⟩
|
||||
instance : Neg ISize where
|
||||
neg := ISize.neg
|
||||
|
||||
@[extern "lean_isize_add"]
|
||||
def ISize.add (a b : ISize) : ISize := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_sub"]
|
||||
def ISize.sub (a b : ISize) : ISize := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_mul"]
|
||||
def ISize.mul (a b : ISize) : ISize := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_div"]
|
||||
def ISize.div (a b : ISize) : ISize := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_mod"]
|
||||
def ISize.mod (a b : ISize) : ISize := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_land"]
|
||||
def ISize.land (a b : ISize) : ISize := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_lor"]
|
||||
def ISize.lor (a b : ISize) : ISize := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_xor"]
|
||||
def ISize.xor (a b : ISize) : ISize := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_shift_left"]
|
||||
def ISize.shiftLeft (a b : ISize) : ISize := ⟨⟨a.toBitVec <<< (b.toBitVec.smod System.Platform.numBits)⟩⟩
|
||||
@[extern "lean_isize_shift_right"]
|
||||
def ISize.shiftRight (a b : ISize) : ISize := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod System.Platform.numBits)⟩⟩
|
||||
@[extern "lean_isize_complement"]
|
||||
def ISize.complement (a : ISize) : ISize := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_isize_dec_eq"]
|
||||
def ISize.decEq (a b : ISize) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => ISize.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def ISize.lt (a b : ISize) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def ISize.le (a b : ISize) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited ISize where
|
||||
default := 0
|
||||
|
||||
instance : Add ISize := ⟨ISize.add⟩
|
||||
instance : Sub ISize := ⟨ISize.sub⟩
|
||||
instance : Mul ISize := ⟨ISize.mul⟩
|
||||
instance : Mod ISize := ⟨ISize.mod⟩
|
||||
instance : Div ISize := ⟨ISize.div⟩
|
||||
instance : LT ISize := ⟨ISize.lt⟩
|
||||
instance : LE ISize := ⟨ISize.le⟩
|
||||
instance : Complement ISize := ⟨ISize.complement⟩
|
||||
instance : AndOp ISize := ⟨ISize.land⟩
|
||||
instance : OrOp ISize := ⟨ISize.lor⟩
|
||||
instance : Xor ISize := ⟨ISize.xor⟩
|
||||
instance : ShiftLeft ISize := ⟨ISize.shiftLeft⟩
|
||||
instance : ShiftRight ISize := ⟨ISize.shiftRight⟩
|
||||
instance : DecidableEq ISize := ISize.decEq
|
||||
|
||||
@[extern "lean_bool_to_isize"]
|
||||
def Bool.toISize (b : Bool) : ISize := if b then 1 else 0
|
||||
|
||||
@[extern "lean_isize_dec_lt"]
|
||||
def ISize.decLt (a b : ISize) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_isize_dec_le"]
|
||||
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : ISize) : Decidable (a < b) := ISize.decLt a b
|
||||
instance (a b : ISize) : Decidable (a ≤ b) := ISize.decLe a b
|
||||
instance : Max ISize := maxOfLe
|
||||
instance : Min ISize := minOfLe
|
||||
|
||||
@@ -94,7 +94,7 @@ instance : Stream (Subarray α) α where
|
||||
next? s :=
|
||||
if h : s.start < s.stop then
|
||||
have : s.start + 1 ≤ s.stop := Nat.succ_le_of_lt h
|
||||
some (s.array.get ⟨s.start, Nat.lt_of_lt_of_le h s.stop_le_array_size⟩,
|
||||
some (s.array[s.start]'(Nat.lt_of_lt_of_le h s.stop_le_array_size),
|
||||
{ s with start := s.start + 1, start_le_stop := this })
|
||||
else
|
||||
none
|
||||
|
||||
@@ -514,9 +514,6 @@ instance : Inhabited String := ⟨""⟩
|
||||
|
||||
instance : Append String := ⟨String.append⟩
|
||||
|
||||
@[deprecated push (since := "2024-04-06")]
|
||||
def str : String → Char → String := push
|
||||
|
||||
@[inline] def pushn (s : String) (c : Char) (n : Nat) : String :=
|
||||
n.repeat (fun s => s.push c) s
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ def toUTF8 (a : @& String) : ByteArray :=
|
||||
/-- Accesses a byte in the UTF-8 encoding of the `String`. O(1) -/
|
||||
@[extern "lean_string_get_byte_fast"]
|
||||
def getUtf8Byte (s : @& String) (n : Nat) (h : n < s.utf8ByteSize) : UInt8 :=
|
||||
(toUTF8 s).get ⟨n, size_toUTF8 _ ▸ h⟩
|
||||
(toUTF8 s)[n]'(size_toUTF8 _ ▸ h)
|
||||
|
||||
theorem Iterator.sizeOf_next_lt_of_hasNext (i : String.Iterator) (h : i.hasNext) : sizeOf i.next < sizeOf i := by
|
||||
cases i; rename_i s pos; simp [Iterator.next, Iterator.sizeOf_eq]; simp [Iterator.hasNext] at h
|
||||
|
||||
@@ -31,7 +31,7 @@ This file defines basic operations on the the sum type `α ⊕ β`.
|
||||
|
||||
## Further material
|
||||
|
||||
See `Batteries.Data.Sum.Lemmas` for theorems about these definitions.
|
||||
See `Init.Data.Sum.Lemmas` for theorems about these definitions.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ instance : Xor UInt8 := ⟨UInt8.xor⟩
|
||||
instance : ShiftLeft UInt8 := ⟨UInt8.shiftLeft⟩
|
||||
instance : ShiftRight UInt8 := ⟨UInt8.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_uint8"]
|
||||
def Bool.toUInt8 (b : Bool) : UInt8 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_uint8_dec_lt"]
|
||||
def UInt8.decLt (a b : UInt8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec < b.toBitVec))
|
||||
@@ -116,6 +119,9 @@ instance : Xor UInt16 := ⟨UInt16.xor⟩
|
||||
instance : ShiftLeft UInt16 := ⟨UInt16.shiftLeft⟩
|
||||
instance : ShiftRight UInt16 := ⟨UInt16.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_uint16"]
|
||||
def Bool.toUInt16 (b : Bool) : UInt16 := if b then 1 else 0
|
||||
|
||||
set_option bootstrap.genMatcherCode false in
|
||||
@[extern "lean_uint16_dec_lt"]
|
||||
def UInt16.decLt (a b : UInt16) : Decidable (a < b) :=
|
||||
@@ -174,6 +180,9 @@ instance : Xor UInt32 := ⟨UInt32.xor⟩
|
||||
instance : ShiftLeft UInt32 := ⟨UInt32.shiftLeft⟩
|
||||
instance : ShiftRight UInt32 := ⟨UInt32.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_uint32"]
|
||||
def Bool.toUInt32 (b : Bool) : UInt32 := if b then 1 else 0
|
||||
|
||||
@[extern "lean_uint64_add"]
|
||||
def UInt64.add (a b : UInt64) : UInt64 := ⟨a.toBitVec + b.toBitVec⟩
|
||||
@[extern "lean_uint64_sub"]
|
||||
@@ -237,6 +246,12 @@ instance (a b : UInt64) : Decidable (a ≤ b) := UInt64.decLe a b
|
||||
instance : Max UInt64 := maxOfLe
|
||||
instance : Min UInt64 := minOfLe
|
||||
|
||||
theorem usize_size_le : USize.size ≤ 18446744073709551616 := by
|
||||
cases usize_size_eq <;> next h => rw [h]; decide
|
||||
|
||||
theorem le_usize_size : 4294967296 ≤ USize.size := by
|
||||
cases usize_size_eq <;> next h => rw [h]; decide
|
||||
|
||||
@[extern "lean_usize_mul"]
|
||||
def USize.mul (a b : USize) : USize := ⟨a.toBitVec * b.toBitVec⟩
|
||||
@[extern "lean_usize_div"]
|
||||
@@ -255,10 +270,29 @@ def USize.xor (a b : USize) : USize := ⟨a.toBitVec ^^^ b.toBitVec⟩
|
||||
def USize.shiftLeft (a b : USize) : USize := ⟨a.toBitVec <<< (mod b (USize.ofNat System.Platform.numBits)).toBitVec⟩
|
||||
@[extern "lean_usize_shift_right"]
|
||||
def USize.shiftRight (a b : USize) : USize := ⟨a.toBitVec >>> (mod b (USize.ofNat System.Platform.numBits)).toBitVec⟩
|
||||
/--
|
||||
Upcast a `Nat` less than `2^32` to a `USize`.
|
||||
This is lossless because `USize.size` is either `2^32` or `2^64`.
|
||||
This function is overridden with a native implementation.
|
||||
-/
|
||||
@[extern "lean_usize_of_nat"]
|
||||
def USize.ofNat32 (n : @& Nat) (h : n < 4294967296) : USize :=
|
||||
USize.ofNatCore n (Nat.lt_of_lt_of_le h le_usize_size)
|
||||
@[extern "lean_uint32_to_usize"]
|
||||
def UInt32.toUSize (a : UInt32) : USize := USize.ofNat32 a.toBitVec.toNat a.toBitVec.isLt
|
||||
@[extern "lean_usize_to_uint32"]
|
||||
def USize.toUInt32 (a : USize) : UInt32 := a.toNat.toUInt32
|
||||
/-- Converts a `UInt64` to a `USize` by reducing modulo `USize.size`. -/
|
||||
@[extern "lean_uint64_to_usize"]
|
||||
def UInt64.toUSize (a : UInt64) : USize := a.toNat.toUSize
|
||||
/--
|
||||
Upcast a `USize` to a `UInt64`.
|
||||
This is lossless because `USize.size` is either `2^32` or `2^64`.
|
||||
This function is overridden with a native implementation.
|
||||
-/
|
||||
@[extern "lean_usize_to_uint64"]
|
||||
def USize.toUInt64 (a : USize) : UInt64 :=
|
||||
UInt64.ofNatCore a.toBitVec.toNat (Nat.lt_of_lt_of_le a.toBitVec.isLt usize_size_le)
|
||||
|
||||
instance : Mul USize := ⟨USize.mul⟩
|
||||
instance : Mod USize := ⟨USize.mod⟩
|
||||
@@ -278,5 +312,8 @@ instance : Xor USize := ⟨USize.xor⟩
|
||||
instance : ShiftLeft USize := ⟨USize.shiftLeft⟩
|
||||
instance : ShiftRight USize := ⟨USize.shiftRight⟩
|
||||
|
||||
@[extern "lean_bool_to_usize"]
|
||||
def Bool.toUSize (b : Bool) : USize := if b then 1 else 0
|
||||
|
||||
instance : Max USize := maxOfLe
|
||||
instance : Min USize := minOfLe
|
||||
|
||||
@@ -94,10 +94,8 @@ def UInt32.toUInt64 (a : UInt32) : UInt64 := ⟨⟨a.toNat, Nat.lt_trans a.toBit
|
||||
|
||||
instance UInt64.instOfNat : OfNat UInt64 n := ⟨UInt64.ofNat n⟩
|
||||
|
||||
theorem usize_size_gt_zero : USize.size > 0 := by
|
||||
cases usize_size_eq with
|
||||
| inl h => rw [h]; decide
|
||||
| inr h => rw [h]; decide
|
||||
@[deprecated usize_size_pos (since := "2024-11-24")] theorem usize_size_gt_zero : USize.size > 0 :=
|
||||
usize_size_pos
|
||||
|
||||
def USize.val (x : USize) : Fin USize.size := x.toBitVec.toFin
|
||||
@[extern "lean_usize_of_nat"]
|
||||
|
||||
@@ -133,6 +133,9 @@ declare_uint_theorems UInt32
|
||||
declare_uint_theorems UInt64
|
||||
declare_uint_theorems USize
|
||||
|
||||
theorem USize.toNat_ofNat_of_lt_32 {n : Nat} (h : n < 4294967296) : toNat (ofNat n) = n :=
|
||||
toNat_ofNat_of_lt (Nat.lt_of_lt_of_le h le_usize_size)
|
||||
|
||||
theorem UInt32.toNat_lt_of_lt {n : UInt32} {m : Nat} (h : m < size) : n < ofNat m → n.toNat < m := by
|
||||
simp [lt_def, BitVec.lt_def, UInt32.toNat, toBitVec_eq_of_lt h]
|
||||
|
||||
@@ -145,22 +148,22 @@ theorem UInt32.toNat_le_of_le {n : UInt32} {m : Nat} (h : m < size) : n ≤ ofNa
|
||||
theorem UInt32.le_toNat_of_le {n : UInt32} {m : Nat} (h : m < size) : ofNat m ≤ n → m ≤ n.toNat := by
|
||||
simp [le_def, BitVec.le_def, UInt32.toNat, toBitVec_eq_of_lt h]
|
||||
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt8.zero_toNat := @UInt8.toNat_zero
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt8.div_toNat := @UInt8.toNat_div
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt8.mod_toNat := @UInt8.toNat_mod
|
||||
@[deprecated UInt8.toNat_zero (since := "2024-06-23")] protected abbrev UInt8.zero_toNat := @UInt8.toNat_zero
|
||||
@[deprecated UInt8.toNat_div (since := "2024-06-23")] protected abbrev UInt8.div_toNat := @UInt8.toNat_div
|
||||
@[deprecated UInt8.toNat_mod (since := "2024-06-23")] protected abbrev UInt8.mod_toNat := @UInt8.toNat_mod
|
||||
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt16.zero_toNat := @UInt16.toNat_zero
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt16.div_toNat := @UInt16.toNat_div
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt16.mod_toNat := @UInt16.toNat_mod
|
||||
@[deprecated UInt16.toNat_zero (since := "2024-06-23")] protected abbrev UInt16.zero_toNat := @UInt16.toNat_zero
|
||||
@[deprecated UInt16.toNat_div (since := "2024-06-23")] protected abbrev UInt16.div_toNat := @UInt16.toNat_div
|
||||
@[deprecated UInt16.toNat_mod (since := "2024-06-23")] protected abbrev UInt16.mod_toNat := @UInt16.toNat_mod
|
||||
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt32.zero_toNat := @UInt32.toNat_zero
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt32.div_toNat := @UInt32.toNat_div
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt32.mod_toNat := @UInt32.toNat_mod
|
||||
@[deprecated UInt32.toNat_zero (since := "2024-06-23")] protected abbrev UInt32.zero_toNat := @UInt32.toNat_zero
|
||||
@[deprecated UInt32.toNat_div (since := "2024-06-23")] protected abbrev UInt32.div_toNat := @UInt32.toNat_div
|
||||
@[deprecated UInt32.toNat_mod (since := "2024-06-23")] protected abbrev UInt32.mod_toNat := @UInt32.toNat_mod
|
||||
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt64.zero_toNat := @UInt64.toNat_zero
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt64.div_toNat := @UInt64.toNat_div
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev UInt64.mod_toNat := @UInt64.toNat_mod
|
||||
@[deprecated UInt64.toNat_zero (since := "2024-06-23")] protected abbrev UInt64.zero_toNat := @UInt64.toNat_zero
|
||||
@[deprecated UInt64.toNat_div (since := "2024-06-23")] protected abbrev UInt64.div_toNat := @UInt64.toNat_div
|
||||
@[deprecated UInt64.toNat_mod (since := "2024-06-23")] protected abbrev UInt64.mod_toNat := @UInt64.toNat_mod
|
||||
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev USize.zero_toNat := @USize.toNat_zero
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev USize.div_toNat := @USize.toNat_div
|
||||
@[deprecated (since := "2024-06-23")] protected abbrev USize.mod_toNat := @USize.toNat_mod
|
||||
@[deprecated USize.toNat_zero (since := "2024-06-23")] protected abbrev USize.zero_toNat := @USize.toNat_zero
|
||||
@[deprecated USize.toNat_div (since := "2024-06-23")] protected abbrev USize.div_toNat := @USize.toNat_div
|
||||
@[deprecated USize.toNat_mod (since := "2024-06-23")] protected abbrev USize.mod_toNat := @USize.toNat_mod
|
||||
|
||||
7
src/Init/Data/Vector.lean
Normal file
7
src/Init/Data/Vector.lean
Normal file
@@ -0,0 +1,7 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Basic
|
||||
253
src/Init/Data/Vector/Basic.lean
Normal file
253
src/Init/Data/Vector/Basic.lean
Normal file
@@ -0,0 +1,253 @@
|
||||
/-
|
||||
Copyright (c) 2024 Shreyas Srinivas. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Shreyas Srinivas, François G. Dorais, Kim Morrison
|
||||
-/
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
|
||||
/-!
|
||||
# Vectors
|
||||
|
||||
`Vector α n` is a thin wrapper around `Array α` for arrays of fixed size `n`.
|
||||
-/
|
||||
|
||||
/-- `Vector α n` is an `Array α` with size `n`. -/
|
||||
structure Vector (α : Type u) (n : Nat) extends Array α where
|
||||
/-- Array size. -/
|
||||
size_toArray : toArray.size = n
|
||||
deriving Repr, DecidableEq
|
||||
|
||||
attribute [simp] Vector.size_toArray
|
||||
|
||||
namespace Vector
|
||||
|
||||
/-- Syntax for `Vector α n` -/
|
||||
syntax "#v[" withoutPosition(sepBy(term, ", ")) "]" : term
|
||||
|
||||
open Lean in
|
||||
macro_rules
|
||||
| `(#v[ $elems,* ]) => `(Vector.mk (n := $(quote elems.getElems.size)) #[$elems,*] rfl)
|
||||
|
||||
/-- Custom eliminator for `Vector α n` through `Array α` -/
|
||||
@[elab_as_elim]
|
||||
def elimAsArray {motive : Vector α n → Sort u}
|
||||
(mk : ∀ (a : Array α) (ha : a.size = n), motive ⟨a, ha⟩) :
|
||||
(v : Vector α n) → motive v
|
||||
| ⟨a, ha⟩ => mk a ha
|
||||
|
||||
/-- Custom eliminator for `Vector α n` through `List α` -/
|
||||
@[elab_as_elim]
|
||||
def elimAsList {motive : Vector α n → Sort u}
|
||||
(mk : ∀ (a : List α) (ha : a.length = n), motive ⟨⟨a⟩, ha⟩) :
|
||||
(v : Vector α n) → motive v
|
||||
| ⟨⟨a⟩, ha⟩ => mk a ha
|
||||
|
||||
/-- Make an empty vector with pre-allocated capacity. -/
|
||||
@[inline] def mkEmpty (capacity : Nat) : Vector α 0 := ⟨.mkEmpty capacity, rfl⟩
|
||||
|
||||
/-- Makes a vector of size `n` with all cells containing `v`. -/
|
||||
@[inline] def mkVector (n) (v : α) : Vector α n := ⟨mkArray n v, by simp⟩
|
||||
|
||||
/-- Returns a vector of size `1` with element `v`. -/
|
||||
@[inline] def singleton (v : α) : Vector α 1 := ⟨#[v], rfl⟩
|
||||
|
||||
instance [Inhabited α] : Inhabited (Vector α n) where
|
||||
default := mkVector n default
|
||||
|
||||
/-- Get an element of a vector using a `Fin` index. -/
|
||||
@[inline] def get (v : Vector α n) (i : Fin n) : α :=
|
||||
v.toArray[(i.cast v.size_toArray.symm).1]
|
||||
|
||||
/-- Get an element of a vector using a `USize` index and a proof that the index is within bounds. -/
|
||||
@[inline] def uget (v : Vector α n) (i : USize) (h : i.toNat < n) : α :=
|
||||
v.toArray.uget i (v.size_toArray.symm ▸ h)
|
||||
|
||||
instance : GetElem (Vector α n) Nat α fun _ i => i < n where
|
||||
getElem x i h := get x ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Get an element of a vector using a `Nat` index. Returns the given default value if the index is out
|
||||
of bounds.
|
||||
-/
|
||||
@[inline] def getD (v : Vector α n) (i : Nat) (default : α) : α := v.toArray.getD i default
|
||||
|
||||
/-- The last element of a vector. Panics if the vector is empty. -/
|
||||
@[inline] def back! [Inhabited α] (v : Vector α n) : α := v.toArray.back!
|
||||
|
||||
/-- The last element of a vector, or `none` if the array is empty. -/
|
||||
@[inline] def back? (v : Vector α n) : Option α := v.toArray.back?
|
||||
|
||||
/-- The last element of a non-empty vector. -/
|
||||
@[inline] def back [NeZero n] (v : Vector α n) : α :=
|
||||
-- TODO: change to just `v[n]`
|
||||
have : Inhabited α := ⟨v[0]'(Nat.pos_of_neZero n)⟩
|
||||
v.back!
|
||||
|
||||
/-- The first element of a non-empty vector. -/
|
||||
@[inline] def head [NeZero n] (v : Vector α n) := v[0]'(Nat.pos_of_neZero n)
|
||||
|
||||
/-- Push an element `x` to the end of a vector. -/
|
||||
@[inline] def push (x : α) (v : Vector α n) : Vector α (n + 1) :=
|
||||
⟨v.toArray.push x, by simp⟩
|
||||
|
||||
/-- Remove the last element of a vector. -/
|
||||
@[inline] def pop (v : Vector α n) : Vector α (n - 1) :=
|
||||
⟨Array.pop v.toArray, by simp⟩
|
||||
|
||||
/--
|
||||
Set an element in a vector using a `Nat` index, with a tactic provided proof that the index is in
|
||||
bounds.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def set (v : Vector α n) (i : Nat) (x : α) (h : i < n := by get_elem_tactic): Vector α n :=
|
||||
⟨v.toArray.set i x (by simp [*]), by simp⟩
|
||||
|
||||
/--
|
||||
Set an element in a vector using a `Nat` index. Returns the vector unchanged if the index is out of
|
||||
bounds.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def setIfInBounds (v : Vector α n) (i : Nat) (x : α) : Vector α n :=
|
||||
⟨v.toArray.setIfInBounds i x, by simp⟩
|
||||
|
||||
/--
|
||||
Set an element in a vector using a `Nat` index. Panics if the index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def set! (v : Vector α n) (i : Nat) (x : α) : Vector α n :=
|
||||
⟨v.toArray.set! i x, by simp⟩
|
||||
|
||||
/-- Append two vectors. -/
|
||||
@[inline] def append (v : Vector α n) (w : Vector α m) : Vector α (n + m) :=
|
||||
⟨v.toArray ++ w.toArray, by simp⟩
|
||||
|
||||
instance : HAppend (Vector α n) (Vector α m) (Vector α (n + m)) where
|
||||
hAppend := append
|
||||
|
||||
/-- Creates a vector from another with a provably equal length. -/
|
||||
@[inline] protected def cast (h : n = m) (v : Vector α n) : Vector α m :=
|
||||
⟨v.toArray, by simp [*]⟩
|
||||
|
||||
/--
|
||||
Extracts the slice of a vector from indices `start` to `stop` (exclusive). If `start ≥ stop`, the
|
||||
result is empty. If `stop` is greater than the size of the vector, the size is used instead.
|
||||
-/
|
||||
@[inline] def extract (v : Vector α n) (start stop : Nat) : Vector α (min stop n - start) :=
|
||||
⟨v.toArray.extract start stop, by simp⟩
|
||||
|
||||
/-- Maps elements of a vector using the function `f`. -/
|
||||
@[inline] def map (f : α → β) (v : Vector α n) : Vector β n :=
|
||||
⟨v.toArray.map f, by simp⟩
|
||||
|
||||
/-- Maps corresponding elements of two vectors of equal size using the function `f`. -/
|
||||
@[inline] def zipWith (a : Vector α n) (b : Vector β n) (f : α → β → φ) : Vector φ n :=
|
||||
⟨Array.zipWith a.toArray b.toArray f, by simp⟩
|
||||
|
||||
/-- The vector of length `n` whose `i`-th element is `f i`. -/
|
||||
@[inline] def ofFn (f : Fin n → α) : Vector α n :=
|
||||
⟨Array.ofFn f, by simp⟩
|
||||
|
||||
/--
|
||||
Swap two elements of a vector using `Fin` indices.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def swap (v : Vector α n) (i j : Nat)
|
||||
(hi : i < n := by get_elem_tactic) (hj : j < n := by get_elem_tactic) : Vector α n :=
|
||||
⟨v.toArray.swap i j (by simpa using hi) (by simpa using hj), by simp⟩
|
||||
|
||||
/--
|
||||
Swap two elements of a vector using `Nat` indices. Panics if either index is out of bounds.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def swapIfInBounds (v : Vector α n) (i j : Nat) : Vector α n :=
|
||||
⟨v.toArray.swapIfInBounds i j, by simp⟩
|
||||
|
||||
/--
|
||||
Swaps an element of a vector with a given value using a `Fin` index. The original value is returned
|
||||
along with the updated vector.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def swapAt (v : Vector α n) (i : Nat) (x : α) (hi : i < n := by get_elem_tactic) :
|
||||
α × Vector α n :=
|
||||
let a := v.toArray.swapAt i x (by simpa using hi)
|
||||
⟨a.fst, a.snd, by simp [a]⟩
|
||||
|
||||
/--
|
||||
Swaps an element of a vector with a given value using a `Nat` index. Panics if the index is out of
|
||||
bounds. The original value is returned along with the updated vector.
|
||||
|
||||
This will perform the update destructively provided that the vector has a reference count of 1.
|
||||
-/
|
||||
@[inline] def swapAt! (v : Vector α n) (i : Nat) (x : α) : α × Vector α n :=
|
||||
let a := v.toArray.swapAt! i x
|
||||
⟨a.fst, a.snd, by simp [a]⟩
|
||||
|
||||
/-- The vector `#v[0,1,2,...,n-1]`. -/
|
||||
@[inline] def range (n : Nat) : Vector Nat n := ⟨Array.range n, by simp⟩
|
||||
|
||||
/--
|
||||
Extract the first `m` elements of a vector. If `m` is greater than or equal to the size of the
|
||||
vector then the vector is returned unchanged.
|
||||
-/
|
||||
@[inline] def take (v : Vector α n) (m : Nat) : Vector α (min m n) :=
|
||||
⟨v.toArray.take m, by simp⟩
|
||||
|
||||
/--
|
||||
Deletes the first `m` elements of a vector. If `m` is greater than or equal to the size of the
|
||||
vector then the empty vector is returned.
|
||||
-/
|
||||
@[inline] def drop (v : Vector α n) (m : Nat) : Vector α (n - m) :=
|
||||
⟨v.toArray.extract m v.size, by simp⟩
|
||||
|
||||
/--
|
||||
Compares two vectors of the same size using a given boolean relation `r`. `isEqv v w r` returns
|
||||
`true` if and only if `r v[i] w[i]` is true for all indices `i`.
|
||||
-/
|
||||
@[inline] def isEqv (v w : Vector α n) (r : α → α → Bool) : Bool :=
|
||||
Array.isEqvAux v.toArray w.toArray (by simp) r n (by simp)
|
||||
|
||||
instance [BEq α] : BEq (Vector α n) where
|
||||
beq a b := isEqv a b (· == ·)
|
||||
|
||||
/-- Reverse the elements of a vector. -/
|
||||
@[inline] def reverse (v : Vector α n) : Vector α n :=
|
||||
⟨v.toArray.reverse, by simp⟩
|
||||
|
||||
/-- Delete an element of a vector using a `Nat` index and a tactic provided proof. -/
|
||||
@[inline] def eraseIdx (v : Vector α n) (i : Nat) (h : i < n := by get_elem_tactic) :
|
||||
Vector α (n-1) :=
|
||||
⟨v.toArray.eraseIdx i (v.size_toArray.symm ▸ h), by simp [Array.size_eraseIdx]⟩
|
||||
|
||||
/-- Delete an element of a vector using a `Nat` index. Panics if the index is out of bounds. -/
|
||||
@[inline] def eraseIdx! (v : Vector α n) (i : Nat) : Vector α (n-1) :=
|
||||
if _ : i < n then
|
||||
v.eraseIdx i
|
||||
else
|
||||
have : Inhabited (Vector α (n-1)) := ⟨v.pop⟩
|
||||
panic! "index out of bounds"
|
||||
|
||||
/-- Delete the first element of a vector. Returns the empty vector if the input vector is empty. -/
|
||||
@[inline] def tail (v : Vector α n) : Vector α (n-1) :=
|
||||
if _ : 0 < n then
|
||||
v.eraseIdx 0
|
||||
else
|
||||
v.cast (by omega)
|
||||
|
||||
/--
|
||||
Finds the first index of a given value in a vector using `==` for comparison. Returns `none` if the
|
||||
no element of the index matches the given value.
|
||||
-/
|
||||
@[inline] def indexOf? [BEq α] (v : Vector α n) (x : α) : Option (Fin n) :=
|
||||
(v.toArray.indexOf? x).map (Fin.cast v.size_toArray)
|
||||
|
||||
/-- Returns `true` when `v` is a prefix of the vector `w`. -/
|
||||
@[inline] def isPrefixOf [BEq α] (v : Vector α m) (w : Vector α n) : Bool :=
|
||||
v.toArray.isPrefixOf w.toArray
|
||||
172
src/Init/Data/Vector/Lemmas.lean
Normal file
172
src/Init/Data/Vector/Lemmas.lean
Normal file
@@ -0,0 +1,172 @@
|
||||
/-
|
||||
Copyright (c) 2024 Shreyas Srinivas. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Shreyas Srinivas, Francois Dorais
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Basic
|
||||
|
||||
/-!
|
||||
## Vectors
|
||||
Lemmas about `Vector α n`
|
||||
-/
|
||||
|
||||
namespace Vector
|
||||
|
||||
theorem length_toList {α n} (xs : Vector α n) : xs.toList.length = n := by simp
|
||||
|
||||
@[simp] theorem getElem_mk {data : Array α} {size : data.size = n} {i : Nat} (h : i < n) :
|
||||
(Vector.mk data size)[i] = data[i] := rfl
|
||||
|
||||
@[simp] theorem getElem_toArray {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toArray.size) :
|
||||
xs.toArray[i] = xs[i]'(by simpa using h) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem getElem_toList {α n} (xs : Vector α n) (i : Nat) (h : i < xs.toList.length) :
|
||||
xs.toList[i] = xs[i]'(by simpa using h) := by simp
|
||||
|
||||
@[simp] theorem getElem_ofFn {α n} (f : Fin n → α) (i : Nat) (h : i < n) :
|
||||
(Vector.ofFn f)[i] = f ⟨i, by simpa using h⟩ := by
|
||||
simp [ofFn]
|
||||
|
||||
/-- The empty vector maps to the empty vector. -/
|
||||
@[simp]
|
||||
theorem map_empty (f : α → β) : map f #v[] = #v[] := by
|
||||
rw [map, mk.injEq]
|
||||
exact Array.map_empty f
|
||||
|
||||
theorem toArray_inj : ∀ {v w : Vector α n}, v.toArray = w.toArray → v = w
|
||||
| {..}, {..}, rfl => rfl
|
||||
|
||||
/-- A vector of length `0` is the empty vector. -/
|
||||
protected theorem eq_empty (v : Vector α 0) : v = #v[] := by
|
||||
apply Vector.toArray_inj
|
||||
apply Array.eq_empty_of_size_eq_zero v.2
|
||||
|
||||
/--
|
||||
`Vector.ext` is an extensionality theorem.
|
||||
Vectors `a` and `b` are equal to each other if their elements are equal for each valid index.
|
||||
-/
|
||||
@[ext]
|
||||
protected theorem ext {a b : Vector α n} (h : (i : Nat) → (_ : i < n) → a[i] = b[i]) : a = b := by
|
||||
apply Vector.toArray_inj
|
||||
apply Array.ext
|
||||
· rw [a.size_toArray, b.size_toArray]
|
||||
· intro i hi _
|
||||
rw [a.size_toArray] at hi
|
||||
exact h i hi
|
||||
|
||||
@[simp] theorem push_mk {data : Array α} {size : data.size = n} {x : α} :
|
||||
(Vector.mk data size).push x =
|
||||
Vector.mk (data.push x) (by simp [size, Nat.succ_eq_add_one]) := rfl
|
||||
|
||||
@[simp] theorem pop_mk {data : Array α} {size : data.size = n} :
|
||||
(Vector.mk data size).pop = Vector.mk data.pop (by simp [size]) := rfl
|
||||
|
||||
@[simp] theorem swap_mk {data : Array α} {size : data.size = n} {i j : Nat} {hi hj} :
|
||||
(Vector.mk data size).swap i j hi hj = Vector.mk (data.swap i j) (by simp_all) := rfl
|
||||
|
||||
@[simp] theorem getElem_push_last {v : Vector α n} {x : α} : (v.push x)[n] = x := by
|
||||
rcases v with ⟨data, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_push_lt {v : Vector α n} {x : α} {i : Nat} (h : i < n) :
|
||||
(v.push x)[i] = v[i] := by
|
||||
rcases v with ⟨data, rfl⟩
|
||||
simp [Array.getElem_push_lt, h]
|
||||
|
||||
@[simp] theorem getElem_pop {v : Vector α n} {i : Nat} (h : i < n - 1) : (v.pop)[i] = v[i] := by
|
||||
rcases v with ⟨data, rfl⟩
|
||||
simp
|
||||
|
||||
/--
|
||||
Variant of `getElem_pop` that will sometimes fire when `getElem_pop` gets stuck because of
|
||||
defeq issues in the implicit size argument.
|
||||
-/
|
||||
@[simp] theorem getElem_pop' (v : Vector α (n + 1)) (i : Nat) (h : i < n + 1 - 1) :
|
||||
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt v.pop i h = v[i] :=
|
||||
getElem_pop h
|
||||
|
||||
@[simp] theorem push_pop_back (v : Vector α (n + 1)) : v.pop.push v.back = v := by
|
||||
ext i
|
||||
by_cases h : i < n
|
||||
· simp [h]
|
||||
· replace h : i = v.size - 1 := by rw [size_toArray]; omega
|
||||
subst h
|
||||
simp [pop, back, back!, ← Array.eq_push_pop_back!_of_size_ne_zero]
|
||||
|
||||
theorem push_swap (a : Vector α n) (x : α) {i j : Nat} {hi hj} :
|
||||
(a.swap i j hi hj).push x = (a.push x).swap i j := by
|
||||
cases a
|
||||
simp [Array.push_swap]
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp] theorem cast_mk {n m} (a : Array α) (w : a.size = n) (h : n = m) :
|
||||
(Vector.mk a w).cast h = ⟨a, h ▸ w⟩ := by
|
||||
simp [Vector.cast]
|
||||
|
||||
@[simp] theorem cast_refl {n} (a : Vector α n) : a.cast rfl = a := by
|
||||
cases a
|
||||
simp
|
||||
|
||||
@[simp] theorem toArray_cast {n m} (a : Vector α n) (h : n = m) :
|
||||
(a.cast h).toArray = a.toArray := by
|
||||
subst h
|
||||
simp
|
||||
|
||||
theorem cast_inj {n m} (a : Vector α n) (b : Vector α n) (h : n = m) :
|
||||
a.cast h = b.cast h ↔ a = b := by
|
||||
cases h
|
||||
simp
|
||||
|
||||
theorem cast_eq_iff {n m} (a : Vector α n) (b : Vector α m) (h : n = m) :
|
||||
a.cast h = b ↔ a = b.cast h.symm := by
|
||||
cases h
|
||||
simp
|
||||
|
||||
theorem eq_cast_iff {n m} (a : Vector α n) (b : Vector α m) (h : m = n) :
|
||||
a = b.cast h ↔ a.cast h.symm = b := by
|
||||
cases h
|
||||
simp
|
||||
|
||||
/-! ### Decidable quantifiers. -/
|
||||
|
||||
theorem forall_zero_iff {P : Vector α 0 → Prop} :
|
||||
(∀ v, P v) ↔ P #v[] := by
|
||||
constructor
|
||||
· intro h
|
||||
apply h
|
||||
· intro h v
|
||||
obtain (rfl : v = #v[]) := (by ext i h; simp at h)
|
||||
apply h
|
||||
|
||||
theorem forall_cons_iff {P : Vector α (n + 1) → Prop} :
|
||||
(∀ v : Vector α (n + 1), P v) ↔ (∀ (x : α) (v : Vector α n), P (v.push x)) := by
|
||||
constructor
|
||||
· intro h _ _
|
||||
apply h
|
||||
· intro h v
|
||||
have w : v = v.pop.push v.back := by simp
|
||||
rw [w]
|
||||
apply h
|
||||
|
||||
instance instDecidableForallVectorZero (P : Vector α 0 → Prop) :
|
||||
∀ [Decidable (P #v[])], Decidable (∀ v, P v)
|
||||
| .isTrue h => .isTrue fun ⟨v, s⟩ => by
|
||||
obtain (rfl : v = .empty) := (by ext i h₁ h₂; exact s; cases h₂)
|
||||
exact h
|
||||
| .isFalse h => .isFalse (fun w => h (w _))
|
||||
|
||||
instance instDecidableForallVectorSucc (P : Vector α (n+1) → Prop)
|
||||
[Decidable (∀ (x : α) (v : Vector α n), P (v.push x))] : Decidable (∀ v, P v) :=
|
||||
decidable_of_iff' (∀ x (v : Vector α n), P (v.push x)) forall_cons_iff
|
||||
|
||||
instance instDecidableExistsVectorZero (P : Vector α 0 → Prop) [Decidable (P #v[])] :
|
||||
Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
|
||||
instance instDecidableExistsVectorSucc (P : Vector α (n+1) → Prop)
|
||||
[Decidable (∀ (x : α) (v : Vector α n), ¬ P (v.push x))] : Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
@@ -166,6 +166,12 @@ theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem d
|
||||
have : Decidable (dom c i) := .isFalse h
|
||||
simp [getElem!_def, getElem?_def, h]
|
||||
|
||||
@[simp] theorem get_getElem? [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) [Decidable (dom c i)] (h) :
|
||||
c[i]?.get h = c[i]'(by simp only [getElem?_def] at h; split at h <;> simp_all) := by
|
||||
simp only [getElem?_def] at h ⊢
|
||||
split <;> simp_all
|
||||
|
||||
namespace Fin
|
||||
|
||||
instance instGetElemFinVal [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
@@ -200,28 +206,32 @@ instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
@[simp] theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
rfl
|
||||
|
||||
@[deprecated (since := "2024-06-12")] abbrev cons_getElem_zero := @getElem_cons_zero
|
||||
@[deprecated getElem_cons_zero (since := "2024-06-12")] abbrev cons_getElem_zero := @getElem_cons_zero
|
||||
|
||||
@[simp] theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
rfl
|
||||
|
||||
@[deprecated (since := "2024-06-12")] abbrev cons_getElem_succ := @getElem_cons_succ
|
||||
@[deprecated getElem_cons_succ (since := "2024-06-12")] abbrev cons_getElem_succ := @getElem_cons_succ
|
||||
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i :=
|
||||
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
| _::_, i+1 => get_drop_eq_drop _ i _
|
||||
| _::_, i+1 => getElem_cons_drop_succ_eq_drop (i := i) _
|
||||
|
||||
@[deprecated getElem_cons_drop_succ_eq_drop (since := "2024-11-05")]
|
||||
abbrev get_drop_eq_drop := @getElem_cons_drop_succ_eq_drop
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
getElem xs i h := xs.get i h
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Additional goodies for writing macros
|
||||
-/
|
||||
prelude
|
||||
import Init.MetaTypes
|
||||
import Init.Syntax
|
||||
import Init.Data.Array.GetLit
|
||||
import Init.Data.Option.BasicAux
|
||||
|
||||
@@ -373,6 +374,9 @@ partial def structEq : Syntax → Syntax → Bool
|
||||
instance : BEq Lean.Syntax := ⟨structEq⟩
|
||||
instance : BEq (Lean.TSyntax k) := ⟨(·.raw == ·.raw)⟩
|
||||
|
||||
/--
|
||||
Finds the first `SourceInfo` from the back of `stx` or `none` if no `SourceInfo` can be found.
|
||||
-/
|
||||
partial def getTailInfo? : Syntax → Option SourceInfo
|
||||
| atom info _ => info
|
||||
| ident info .. => info
|
||||
@@ -381,14 +385,39 @@ partial def getTailInfo? : Syntax → Option SourceInfo
|
||||
| node info _ _ => info
|
||||
| _ => none
|
||||
|
||||
/--
|
||||
Finds the first `SourceInfo` from the back of `stx` or `SourceInfo.none`
|
||||
if no `SourceInfo` can be found.
|
||||
-/
|
||||
def getTailInfo (stx : Syntax) : SourceInfo :=
|
||||
stx.getTailInfo?.getD SourceInfo.none
|
||||
|
||||
/--
|
||||
Finds the trailing size of the first `SourceInfo` from the back of `stx`.
|
||||
If no `SourceInfo` can be found or the first `SourceInfo` from the back of `stx` contains no
|
||||
trailing whitespace, the result is `0`.
|
||||
-/
|
||||
def getTrailingSize (stx : Syntax) : Nat :=
|
||||
match stx.getTailInfo? with
|
||||
| some (SourceInfo.original (trailing := trailing) ..) => trailing.bsize
|
||||
| _ => 0
|
||||
|
||||
/--
|
||||
Finds the trailing whitespace substring of the first `SourceInfo` from the back of `stx`.
|
||||
If no `SourceInfo` can be found or the first `SourceInfo` from the back of `stx` contains
|
||||
no trailing whitespace, the result is `none`.
|
||||
-/
|
||||
def getTrailing? (stx : Syntax) : Option Substring :=
|
||||
stx.getTailInfo.getTrailing?
|
||||
|
||||
/--
|
||||
Finds the tail position of the trailing whitespace of the first `SourceInfo` from the back of `stx`.
|
||||
If no `SourceInfo` can be found or the first `SourceInfo` from the back of `stx` contains
|
||||
no trailing whitespace and lacks a tail position, the result is `none`.
|
||||
-/
|
||||
def getTrailingTailPos? (stx : Syntax) (canonicalOnly := false) : Option String.Pos :=
|
||||
stx.getTailInfo.getTrailingTailPos? canonicalOnly
|
||||
|
||||
/--
|
||||
Return substring of original input covering `stx`.
|
||||
Result is meaningful only if all involved `SourceInfo.original`s refer to the same string (as is the case after parsing). -/
|
||||
@@ -402,21 +431,20 @@ def getSubstring? (stx : Syntax) (withLeading := true) (withTrailing := true) :
|
||||
}
|
||||
| _, _ => none
|
||||
|
||||
@[specialize] private partial def updateLast {α} [Inhabited α] (a : Array α) (f : α → Option α) (i : Nat) : Option (Array α) :=
|
||||
if i == 0 then
|
||||
none
|
||||
else
|
||||
let i := i - 1
|
||||
let v := a[i]!
|
||||
@[specialize] private partial def updateLast {α} (a : Array α) (f : α → Option α) (i : Fin (a.size + 1)) : Option (Array α) :=
|
||||
match i with
|
||||
| 0 => none
|
||||
| ⟨i + 1, h⟩ =>
|
||||
let v := a[i]'(Nat.succ_lt_succ_iff.mp h)
|
||||
match f v with
|
||||
| some v => some <| a.set! i v
|
||||
| none => updateLast a f i
|
||||
| some v => some <| a.set i v (Nat.succ_lt_succ_iff.mp h)
|
||||
| none => updateLast a f ⟨i, Nat.lt_of_succ_lt h⟩
|
||||
|
||||
partial def setTailInfoAux (info : SourceInfo) : Syntax → Option Syntax
|
||||
| atom _ val => some <| atom info val
|
||||
| ident _ rawVal val pre => some <| ident info rawVal val pre
|
||||
| node info' k args =>
|
||||
match updateLast args (setTailInfoAux info) args.size with
|
||||
match updateLast args (setTailInfoAux info) ⟨args.size, by simp⟩ with
|
||||
| some args => some <| node info' k args
|
||||
| none => none
|
||||
| _ => none
|
||||
@@ -442,7 +470,7 @@ def unsetTrailing (stx : Syntax) : Syntax :=
|
||||
if h : i < a.size then
|
||||
let v := a[i]
|
||||
match f v with
|
||||
| some v => some <| a.set ⟨i, h⟩ v
|
||||
| some v => some <| a.set i v h
|
||||
| none => updateFirst a f (i+1)
|
||||
else
|
||||
none
|
||||
|
||||
@@ -251,10 +251,16 @@ def neutralConfig : Simp.Config := {
|
||||
|
||||
end Simp
|
||||
|
||||
/-- Configuration for which occurrences that match an expression should be rewritten. -/
|
||||
inductive Occurrences where
|
||||
/-- All occurrences should be rewritten. -/
|
||||
| all
|
||||
/-- A list of indices for which occurrences should be rewritten. -/
|
||||
| pos (idxs : List Nat)
|
||||
/-- A list of indices for which occurrences should not be rewritten. -/
|
||||
| neg (idxs : List Nat)
|
||||
deriving Inhabited, BEq
|
||||
|
||||
instance : Coe (List Nat) Occurrences := ⟨.pos⟩
|
||||
|
||||
end Lean.Meta
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user