mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-03 02:34:08 +00:00
Compare commits
1 Commits
map_grind_
...
grind_spli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1246d59a80 |
24
.github/workflows/awaiting-mathlib.yml
vendored
24
.github/workflows/awaiting-mathlib.yml
vendored
@@ -10,29 +10,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check awaiting-mathlib label
|
||||
id: check-awaiting-mathlib-label
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { labels, number: prNumber } = context.payload.pull_request;
|
||||
const hasAwaiting = labels.some(label => label.name == "awaiting-mathlib");
|
||||
const hasBreaks = labels.some(label => label.name == "breaks-mathlib");
|
||||
const hasBuilds = labels.some(label => label.name == "builds-mathlib");
|
||||
|
||||
if (hasAwaiting && hasBreaks) {
|
||||
core.setFailed('PR has both "awaiting-mathlib" and "breaks-mathlib" labels.');
|
||||
} else if (hasAwaiting && !hasBreaks && !hasBuilds) {
|
||||
core.info('PR is marked "awaiting-mathlib" but neither "breaks-mathlib" nor "builds-mathlib" labels are present.');
|
||||
core.setOutput('awaiting', 'true');
|
||||
const { labels } = context.payload.pull_request;
|
||||
if (labels.some(label => label.name == "awaiting-mathlib") && !labels.some(label => label.name == "builds-mathlib")) {
|
||||
core.setFailed('PR is marked "awaiting-mathlib" but "builds-mathlib" label has not been applied yet by the bot');
|
||||
}
|
||||
|
||||
- name: Wait for mathlib compatibility
|
||||
if: github.event_name == 'pull_request' && steps.check-awaiting-mathlib-label.outputs.awaiting == 'true'
|
||||
run: |
|
||||
echo "::notice title=Awaiting mathlib::PR is marked 'awaiting-mathlib' but neither 'breaks-mathlib' nor 'builds-mathlib' labels are present."
|
||||
echo "This check will remain in progress until the PR is updated with appropriate mathlib compatibility labels."
|
||||
# Keep the job running indefinitely to show "in progress" status
|
||||
while true; do
|
||||
sleep 3600 # Sleep for 1 hour at a time
|
||||
done
|
||||
|
||||
27
.github/workflows/build-template.yml
vendored
27
.github/workflows/build-template.yml
vendored
@@ -82,7 +82,7 @@ jobs:
|
||||
- name: CI Merge Checkout
|
||||
run: |
|
||||
git fetch --depth=1 origin ${{ github.sha }}
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-* tests/lean/run/importStructure.lean
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-*
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
@@ -104,12 +104,12 @@ jobs:
|
||||
# NOTE: must be in sync with `save` below
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake' && false && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*' || '' }}
|
||||
key: ${{ matrix.name }}-build-v3-${{ github.sha }}
|
||||
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
|
||||
# fall back to (latest) previous cache
|
||||
restore-keys: |
|
||||
${{ matrix.name }}-build-v3
|
||||
@@ -127,12 +127,9 @@ jobs:
|
||||
[ -d build ] || mkdir build
|
||||
cd build
|
||||
# arguments passed to `cmake`
|
||||
OPTIONS=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
|
||||
if [[ -n '${{ matrix.release }}' ]]; then
|
||||
# this also enables githash embedding into stage 1 library, which prohibits reusing
|
||||
# `.olean`s across commits, so we don't do it in the fast non-release CI
|
||||
OPTIONS+=(-DCHECK_OLEAN_VERSION=ON)
|
||||
fi
|
||||
# this also enables githash embedding into stage 1 library
|
||||
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
|
||||
OPTIONS+=(-DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true)
|
||||
if [[ -n '${{ matrix.cross_target }}' ]]; then
|
||||
# used by `prepare-llvm`
|
||||
export EXTRA_FLAGS=--target=${{ matrix.cross_target }}
|
||||
@@ -196,7 +193,7 @@ jobs:
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.name == 'Linux release')
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
with:
|
||||
@@ -213,7 +210,7 @@ jobs:
|
||||
- name: Check Stage 3
|
||||
run: |
|
||||
make -C build -j$NPROC check-stage3
|
||||
if: matrix.check-stage3
|
||||
if: matrix.test-speedcenter
|
||||
- name: Test Speedcenter Benchmarks
|
||||
run: |
|
||||
# Necessary for some timing metrics but does not work on Namespace runners
|
||||
@@ -227,7 +224,7 @@ jobs:
|
||||
run: |
|
||||
# clean rebuild in case of Makefile changes
|
||||
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
|
||||
if: matrix.check-rebootstrap
|
||||
if: matrix.name == 'Linux' && inputs.check-level >= 1
|
||||
- name: CCache stats
|
||||
if: always()
|
||||
run: ccache -s
|
||||
@@ -245,8 +242,8 @@ jobs:
|
||||
# NOTE: must be in sync with `restore` above
|
||||
path: |
|
||||
.ccache
|
||||
${{ matrix.name == 'Linux Lake' && false && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean*
|
||||
${{ matrix.name == 'Linux Lake' && 'build/stage1/**/*.trace
|
||||
build/stage1/**/*.olean
|
||||
build/stage1/**/*.ilean
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*' || '' }}
|
||||
|
||||
58
.github/workflows/ci.yml
vendored
58
.github/workflows/ci.yml
vendored
@@ -103,13 +103,6 @@ jobs:
|
||||
echo "Tag ${TAG_NAME} did not match SemVer regex."
|
||||
fi
|
||||
|
||||
- name: Check for custom releases (e.g., not in the main lean repository)
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository != 'leanprover/lean4'
|
||||
id: set-release-custom
|
||||
run: |
|
||||
TAG_NAME="${GITHUB_REF##*/}"
|
||||
echo "RELEASE_TAG=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set check level
|
||||
id: set-level
|
||||
# We do not use github.event.pull_request.labels.*.name here because
|
||||
@@ -118,7 +111,7 @@ jobs:
|
||||
run: |
|
||||
check_level=0
|
||||
|
||||
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" || -n "${{ steps.set-release-custom.outputs.RELEASE_TAG }}" ]]; then
|
||||
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" ]]; then
|
||||
check_level=2
|
||||
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
|
||||
check_level=1
|
||||
@@ -145,7 +138,6 @@ jobs:
|
||||
// use large runners where available (original repo)
|
||||
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||
const isPr = "${{ github.event_name }}" == "pull_request";
|
||||
const isPushToMaster = "${{ github.event_name }}" == "push" && "${{ github.ref_name }}" == "master";
|
||||
let matrix = [
|
||||
/* TODO: to be updated to new LLVM
|
||||
{
|
||||
@@ -165,17 +157,9 @@ jobs:
|
||||
{
|
||||
// portable release build: use channel with older glibc (2.26)
|
||||
"name": "Linux release",
|
||||
"os": large && level < 2 ? "nscloud-ubuntu-22.04-amd64-4x16" : "ubuntu-latest",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"release": true,
|
||||
// Special handling for release jobs. We want:
|
||||
// 1. To run it in PRs so developers get PR toolchains (so secondary is sufficient)
|
||||
// 2. To skip it in merge queues as it takes longer than the
|
||||
// Linux lake build and adds little value in the merge queue
|
||||
// 3. To run it in release (obviously)
|
||||
// 4. To run it for pushes to master so that pushes to master have a Linux toolchain
|
||||
// available as an artifact for Grove to use.
|
||||
"check-level": (isPr || isPushToMaster) ? 0 : 2,
|
||||
"secondary": isPr,
|
||||
"check-level": 0,
|
||||
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-linux-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||
@@ -185,14 +169,21 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux Lake",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x16" : "ubuntu-latest",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"check-level": 0,
|
||||
"test": true,
|
||||
"check-rebootstrap": level >= 1,
|
||||
"check-stage3": level >= 2,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
// just a secondary build job for now until false positives can be excluded
|
||||
"secondary": true,
|
||||
"CMAKE_OPTIONS": "-DUSE_LAKE=ON",
|
||||
// TODO: importStructure is not compatible with .olean caching
|
||||
// TODO: why does scopedMacros fail?
|
||||
"CTEST_OPTIONS": "-E 'scopedMacros|importStructure'"
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"check-stage3": level >= 2,
|
||||
"test-speedcenter": level >= 2,
|
||||
"check-level": 1,
|
||||
},
|
||||
{
|
||||
"name": "Linux Reldebug",
|
||||
@@ -225,8 +216,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "macOS aarch64",
|
||||
// standard GH runner only comes with 7GB so use large runner if possible
|
||||
"os": large ? "nscloud-macos-sonoma-arm64-6x14" : "macos-14",
|
||||
"os": "macos-14",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
|
||||
"release": true,
|
||||
"shell": "bash -euxo pipefail {0}",
|
||||
@@ -234,7 +224,11 @@ jobs:
|
||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||
"binary-check": "otool -L",
|
||||
"tar": "gtar", // https://github.com/actions/runner-images/issues/2619
|
||||
// See above for release job levels
|
||||
// Special handling for MacOS aarch64, we want:
|
||||
// 1. To run it in PRs so Mac devs get PR toolchains (so secondary is sufficient)
|
||||
// 2. To skip it in merge queues as it takes longer than the Linux build and adds
|
||||
// little value in the merge queue
|
||||
// 3. To run it in release (obviously)
|
||||
"check-level": isPr ? 0 : 2,
|
||||
"secondary": isPr,
|
||||
},
|
||||
@@ -253,7 +247,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux aarch64",
|
||||
"os": "nscloud-ubuntu-22.04-arm64-4x16",
|
||||
"os": "nscloud-ubuntu-22.04-arm64-4x8",
|
||||
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
@@ -363,7 +357,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -407,7 +401,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@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
@@ -424,6 +418,6 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_INDEX_TOKEN }}
|
||||
- name: Update toolchain on mathlib4's nightly-testing branch
|
||||
run: |
|
||||
gh workflow -R leanprover-community/mathlib4-nightly-testing run nightly_bump_toolchain.yml
|
||||
gh workflow -R leanprover-community/mathlib4 run nightly_bump_toolchain.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.MATHLIB4_BOT }}
|
||||
|
||||
161
.github/workflows/grove.yml
vendored
161
.github/workflows/grove.yml
vendored
@@ -1,161 +0,0 @@
|
||||
name: Grove
|
||||
|
||||
on:
|
||||
workflow_run: # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
grove-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.workflow_run.conclusion == 'success' && github.repository == 'leanprover/lean4'
|
||||
|
||||
steps:
|
||||
- name: Retrieve information about the original workflow
|
||||
uses: potiuk/get-workflow-origin@v1_1 # https://github.com/marketplace/actions/get-workflow-origin
|
||||
# This action is deprecated and archived, but it seems hard to find a
|
||||
# better solution for getting the PR number
|
||||
# see https://github.com/orgs/community/discussions/25220 for some discussion
|
||||
id: workflow-info
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sourceRunId: ${{ github.event.workflow_run.id }}
|
||||
|
||||
- name: Check if should run
|
||||
id: should-run
|
||||
run: |
|
||||
# Check if it's a push to master (no PR number and target branch is master)
|
||||
if [ -z "${{ steps.workflow-info.outputs.pullRequestNumber }}" ]; then
|
||||
if [ "${{ github.event.workflow_run.head_branch }}" = "master" ]; then
|
||||
echo "Push to master detected. Skipping for now, to be enabled later."
|
||||
echo "should-run=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "Push to non-master branch, skipping"
|
||||
echo "should-run=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
else
|
||||
# Check if it's a PR with grove label
|
||||
PR_LABELS='${{ steps.workflow-info.outputs.pullRequestLabels }}'
|
||||
if echo "$PR_LABELS" | grep -q '"grove"'; then
|
||||
echo "PR with grove label detected"
|
||||
echo "should-run=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "PR without grove label, skipping"
|
||||
echo "should-run=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Fetch upstream invalidated facts
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' && steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: fetch-upstream
|
||||
uses: TwoFx/grove-action/fetch-upstream@v0.3
|
||||
with:
|
||||
artifact-name: grove-invalidated-facts
|
||||
base-ref: master
|
||||
|
||||
- name: Download toolchain for this commit
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
id: download-toolchain
|
||||
uses: dawidd6/action-download-artifact@v11
|
||||
with:
|
||||
commit: ${{ steps.workflow-info.outputs.sourceHeadSha }}
|
||||
workflow: ci.yml
|
||||
path: artifacts
|
||||
name: build-Linux.*
|
||||
name_is_regexp: true
|
||||
|
||||
- name: Unpack toolchain
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
id: unpack-toolchain
|
||||
run: |
|
||||
cd artifacts
|
||||
# Find the tar.zst file
|
||||
TAR_FILE=$(find . -name "lean-*.tar.zst" -type f | head -1)
|
||||
if [ -z "$TAR_FILE" ]; then
|
||||
echo "Error: No lean-*.tar.zst file found"
|
||||
exit 1
|
||||
fi
|
||||
echo "Found archive: $TAR_FILE"
|
||||
|
||||
# Extract the archive
|
||||
tar --zstd -xf "$TAR_FILE"
|
||||
|
||||
# Find the extracted directory name
|
||||
LEAN_DIR=$(find . -maxdepth 1 -name "lean-*" -type d | head -1)
|
||||
if [ -z "$LEAN_DIR" ]; then
|
||||
echo "Error: No lean-* directory found after extraction"
|
||||
exit 1
|
||||
fi
|
||||
echo "Extracted directory: $LEAN_DIR"
|
||||
echo "lean-dir=$LEAN_DIR" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
id: build
|
||||
uses: TwoFx/grove-action/build@v0.3
|
||||
with:
|
||||
project-path: doc/std/grove
|
||||
script-name: grove-stdlib
|
||||
invalidated-facts-artifact-name: grove-invalidated-facts
|
||||
comment-artifact-name: grove-comment
|
||||
toolchain-id: lean4
|
||||
toolchain-path: artifacts/${{ steps.unpack-toolchain.outputs.lean-dir }}
|
||||
project-ref: ${{ steps.workflow-info.outputs.sourceHeadSha }}
|
||||
|
||||
# deploy-alias computes a URL component for the PR preview. This
|
||||
# is so we can have a stable name to use for feedback on draft
|
||||
# material.
|
||||
- id: deploy-alias
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
uses: actions/github-script@v7
|
||||
name: Compute Alias
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
if (process.env.PR) {
|
||||
return `pr-${process.env.PR}`
|
||||
} else {
|
||||
return 'deploy-preview-main';
|
||||
}
|
||||
env:
|
||||
PR: ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
|
||||
- name: Deploy to Netlify
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
id: deploy-draft
|
||||
uses: nwtgck/actions-netlify@v3.0
|
||||
with:
|
||||
publish-dir: ${{ steps.build.outputs.out-path }}
|
||||
production-deploy: false
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
alias: ${{ steps.deploy-alias.outputs.result }}
|
||||
enable-commit-comment: false
|
||||
enable-pull-request-comment: false
|
||||
fails-without-credentials: true
|
||||
enable-github-deployment: false
|
||||
enable-commit-status: false
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
NETLIFY_SITE_ID: "1cacfa39-a11c-467c-99e7-2e01d7b4089e"
|
||||
|
||||
# actions-netlify cannot add deploy links to a PR because it assumes a
|
||||
# pull_request context, not a workflow_run context, see
|
||||
# https://github.com/nwtgck/actions-netlify/issues/545
|
||||
# We work around by using a comment to post the latest link
|
||||
- name: "Comment on PR with preview links"
|
||||
uses: marocchino/sticky-pull-request-comment@v2
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' && steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
with:
|
||||
number: ${{ env.PR_NUMBER }}
|
||||
header: preview-comment
|
||||
recreate: true
|
||||
message: |
|
||||
[Grove](${{ steps.deploy-draft.outputs.deploy-url }}) for revision ${{ steps.workflow-info.outputs.sourceHeadSha }}.
|
||||
|
||||
${{ steps.build.outputs.comment-text }}
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
PR_HEADSHA: ${{ steps.workflow-info.outputs.sourceHeadSha }}
|
||||
70
.github/workflows/pr-release.yml
vendored
70
.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@v10 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v9 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -48,30 +48,19 @@ jobs:
|
||||
git -C lean4.git remote add origin https://github.com/${{ github.repository_owner }}/lean4.git
|
||||
git -C lean4.git fetch -n origin master
|
||||
git -C lean4.git fetch -n origin "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
|
||||
# Create both the original tag and the SHA-suffixed tag
|
||||
SHORT_SHA="${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
SHORT_SHA="${SHORT_SHA:0:7}"
|
||||
|
||||
# Export the short SHA for use in subsequent steps
|
||||
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"
|
||||
|
||||
git -C lean4.git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
git -C lean4.git tag -f pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-"${SHORT_SHA}" "${{ steps.workflow-info.outputs.sourceHeadSha }}"
|
||||
|
||||
git -C lean4.git remote add pr-releases https://foo:'${{ secrets.PR_RELEASES_TOKEN }}'@github.com/${{ github.repository_owner }}/lean4-pr-releases.git
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
git -C lean4.git push -f pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-"${SHORT_SHA}"
|
||||
- name: Delete existing release if present
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
run: |
|
||||
# Try to delete any existing release for the current PR (just the version without the SHA suffix).
|
||||
# Try to delete any existing release for the current PR.
|
||||
gh release delete --repo ${{ github.repository_owner }}/lean4-pr-releases pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }} -y || true
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release (short format)
|
||||
- name: Release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
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.
|
||||
@@ -84,22 +73,7 @@ jobs:
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
draft: false
|
||||
tag_name: pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}
|
||||
repository: ${{ github.repository_owner }}/lean4-pr-releases
|
||||
env:
|
||||
# The token used here must have `workflow` privileges.
|
||||
GITHUB_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
|
||||
- name: Report release status (short format)
|
||||
- name: Report release status
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
@@ -113,20 +87,6 @@ jobs:
|
||||
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}",
|
||||
});
|
||||
|
||||
- name: Report release status (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: "${{ steps.workflow-info.outputs.sourceHeadSha }}",
|
||||
state: "success",
|
||||
context: "PR toolchain (SHA-suffixed)",
|
||||
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}",
|
||||
});
|
||||
|
||||
- name: Add label
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v7
|
||||
@@ -167,7 +127,7 @@ jobs:
|
||||
echo "The merge base of this PR coincides with the nightly release"
|
||||
|
||||
BATTERIES_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/batteries.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
MATHLIB_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/mathlib4-nightly-testing.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
MATHLIB_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/mathlib4.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
|
||||
if [[ -n "$BATTERIES_REMOTE_TAGS" ]]; then
|
||||
echo "... and Batteries has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
@@ -322,18 +282,16 @@ jobs:
|
||||
if [ "$EXISTS" = "0" ]; then
|
||||
echo "Branch does not exist, creating it."
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain."
|
||||
echo "Branch already exists, pushing an empty commit."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The Batteries `nightly-testing` or `nightly-testing-YYYY-MM-DD` branch may have moved since this branch was created, so merge their changes.
|
||||
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
|
||||
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
@@ -355,7 +313,7 @@ jobs:
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
repository: leanprover-community/mathlib4
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
@@ -388,23 +346,21 @@ jobs:
|
||||
if [ "$EXISTS" = "0" ]; then
|
||||
echo "Branch does not exist, creating it."
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}",' lakefile.lean
|
||||
lake update batteries
|
||||
git add lakefile.lean lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain and bumping Batteries."
|
||||
echo "Branch already exists, merging $BASE and bumping Batteries."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The Mathlib `nightly-testing` branch or `nightly-testing-YYYY-MM-DD` tag may have moved since this branch was created, so merge their changes.
|
||||
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
|
||||
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
lake update batteries
|
||||
git add lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
|
||||
38
.github/workflows/update-stage0.yml
vendored
38
.github/workflows/update-stage0.yml
vendored
@@ -40,24 +40,34 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name "Lean stage0 autoupdater"
|
||||
git config --global user.email "<>"
|
||||
# Would be nice, but does not work yet:
|
||||
# https://github.com/DeterminateSystems/magic-nix-cache/issues/39
|
||||
# This action does not run that often and building runs in a few minutes, so ok for now
|
||||
#- if: env.should_update_stage0 == 'yes'
|
||||
# uses: DeterminateSystems/magic-nix-cache-action@v2
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Restore Build Cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: nix-store-cache
|
||||
key: Nix Linux-nix-store-cache-${{ github.sha }}
|
||||
# fall back to (latest) previous cache
|
||||
restore-keys: |
|
||||
Nix Linux-nix-store-cache
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Further Set Up Nix Cache
|
||||
shell: bash -euxo pipefail {0}
|
||||
run: |
|
||||
# Nix seems to mutate the cache, so make a copy
|
||||
cp -r nix-store-cache nix-store-cache-copy || true
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
- name: Open Nix shell once
|
||||
if: env.should_update_stage0 == 'yes'
|
||||
run: true
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- name: Set up NPROC
|
||||
if: env.should_update_stage0 == 'yes'
|
||||
run: |
|
||||
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
with:
|
||||
extra-conf: |
|
||||
substituters = file://${{ github.workspace }}/nix-store-cache-copy?priority=10&trusted=true https://cache.nixos.org
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: cmake --preset release
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: make -j$NPROC -C build/release update-stage0-commit
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
run: nix run .#update-stage0-commit
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: git show --stat
|
||||
- if: env.should_update_stage0 == 'yes' && github.event_name == 'push'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
lake-manifest.json
|
||||
/build
|
||||
/src/lakefile.toml
|
||||
/tests/lakefile.toml
|
||||
/lakefile.toml
|
||||
GPATH
|
||||
GRTAGS
|
||||
|
||||
@@ -85,6 +85,5 @@ such that changing files in `Init` doesn't force a full rebuild of `Lean`.
|
||||
You can test a Lean PR against Mathlib and Batteries by rebasing your PR
|
||||
on to `nightly-with-mathlib` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of Mathlib and Batteries called `lean-pr-testing-NNNN`
|
||||
on the `leanprover-community/mathlib4-nightly-testing` fork of Mathlib.
|
||||
This branch uses the toolchain for your PR, and will report back to the Lean PR with results from Mathlib CI.
|
||||
that uses the toolchain for your PR, and will report back to the Lean PR with results from Mathlib CI.
|
||||
See https://leanprover-community.github.io/contribute/tags_and_branches.html for more details.
|
||||
|
||||
@@ -50,7 +50,7 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- Re-running `script/release_checklist.py` will then create the tag `v4.6.0` from `master`/`main` and push it (unless `toolchain-tag: false` in the `release_repos.yml` file)
|
||||
- `script/release_checklist.py` will then merge the tag `v4.6.0` into the `stable` branch and push it (unless `stable-branch: false` in the `release_repos.yml` file).
|
||||
- Special notes on repositories with exceptional requirements:
|
||||
- `doc-gen4` has additional dependencies which we do not update at each toolchain release, although occasionally these break and need to be updated manually.
|
||||
- `doc-gen4` has addition dependencies which we do not update at each toolchain release, although occasionally these break and need to be updated manually.
|
||||
- `verso`:
|
||||
- The `subverso` dependency is unusual in that it needs to be compatible with _every_ Lean release simultaneously.
|
||||
Usually you don't need to do anything.
|
||||
@@ -94,8 +94,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
|
||||
This checklist walks you through creating the first release candidate for a version of Lean.
|
||||
|
||||
For subsequent release candidates, the process is essentially the same, but we start out with the `releases/v4.7.0` branch already created.
|
||||
|
||||
We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
|
||||
- Decide which nightly release you want to turn into a release candidate.
|
||||
@@ -114,7 +112,7 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
git fetch nightly tag nightly-2024-02-29
|
||||
git checkout nightly-2024-02-29
|
||||
git checkout -b releases/v4.7.0
|
||||
git push --set-upstream origin releases/v4.7.0
|
||||
git push --set-upstream origin releases/v4.18.0
|
||||
```
|
||||
- In `src/CMakeLists.txt`,
|
||||
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
|
||||
|
||||
4
doc/std/grove/.gitignore
vendored
4
doc/std/grove/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
/.lake
|
||||
!lake-manifest.json
|
||||
metadata.json
|
||||
invalidated.json
|
||||
@@ -1,13 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Generated
|
||||
|
||||
def restoreState : RestoreStateM Unit := do
|
||||
return ()
|
||||
@@ -1,31 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import GroveStdlib.Std.CoreTypesAndOperations
|
||||
import GroveStdlib.Std.LanguageConstructs
|
||||
import GroveStdlib.Std.Libraries
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib
|
||||
|
||||
namespace Std
|
||||
|
||||
def introduction : Node :=
|
||||
.text "Welcome to the interactive Lean standard library outline!"
|
||||
|
||||
end Std
|
||||
|
||||
def std : Node :=
|
||||
.section "stdlib" "The Lean standard library" #[
|
||||
Std.introduction,
|
||||
Std.coreTypesAndOperations,
|
||||
Std.languageConstructs,
|
||||
Std.libraries,
|
||||
Std.operatingSystemAbstractions
|
||||
]
|
||||
|
||||
end GroveStdlib
|
||||
@@ -1,28 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
import GroveStdlib.Std.CoreTypesAndOperations.BasicTypes
|
||||
import GroveStdlib.Std.CoreTypesAndOperations.Containers
|
||||
import GroveStdlib.Std.CoreTypesAndOperations.Numbers
|
||||
import GroveStdlib.Std.CoreTypesAndOperations.StringsAndFormatting
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std
|
||||
|
||||
namespace CoreTypesAndOperations
|
||||
|
||||
end CoreTypesAndOperations
|
||||
|
||||
def coreTypesAndOperations : Node :=
|
||||
.section "core-types-and-operations" "Core types and operations" #[
|
||||
CoreTypesAndOperations.basicTypes,
|
||||
CoreTypesAndOperations.containers,
|
||||
CoreTypesAndOperations.numbers,
|
||||
CoreTypesAndOperations.stringsAndFormatting
|
||||
]
|
||||
|
||||
end GroveStdlib.Std
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
namespace BasicTypes
|
||||
|
||||
end BasicTypes
|
||||
|
||||
def basicTypes : Node :=
|
||||
.section "basic-types" "Basic types" #[]
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
namespace Containers
|
||||
|
||||
end Containers
|
||||
|
||||
def containers : Node :=
|
||||
.section "containers" "Containers" #[]
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
namespace Numbers
|
||||
|
||||
end Numbers
|
||||
|
||||
def numbers : Node :=
|
||||
.section "numbers" "Numbers" #[]
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
namespace StringsAndFormatting
|
||||
|
||||
end StringsAndFormatting
|
||||
|
||||
def stringsAndFormatting : Node :=
|
||||
.section "strings-and-formatting" "Strings and formatting" #[]
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
@@ -1,26 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
import GroveStdlib.Std.LanguageConstructs.ComparisonOrderingHashing
|
||||
import GroveStdlib.Std.LanguageConstructs.Monads
|
||||
import GroveStdlib.Std.LanguageConstructs.RangesAndIterators
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std
|
||||
|
||||
namespace LanguageConstructs
|
||||
|
||||
end LanguageConstructs
|
||||
|
||||
def languageConstructs : Node :=
|
||||
.section "language-constructs" "Language constructs" #[
|
||||
LanguageConstructs.comparisonOrderingHashing,
|
||||
LanguageConstructs.monads,
|
||||
LanguageConstructs.rangesAndIterators
|
||||
]
|
||||
|
||||
end GroveStdlib.Std
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.LanguageConstructs
|
||||
|
||||
namespace ComparisonOrderingHashing
|
||||
|
||||
end ComparisonOrderingHashing
|
||||
|
||||
def comparisonOrderingHashing : Node :=
|
||||
.section "comparison-ordering-hashing" "Comparison, ordering, hashing" #[]
|
||||
|
||||
end GroveStdlib.Std.LanguageConstructs
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.LanguageConstructs
|
||||
|
||||
namespace Monads
|
||||
|
||||
end Monads
|
||||
|
||||
def monads : Node :=
|
||||
.section "monads" "Monads" #[]
|
||||
|
||||
end GroveStdlib.Std.LanguageConstructs
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.LanguageConstructs
|
||||
|
||||
namespace RangesAndIterators
|
||||
|
||||
end RangesAndIterators
|
||||
|
||||
def rangesAndIterators : Node :=
|
||||
.section "ranges-and-iterators" "Ranges and iterators" #[]
|
||||
|
||||
end GroveStdlib.Std.LanguageConstructs
|
||||
@@ -1,24 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
import GroveStdlib.Std.Libraries.DateAndTime
|
||||
import GroveStdlib.Std.Libraries.RandomNumbers
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std
|
||||
|
||||
namespace Libraries
|
||||
|
||||
end Libraries
|
||||
|
||||
def libraries : Node :=
|
||||
.section "libraries" "Libraries" #[
|
||||
Libraries.dateAndTime,
|
||||
Libraries.randomNumbers
|
||||
]
|
||||
|
||||
end GroveStdlib.Std
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.Libraries
|
||||
|
||||
namespace DateAndTime
|
||||
|
||||
end DateAndTime
|
||||
|
||||
def dateAndTime : Node :=
|
||||
.section "date-and-time" "Date and time" #[]
|
||||
|
||||
end GroveStdlib.Std.Libraries
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.Libraries
|
||||
|
||||
namespace RandomNumbers
|
||||
|
||||
end RandomNumbers
|
||||
|
||||
def randomNumbers : Node :=
|
||||
.section "random-numbers" "Random numbers" #[]
|
||||
|
||||
end GroveStdlib.Std.Libraries
|
||||
@@ -1,30 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions.AsynchronousIO
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions.BasicIO
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions.ConcurrencyAndParallelism
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions.EnvironmentFileSystemProcesses
|
||||
import GroveStdlib.Std.OperatingSystemAbstractions.Locales
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std
|
||||
|
||||
namespace OperatingSystemAbstractions
|
||||
|
||||
end OperatingSystemAbstractions
|
||||
|
||||
def operatingSystemAbstractions : Node :=
|
||||
.section "operating-system-abstractions" "Operating system abstractions" #[
|
||||
OperatingSystemAbstractions.asynchronousIO,
|
||||
OperatingSystemAbstractions.basicIO,
|
||||
OperatingSystemAbstractions.concurrencyAndParallelism,
|
||||
OperatingSystemAbstractions.environmentFileSystemProcesses,
|
||||
OperatingSystemAbstractions.locales
|
||||
]
|
||||
|
||||
end GroveStdlib.Std
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
namespace AsynchronousIO
|
||||
|
||||
end AsynchronousIO
|
||||
|
||||
def asynchronousIO : Node :=
|
||||
.section "asynchronous-io" "Asynchronous I/O" #[]
|
||||
|
||||
end GroveStdlib.Std.OperatingSystemAbstractions
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
namespace BasicIO
|
||||
|
||||
end BasicIO
|
||||
|
||||
def basicIO : Node :=
|
||||
.section "basic-io" "Basic I/O" #[]
|
||||
|
||||
end GroveStdlib.Std.OperatingSystemAbstractions
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
namespace ConcurrencyAndParallelism
|
||||
|
||||
end ConcurrencyAndParallelism
|
||||
|
||||
def concurrencyAndParallelism : Node :=
|
||||
.section "concurrency-and-parallelism" "Concurrency and parallelism" #[]
|
||||
|
||||
end GroveStdlib.Std.OperatingSystemAbstractions
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
namespace EnvironmentFileSystemProcesses
|
||||
|
||||
end EnvironmentFileSystemProcesses
|
||||
|
||||
def environmentFileSystemProcesses : Node :=
|
||||
.section "environment-filesystem-processes" "Environment, file system, processes" #[]
|
||||
|
||||
end GroveStdlib.Std.OperatingSystemAbstractions
|
||||
@@ -1,19 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import Grove.Framework
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Std.OperatingSystemAbstractions
|
||||
|
||||
namespace Locales
|
||||
|
||||
end Locales
|
||||
|
||||
def locales : Node :=
|
||||
.section "locales" "Locales" #[]
|
||||
|
||||
end GroveStdlib.Std.OperatingSystemAbstractions
|
||||
@@ -1,18 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
import GroveStdlib.Std
|
||||
import GroveStdlib.Generated
|
||||
|
||||
def config : Grove.Framework.Project.Configuration where
|
||||
projectNamespace := `GroveStdlib
|
||||
|
||||
def project : Grove.Framework.Project where
|
||||
config := config
|
||||
rootNode := GroveStdlib.std
|
||||
restoreState := GroveStdlib.Generated.restoreState
|
||||
|
||||
def main (args : List String) : IO UInt32 :=
|
||||
Grove.Framework.main project #[`Init, `Std, `Lean] args
|
||||
@@ -1,3 +0,0 @@
|
||||
# Standard library QA
|
||||
|
||||
This directory contains the [Grove](github.com/TwoFX/grove) data files for the standard library.
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
lake exe grove-stdlib --full metadata.json
|
||||
cd .lake/packages/grove/frontend
|
||||
npm install
|
||||
if [ -f "../../../../invalidated.json" ]; then
|
||||
GROVE_DATA_LOCATION=../../../../metadata.json GROVE_UPSTREAM_INVALIDATED_FACTS_LOCATION=../../../../invalidated.json npm run dev
|
||||
else
|
||||
GROVE_DATA_LOCATION=../../../../metadata.json npm run dev
|
||||
fi
|
||||
@@ -1,25 +0,0 @@
|
||||
{"version": "1.1.0",
|
||||
"packagesDir": ".lake/packages",
|
||||
"packages":
|
||||
[{"url": "https://github.com/TwoFx/grove.git",
|
||||
"type": "git",
|
||||
"subDir": "backend",
|
||||
"scope": "",
|
||||
"rev": "78110476d9c76abd4103d91a0ae3f89405558065",
|
||||
"name": "grove",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "master",
|
||||
"inherited": false,
|
||||
"configFile": "lakefile.toml"},
|
||||
{"url": "https://github.com/leanprover/lean4-cli",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover",
|
||||
"rev": "1604206fcd0462da9a241beeac0e2df471647435",
|
||||
"name": "Cli",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"}],
|
||||
"name": "grovestdlib",
|
||||
"lakeDir": ".lake"}
|
||||
@@ -1,18 +0,0 @@
|
||||
name = "grovestdlib"
|
||||
version = "0.1.0"
|
||||
defaultTargets = ["grove-stdlib"]
|
||||
|
||||
[[require]]
|
||||
name = "grove"
|
||||
git = "https://github.com/TwoFx/grove.git"
|
||||
rev = "master"
|
||||
subDir = "backend"
|
||||
|
||||
[[lean_lib]]
|
||||
name = "GroveStdlib"
|
||||
root = "GroveStdlib"
|
||||
|
||||
[[lean_exe]]
|
||||
name = "grove-stdlib"
|
||||
supportInterpreter = true
|
||||
root = "Main"
|
||||
@@ -1 +0,0 @@
|
||||
lean4
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
lake exe grove-stdlib --invalidated invalidated.json
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# We benchmark against stage 2 to test new optimizations.
|
||||
timeout -s KILL 1h time bash -c 'mkdir -p build/release; cd build/release; cmake ../.. && make -j$(nproc) stage2' 1>&2
|
||||
export PATH=$PWD/build/release/stage2/bin:$PATH
|
||||
cd tests/bench
|
||||
timeout -s KILL 1h time temci exec --config speedcenter.yaml --in speedcenter.exec.velcom.yaml 1>&2
|
||||
temci report run_output.yaml --reporter codespeed2
|
||||
@@ -5,11 +5,8 @@ set -euo pipefail
|
||||
|
||||
[ $# -eq 1 ] || (echo "usage: $0 <lean4 PR #>"; exit 1)
|
||||
|
||||
echo "Warning: the speedcenter is probably not listening on mathlib4-nightly-testing yet."
|
||||
echo "If you're using this script, please contact @kim-em or @Kha to get this set up, and then remove this notice."
|
||||
|
||||
LEAN_PR=$1
|
||||
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4-nightly-testing/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
|
||||
PR_RESPONSE=$(gh api repos/leanprover-community/mathlib4/pulls -X POST -f head=lean-pr-testing-$LEAN_PR -f base=nightly-testing -f title="leanprover/lean4#$LEAN_PR benchmarking" -f draft=true -f body="ignore me")
|
||||
PR_NUMBER=$(echo "$PR_RESPONSE" | jq '.number')
|
||||
echo "opened https://github.com/leanprover-community/mathlib4-nightly-testing/pull/$PR_NUMBER"
|
||||
gh api repos/leanprover-community/mathlib4-nightly-testing/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null
|
||||
echo "opened https://github.com/leanprover-community/mathlib4/pull/$PR_NUMBER"
|
||||
gh api repos/leanprover-community/mathlib4/issues/$PR_NUMBER/comments -X POST -f body="!bench" > /dev/null
|
||||
|
||||
@@ -50,4 +50,5 @@ echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='--sysroot ROOT -L ROOT/lib -Wl,-Bstatic
|
||||
# when not using the above flags, link GMP dynamically/as usual. Always link ICU dynamically.
|
||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp $(pkg-config --libs libuv) -lucrtbase'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"
|
||||
echo -n " -DLEAN_TEST_VARS=''"
|
||||
|
||||
@@ -53,23 +53,6 @@ def tag_exists(repo_url, tag_name, github_token):
|
||||
matching_tags = response.json()
|
||||
return any(tag["ref"] == f"refs/tags/{tag_name}" for tag in matching_tags)
|
||||
|
||||
def commit_hash_for_tag(repo_url, tag_name, github_token):
|
||||
# Use /git/matching-refs/tags/ to get all matching tags
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/git/matching-refs/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
# Check if any of the returned refs exactly match our tag
|
||||
matching_tags = response.json()
|
||||
matching_commits = [tag["object"]["sha"] for tag in matching_tags if tag["ref"] == f"refs/tags/{tag_name}"]
|
||||
if len(matching_commits) != 1:
|
||||
return None
|
||||
else:
|
||||
return matching_commits[0]
|
||||
|
||||
def release_page_exists(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/releases/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
@@ -303,14 +286,6 @@ def main():
|
||||
lean4_success = False
|
||||
else:
|
||||
print(f" ✅ Tag {toolchain} exists")
|
||||
commit_hash = commit_hash_for_tag(lean_repo_url, toolchain, github_token)
|
||||
SHORT_HASH_LENGTH = 7 # Lake abbreviates the Lean commit to 7 characters.
|
||||
if commit_hash is None:
|
||||
print(f" ❌ Could not resolve tag {toolchain} to a commit.")
|
||||
lean4_success = False
|
||||
elif commit_hash[0] == '0' and commit_hash[:SHORT_HASH_LENGTH].isnumeric():
|
||||
print(f" ❌ Short commit hash {commit_hash[:SHORT_HASH_LENGTH]} is numeric and starts with 0, causing issues for version parsing. Try regenerating the last commit to get a new hash.")
|
||||
lean4_success = False
|
||||
|
||||
if not release_page_exists(lean_repo_url, toolchain, github_token):
|
||||
print(f" ❌ Release page for {toolchain} does not exist")
|
||||
|
||||
@@ -94,7 +94,6 @@ def generate_script(repo, version, config):
|
||||
"echo 'This repo has nightly-testing infrastructure'",
|
||||
f"git merge origin/bump/{version.split('-rc')[0]}",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
"grep nightly-testing lakefile.* && echo 'Please ensure the lakefile does not include nightly-testing versions.'",
|
||||
""
|
||||
])
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 22)
|
||||
set(LEAN_VERSION_MINOR 21)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -58,6 +58,9 @@ option(USE_GITHASH "GIT_HASH" ON)
|
||||
option(INSTALL_LICENSE "INSTALL_LICENSE" ON)
|
||||
# When ON we install a copy of cadical
|
||||
option(INSTALL_CADICAL "Install a copy of cadical" ON)
|
||||
# When ON thread storage is automatically finalized, it assumes platform support pthreads.
|
||||
# This option is important when using Lean as library that is invoked from a different programming language (e.g., Haskell).
|
||||
option(AUTO_THREAD_FINALIZATION "AUTO_THREAD_FINALIZATION" ON)
|
||||
|
||||
# FLAGS for disabling optimizations and debugging
|
||||
option(FREE_VAR_RANGE_OPT "FREE_VAR_RANGE_OPT" ON)
|
||||
@@ -179,6 +182,10 @@ else()
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_MULTI_THREAD")
|
||||
endif()
|
||||
|
||||
if(AUTO_THREAD_FINALIZATION AND NOT MSVC)
|
||||
string(APPEND LEAN_EXTRA_CXX_FLAGS " -D LEAN_AUTO_THREAD_FINALIZATION")
|
||||
endif()
|
||||
|
||||
# Set Module Path
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import Init.Ext
|
||||
import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.GrindInstances
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
import Init.Internal
|
||||
|
||||
@@ -45,7 +45,7 @@ theorem em (p : Prop) : p ∨ ¬p :=
|
||||
| Or.inr h, _ => Or.inr h
|
||||
| _, Or.inr h => Or.inr h
|
||||
| Or.inl hut, Or.inl hvf =>
|
||||
have hne : u ≠ v := by simp [hvf, hut]
|
||||
have hne : u ≠ v := by simp [hvf, hut, true_ne_false]
|
||||
Or.inl hne
|
||||
have p_implies_uv : p → u = v :=
|
||||
fun hp =>
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Prelude
|
||||
meta import Init.Prelude
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
/-!
|
||||
|
||||
@@ -49,7 +49,7 @@ abbrev forIn_eq_forin' := @forIn_eq_forIn'
|
||||
/--
|
||||
Extracts the value from a `ForInStep`, ignoring whether it is `ForInStep.done` or `ForInStep.yield`.
|
||||
-/
|
||||
@[expose] def ForInStep.value (x : ForInStep α) : α :=
|
||||
def ForInStep.value (x : ForInStep α) : α :=
|
||||
match x with
|
||||
| ForInStep.done b => b
|
||||
| ForInStep.yield b => b
|
||||
|
||||
@@ -136,7 +136,7 @@ may throw the corresponding exception.
|
||||
|
||||
This is the inverse of `ExceptT.run`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def ExceptT.mk {ε : Type u} {m : Type u → Type v} {α : Type u} (x : m (Except ε α)) : ExceptT ε m α := x
|
||||
|
||||
/--
|
||||
@@ -144,7 +144,7 @@ Use a monadic action that may throw an exception as an action that may return an
|
||||
|
||||
This is the inverse of `ExceptT.mk`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def ExceptT.run {ε : Type u} {m : Type u → Type v} {α : Type u} (x : ExceptT ε m α) : m (Except ε α) := x
|
||||
|
||||
namespace ExceptT
|
||||
@@ -154,14 +154,14 @@ variable {ε : Type u} {m : Type u → Type v} [Monad m]
|
||||
/--
|
||||
Returns the value `a` without throwing exceptions or having any other effect.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def pure {α : Type u} (a : α) : ExceptT ε m α :=
|
||||
ExceptT.mk <| pure (Except.ok a)
|
||||
|
||||
/--
|
||||
Handles exceptions thrown by an action that can have no effects _other_ than throwing exceptions.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def bindCont {α β : Type u} (f : α → ExceptT ε m β) : Except ε α → m (Except ε β)
|
||||
| Except.ok a => f a
|
||||
| Except.error e => pure (Except.error e)
|
||||
@@ -170,14 +170,14 @@ protected def bindCont {α β : Type u} (f : α → ExceptT ε m β) : Except ε
|
||||
Sequences two actions that may throw exceptions. Typically used via `do`-notation or the `>>=`
|
||||
operator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def bind {α β : Type u} (ma : ExceptT ε m α) (f : α → ExceptT ε m β) : ExceptT ε m β :=
|
||||
ExceptT.mk <| ma >>= ExceptT.bindCont f
|
||||
|
||||
/--
|
||||
Transforms a successful computation's value using `f`. Typically used via the `<$>` operator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def map {α β : Type u} (f : α → β) (x : ExceptT ε m α) : ExceptT ε m β :=
|
||||
ExceptT.mk <| x >>= fun a => match a with
|
||||
| (Except.ok a) => pure <| Except.ok (f a)
|
||||
@@ -186,7 +186,7 @@ protected def map {α β : Type u} (f : α → β) (x : ExceptT ε m α) : Excep
|
||||
/--
|
||||
Runs a computation from an underlying monad in the transformed monad with exceptions.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def lift {α : Type u} (t : m α) : ExceptT ε m α :=
|
||||
ExceptT.mk <| Except.ok <$> t
|
||||
|
||||
@@ -197,7 +197,7 @@ instance : MonadLift m (ExceptT ε m) := ⟨ExceptT.lift⟩
|
||||
/--
|
||||
Handles exceptions produced in the `ExceptT ε` transformer.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def tryCatch {α : Type u} (ma : ExceptT ε m α) (handle : ε → ExceptT ε m α) : ExceptT ε m α :=
|
||||
ExceptT.mk <| ma >>= fun res => match res with
|
||||
| Except.ok a => pure (Except.ok a)
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace ExceptCpsT
|
||||
/--
|
||||
Use a monadic action that may throw an exception as an action that may return an exception's value.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def run {ε α : Type u} [Monad m] (x : ExceptCpsT ε m α) : m (Except ε α) :=
|
||||
x _ (fun a => pure (Except.ok a)) (fun e => pure (Except.error e))
|
||||
|
||||
@@ -43,7 +43,7 @@ Returns the value of a computation, forgetting whether it was an exception or a
|
||||
|
||||
This corresponds to early return.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def runCatch [Monad m] (x : ExceptCpsT α m α) : m α :=
|
||||
x α pure pure
|
||||
|
||||
@@ -63,7 +63,7 @@ instance : MonadExceptOf ε (ExceptCpsT ε m) where
|
||||
/--
|
||||
Run an action from the transformed monad in the exception monad.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def lift [Monad m] (x : m α) : ExceptCpsT ε m α :=
|
||||
fun _ k _ => x >>= k
|
||||
|
||||
|
||||
@@ -62,7 +62,4 @@ protected def run (x : Id α) : α := x
|
||||
instance [OfNat α n] : OfNat (Id α) n :=
|
||||
inferInstanceAs (OfNat α n)
|
||||
|
||||
instance {m : Type u → Type v} [Pure m] : MonadLiftT Id m where
|
||||
monadLift x := pure x.run
|
||||
|
||||
end Id
|
||||
|
||||
@@ -9,4 +9,3 @@ prelude
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Control.Lawful.Instances
|
||||
import Init.Control.Lawful.Lemmas
|
||||
import Init.Control.Lawful.MonadLift
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Ext
|
||||
import Init.SimpLemmas
|
||||
import Init.Meta
|
||||
|
||||
@@ -50,7 +49,7 @@ attribute [simp] id_map
|
||||
(comp_map _ _ _).symm
|
||||
|
||||
theorem Functor.map_unit [Functor f] [LawfulFunctor f] {a : f PUnit} : (fun _ => PUnit.unit) <$> a = a := by
|
||||
simp
|
||||
simp [map]
|
||||
|
||||
/--
|
||||
An applicative functor satisfies the laws of an applicative functor.
|
||||
@@ -148,7 +147,7 @@ attribute [simp] pure_bind bind_assoc bind_pure_comp
|
||||
attribute [grind] pure_bind
|
||||
|
||||
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
|
||||
change x >>= (fun a => pure (id a)) = x
|
||||
show x >>= (fun a => pure (id a)) = x
|
||||
rw [bind_pure_comp, id_map]
|
||||
|
||||
/--
|
||||
@@ -242,23 +241,13 @@ theorem LawfulMonad.mk' (m : Type u → Type v) [Monad m]
|
||||
|
||||
namespace Id
|
||||
|
||||
@[ext] theorem ext {x y : Id α} (h : x.run = y.run) : x = y := h
|
||||
@[simp] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[simp] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
|
||||
instance : LawfulMonad Id := by
|
||||
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||
|
||||
@[simp] theorem run_map (x : Id α) (f : α → β) : (f <$> x).run = f x.run := rfl
|
||||
@[simp] theorem run_bind (x : Id α) (f : α → Id β) : (x >>= f).run = (f x.run).run := rfl
|
||||
@[simp] theorem run_pure (a : α) : (pure a : Id α).run = a := rfl
|
||||
@[simp] theorem run_seqRight (x y : Id α) : (x *> y).run = y.run := rfl
|
||||
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
|
||||
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
|
||||
|
||||
-- These lemmas are bad as they abuse the defeq of `Id α` and `α`
|
||||
@[deprecated run_map (since := "2025-03-05")] theorem map_eq (x : Id α) (f : α → β) : f <$> x = f x := rfl
|
||||
@[deprecated run_bind (since := "2025-03-05")] theorem bind_eq (x : Id α) (f : α → id β) : x >>= f = f x := rfl
|
||||
@[deprecated run_pure (since := "2025-03-05")] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||
|
||||
end Id
|
||||
|
||||
/-! # Option -/
|
||||
|
||||
@@ -58,7 +58,7 @@ protected theorem bind_pure_comp [Monad m] (f : α → β) (x : ExceptT ε m α)
|
||||
intros; rfl
|
||||
|
||||
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
|
||||
change (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
|
||||
show (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
|
||||
rw [← ExceptT.bind_pure_comp]
|
||||
apply ext
|
||||
simp [run_bind]
|
||||
@@ -67,10 +67,10 @@ protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad
|
||||
| Except.error _ => simp
|
||||
| Except.ok _ =>
|
||||
simp [←bind_pure_comp]; apply bind_congr; intro b;
|
||||
cases b <;> simp [Except.map, const]
|
||||
cases b <;> simp [comp, Except.map, const]
|
||||
|
||||
protected theorem seqRight_eq [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x *> y = const α id <$> x <*> y := by
|
||||
change (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
|
||||
show (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
|
||||
rw [← ExceptT.bind_pure_comp]
|
||||
apply ext
|
||||
simp [run_bind]
|
||||
@@ -206,15 +206,15 @@ theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f :
|
||||
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||
change (f >>= fun g => g <$> x).run s = _
|
||||
show (f >>= fun g => g <$> x).run s = _
|
||||
simp
|
||||
|
||||
@[simp] theorem run_seqRight [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
|
||||
change (x >>= fun _ => y).run s = _
|
||||
show (x >>= fun _ => y).run s = _
|
||||
simp
|
||||
|
||||
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
|
||||
change (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||
show (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||
simp
|
||||
|
||||
theorem seqRight_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x *> y = const α id <$> x <*> y := by
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Control.Lawful.MonadLift.Basic
|
||||
import Init.Control.Lawful.MonadLift.Lemmas
|
||||
import Init.Control.Lawful.MonadLift.Instances
|
||||
@@ -1,52 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Quang Dao. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Quang Dao
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Control.Basic
|
||||
|
||||
/-!
|
||||
# LawfulMonadLift and LawfulMonadLiftT
|
||||
|
||||
This module provides classes asserting that `MonadLift` and `MonadLiftT` are lawful, which means
|
||||
that `monadLift` is compatible with `pure` and `bind`.
|
||||
-/
|
||||
|
||||
section MonadLift
|
||||
|
||||
/-- The `MonadLift` typeclass only contains the lifting operation. `LawfulMonadLift` further
|
||||
asserts that lifting commutes with `pure` and `bind`:
|
||||
```
|
||||
monadLift (pure a) = pure a
|
||||
monadLift (ma >>= f) = monadLift ma >>= monadLift ∘ f
|
||||
```
|
||||
-/
|
||||
class LawfulMonadLift (m : semiOutParam (Type u → Type v)) (n : Type u → Type w)
|
||||
[Monad m] [Monad n] [inst : MonadLift m n] : Prop where
|
||||
/-- Lifting preserves `pure` -/
|
||||
monadLift_pure {α : Type u} (a : α) : inst.monadLift (pure a) = pure a
|
||||
/-- Lifting preserves `bind` -/
|
||||
monadLift_bind {α β : Type u} (ma : m α) (f : α → m β) :
|
||||
inst.monadLift (ma >>= f) = inst.monadLift ma >>= (fun x => inst.monadLift (f x))
|
||||
|
||||
/-- The `MonadLiftT` typeclass only contains the transitive lifting operation.
|
||||
`LawfulMonadLiftT` further asserts that lifting commutes with `pure` and `bind`:
|
||||
```
|
||||
monadLift (pure a) = pure a
|
||||
monadLift (ma >>= f) = monadLift ma >>= monadLift ∘ f
|
||||
```
|
||||
-/
|
||||
class LawfulMonadLiftT (m : Type u → Type v) (n : Type u → Type w) [Monad m] [Monad n]
|
||||
[inst : MonadLiftT m n] : Prop where
|
||||
/-- Lifting preserves `pure` -/
|
||||
monadLift_pure {α : Type u} (a : α) : inst.monadLift (pure a) = pure a
|
||||
/-- Lifting preserves `bind` -/
|
||||
monadLift_bind {α β : Type u} (ma : m α) (f : α → m β) :
|
||||
inst.monadLift (ma >>= f) = monadLift ma >>= (fun x => monadLift (f x))
|
||||
|
||||
export LawfulMonadLiftT (monadLift_pure monadLift_bind)
|
||||
|
||||
end MonadLift
|
||||
@@ -1,146 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Quang Dao. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Quang Dao, Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import all Init.Control.Option
|
||||
import all Init.Control.Except
|
||||
import all Init.Control.ExceptCps
|
||||
import all Init.Control.StateRef
|
||||
import all Init.Control.StateCps
|
||||
import all Init.Control.Id
|
||||
import Init.Control.Lawful.MonadLift.Lemmas
|
||||
import Init.Control.Lawful.Instances
|
||||
|
||||
universe u v w x
|
||||
|
||||
variable {m : Type u → Type v} {n : Type u → Type w} {o : Type u → Type x}
|
||||
|
||||
variable (m n o) in
|
||||
instance [Monad m] [Monad n] [Monad o] [MonadLift n o] [MonadLiftT m n]
|
||||
[LawfulMonadLift n o] [LawfulMonadLiftT m n] : LawfulMonadLiftT m o where
|
||||
monadLift_pure := fun a => by
|
||||
simp only [monadLift, LawfulMonadLift.monadLift_pure, liftM_pure]
|
||||
monadLift_bind := fun ma f => by
|
||||
simp only [monadLift, LawfulMonadLift.monadLift_bind, liftM_bind]
|
||||
|
||||
variable (m) in
|
||||
instance [Monad m] : LawfulMonadLiftT m m where
|
||||
monadLift_pure _ := rfl
|
||||
monadLift_bind _ _ := rfl
|
||||
|
||||
namespace StateT
|
||||
|
||||
variable [Monad m] [LawfulMonad m]
|
||||
|
||||
instance {σ : Type u} : LawfulMonadLift m (StateT σ m) where
|
||||
monadLift_pure _ := by ext; simp [MonadLift.monadLift]
|
||||
monadLift_bind _ _ := by ext; simp [MonadLift.monadLift]
|
||||
|
||||
end StateT
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
variable [Monad m]
|
||||
|
||||
instance {ρ : Type u} : LawfulMonadLift m (ReaderT ρ m) where
|
||||
monadLift_pure _ := rfl
|
||||
monadLift_bind _ _ := rfl
|
||||
|
||||
end ReaderT
|
||||
|
||||
namespace OptionT
|
||||
|
||||
variable [Monad m] [LawfulMonad m]
|
||||
|
||||
@[simp]
|
||||
theorem lift_pure {α : Type u} (a : α) : OptionT.lift (pure a : m α) = pure a := by
|
||||
simp only [OptionT.lift, OptionT.mk, bind_pure_comp, map_pure, pure, OptionT.pure]
|
||||
|
||||
@[simp]
|
||||
theorem lift_bind {α β : Type u} (ma : m α) (f : α → m β) :
|
||||
OptionT.lift (ma >>= f) = OptionT.lift ma >>= (fun a => OptionT.lift (f a)) := by
|
||||
simp only [instMonad, OptionT.bind, OptionT.mk, OptionT.lift, bind_pure_comp, bind_map_left,
|
||||
map_bind]
|
||||
|
||||
instance : LawfulMonadLift m (OptionT m) where
|
||||
monadLift_pure := lift_pure
|
||||
monadLift_bind := lift_bind
|
||||
|
||||
end OptionT
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
variable [Monad m] [LawfulMonad m]
|
||||
|
||||
@[simp]
|
||||
theorem lift_bind {α β ε : Type u} (ma : m α) (f : α → m β) :
|
||||
ExceptT.lift (ε := ε) (ma >>= f) = ExceptT.lift ma >>= (fun a => ExceptT.lift (f a)) := by
|
||||
simp only [instMonad, ExceptT.bind, mk, ExceptT.lift, bind_map_left, ExceptT.bindCont, map_bind]
|
||||
|
||||
instance : LawfulMonadLift m (ExceptT ε m) where
|
||||
monadLift_pure := lift_pure
|
||||
monadLift_bind := lift_bind
|
||||
|
||||
instance : LawfulMonadLift (Except ε) (ExceptT ε m) where
|
||||
monadLift_pure _ := by
|
||||
simp only [MonadLift.monadLift, mk, pure, Except.pure, ExceptT.pure]
|
||||
monadLift_bind ma _ := by
|
||||
simp only [instMonad, ExceptT.bind, mk, MonadLift.monadLift, pure_bind, ExceptT.bindCont,
|
||||
Except.instMonad, Except.bind]
|
||||
rcases ma with _ | _ <;> simp
|
||||
|
||||
end ExceptT
|
||||
|
||||
namespace StateRefT'
|
||||
|
||||
instance {ω σ : Type} {m : Type → Type} [Monad m] : LawfulMonadLift m (StateRefT' ω σ m) where
|
||||
monadLift_pure _ := by
|
||||
simp only [MonadLift.monadLift, pure]
|
||||
unfold StateRefT'.lift ReaderT.pure
|
||||
simp only
|
||||
monadLift_bind _ _ := by
|
||||
simp only [MonadLift.monadLift, bind]
|
||||
unfold StateRefT'.lift ReaderT.bind
|
||||
simp only
|
||||
|
||||
end StateRefT'
|
||||
|
||||
namespace StateCpsT
|
||||
|
||||
instance {σ : Type u} [Monad m] [LawfulMonad m] : LawfulMonadLift m (StateCpsT σ m) where
|
||||
monadLift_pure _ := by
|
||||
simp only [MonadLift.monadLift, pure]
|
||||
unfold StateCpsT.lift
|
||||
simp only [pure_bind]
|
||||
monadLift_bind _ _ := by
|
||||
simp only [MonadLift.monadLift, bind]
|
||||
unfold StateCpsT.lift
|
||||
simp only [bind_assoc]
|
||||
|
||||
end StateCpsT
|
||||
|
||||
namespace ExceptCpsT
|
||||
|
||||
instance {ε : Type u} [Monad m] [LawfulMonad m] : LawfulMonadLift m (ExceptCpsT ε m) where
|
||||
monadLift_pure _ := by
|
||||
simp only [MonadLift.monadLift, pure]
|
||||
unfold ExceptCpsT.lift
|
||||
simp only [pure_bind]
|
||||
monadLift_bind _ _ := by
|
||||
simp only [MonadLift.monadLift, bind]
|
||||
unfold ExceptCpsT.lift
|
||||
simp only [bind_assoc]
|
||||
|
||||
end ExceptCpsT
|
||||
|
||||
namespace Id
|
||||
|
||||
instance [Monad m] [LawfulMonad m] : LawfulMonadLiftT Id m where
|
||||
monadLift_pure a := by simp [monadLift]
|
||||
monadLift_bind a f := by simp [monadLift]
|
||||
|
||||
end Id
|
||||
@@ -1,63 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Quang Dao. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Quang Dao
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Control.Lawful.MonadLift.Basic
|
||||
|
||||
universe u v w
|
||||
|
||||
variable {m : Type u → Type v} {n : Type u → Type w} [Monad m] [Monad n] [MonadLiftT m n]
|
||||
[LawfulMonadLiftT m n] {α β : Type u}
|
||||
|
||||
theorem monadLift_map [LawfulMonad m] [LawfulMonad n] (f : α → β) (ma : m α) :
|
||||
monadLift (f <$> ma) = f <$> (monadLift ma : n α) := by
|
||||
rw [← bind_pure_comp, ← bind_pure_comp, monadLift_bind]
|
||||
simp only [bind_pure_comp, monadLift_pure]
|
||||
|
||||
theorem monadLift_seq [LawfulMonad m] [LawfulMonad n] (mf : m (α → β)) (ma : m α) :
|
||||
monadLift (mf <*> ma) = monadLift mf <*> (monadLift ma : n α) := by
|
||||
simp only [seq_eq_bind, monadLift_map, monadLift_bind]
|
||||
|
||||
theorem monadLift_seqLeft [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
|
||||
monadLift (x <* y) = (monadLift x : n α) <* (monadLift y : n β) := by
|
||||
simp only [seqLeft_eq, monadLift_map, monadLift_seq]
|
||||
|
||||
theorem monadLift_seqRight [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
|
||||
monadLift (x *> y) = (monadLift x : n α) *> (monadLift y : n β) := by
|
||||
simp only [seqRight_eq, monadLift_map, monadLift_seq]
|
||||
|
||||
/-! We duplicate the theorems for `monadLift` to `liftM` since `rw` matches on syntax only. -/
|
||||
|
||||
@[simp]
|
||||
theorem liftM_pure (a : α) : liftM (pure a : m α) = pure (f := n) a :=
|
||||
monadLift_pure _
|
||||
|
||||
@[simp]
|
||||
theorem liftM_bind (ma : m α) (f : α → m β) :
|
||||
liftM (n := n) (ma >>= f) = liftM ma >>= (fun a => liftM (f a)) :=
|
||||
monadLift_bind _ _
|
||||
|
||||
@[simp]
|
||||
theorem liftM_map [LawfulMonad m] [LawfulMonad n] (f : α → β) (ma : m α) :
|
||||
liftM (f <$> ma) = f <$> (liftM ma : n α) :=
|
||||
monadLift_map _ _
|
||||
|
||||
@[simp]
|
||||
theorem liftM_seq [LawfulMonad m] [LawfulMonad n] (mf : m (α → β)) (ma : m α) :
|
||||
liftM (mf <*> ma) = liftM mf <*> (liftM ma : n α) :=
|
||||
monadLift_seq _ _
|
||||
|
||||
@[simp]
|
||||
theorem liftM_seqLeft [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
|
||||
liftM (x <* y) = (liftM x : n α) <* (liftM y : n β) :=
|
||||
monadLift_seqLeft _ _
|
||||
|
||||
@[simp]
|
||||
theorem liftM_seqRight [LawfulMonad m] [LawfulMonad n] (x : m α) (y : m β) :
|
||||
liftM (x *> y) = (liftM x : n α) *> (liftM y : n β) :=
|
||||
monadLift_seqRight _ _
|
||||
@@ -29,7 +29,7 @@ of a value and a state.
|
||||
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
|
||||
state, it returns a value paired with the final state.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def StateT.run {σ : Type u} {m : Type u → Type v} {α : Type u} (x : StateT σ m α) (s : σ) : m (α × σ) :=
|
||||
x s
|
||||
|
||||
@@ -37,7 +37,7 @@ def StateT.run {σ : Type u} {m : Type u → Type v} {α : Type u} (x : StateT
|
||||
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
|
||||
state, it returns a value, discarding the final state.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def StateT.run' {σ : Type u} {m : Type u → Type v} [Functor m] {α : Type u} (x : StateT σ m α) (s : σ) : m α :=
|
||||
(·.1) <$> x s
|
||||
|
||||
@@ -66,21 +66,21 @@ variable [Monad m] {α β : Type u}
|
||||
/--
|
||||
Returns the given value without modifying the state. Typically used via `Pure.pure`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def pure (a : α) : StateT σ m α :=
|
||||
fun s => pure (a, s)
|
||||
|
||||
/--
|
||||
Sequences two actions. Typically used via the `>>=` operator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def bind (x : StateT σ m α) (f : α → StateT σ m β) : StateT σ m β :=
|
||||
fun s => do let (a, s) ← x s; f a s
|
||||
|
||||
/--
|
||||
Modifies the value returned by a computation. Typically used via the `<$>` operator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def map (f : α → β) (x : StateT σ m α) : StateT σ m β :=
|
||||
fun s => do let (a, s) ← x s; pure (f a, s)
|
||||
|
||||
@@ -114,14 +114,14 @@ Retrieves the current value of the monad's mutable state.
|
||||
|
||||
This increments the reference count of the state, which may inhibit in-place updates.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def get : StateT σ m σ :=
|
||||
fun s => pure (s, s)
|
||||
|
||||
/--
|
||||
Replaces the mutable state with a new value.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def set : σ → StateT σ m PUnit :=
|
||||
fun s' _ => pure (⟨⟩, s')
|
||||
|
||||
@@ -133,7 +133,7 @@ It is equivalent to `do let (a, s) := f (← StateT.get); StateT.set s; pure a`.
|
||||
`StateT.modifyGet` may lead to better performance because it doesn't add a new reference to the
|
||||
state value, and additional references can inhibit in-place updates of data.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def modifyGet (f : σ → α × σ) : StateT σ m α :=
|
||||
fun s => pure (f s)
|
||||
|
||||
@@ -143,7 +143,7 @@ Runs an action from the underlying monad in the monad with state. The state is n
|
||||
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
|
||||
lifting](lean-manual://section/monad-lifting).
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def lift {α : Type u} (t : m α) : StateT σ m α :=
|
||||
fun s => do let a ← t; pure (a, s)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ variable {α σ : Type u} {m : Type u → Type v}
|
||||
Runs a stateful computation that's represented using continuation passing style by providing it with
|
||||
an initial state and a continuation.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def runK (x : StateCpsT σ m α) (s : σ) (k : α → σ → m β) : m β :=
|
||||
x _ s k
|
||||
|
||||
@@ -39,7 +39,7 @@ state, it returns a value paired with the final state.
|
||||
While the state is internally represented in continuation passing style, the resulting value is the
|
||||
same as for a non-CPS state monad.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
||||
runK x s (fun a s => pure (a, s))
|
||||
|
||||
@@ -47,7 +47,7 @@ def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
||||
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
|
||||
state, it returns a value, discarding the final state.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
|
||||
runK x s (fun a _ => pure a)
|
||||
|
||||
@@ -72,7 +72,7 @@ Runs an action from the underlying monad in the monad with state. The state is n
|
||||
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
|
||||
lifting](lean-manual://section/monad-lifting).
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline]
|
||||
protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
|
||||
fun _ s k => x >>= (k . s)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Tactics
|
||||
meta import Init.Meta
|
||||
import Init.Meta
|
||||
|
||||
namespace Lean.Parser.Tactic.Conv
|
||||
|
||||
@@ -339,12 +339,6 @@ This is the conv mode version of the `lift_lets` tactic.
|
||||
-/
|
||||
syntax (name := liftLets) "lift_lets " optConfig : conv
|
||||
|
||||
/--
|
||||
Transforms `let` expressions into `have` expressions within th etarget expression when possible.
|
||||
This is the conv mode version of the `let_to_have` tactic.
|
||||
-/
|
||||
syntax (name := letToHave) "let_to_have" : conv
|
||||
|
||||
/--
|
||||
`conv => ...` allows the user to perform targeted rewriting on a goal or hypothesis,
|
||||
by focusing on particular subexpressions.
|
||||
|
||||
@@ -8,7 +8,7 @@ notation, basic datatypes and type classes
|
||||
module
|
||||
|
||||
prelude
|
||||
meta import Init.Prelude
|
||||
import Init.Prelude
|
||||
import Init.SizeOf
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
@@ -43,14 +43,14 @@ and `flip (·<·)` is the greater-than relation.
|
||||
theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g = fun x => f (g x) := rfl
|
||||
|
||||
@[simp] theorem Function.const_comp {f : α → β} {c : γ} :
|
||||
(Function.const β c ∘ f) = Function.const α c :=
|
||||
(Function.const β c ∘ f) = Function.const α c := by
|
||||
rfl
|
||||
@[simp] theorem Function.comp_const {f : β → γ} {b : β} :
|
||||
(f ∘ Function.const α b) = Function.const α (f b) :=
|
||||
(f ∘ Function.const α b) = Function.const α (f b) := by
|
||||
rfl
|
||||
@[simp] theorem Function.true_comp {f : α → β} : ((fun _ => true) ∘ f) = fun _ => true :=
|
||||
@[simp] theorem Function.true_comp {f : α → β} : ((fun _ => true) ∘ f) = fun _ => true := by
|
||||
rfl
|
||||
@[simp] theorem Function.false_comp {f : α → β} : ((fun _ => false) ∘ f) = fun _ => false :=
|
||||
@[simp] theorem Function.false_comp {f : α → β} : ((fun _ => false) ∘ f) = fun _ => false := by
|
||||
rfl
|
||||
|
||||
@[simp] theorem Function.comp_id (f : α → β) : f ∘ id = f := rfl
|
||||
@@ -95,8 +95,7 @@ structure Thunk (α : Type u) : Type u where
|
||||
-/
|
||||
mk ::
|
||||
/-- Extract the getter function out of a thunk. Use `Thunk.get` instead. -/
|
||||
-- The field is public so as to allow computation through it.
|
||||
fn : Unit → α
|
||||
private fn : Unit → α
|
||||
|
||||
attribute [extern "lean_mk_thunk"] Thunk.mk
|
||||
|
||||
@@ -118,10 +117,6 @@ Computed values are cached, so the value is not recomputed.
|
||||
@[extern "lean_thunk_get_own"] protected def Thunk.get (x : @& Thunk α) : α :=
|
||||
x.fn ()
|
||||
|
||||
-- Ensure `Thunk.fn` is still computable even if it shouldn't be accessed directly.
|
||||
@[inline] private def Thunk.fnImpl (x : Thunk α) : Unit → α := fun _ => x.get
|
||||
@[csimp] private theorem Thunk.fn_eq_fnImpl : @Thunk.fn = @Thunk.fnImpl := rfl
|
||||
|
||||
/--
|
||||
Constructs a new thunk that forces `x` and then applies `x` to the result. Upon forcing, the result
|
||||
of `f` is cached and the reference to the thunk `x` is dropped.
|
||||
@@ -902,43 +897,43 @@ section
|
||||
variable {α β φ : Sort u} {a a' : α} {b b' : β} {c : φ}
|
||||
|
||||
/-- Non-dependent recursor for `HEq` -/
|
||||
noncomputable def HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : a ≍ b) : motive b :=
|
||||
noncomputable def HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : HEq a b) : motive b :=
|
||||
h.rec m
|
||||
|
||||
/-- `HEq.ndrec` variant -/
|
||||
noncomputable def HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} {β : Sort u2} {b : β} (h : a ≍ b) (m : motive a) : motive b :=
|
||||
noncomputable def HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} {β : Sort u2} {b : β} (h : HEq a b) (m : motive a) : motive b :=
|
||||
h.rec m
|
||||
|
||||
/-- `HEq.ndrec` variant -/
|
||||
noncomputable def HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : a ≍ b) (h₂ : p a) : p b :=
|
||||
noncomputable def HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : HEq a b) (h₂ : p a) : p b :=
|
||||
eq_of_heq h₁ ▸ h₂
|
||||
|
||||
/-- Substitution with heterogeneous equality. -/
|
||||
theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : a ≍ b) (h₂ : p α a) : p β b :=
|
||||
theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b :=
|
||||
HEq.ndrecOn h₁ h₂
|
||||
|
||||
/-- Heterogeneous equality is symmetric. -/
|
||||
@[symm] theorem HEq.symm (h : a ≍ b) : b ≍ a :=
|
||||
@[symm] theorem HEq.symm (h : HEq a b) : HEq b a :=
|
||||
h.rec (HEq.refl a)
|
||||
|
||||
/-- Propositionally equal terms are also heterogeneously equal. -/
|
||||
theorem heq_of_eq (h : a = a') : a ≍ a' :=
|
||||
theorem heq_of_eq (h : a = a') : HEq a a' :=
|
||||
Eq.subst h (HEq.refl a)
|
||||
|
||||
/-- Heterogeneous equality is transitive. -/
|
||||
theorem HEq.trans (h₁ : a ≍ b) (h₂ : b ≍ c) : a ≍ c :=
|
||||
theorem HEq.trans (h₁ : HEq a b) (h₂ : HEq b c) : HEq a c :=
|
||||
HEq.subst h₂ h₁
|
||||
|
||||
/-- Heterogeneous equality precomposes with propositional equality. -/
|
||||
theorem heq_of_heq_of_eq (h₁ : a ≍ b) (h₂ : b = b') : a ≍ b' :=
|
||||
theorem heq_of_heq_of_eq (h₁ : HEq a b) (h₂ : b = b') : HEq a b' :=
|
||||
HEq.trans h₁ (heq_of_eq h₂)
|
||||
|
||||
/-- Heterogeneous equality postcomposes with propositional equality. -/
|
||||
theorem heq_of_eq_of_heq (h₁ : a = a') (h₂ : a' ≍ b) : a ≍ b :=
|
||||
theorem heq_of_eq_of_heq (h₁ : a = a') (h₂ : HEq a' b) : HEq a b :=
|
||||
HEq.trans (heq_of_eq h₁) h₂
|
||||
|
||||
/-- If two terms are heterogeneously equal then their types are propositionally equal. -/
|
||||
theorem type_eq_of_heq (h : a ≍ b) : α = β :=
|
||||
theorem type_eq_of_heq (h : HEq a b) : α = β :=
|
||||
h.rec (Eq.refl α)
|
||||
|
||||
end
|
||||
@@ -947,7 +942,7 @@ end
|
||||
Rewriting inside `φ` using `Eq.recOn` yields a term that's heterogeneously equal to the original
|
||||
term.
|
||||
-/
|
||||
theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → Eq.recOn (motive := fun x _ => φ x) h p ≍ p
|
||||
theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → HEq (Eq.recOn (motive := fun x _ => φ x) h p) p
|
||||
| rfl, p => HEq.refl p
|
||||
|
||||
/--
|
||||
@@ -955,8 +950,8 @@ Heterogeneous equality with an `Eq.rec` application on the left is equivalent to
|
||||
equality on the original term.
|
||||
-/
|
||||
theorem eqRec_heq_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v}
|
||||
{b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h}
|
||||
: @Eq.rec α a motive refl b h ≍ c ↔ refl ≍ c :=
|
||||
{b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} :
|
||||
HEq (@Eq.rec α a motive refl b h) c ↔ HEq refl c :=
|
||||
h.rec (fun _ => ⟨id, id⟩) c
|
||||
|
||||
/--
|
||||
@@ -965,7 +960,7 @@ equality on the original term.
|
||||
-/
|
||||
theorem heq_eqRec_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v}
|
||||
{b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} :
|
||||
c ≍ @Eq.rec α a motive refl b h ↔ c ≍ refl :=
|
||||
HEq c (@Eq.rec α a motive refl b h) ↔ HEq c refl :=
|
||||
h.rec (fun _ => ⟨id, id⟩) c
|
||||
|
||||
/--
|
||||
@@ -982,7 +977,7 @@ theorem apply_eqRec {α : Sort u} {a : α} (motive : (b : α) → a = b → Sort
|
||||
If casting a term with `Eq.rec` to another type makes it equal to some other term, then the two
|
||||
terms are heterogeneously equal.
|
||||
-/
|
||||
theorem heq_of_eqRec_eq {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : Eq.rec (motive := fun α _ => α) a h₁ = b) : a ≍ b := by
|
||||
theorem heq_of_eqRec_eq {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : Eq.rec (motive := fun α _ => α) a h₁ = b) : HEq a b := by
|
||||
subst h₁
|
||||
apply heq_of_eq
|
||||
exact h₂
|
||||
@@ -990,7 +985,7 @@ theorem heq_of_eqRec_eq {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h
|
||||
/--
|
||||
The result of casting a term with `cast` is heterogeneously equal to the original term.
|
||||
-/
|
||||
theorem cast_heq {α β : Sort u} : (h : α = β) → (a : α) → cast h a ≍ a
|
||||
theorem cast_heq {α β : Sort u} : (h : α = β) → (a : α) → HEq (cast h a) a
|
||||
| rfl, a => HEq.refl a
|
||||
|
||||
variable {a b c d : Prop}
|
||||
@@ -1019,8 +1014,8 @@ instance : Trans Iff Iff Iff where
|
||||
theorem Eq.comm {a b : α} : a = b ↔ b = a := Iff.intro Eq.symm Eq.symm
|
||||
theorem eq_comm {a b : α} : a = b ↔ b = a := Eq.comm
|
||||
|
||||
theorem HEq.comm {a : α} {b : β} : a ≍ b ↔ b ≍ a := Iff.intro HEq.symm HEq.symm
|
||||
theorem heq_comm {a : α} {b : β} : a ≍ b ↔ b ≍ a := HEq.comm
|
||||
theorem HEq.comm {a : α} {b : β} : HEq a b ↔ HEq b a := Iff.intro HEq.symm HEq.symm
|
||||
theorem heq_comm {a : α} {b : β} : HEq a b ↔ HEq b a := HEq.comm
|
||||
|
||||
@[symm] theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp
|
||||
theorem Iff.comm : (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm
|
||||
@@ -1053,6 +1048,11 @@ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
|
||||
| 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)
|
||||
@@ -1239,7 +1239,7 @@ protected theorem Subsingleton.elim {α : Sort u} [h : Subsingleton α] : (a b :
|
||||
If two types are equal and one of them is a subsingleton, then all of their elements are
|
||||
[heterogeneously equal](lean-manual://section/HEq).
|
||||
-/
|
||||
protected theorem Subsingleton.helim {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : a ≍ b := by
|
||||
protected theorem Subsingleton.helim {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : HEq a b := by
|
||||
subst h₂
|
||||
apply heq_of_eq
|
||||
apply Subsingleton.elim
|
||||
@@ -1690,7 +1690,7 @@ theorem true_iff_false : (True ↔ False) ↔ False := iff_false_intro (·.mp T
|
||||
theorem false_iff_true : (False ↔ True) ↔ False := iff_false_intro (·.mpr True.intro)
|
||||
|
||||
theorem iff_not_self : ¬(a ↔ ¬a) | H => let f h := H.1 h h; f (H.2 f)
|
||||
theorem heq_self_iff_true (a : α) : a ≍ a ↔ True := iff_true_intro HEq.rfl
|
||||
theorem heq_self_iff_true (a : α) : HEq a a ↔ True := iff_true_intro HEq.rfl
|
||||
|
||||
/-! ## implies -/
|
||||
|
||||
@@ -1890,7 +1890,7 @@ a structure.
|
||||
protected abbrev hrecOn
|
||||
(q : Quot r)
|
||||
(f : (a : α) → motive (Quot.mk r a))
|
||||
(c : (a b : α) → (p : r a b) → f a ≍ f b)
|
||||
(c : (a b : α) → (p : r a b) → HEq (f a) (f b))
|
||||
: motive q :=
|
||||
Quot.recOn q f fun a b p => eq_of_heq (eqRec_heq_iff.mpr (c a b p))
|
||||
|
||||
@@ -2088,7 +2088,7 @@ a structure.
|
||||
protected abbrev hrecOn
|
||||
(q : Quotient s)
|
||||
(f : (a : α) → motive (Quotient.mk s a))
|
||||
(c : (a b : α) → (p : a ≈ b) → f a ≍ f b)
|
||||
(c : (a b : α) → (p : a ≈ b) → HEq (f a) (f b))
|
||||
: motive q :=
|
||||
Quot.hrecOn q f c
|
||||
end
|
||||
@@ -2252,7 +2252,7 @@ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
|
||||
Quot.liftOn f
|
||||
(fun (f : ∀ (x : α), β x) => f x)
|
||||
(fun _ _ h => h x)
|
||||
change extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
|
||||
show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
|
||||
exact congrArg extfunApp (Quot.sound h)
|
||||
|
||||
/--
|
||||
|
||||
@@ -46,6 +46,3 @@ import Init.Data.NeZero
|
||||
import Init.Data.Function
|
||||
import Init.Data.RArray
|
||||
import Init.Data.Vector
|
||||
import Init.Data.Iterators
|
||||
import Init.Data.Range.Polymorphic
|
||||
import Init.Data.Slice
|
||||
|
||||
@@ -209,7 +209,7 @@ theorem Context.evalList_sort_congr
|
||||
induction c generalizing a b with
|
||||
| nil => simp [sort.loop, h₂]
|
||||
| cons c _ ih =>
|
||||
simp [sort.loop]; apply ih; simp [evalList_insert ctx h]
|
||||
simp [sort.loop]; apply ih; simp [evalList_insert ctx h, evalList]
|
||||
cases a with
|
||||
| nil => apply absurd h₃; simp
|
||||
| cons a as =>
|
||||
@@ -282,7 +282,7 @@ theorem Context.toList_nonEmpty (e : Expr) : e.toList ≠ [] := by
|
||||
simp [Expr.toList]
|
||||
cases h : l.toList with
|
||||
| nil => contradiction
|
||||
| cons => simp
|
||||
| cons => simp [List.append]
|
||||
|
||||
theorem Context.unwrap_isNeutral
|
||||
{ctx : Context α}
|
||||
@@ -328,13 +328,13 @@ theorem Context.eval_toList (ctx : Context α) (e : Expr) : evalList α ctx e.to
|
||||
induction e with
|
||||
| var x => rfl
|
||||
| op l r ih₁ ih₂ =>
|
||||
simp [Expr.toList, eval, ←ih₁, ←ih₂]
|
||||
simp [evalList, Expr.toList, eval, ←ih₁, ←ih₂]
|
||||
apply evalList_append <;> apply toList_nonEmpty
|
||||
|
||||
theorem Context.eval_norm (ctx : Context α) (e : Expr) : evalList α ctx (norm ctx e) = eval α ctx e := by
|
||||
simp [norm]
|
||||
cases h₁ : ContextInformation.isIdem ctx <;> cases h₂ : ContextInformation.isComm ctx <;>
|
||||
simp_all [evalList_removeNeutrals, eval_toList, evalList_mergeIdem, evalList_sort]
|
||||
simp_all [evalList_removeNeutrals, eval_toList, toList_nonEmpty, evalList_mergeIdem, evalList_sort]
|
||||
|
||||
theorem Context.eq_of_norm (ctx : Context α) (a b : Expr) (h : norm ctx a == norm ctx b) : eval α ctx a = eval α ctx b := by
|
||||
have h := congrArg (evalList α ctx) (eq_of_beq h)
|
||||
|
||||
@@ -22,7 +22,7 @@ an array `xs : Array α`, given a proof that every element of `xs` in fact satis
|
||||
|
||||
`Array.pmap`, named for “partial map,” is the equivalent of `Array.map` for such partial functions.
|
||||
-/
|
||||
@[expose]
|
||||
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) (xs : Array α) (H : ∀ a ∈ xs, P a) : Array β :=
|
||||
(xs.toList.pmap f (fun a m => H a (mem_def.mpr m))).toArray
|
||||
|
||||
@@ -39,7 +39,7 @@ of elements in the corresponding subtype `{ x // P x }`.
|
||||
|
||||
`O(1)`.
|
||||
-/
|
||||
@[implemented_by attachWithImpl, expose] def attachWith
|
||||
@[implemented_by attachWithImpl] def attachWith
|
||||
(xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} :=
|
||||
⟨xs.toList.attachWith P fun x h => H x (Array.Mem.mk h)⟩
|
||||
|
||||
@@ -54,7 +54,7 @@ recursion](lean-manual://section/well-founded-recursion) that use higher-order f
|
||||
`Array.map`) to prove that an value taken from a list is smaller than the list. This allows the
|
||||
well-founded recursion mechanism to prove that the function terminates.
|
||||
-/
|
||||
@[inline, expose] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id
|
||||
@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id
|
||||
|
||||
@[simp, grind =] theorem _root_.List.attachWith_toArray {l : List α} {P : α → Prop} {H : ∀ x ∈ l.toArray, P x} :
|
||||
l.toArray.attachWith P H = (l.attachWith P (by simpa using H)).toArray := by
|
||||
@@ -68,15 +68,15 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
l.toArray.pmap f H = (l.pmap f (by simpa using H)).toArray := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp, grind =] theorem toList_attachWith {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs, P x} :
|
||||
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList_iff] using H) := by
|
||||
@[simp] theorem toList_attachWith {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs, P x} :
|
||||
(xs.attachWith P H).toList = xs.toList.attachWith P (by simpa [mem_toList] using H) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp, grind =] theorem toList_attach {xs : Array α} :
|
||||
xs.attach.toList = xs.toList.attachWith (· ∈ xs) (by simp [mem_toList_iff]) := by
|
||||
@[simp] theorem toList_attach {xs : Array α} :
|
||||
xs.attach.toList = xs.toList.attachWith (· ∈ xs) (by simp [mem_toList]) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp, grind =] theorem toList_pmap {xs : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ xs, P a} :
|
||||
@[simp] theorem toList_pmap {xs : Array α} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.pmap f H).toList = xs.toList.pmap f (fun a m => H a (mem_def.mpr m)) := by
|
||||
simp [pmap]
|
||||
|
||||
@@ -92,16 +92,16 @@ well-founded recursion mechanism to prove that the function terminates.
|
||||
intro a m h₁ h₂
|
||||
congr
|
||||
|
||||
@[simp, grind =] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
@[simp] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #[] (by simp) = #[] := rfl
|
||||
|
||||
@[simp, grind =] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (xs : Array α) (h : ∀ b ∈ xs.push a, P b) :
|
||||
@[simp] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (xs : Array α) (h : ∀ b ∈ xs.push a, P b) :
|
||||
pmap f (xs.push a) h =
|
||||
(pmap f xs (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp, grind =] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
@[simp] theorem attach_empty : (#[] : Array α).attach = #[] := rfl
|
||||
|
||||
@[simp, grind =] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #[], P x) : (#[] : Array α).attachWith P H = #[] := 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) =
|
||||
@@ -122,13 +122,11 @@ theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a,
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
@[grind =]
|
||||
theorem map_pmap {p : α → Prop} {g : β → γ} {f : ∀ a, p a → β} {xs : Array α} (H) :
|
||||
map g (pmap f xs H) = pmap (fun a h => g (f a h)) xs H := by
|
||||
cases xs
|
||||
simp [List.map_pmap]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_map {p : β → Prop} {g : ∀ b, p b → γ} {f : α → β} {xs : Array α} (H) :
|
||||
pmap g (map f xs) H = pmap (fun a h => g (f a) h) xs fun _ h => H _ (mem_map_of_mem h) := by
|
||||
cases xs
|
||||
@@ -144,18 +142,18 @@ theorem attachWith_congr {xs ys : Array α} (w : xs = ys) {P : α → Prop} {H :
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem attach_push {a : α} {xs : Array α} :
|
||||
@[simp] theorem attach_push {a : α} {xs : Array α} :
|
||||
(xs.push a).attach =
|
||||
(xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_push_of_mem a h⟩)).push ⟨a, by simp⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr (List.push_toArray _ _)]
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp, grind =] theorem attachWith_push {a : α} {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs.push a, P x} :
|
||||
@[simp] theorem attachWith_push {a : α} {xs : Array α} {P : α → Prop} {H : ∀ x ∈ xs.push a, P x} :
|
||||
(xs.push a).attachWith P H =
|
||||
(xs.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push ⟨a, H a (by simp)⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
simp [attachWith_congr (List.push_toArray _ _)]
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} {f : ∀ a, p a → β} {xs : Array α} (H) :
|
||||
pmap f xs H = xs.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
@@ -191,39 +189,38 @@ theorem attachWith_map_subtype_val {p : α → Prop} {xs : Array α} (H : ∀ a
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem mem_attachWith {xs : Array α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem size_attach {xs : Array α} : xs.attach.size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem size_attachWith {p : α → Prop} {xs : Array α} {H} : (xs.attachWith p H).size = xs.size := by
|
||||
cases xs; simp
|
||||
|
||||
@@ -255,13 +252,13 @@ theorem attachWith_ne_empty_iff {xs : Array α} {P : α → Prop} {H : ∀ a ∈
|
||||
xs.attachWith P H ≠ #[] ↔ xs ≠ #[] := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Array α} (h : ∀ a ∈ xs, p a) (i : Nat) :
|
||||
(pmap f xs h)[i]? = Option.pmap f xs[i]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases xs; simp
|
||||
|
||||
-- The argument `f` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {xs : Array α} (h : ∀ a ∈ xs, p a) {i : Nat}
|
||||
(hi : i < (pmap f xs h).size) :
|
||||
(pmap f xs h)[i] =
|
||||
@@ -269,59 +266,57 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {xs : Array α} (
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f xs h ▸ hi))) := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[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, grind =]
|
||||
@[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, grind =]
|
||||
@[simp]
|
||||
theorem getElem_attachWith {xs : Array α} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < (xs.attachWith P H).size) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap _ _ h
|
||||
|
||||
@[simp, grind =]
|
||||
@[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
|
||||
|
||||
@[simp, grind =] theorem pmap_attach {xs : Array α} {p : {x // x ∈ xs} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
@[simp] theorem pmap_attach {xs : Array α} {p : {x // x ∈ xs} → Prop} {f : ∀ a, p a → β} (H) :
|
||||
pmap f xs.attach H =
|
||||
xs.pmap (P := fun a => ∃ h : a ∈ xs, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp, grind =] theorem pmap_attachWith {xs : Array α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
@[simp] theorem pmap_attachWith {xs : Array α} {p : {x // q x} → Prop} {f : ∀ a, p a → β} (H₁ H₂) :
|
||||
pmap f (xs.attachWith q H₁) H₂ =
|
||||
xs.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem foldl_pmap {xs : Array α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (g : γ → β → γ) (x : γ) :
|
||||
(xs.pmap f H).foldl g x = xs.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind =]
|
||||
theorem foldr_pmap {xs : Array α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) (g : β → γ → γ) (x : γ) :
|
||||
(xs.pmap f H).foldr g x = xs.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
@[simp, grind =] theorem foldl_attachWith
|
||||
@[simp] theorem foldl_attachWith
|
||||
{xs : Array α} {q : α → Prop} (H : ∀ a, a ∈ xs → q a) {f : β → { x // q x} → β} {b} (w : stop = xs.size) :
|
||||
(xs.attachWith q H).foldl f b 0 stop = xs.attach.foldl (fun b ⟨a, h⟩ => f b ⟨a, H _ h⟩) b := by
|
||||
subst w
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_attachWith, List.foldl_map]
|
||||
|
||||
@[simp, grind =] theorem foldr_attachWith
|
||||
@[simp] theorem foldr_attachWith
|
||||
{xs : Array α} {q : α → Prop} (H : ∀ a, a ∈ xs → q a) {f : { x // q x} → β → β} {b} (w : start = xs.size) :
|
||||
(xs.attachWith q H).foldr f b start 0 = xs.attach.foldr (fun a acc => f ⟨a.1, H _ a.2⟩ acc) b := by
|
||||
subst w
|
||||
@@ -342,7 +337,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
|
||||
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
List.length_pmap, List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -361,25 +356,23 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
|
||||
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
List.length_pmap, List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
@[grind =]
|
||||
theorem attach_map {xs : Array α} {f : α → β} :
|
||||
(xs.map f).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem h⟩) := by
|
||||
cases xs
|
||||
ext <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem attachWith_map {xs : Array α} {f : α → β} {P : β → Prop} (H : ∀ (b : β), b ∈ xs.map f → P b) :
|
||||
(xs.map f).attachWith P H = (xs.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases xs
|
||||
simp [List.attachWith_map]
|
||||
|
||||
@[simp, grind =] theorem map_attachWith {xs : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ xs → P a}
|
||||
@[simp] theorem map_attachWith {xs : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ xs → P a}
|
||||
{f : { x // P x } → β} :
|
||||
(xs.attachWith P H).map f = xs.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
cases xs <;> simp_all
|
||||
@@ -400,7 +393,6 @@ theorem map_attach_eq_pmap {xs : Array α} {f : { x // x ∈ xs } → β} :
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
(xs.filterMap f).attach = xs.attach.filterMap
|
||||
fun ⟨x, h⟩ => (f x).pbind (fun b m => some ⟨b, mem_filterMap.mpr ⟨x, h, m⟩⟩) := by
|
||||
@@ -408,7 +400,6 @@ theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
rw [attach_congr List.filterMap_toArray]
|
||||
simp [List.attach_filterMap, List.map_filterMap, Function.comp_def]
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filter {xs : Array α} (p : α → Bool) :
|
||||
(xs.filter p).attach = xs.attach.filterMap
|
||||
fun x => if w : p x.1 then some ⟨x.1, mem_filter.mpr ⟨x.2, w⟩⟩ else none := by
|
||||
@@ -418,7 +409,7 @@ theorem attach_filter {xs : Array α} (p : α → Bool) :
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem filterMap_attachWith {q : α → Prop} {xs : Array α} {f : {x // q x} → Option β} (H)
|
||||
(w : stop = (xs.attachWith q H).size) :
|
||||
(xs.attachWith q H).filterMap f 0 stop = xs.attach.filterMap (fun ⟨x, h⟩ => f ⟨x, H _ h⟩) := by
|
||||
@@ -426,7 +417,7 @@ theorem filterMap_attachWith {q : α → Prop} {xs : Array α} {f : {x // q x}
|
||||
cases xs
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem filter_attachWith {q : α → Prop} {xs : Array α} {p : {x // q x} → Bool} (H)
|
||||
(w : stop = (xs.attachWith q H).size) :
|
||||
(xs.attachWith q H).filter p 0 stop =
|
||||
@@ -435,7 +426,6 @@ theorem filter_attachWith {q : α → Prop} {xs : Array α} {p : {x // q x} →
|
||||
cases xs
|
||||
simp [Function.comp_def, List.filter_map]
|
||||
|
||||
@[grind =]
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f : ∀ b, q b → γ} {xs} (H₁ H₂) :
|
||||
pmap f (pmap g xs H₁) H₂ =
|
||||
pmap (α := { x // x ∈ xs }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) xs.attach
|
||||
@@ -443,7 +433,7 @@ theorem pmap_pmap {p : α → Prop} {q : β → Prop} {g : ∀ a, p a → β} {f
|
||||
cases xs
|
||||
simp [List.pmap_pmap, List.pmap_map]
|
||||
|
||||
@[simp, grind =] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {xs ys : Array ι}
|
||||
@[simp] theorem pmap_append {p : ι → Prop} {f : ∀ a : ι, p a → α} {xs ys : Array ι}
|
||||
(h : ∀ a ∈ xs ++ ys, p a) :
|
||||
(xs ++ ys).pmap f h =
|
||||
(xs.pmap f fun a ha => h a (mem_append_left ys ha)) ++
|
||||
@@ -458,7 +448,7 @@ theorem pmap_append' {p : α → Prop} {f : ∀ a : α, p a → β} {xs ys : Arr
|
||||
xs.pmap f h₁ ++ ys.pmap f h₂ :=
|
||||
pmap_append _
|
||||
|
||||
@[simp, grind =] theorem attach_append {xs ys : Array α} :
|
||||
@[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
|
||||
@@ -466,62 +456,59 @@ theorem pmap_append' {p : α → Prop} {f : ∀ a : α, p a → β} {xs ys : Arr
|
||||
rw [attach_congr (List.append_toArray _ _)]
|
||||
simp [List.attach_append, Function.comp_def]
|
||||
|
||||
@[simp, grind =] theorem attachWith_append {P : α → Prop} {xs ys : Array α}
|
||||
@[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]
|
||||
simp [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp, grind =] theorem pmap_reverse {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
@[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
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp, grind =] theorem attachWith_reverse {P : α → Prop} {xs : Array α}
|
||||
@[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
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem attach_reverse {xs : Array α} :
|
||||
@[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
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_attach {xs : Array α} :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem back?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
@[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, grind =] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
@[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? h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem back?_attach {xs : Array α} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back? h⟩ := by
|
||||
cases xs
|
||||
@@ -539,7 +526,7 @@ theorem countP_attachWith {p : α → Prop} {q : α → Bool} {xs : Array α} {H
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem count_attach [BEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
xs.attach.count a = xs.count ↑a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -548,13 +535,13 @@ theorem count_attach [BEq α] {xs : Array α} {a : {x // x ∈ xs}} :
|
||||
simp only [Subtype.beq_iff]
|
||||
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem count_attachWith [BEq α] {p : α → Prop} {xs : Array α} (H : ∀ a ∈ xs, p a) {a : {x // p x}} :
|
||||
(xs.attachWith p H).count a = xs.count ↑a := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {xs : Array α} (H₁) :
|
||||
@[simp] theorem countP_pmap {p : α → Prop} {g : ∀ a, p a → β} {f : β → Bool} {xs : Array α} (H₁) :
|
||||
(xs.pmap g H₁).countP f =
|
||||
xs.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
|
||||
@@ -587,12 +574,9 @@ state, the right approach is usually the tactic `simp [Array.unattach, -Array.ma
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array α := xs.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_empty {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := by
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_empty (since := "2025-05-26")]
|
||||
abbrev unattach_nil := @unattach_empty
|
||||
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {xs : Array { x // p x }} :
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
simp only [unattach, Array.map_push]
|
||||
@@ -703,7 +687,7 @@ and simplifies these to the function directly taking the value.
|
||||
{f : { x // p x } → Array β} {g : α → Array β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(xs.flatMap f) = xs.unattach.flatMap g := by
|
||||
cases xs
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
simp only [List.size_toArray, List.flatMap_toArray, List.unattach_toArray, List.length_unattach,
|
||||
mk.injEq]
|
||||
rw [List.flatMap_subtype]
|
||||
simp [hf]
|
||||
|
||||
@@ -91,8 +91,7 @@ theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
|
||||
@[simp, grind =] theorem getElem_toList {xs : Array α} {i : Nat} (h : i < xs.size) : xs.toList[i] = xs[i] := rfl
|
||||
|
||||
@[simp, grind =] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
|
||||
simp only [getElem?_def, getElem_toList]
|
||||
simp only [Array.size]
|
||||
simp [getElem?_def]
|
||||
|
||||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||
@@ -113,10 +112,6 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
@@ -168,7 +163,7 @@ Low-level indexing operator which is as fast as a C array read.
|
||||
|
||||
This avoids overhead due to unboxing a `Nat` used as an index.
|
||||
-/
|
||||
@[extern "lean_array_uget", simp, expose]
|
||||
@[extern "lean_array_uget", simp]
|
||||
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
a[i.toNat]
|
||||
|
||||
@@ -191,7 +186,7 @@ Examples:
|
||||
* `#["orange", "yellow"].pop = #["orange"]`
|
||||
* `(#[] : Array String).pop = #[]`
|
||||
-/
|
||||
@[extern "lean_array_pop", expose]
|
||||
@[extern "lean_array_pop"]
|
||||
def pop (xs : Array α) : Array α where
|
||||
toList := xs.toList.dropLast
|
||||
|
||||
@@ -210,7 +205,7 @@ Examples:
|
||||
* `Array.replicate 3 () = #[(), (), ()]`
|
||||
* `Array.replicate 0 "anything" = #[]`
|
||||
-/
|
||||
@[extern "lean_mk_array", expose]
|
||||
@[extern "lean_mk_array"]
|
||||
def replicate {α : Type u} (n : Nat) (v : α) : Array α where
|
||||
toList := List.replicate n v
|
||||
|
||||
@@ -238,7 +233,7 @@ Examples:
|
||||
* `#["red", "green", "blue", "brown"].swap 1 2 = #["red", "blue", "green", "brown"]`
|
||||
* `#["red", "green", "blue", "brown"].swap 3 0 = #["brown", "green", "blue", "red"]`
|
||||
-/
|
||||
@[extern "lean_array_fswap", expose]
|
||||
@[extern "lean_array_fswap"]
|
||||
def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic) (hj : j < xs.size := by get_elem_tactic) : Array α :=
|
||||
let v₁ := xs[i]
|
||||
let v₂ := xs[j]
|
||||
@@ -246,7 +241,7 @@ def swap (xs : Array α) (i j : @& Nat) (hi : i < xs.size := by get_elem_tactic)
|
||||
xs'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set _).symm)
|
||||
|
||||
@[simp] theorem size_swap {xs : Array α} {i j : Nat} {hi hj} : (xs.swap i j hi hj).size = xs.size := by
|
||||
change ((xs.set i xs[j]).set j xs[i]
|
||||
show ((xs.set i xs[j]).set j xs[i]
|
||||
(Nat.lt_of_lt_of_eq hj (size_set _).symm)).size = xs.size
|
||||
rw [size_set, size_set]
|
||||
|
||||
@@ -268,6 +263,8 @@ def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
|
||||
else xs
|
||||
else xs
|
||||
|
||||
@[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
|
||||
@@ -289,7 +286,6 @@ Examples:
|
||||
* `#[1, 2].isEmpty = false`
|
||||
* `#[()].isEmpty = false`
|
||||
-/
|
||||
@[expose]
|
||||
def isEmpty (xs : Array α) : Bool :=
|
||||
xs.size = 0
|
||||
|
||||
@@ -331,16 +327,12 @@ Examples:
|
||||
* `Array.ofFn (n := 3) toString = #["0", "1", "2"]`
|
||||
* `Array.ofFn (fun i => #["red", "green", "blue"].get i.val i.isLt) = #["red", "green", "blue"]`
|
||||
-/
|
||||
def ofFn {n} (f : Fin n → α) : Array α := go (emptyWithCapacity n) n (Nat.le_refl n) where
|
||||
/-- Auxiliary for `ofFn`. `ofFn.go f acc i h = acc ++ #[f (n - i), ..., f(n - 1)]` -/
|
||||
go (acc : Array α) : (i : Nat) → i ≤ n → Array α
|
||||
| i + 1, h =>
|
||||
have w : n - i - 1 < n :=
|
||||
Nat.lt_of_lt_of_le (Nat.sub_one_lt (Nat.sub_ne_zero_iff_lt.mpr h)) (Nat.sub_le n i)
|
||||
go (acc.push (f ⟨n - i - 1, w⟩)) i (Nat.le_of_succ_le h)
|
||||
| 0, _ => acc
|
||||
|
||||
-- See also `Array.ofFnM` defined in `Init.Data.Array.OfFn`.
|
||||
def ofFn {n} (f : Fin n → α) : Array α := go 0 (emptyWithCapacity n) where
|
||||
/-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
go (i : Nat) (acc : Array α) : Array α :=
|
||||
if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
/--
|
||||
Constructs an array that contains all the numbers from `0` to `n`, exclusive.
|
||||
@@ -375,7 +367,7 @@ Examples:
|
||||
* `Array.singleton 5 = #[5]`
|
||||
* `Array.singleton "one" = #["one"]`
|
||||
-/
|
||||
@[inline, expose] protected def singleton (v : α) : Array α := #[v]
|
||||
@[inline] protected def singleton (v : α) : Array α := #[v]
|
||||
|
||||
/--
|
||||
Returns the last element of an array, or panics if the array is empty.
|
||||
@@ -404,7 +396,7 @@ that requires a proof the array is non-empty.
|
||||
def back? (xs : Array α) : Option α :=
|
||||
xs[xs.size - 1]?
|
||||
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
|
||||
def get? (xs : Array α) (i : Nat) : Option α :=
|
||||
if h : i < xs.size then some xs[i] else none
|
||||
|
||||
@@ -418,7 +410,7 @@ Examples:
|
||||
* `#["spinach", "broccoli", "carrot"].swapAt 1 "pepper" = ("broccoli", #["spinach", "pepper", "carrot"])`
|
||||
* `#["spinach", "broccoli", "carrot"].swapAt 2 "pepper" = ("carrot", #["spinach", "broccoli", "pepper"])`
|
||||
-/
|
||||
@[inline, expose] def swapAt (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α :=
|
||||
@[inline] def swapAt (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α :=
|
||||
let e := xs[i]
|
||||
let xs' := xs.set i v
|
||||
(e, xs')
|
||||
@@ -433,7 +425,7 @@ Examples:
|
||||
* `#["spinach", "broccoli", "carrot"].swapAt! 1 "pepper" = (#["spinach", "pepper", "carrot"], "broccoli")`
|
||||
* `#["spinach", "broccoli", "carrot"].swapAt! 2 "pepper" = (#["spinach", "broccoli", "pepper"], "carrot")`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
if h : i < xs.size then
|
||||
swapAt xs i v
|
||||
@@ -546,7 +538,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def modify (xs : Array α) (i : Nat) (f : α → α) : Array α :=
|
||||
Id.run <| modifyM xs i (pure <| f ·)
|
||||
Id.run <| modifyM xs i f
|
||||
|
||||
set_option linter.indexVariables false in -- Changing `idx` causes bootstrapping issues, haven't investigated.
|
||||
/--
|
||||
@@ -579,7 +571,7 @@ def modifyOp (xs : Array α) (idx : Nat) (f : α → α) : Array α :=
|
||||
loop 0 b
|
||||
|
||||
/-- Reference implementation for `forIn'` -/
|
||||
@[implemented_by Array.forIn'Unsafe, expose]
|
||||
@[implemented_by Array.forIn'Unsafe]
|
||||
protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
|
||||
match i, h with
|
||||
@@ -646,7 +638,7 @@ example [Monad m] (f : α → β → m α) :
|
||||
```
|
||||
-/
|
||||
-- Reference implementation for `foldlM`
|
||||
@[implemented_by foldlMUnsafe, expose]
|
||||
@[implemented_by foldlMUnsafe]
|
||||
def foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Array α) (start := 0) (stop := as.size) : m β :=
|
||||
let fold (stop : Nat) (h : stop ≤ as.size) :=
|
||||
let rec loop (i : Nat) (j : Nat) (b : β) : m β := do
|
||||
@@ -711,7 +703,7 @@ example [Monad m] (f : α → β → m β) :
|
||||
```
|
||||
-/
|
||||
-- Reference implementation for `foldrM`
|
||||
@[implemented_by foldrMUnsafe, expose]
|
||||
@[implemented_by foldrMUnsafe]
|
||||
def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → β → m β) (init : β) (as : Array α) (start := as.size) (stop := 0) : m β :=
|
||||
let rec fold (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
|
||||
if i == stop then
|
||||
@@ -766,11 +758,13 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
map 0 (emptyWithCapacity as.size)
|
||||
|
||||
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` to every element in the array, along with the element's index and a
|
||||
proof that the index is in bounds, from left to right. Returns the array of results.
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
(as : Array α) (f : (i : Nat) → α → (h : i < as.size) → m β) : m (Array β) :=
|
||||
let rec @[specialize] map (i : Nat) (j : Nat) (inv : i + j = as.size) (bs : Array β) : m (Array β) := do
|
||||
@@ -788,7 +782,7 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
Applies the monadic action `f` to every element in the array, along with the element's index, from
|
||||
left to right. Returns the array of results.
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
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
|
||||
|
||||
@@ -834,7 +828,7 @@ Almost! 5
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
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
|
||||
@@ -915,7 +909,7 @@ The optional parameters `start` and `stop` control the region of the array to be
|
||||
elements with indices from `start` (inclusive) to `stop` (exclusive) are checked. By default, the
|
||||
entire array is checked.
|
||||
-/
|
||||
@[implemented_by anyMUnsafe, expose]
|
||||
@[implemented_by anyMUnsafe]
|
||||
def anyM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool :=
|
||||
let any (stop : Nat) (h : stop ≤ as.size) :=
|
||||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
@@ -1057,9 +1051,9 @@ Examples:
|
||||
* `#[1, 2, 3].foldl (· ++ toString ·) "" = "123"`
|
||||
* `#[1, 2, 3].foldl (s!"({·} {·})") "" = "((( 1) 2) 3)"`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Array α) (start := 0) (stop := as.size) : β :=
|
||||
Id.run <| as.foldlM (pure <| f · ·) init start stop
|
||||
Id.run <| as.foldlM f init start stop
|
||||
|
||||
/--
|
||||
Folds a function over an array from the right, accumulating a value starting with `init`. The
|
||||
@@ -1074,9 +1068,9 @@ Examples:
|
||||
* `#[1, 2, 3].foldr (toString · ++ ·) "" = "123"`
|
||||
* `#[1, 2, 3].foldr (s!"({·} {·})") "!" = "(1 (2 (3 !)))"`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Array α) (start := as.size) (stop := 0) : β :=
|
||||
Id.run <| as.foldrM (pure <| f · ·) init start stop
|
||||
Id.run <| as.foldrM f init start stop
|
||||
|
||||
/--
|
||||
Computes the sum of the elements of an array.
|
||||
@@ -1085,7 +1079,7 @@ Examples:
|
||||
* `#[a, b, c].sum = a + (b + (c + 0))`
|
||||
* `#[1, 2, 5].sum = 8`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def sum {α} [Add α] [Zero α] : Array α → α :=
|
||||
foldr (· + ·) 0
|
||||
|
||||
@@ -1097,7 +1091,7 @@ Examples:
|
||||
* `#[1, 2, 3, 4, 5].countP (· < 5) = 4`
|
||||
* `#[1, 2, 3, 4, 5].countP (· > 5) = 0`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def countP {α : Type u} (p : α → Bool) (as : Array α) : Nat :=
|
||||
as.foldr (init := 0) fun a acc => bif p a then acc + 1 else acc
|
||||
|
||||
@@ -1109,7 +1103,7 @@ Examples:
|
||||
* `#[1, 1, 2, 3, 5].count 5 = 1`
|
||||
* `#[1, 1, 2, 3, 5].count 4 = 0`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def count {α : Type u} [BEq α] (a : α) (as : Array α) : Nat :=
|
||||
countP (· == a) as
|
||||
|
||||
@@ -1122,9 +1116,9 @@ Examples:
|
||||
* `#["one", "two", "three"].map (·.length) = #[3, 3, 5]`
|
||||
* `#["one", "two", "three"].map (·.reverse) = #["eno", "owt", "eerht"]`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapM (pure <| f ·)
|
||||
Id.run <| as.mapM f
|
||||
|
||||
instance : Functor Array where
|
||||
map := map
|
||||
@@ -1137,9 +1131,9 @@ that the index is valid.
|
||||
`Array.mapIdx` is a variant that does not provide the function with evidence that the index is
|
||||
valid.
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β) : Array β :=
|
||||
Id.run <| as.mapFinIdxM (pure <| f · · ·)
|
||||
Id.run <| as.mapFinIdxM f
|
||||
|
||||
/--
|
||||
Applies a function to each element of the array along with the index at which that element is found,
|
||||
@@ -1148,9 +1142,9 @@ returning the array of results.
|
||||
`Array.mapFinIdx` is a variant that additionally provides the function with a proof that the index
|
||||
is valid.
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapIdxM (pure <| f · ·)
|
||||
Id.run <| as.mapIdxM f
|
||||
|
||||
/--
|
||||
Pairs each element of an array with its index, optionally starting from an index other than `0`.
|
||||
@@ -1159,7 +1153,6 @@ Examples:
|
||||
* `#[a, b, c].zipIdx = #[(a, 0), (b, 1), (c, 2)]`
|
||||
* `#[a, b, c].zipIdx 5 = #[(a, 5), (b, 6), (c, 7)]`
|
||||
-/
|
||||
@[expose]
|
||||
def zipIdx (xs : Array α) (start := 0) : Array (α × Nat) :=
|
||||
xs.mapIdx fun i a => (a, start + i)
|
||||
|
||||
@@ -1173,7 +1166,7 @@ Examples:
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].find? (· < 5) = some 1`
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].find? (· < 1) = none`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run do
|
||||
for a in as do
|
||||
@@ -1197,9 +1190,9 @@ Example:
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeM? (pure <| f ·)
|
||||
Id.run <| as.findSomeM? f
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the function `f` to each element of the
|
||||
@@ -1233,7 +1226,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||||
Id.run <| as.findSomeRevM? (pure <| f ·)
|
||||
Id.run <| as.findSomeRevM? f
|
||||
|
||||
/--
|
||||
Returns the last element of the array for which the predicate `p` returns `true`, or `none` if no
|
||||
@@ -1245,7 +1238,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||||
Id.run <| as.findRevM? (pure <| p ·)
|
||||
Id.run <| as.findRevM? p
|
||||
|
||||
/--
|
||||
Returns the index of the first element for which `p` returns `true`, or `none` if there is no such
|
||||
@@ -1255,7 +1248,7 @@ Examples:
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5) = some 4`
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1) = none`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
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) :=
|
||||
@@ -1309,7 +1302,7 @@ Examples:
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5) = 4`
|
||||
* `#[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1) = 7`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def findIdx (p : α → Bool) (as : Array α) : Nat := (as.findIdx? p).getD as.size
|
||||
|
||||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||||
@@ -1363,6 +1356,10 @@ Examples:
|
||||
def idxOf? [BEq α] (xs : Array α) (v : α) : Option Nat :=
|
||||
(xs.finIdxOf? v).map (·.val)
|
||||
|
||||
@[deprecated idxOf? (since := "2024-11-20")]
|
||||
def getIdx? [BEq α] (xs : Array α) (v : α) : Option Nat :=
|
||||
xs.findIdx? fun a => a == v
|
||||
|
||||
/--
|
||||
Returns `true` if `p` returns `true` for any element of `as`.
|
||||
|
||||
@@ -1378,9 +1375,9 @@ Examples:
|
||||
* `#[2, 4, 5, 6].any (· % 2 = 0) = true`
|
||||
* `#[2, 4, 5, 6].any (· % 2 = 1) = true`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.anyM (pure <| p ·) start stop
|
||||
Id.run <| as.anyM p start stop
|
||||
|
||||
/--
|
||||
Returns `true` if `p` returns `true` for every element of `as`.
|
||||
@@ -1398,7 +1395,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.allM (pure <| p ·) start stop
|
||||
Id.run <| as.allM p start stop
|
||||
|
||||
/--
|
||||
Checks whether `a` is an element of `as`, using `==` to compare elements.
|
||||
@@ -1409,7 +1406,6 @@ Examples:
|
||||
* `#[1, 4, 2, 3, 3, 7].contains 3 = true`
|
||||
* `Array.contains #[1, 4, 2, 3, 3, 7] 5 = false`
|
||||
-/
|
||||
@[expose]
|
||||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||||
as.any (a == ·)
|
||||
|
||||
@@ -1458,7 +1454,6 @@ Examples:
|
||||
* `#[] ++ #[4, 5] = #[4, 5]`.
|
||||
* `#[1, 2, 3] ++ #[] = #[1, 2, 3]`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def append (as : Array α) (bs : Array α) : Array α :=
|
||||
bs.foldl (init := as) fun xs v => xs.push v
|
||||
|
||||
@@ -1496,7 +1491,7 @@ Examples:
|
||||
* `#[2, 3, 2].flatMap Array.range = #[0, 1, 0, 1, 2, 0, 1]`
|
||||
* `#[['a', 'b'], ['c', 'd', 'e']].flatMap List.toArray = #['a', 'b', 'c', 'd', 'e']`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def flatMap (f : α → Array β) (as : Array α) : Array β :=
|
||||
as.foldl (init := empty) fun bs a => bs ++ f a
|
||||
|
||||
@@ -1509,7 +1504,7 @@ Examples:
|
||||
* `#[#[0, 1], #[], #[2], #[1, 0, 1]].flatten = #[0, 1, 2, 1, 0, 1]`
|
||||
* `(#[] : Array Nat).flatten = #[]`
|
||||
-/
|
||||
@[inline, expose] def flatten (xss : Array (Array α)) : Array α :=
|
||||
@[inline] def flatten (xss : Array (Array α)) : Array α :=
|
||||
xss.foldl (init := empty) fun acc xs => acc ++ xs
|
||||
|
||||
/--
|
||||
@@ -1522,7 +1517,6 @@ Examples:
|
||||
* `#[0, 1].reverse = #[1, 0]`
|
||||
* `#[0, 1, 2].reverse = #[2, 1, 0]`
|
||||
-/
|
||||
@[expose]
|
||||
def reverse (as : Array α) : Array α :=
|
||||
if h : as.size ≤ 1 then
|
||||
as
|
||||
@@ -1555,7 +1549,7 @@ Examples:
|
||||
* `#[1, 2, 5, 2, 7, 7].filter (fun _ => true) (start := 3) = #[2, 7, 7]`
|
||||
* `#[1, 2, 5, 2, 7, 7].filter (fun _ => true) (stop := 3) = #[1, 2, 5]`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def filter (p : α → Bool) (as : Array α) (start := 0) (stop := as.size) : Array α :=
|
||||
as.foldl (init := #[]) (start := start) (stop := stop) fun acc a =>
|
||||
if p a then acc.push a else acc
|
||||
@@ -1648,7 +1642,7 @@ Examining 7
|
||||
#[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[specialize, expose]
|
||||
@[specialize]
|
||||
def filterMapM [Monad m] (f : α → m (Option β)) (as : Array α) (start := 0) (stop := as.size) : m (Array β) :=
|
||||
as.foldlM (init := #[]) (start := start) (stop := stop) fun bs a => do
|
||||
match (← f a) with
|
||||
@@ -1668,9 +1662,9 @@ Example:
|
||||
#[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
def filterMap (f : α → Option β) (as : Array α) (start := 0) (stop := as.size) : Array β :=
|
||||
Id.run <| as.filterMapM (pure <| f ·) (start := start) (stop := stop)
|
||||
Id.run <| as.filterMapM f (start := start) (stop := stop)
|
||||
|
||||
/--
|
||||
Returns the largest element of the array, as determined by the comparison `lt`, or `none` if
|
||||
@@ -1788,7 +1782,7 @@ decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||||
induction xs, i, h using Array.eraseIdx.induct with
|
||||
| @case1 xs i h h' xs' ih =>
|
||||
unfold eraseIdx
|
||||
simp +zetaDelta [h', ih]
|
||||
simp +zetaDelta [h', xs', ih]
|
||||
| case2 xs i h h' =>
|
||||
unfold eraseIdx
|
||||
simp [h']
|
||||
@@ -1881,6 +1875,8 @@ Examples:
|
||||
let as := as.push a
|
||||
loop as ⟨j, size_push .. ▸ j.lt_succ_self⟩
|
||||
|
||||
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
|
||||
|
||||
/--
|
||||
Inserts an element into an array at the specified index. Panics if the index is greater than the
|
||||
size of the array.
|
||||
@@ -1901,6 +1897,8 @@ def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
insertIdx as i a
|
||||
else panic! "invalid index"
|
||||
|
||||
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
|
||||
|
||||
/--
|
||||
Inserts an element into an array at the specified index. The array is returned unmodified if the
|
||||
index is greater than the size of the array.
|
||||
@@ -2023,6 +2021,11 @@ Examples:
|
||||
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)
|
||||
|
||||
/--
|
||||
Replaces the first occurrence of `a` with `b` in an array. The modification is performed in-place
|
||||
when the reference to the array is unique. Returns the array unmodified when `a` is not present.
|
||||
|
||||
@@ -88,4 +88,4 @@ pointer equality, and does not allocate a new array if the result of each functi
|
||||
pointer-equal to its argument.
|
||||
-/
|
||||
@[inline] def Array.mapMono (as : Array α) (f : α → α) : Array α :=
|
||||
Id.run <| as.mapMonoM (pure <| f ·)
|
||||
Id.run <| as.mapMonoM f
|
||||
|
||||
@@ -129,6 +129,6 @@ Examples:
|
||||
* `#[].binInsert (· < ·) 1 = #[1]`
|
||||
-/
|
||||
@[inline] def binInsert {α : Type u} (lt : α → α → Bool) (as : Array α) (k : α) : Array α :=
|
||||
Id.run <| binInsertM lt (fun _ => pure k) (fun _ => pure k) as k
|
||||
Id.run <| binInsertM lt (fun _ => k) (fun _ => k) as k
|
||||
|
||||
end Array
|
||||
|
||||
@@ -40,7 +40,7 @@ Use the indexing notation `a[i]!` instead.
|
||||
|
||||
Access an element from an array, or panic if the index is out of bounds.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17")]
|
||||
def get! {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD a i default
|
||||
|
||||
@@ -78,8 +78,7 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] {f : α → β → m β} {init
|
||||
have : xs = #[] ∨ 0 < xs.size :=
|
||||
match xs with | ⟨[]⟩ => .inl rfl | ⟨a::l⟩ => .inr (Nat.zero_lt_succ _)
|
||||
match xs, this with | _, .inl rfl => simp [foldrM] | xs, .inr h => ?_
|
||||
simp only [foldrM, h, ← foldrM_eq_reverse_foldlM_toList.aux]
|
||||
simp [Array.size]
|
||||
simp [foldrM, h, ← foldrM_eq_reverse_foldlM_toList.aux, List.take_length]
|
||||
|
||||
@[simp, grind =] theorem foldrM_toList [Monad m]
|
||||
{f : α → β → m β} {init : β} {xs : Array α} :
|
||||
@@ -90,13 +89,9 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] {f : α → β → m β} {init
|
||||
xs.toList.foldr f init = xs.foldr f init :=
|
||||
List.foldr_eq_foldrM .. ▸ foldrM_toList ..
|
||||
|
||||
@[simp, grind =] theorem toList_push {xs : Array α} {x : α} : (xs.push x).toList = xs.toList ++ [x] := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@[simp, grind =] theorem push_toList {xs : Array α} {a : α} : (xs.push a).toList = xs.toList ++ [a] := by
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[deprecated toList_push (since := "2025-05-26")]
|
||||
abbrev push_toList := @toList_push
|
||||
|
||||
@[simp, grind =] theorem toListAppend_eq {xs : Array α} {l : List α} : xs.toListAppend l = xs.toList ++ l := by
|
||||
simp [toListAppend, ← foldr_toList]
|
||||
|
||||
@@ -119,13 +114,13 @@ abbrev pop_toList := @Array.toList_pop
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp, grind =] theorem append_empty {xs : Array α} : xs ++ #[] = xs := by
|
||||
apply ext'; simp only [toList_append, List.append_nil]
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[deprecated append_empty (since := "2025-01-13")]
|
||||
abbrev append_nil := @append_empty
|
||||
|
||||
@[simp, grind =] theorem empty_append {xs : Array α} : #[] ++ xs = xs := by
|
||||
apply ext'; simp only [toList_append, List.nil_append]
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[deprecated empty_append (since := "2025-01-13")]
|
||||
abbrev nil_append := @empty_append
|
||||
@@ -143,4 +138,26 @@ abbrev nil_append := @empty_append
|
||||
@[deprecated toList_appendList (since := "2024-12-11")]
|
||||
abbrev appendList_toList := @toList_appendList
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldrM_toList`." (since := "2024-11-13")]
|
||||
theorem foldrM_eq_foldrM_toList [Monad m]
|
||||
{f : α → β → m β} {init : β} {xs : Array α} :
|
||||
xs.foldrM f init = xs.toList.foldrM f init := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use the reverse direction of `foldlM_toList`." (since := "2024-11-13")]
|
||||
theorem foldlM_eq_foldlM_toList [Monad m]
|
||||
{f : β → α → m β} {init : β} {xs : Array α} :
|
||||
xs.foldlM f init = xs.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 : β} {xs : Array α} :
|
||||
xs.foldr f init = xs.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 : β} {xs : Array α} :
|
||||
xs.foldl f init = xs.toList.foldl f init:= by
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
@@ -52,20 +52,17 @@ theorem countP_push {a : α} {xs : Array α} : countP p (xs.push a) = countP p x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem countP_singleton {a : α} : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp
|
||||
@[simp] theorem countP_singleton {a : α} : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp [countP_push]
|
||||
|
||||
theorem size_eq_countP_add_countP {xs : Array α} : xs.size = countP p xs + countP (fun a => ¬p a) xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.length_eq_countP_add_countP (p := p)]
|
||||
|
||||
@[grind _=_]
|
||||
theorem countP_eq_size_filter {xs : Array α} : countP p xs = (filter p xs).size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_eq_length_filter]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_eq_size_filter' : countP p = size ∘ filter p := by
|
||||
funext xs
|
||||
apply countP_eq_size_filter
|
||||
@@ -74,7 +71,7 @@ theorem countP_le_size : countP p xs ≤ xs.size := by
|
||||
simp only [countP_eq_size_filter]
|
||||
apply size_filter_le
|
||||
|
||||
@[simp, grind =] theorem countP_append {xs ys : Array α} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
@[simp] theorem countP_append {xs ys : Array α} : countP p (xs ++ ys) = countP p xs + countP p ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp
|
||||
@@ -105,11 +102,9 @@ theorem boole_getElem_le_countP {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.boole_getElem_le_countP]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_set {xs : Array α} {i : Nat} {a : α} (h : i < xs.size) :
|
||||
(xs.set i a).countP p = xs.countP p - (if p xs[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp at h
|
||||
simp [List.countP_set, h]
|
||||
|
||||
theorem countP_filter {xs : Array α} :
|
||||
@@ -150,7 +145,7 @@ theorem countP_flatMap {p : β → Bool} {xs : Array α} {f : α → Array β} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_flatMap, Function.comp_def]
|
||||
|
||||
@[simp, grind =] theorem countP_reverse {xs : Array α} : countP p xs.reverse = countP p xs := by
|
||||
@[simp] theorem countP_reverse {xs : Array α} : countP p xs.reverse = countP p xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_reverse]
|
||||
|
||||
@@ -177,7 +172,7 @@ variable [BEq α]
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem count_empty {a : α} : count a #[] = 0 := rfl
|
||||
@[simp] theorem count_empty {a : α} : count a #[] = 0 := rfl
|
||||
|
||||
theorem count_push {a b : α} {xs : Array α} :
|
||||
count a (xs.push b) = count a xs + if b == a then 1 else 0 := by
|
||||
@@ -190,28 +185,21 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
|
||||
theorem count_le_size {a : α} {xs : Array α} : count a xs ≤ xs.size := countP_le_size
|
||||
|
||||
grind_pattern count_le_size => count a xs
|
||||
|
||||
@[grind =]
|
||||
theorem count_eq_size_filter {a : α} {xs : Array α} : count a xs = (filter (· == a) xs).size := by
|
||||
simp [count, countP_eq_size_filter]
|
||||
|
||||
theorem count_le_count_push {a b : α} {xs : Array α} : count a xs ≤ count a (xs.push b) := by
|
||||
simp [count_push]
|
||||
|
||||
@[grind =]
|
||||
theorem count_singleton {a b : α} : count a #[b] = if b == a then 1 else 0 := by
|
||||
simp [count_eq_countP]
|
||||
|
||||
@[simp, grind =] theorem count_append {a : α} {xs ys : Array α} : count a (xs ++ ys) = count a xs + count a ys :=
|
||||
@[simp] theorem count_append {a : α} {xs ys : Array α} : count a (xs ++ ys) = count a xs + count a ys :=
|
||||
countP_append
|
||||
|
||||
@[simp, grind =] theorem count_flatten {a : α} {xss : Array (Array α)} :
|
||||
@[simp] theorem count_flatten {a : α} {xss : Array (Array α)} :
|
||||
count a xss.flatten = (xss.map (count a)).sum := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.count_flatten, Function.comp_def]
|
||||
|
||||
@[simp, grind =] theorem count_reverse {a : α} {xs : Array α} : count a xs.reverse = count a xs := by
|
||||
@[simp] theorem count_reverse {a : α} {xs : Array α} : count a xs.reverse = count a xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@@ -220,10 +208,9 @@ theorem boole_getElem_le_count {xs : Array α} {i : Nat} {a : α} (h : i < xs.si
|
||||
rw [count_eq_countP]
|
||||
apply boole_getElem_le_countP (p := (· == a))
|
||||
|
||||
@[grind =]
|
||||
theorem count_set {xs : Array α} {i : Nat} {a b : α} (h : i < xs.size) :
|
||||
(xs.set i a).count b = xs.count b - (if xs[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
simp [count_eq_countP, countP_set]
|
||||
simp [count_eq_countP, countP_set, h]
|
||||
|
||||
variable [LawfulBEq α]
|
||||
|
||||
@@ -231,7 +218,7 @@ variable [LawfulBEq α]
|
||||
simp [count_push]
|
||||
|
||||
@[simp] theorem count_push_of_ne {xs : Array α} (h : b ≠ a) : count a (xs.push b) = count a xs := by
|
||||
simp_all [count_push]
|
||||
simp_all [count_push, h]
|
||||
|
||||
theorem count_singleton_self {a : α} : count a #[a] = 1 := by simp
|
||||
|
||||
@@ -292,17 +279,17 @@ abbrev mkArray_count_eq_of_count_eq_size := @replicate_count_eq_of_count_eq_size
|
||||
theorem count_le_count_map [BEq β] [LawfulBEq β] {xs : Array α} {f : α → β} {x : α} :
|
||||
count x xs ≤ count (f x) (map f xs) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_le_count_map]
|
||||
simp [List.count_le_count_map, countP_map]
|
||||
|
||||
theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {xs : Array α} :
|
||||
count b (filterMap f xs) = countP (fun a => f a == some b) xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_filterMap]
|
||||
simp [List.count_filterMap, countP_filterMap]
|
||||
|
||||
theorem count_flatMap {α} [BEq β] {xs : Array α} {f : α → Array β} {x : β} :
|
||||
count x (xs.flatMap f) = sum (map (count x ∘ f) xs) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.count_flatMap, Function.comp_def]
|
||||
simp [List.count_flatMap, countP_flatMap, Function.comp_def]
|
||||
|
||||
theorem countP_replace {a b : α} {xs : Array α} {p : α → Bool} :
|
||||
(xs.replace a b).countP p =
|
||||
|
||||
@@ -23,7 +23,7 @@ private theorem rel_of_isEqvAux
|
||||
induction i with
|
||||
| zero => contradiction
|
||||
| succ i ih =>
|
||||
simp only [Array.isEqvAux, Bool.and_eq_true] at heqv
|
||||
simp only [Array.isEqvAux, Bool.and_eq_true, decide_eq_true_eq] at heqv
|
||||
by_cases hj' : j < i
|
||||
next =>
|
||||
exact ih _ heqv.right hj'
|
||||
@@ -69,7 +69,7 @@ theorem isEqv_eq_decide (xs ys : Array α) (r) :
|
||||
simpa [isEqv_iff_rel] using h'
|
||||
|
||||
@[simp, grind =] theorem isEqv_toList [BEq α] (xs ys : Array α) : (xs.toList.isEqv ys.toList r) = (xs.isEqv ys r) := by
|
||||
simp [isEqv_eq_decide, List.isEqv_eq_decide, Array.size]
|
||||
simp [isEqv_eq_decide, List.isEqv_eq_decide]
|
||||
|
||||
theorem eq_of_isEqv [DecidableEq α] (xs ys : Array α) (h : Array.isEqv xs ys (fun x y => x = y)) : xs = ys := by
|
||||
have ⟨h, h'⟩ := rel_of_isEqv h
|
||||
@@ -100,7 +100,7 @@ theorem beq_eq_decide [BEq α] (xs ys : Array α) :
|
||||
simp [BEq.beq, isEqv_eq_decide]
|
||||
|
||||
@[simp, grind =] theorem beq_toList [BEq α] (xs ys : Array α) : (xs.toList == ys.toList) = (xs == ys) := by
|
||||
simp [beq_eq_decide, List.beq_eq_decide, Array.size]
|
||||
simp [beq_eq_decide, List.beq_eq_decide]
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@ open Nat
|
||||
|
||||
/-! ### eraseP -/
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_empty : #[].eraseP p = #[] := by simp
|
||||
@[simp] theorem eraseP_empty : #[].eraseP p = #[] := by simp
|
||||
|
||||
theorem eraseP_of_forall_mem_not {xs : Array α} (h : ∀ a, a ∈ xs → ¬p a) : xs.eraseP p = xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -65,7 +64,6 @@ theorem exists_or_eq_self_of_eraseP (p) (xs : Array α) :
|
||||
let ⟨_, ys, zs, _, _, e₁, e₂⟩ := exists_of_eraseP al pa
|
||||
rw [e₂]; simp [size_append, e₁]
|
||||
|
||||
@[grind =]
|
||||
theorem size_eraseP {xs : Array α} : (xs.eraseP p).size = if xs.any p then xs.size - 1 else xs.size := by
|
||||
split <;> rename_i h
|
||||
· simp only [any_eq_true] at h
|
||||
@@ -83,12 +81,11 @@ theorem le_size_eraseP {xs : Array α} : xs.size - 1 ≤ (xs.eraseP p).size := b
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.le_length_eraseP
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseP
|
||||
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
@[simp] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_eraseP_of_neg pa
|
||||
|
||||
@@ -96,18 +93,15 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem eraseP_map {f : β → α} {xs : Array β} : (xs.map f).eraseP p = (xs.eraseP (p ∘ f)).map f := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.eraseP_map
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filterMap {f : α → Option β} {xs : Array α} :
|
||||
(filterMap f xs).eraseP p = filterMap f (xs.eraseP (fun x => match f x with | some y => p y | none => false)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.eraseP_filterMap
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_filter {f : α → Bool} {xs : Array α} :
|
||||
(filter f xs).eraseP p = filter f (xs.eraseP (fun x => p x && f x)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -125,7 +119,6 @@ theorem eraseP_append_right {xs : Array α} ys (h : ∀ b ∈ xs, ¬p b) :
|
||||
rcases ys with ⟨ys⟩
|
||||
simpa using List.eraseP_append_right ys (by simpa using h)
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_append {xs : Array α} {ys : Array α} :
|
||||
(xs ++ ys).eraseP p = if xs.any p then xs.eraseP p ++ ys else xs ++ ys.eraseP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -133,7 +126,6 @@ theorem eraseP_append {xs : Array α} {ys : Array α} :
|
||||
simp only [List.append_toArray, List.eraseP_toArray, List.eraseP_append, List.any_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_replicate {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).eraseP p = if p a then replicate (n - 1) a else replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.eraseP_toArray, List.eraseP_replicate]
|
||||
@@ -173,7 +165,6 @@ theorem eraseP_eq_iff {p} {xs : Array α} :
|
||||
· exact Or.inl h
|
||||
· exact Or.inr ⟨a, l₁, by simpa using h₁, h₂, ⟨l, by simp⟩⟩
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {xs : Array α} (h : ∀ a ∈ xs, ¬ p a ∨ ¬ q a) :
|
||||
(xs.eraseP p).eraseP q = (xs.eraseP q).eraseP p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -206,7 +197,7 @@ theorem erase_eq_eraseP [LawfulBEq α] (a : α) (xs : Array α) : xs.erase a = x
|
||||
theorem erase_ne_empty_iff [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.erase a ≠ #[] ↔ xs ≠ #[] ∧ xs ≠ #[a] := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
simp [List.erase_ne_nil_iff]
|
||||
|
||||
theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a ∈ xs) :
|
||||
∃ ys zs, a ∉ ys ∧ xs = ys.push a ++ zs ∧ xs.erase a = ys ++ zs := by
|
||||
@@ -217,7 +208,6 @@ theorem exists_erase_eq [LawfulBEq α] {a : α} {xs : Array α} (h : a ∈ xs) :
|
||||
(xs.erase a).size = xs.size - 1 := by
|
||||
rw [erase_eq_eraseP]; exact size_eraseP_of_mem h (beq_self_eq_true a)
|
||||
|
||||
@[grind =]
|
||||
theorem size_erase [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
(xs.erase a).size = if a ∈ xs then xs.size - 1 else xs.size := by
|
||||
rw [erase_eq_eraseP, size_eraseP]
|
||||
@@ -232,12 +222,11 @@ theorem le_size_erase [LawfulBEq α] {a : α} {xs : Array α} : xs.size - 1 ≤
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.le_length_erase
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_erase (by simpa using h)
|
||||
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
@[simp] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
a ∈ xs.erase b ↔ a ∈ xs :=
|
||||
erase_eq_eraseP b xs ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -245,7 +234,6 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
|
||||
rw [erase_eq_eraseP', eraseP_eq_self_iff]
|
||||
simp [forall_mem_ne']
|
||||
|
||||
@[grind _=_]
|
||||
theorem erase_filter [LawfulBEq α] {f : α → Bool} {xs : Array α} :
|
||||
(filter f xs).erase a = filter f (xs.erase a) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -263,7 +251,6 @@ theorem erase_append_right [LawfulBEq α] {a : α} {xs : Array α} (ys : Array
|
||||
rcases ys with ⟨ys⟩
|
||||
simpa using List.erase_append_right ys (by simpa using h)
|
||||
|
||||
@[grind =]
|
||||
theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
(xs ++ ys).erase a = if a ∈ xs then xs.erase a ++ ys else xs ++ ys.erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -271,7 +258,6 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem erase_replicate [LawfulBEq α] {n : Nat} {a b : α} :
|
||||
(replicate n a).erase b = if b == a then replicate (n - 1) a else replicate n a := by
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
@@ -283,7 +269,6 @@ abbrev erase_mkArray := @erase_replicate
|
||||
|
||||
-- The arguments `a b` are explicit,
|
||||
-- so they can be specified to prevent `simp` repeatedly applying the lemma.
|
||||
@[grind =]
|
||||
theorem erase_comm [LawfulBEq α] (a b : α) {xs : Array α} :
|
||||
(xs.erase a).erase b = (xs.erase b).erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -306,7 +291,7 @@ theorem erase_eq_iff [LawfulBEq α] {a : α} {xs : Array α} :
|
||||
@[simp] theorem erase_replicate_self [LawfulBEq α] {a : α} :
|
||||
(replicate n a).erase a = replicate (n - 1) a := by
|
||||
simp only [← List.toArray_replicate, List.erase_toArray]
|
||||
simp
|
||||
simp [List.erase_replicate]
|
||||
|
||||
@[deprecated erase_replicate_self (since := "2025-03-18")]
|
||||
abbrev erase_mkArray_self := @erase_replicate_self
|
||||
@@ -327,7 +312,6 @@ theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.siz
|
||||
xs.eraseIdx i h = xs.eraseIdxIfInBounds i := by
|
||||
simp [eraseIdxIfInBounds, h]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_eq_take_drop_succ {xs : Array α} {i : Nat} (h) :
|
||||
xs.eraseIdx i h = xs.take i ++ xs.drop (i + 1) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -338,7 +322,6 @@ theorem eraseIdx_eq_take_drop_succ {xs : Array α} {i : Nat} (h) :
|
||||
rw [List.take_of_length_le]
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_eraseIdx {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} :
|
||||
(xs.eraseIdx i)[j]? = if j < i then xs[j]? else xs[j + 1]? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -352,11 +335,10 @@ theorem getElem?_eraseIdx_of_lt {xs : Array α} {i : Nat} (h : i < xs.size) {j :
|
||||
theorem getElem?_eraseIdx_of_ge {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} (h' : i ≤ j) :
|
||||
(xs.eraseIdx i)[j]? = xs[j + 1]? := by
|
||||
rw [getElem?_eraseIdx]
|
||||
simp only [ite_eq_right_iff]
|
||||
simp only [dite_eq_ite, ite_eq_right_iff]
|
||||
intro h'
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_eraseIdx {xs : Array α} {i : Nat} (h : i < xs.size) {j : Nat} (h' : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i)[j] = if h'' : j < i then
|
||||
xs[j]
|
||||
@@ -380,7 +362,6 @@ theorem eraseIdx_ne_empty_iff {xs : Array α} {i : Nat} {h} : xs.eraseIdx i ≠
|
||||
simp [h]
|
||||
· simp
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseIdx {xs : Array α} {i : Nat} {h} {a : α} (h : a ∈ xs.eraseIdx i) : a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseIdx (by simpa using h)
|
||||
@@ -392,29 +373,13 @@ theorem eraseIdx_append_of_lt_size {xs : Array α} {k : Nat} (hk : k < xs.size)
|
||||
simp at hk
|
||||
simp [List.eraseIdx_append_of_lt_length, *]
|
||||
|
||||
theorem eraseIdx_append_of_size_le {xs : Array α} {k : Nat} (hk : xs.size ≤ k) (ys : Array α) (h) :
|
||||
theorem eraseIdx_append_of_length_le {xs : Array α} {k : Nat} (hk : xs.size ≤ k) (ys : Array α) (h) :
|
||||
eraseIdx (xs ++ ys) k = xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
|
||||
rcases xs with ⟨l⟩
|
||||
rcases ys with ⟨l'⟩
|
||||
simp at hk
|
||||
simp [List.eraseIdx_append_of_length_le, *]
|
||||
|
||||
@[deprecated eraseIdx_append_of_size_le (since := "2025-06-11")]
|
||||
abbrev eraseIdx_append_of_length_le := @eraseIdx_append_of_size_le
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_append {xs ys : Array α} (h : k < (xs ++ ys).size) :
|
||||
eraseIdx (xs ++ ys) k =
|
||||
if h' : k < xs.size then
|
||||
eraseIdx xs k ++ ys
|
||||
else
|
||||
xs ++ eraseIdx ys (k - xs.size) (by simp at h; omega) := by
|
||||
split <;> rename_i h
|
||||
· simp [eraseIdx_append_of_lt_size h]
|
||||
· rw [eraseIdx_append_of_size_le]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} {h} :
|
||||
(replicate n a).eraseIdx k = replicate (n - 1) a := by
|
||||
simp at h
|
||||
@@ -463,48 +428,6 @@ theorem eraseIdx_set_gt {xs : Array α} {i : Nat} {j : Nat} {a : α} (h : i < j)
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.eraseIdx_set_gt, *]
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_set {xs : Array α} {i : Nat} {a : α} {hi : i < xs.size} {j : Nat} {hj : j < (xs.set i a).size} :
|
||||
(xs.set i a).eraseIdx j =
|
||||
if h' : j < i then
|
||||
(xs.eraseIdx j).set (i - 1) a (by simp; omega)
|
||||
else if h'' : j = i then
|
||||
xs.eraseIdx i
|
||||
else
|
||||
(xs.eraseIdx j (by simp at hj; omega)).set i a (by simp at hj ⊢; omega) := by
|
||||
split <;> rename_i h'
|
||||
· rw [eraseIdx_set_lt]
|
||||
omega
|
||||
· split <;> rename_i h''
|
||||
· subst h''
|
||||
rw [eraseIdx_set_eq]
|
||||
· rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
theorem set_eraseIdx_le {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : i ≤ j) (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a = (xs.set (j + 1) a (by simp at hj; omega)).eraseIdx i (by simp at ⊢; omega) := by
|
||||
rw [eraseIdx_set_lt]
|
||||
· simp
|
||||
· omega
|
||||
|
||||
theorem set_eraseIdx_gt {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (h : j < i) (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a = (xs.set j a).eraseIdx i (by simp at ⊢; omega) := by
|
||||
rw [eraseIdx_set_gt]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_eraseIdx {xs : Array α} {i : Nat} {w : i < xs.size} {j : Nat} {a : α} (hj : j < (xs.eraseIdx i).size) :
|
||||
(xs.eraseIdx i).set j a =
|
||||
if h' : i ≤ j then
|
||||
(xs.set (j + 1) a (by simp at hj; omega)).eraseIdx i (by simp at ⊢; omega)
|
||||
else
|
||||
(xs.set j a).eraseIdx i (by simp at ⊢; omega) := by
|
||||
split <;> rename_i h'
|
||||
· rw [set_eraseIdx_le]
|
||||
omega
|
||||
· rw [set_eraseIdx_gt]
|
||||
omega
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{xs : Array α} {i : Nat} (h : i + 1 < xs.size) :
|
||||
(xs.eraseIdx (i + 1)).set i xs[i + 1] (by simp; omega) = xs.eraseIdx i := by
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Array
|
||||
· simp
|
||||
omega
|
||||
· simp only [size_extract] at h₁ h₂
|
||||
simp
|
||||
simp [h]
|
||||
|
||||
theorem size_extract_le {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).size ≤ j - i := by
|
||||
@@ -46,7 +46,7 @@ theorem size_extract_of_le {as : Array α} {i j : Nat} (h : j ≤ as.size) :
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop ≤ as.size) :
|
||||
(as.push b).extract start stop = as.extract start stop := by
|
||||
ext i h₁ h₂
|
||||
@@ -56,7 +56,7 @@ theorem extract_push {as : Array α} {b : α} {start stop : Nat} (h : stop ≤ a
|
||||
simp only [getElem_extract, getElem_push]
|
||||
rw [dif_pos (by omega)]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
|
||||
as.extract 0 stop = as.pop := by
|
||||
ext i h₁ h₂
|
||||
@@ -65,7 +65,7 @@ theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
|
||||
· simp only [size_extract, size_pop] at h₁ h₂
|
||||
simp [getElem_extract, getElem_pop]
|
||||
|
||||
@[simp, grind _=_]
|
||||
@[simp]
|
||||
theorem extract_append_extract {as : Array α} {i j k : Nat} :
|
||||
as.extract i j ++ as.extract j k = as.extract (min i j) (max j k) := by
|
||||
ext l h₁ h₂
|
||||
@@ -162,14 +162,14 @@ theorem extract_sub_one {as : Array α} {i j : Nat} (h : j < as.size) :
|
||||
@[simp]
|
||||
theorem getElem?_extract_of_lt {as : Array α} {i j k : Nat} (h : k < min j as.size - i) :
|
||||
(as.extract i j)[k]? = some (as[i + k]'(by omega)) := by
|
||||
simp [h]
|
||||
simp [getElem?_extract, h]
|
||||
|
||||
theorem getElem?_extract_of_succ {as : Array α} {j : Nat} :
|
||||
(as.extract 0 (j + 1))[j]? = as[j]? := by
|
||||
simp [getElem?_extract]
|
||||
omega
|
||||
|
||||
@[simp, grind =] theorem extract_extract {as : Array α} {i j k l : Nat} :
|
||||
@[simp] theorem extract_extract {as : Array α} {i j k l : Nat} :
|
||||
(as.extract i j).extract k l = as.extract (i + k) (min (i + l) j) := by
|
||||
ext m h₁ h₂
|
||||
· simp
|
||||
@@ -185,7 +185,6 @@ theorem ne_empty_of_extract_ne_empty {as : Array α} {i j : Nat} (h : as.extract
|
||||
as ≠ #[] :=
|
||||
mt extract_eq_empty_of_eq_empty h
|
||||
|
||||
@[grind =]
|
||||
theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
|
||||
(as.set k a).extract i j =
|
||||
if _ : k < i then
|
||||
@@ -212,14 +211,13 @@ theorem extract_set {as : Array α} {i j k : Nat} (h : k < as.size) {a : α} :
|
||||
simp [getElem_set]
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem set_extract {as : Array α} {i j k : Nat} (h : k < (as.extract i j).size) {a : α} :
|
||||
(as.extract i j).set k a = (as.set (i + k) a (by simp at h; omega)).extract i j := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
· simp_all [getElem_set]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem extract_append {as bs : Array α} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext l h₁ h₂
|
||||
@@ -240,18 +238,20 @@ theorem extract_append_left {as bs : Array α} :
|
||||
(as ++ bs).extract 0 as.size = as.extract 0 as.size := by
|
||||
simp
|
||||
|
||||
theorem extract_append_right {as bs : Array α} :
|
||||
@[simp] theorem extract_append_right {as bs : Array α} :
|
||||
(as ++ bs).extract as.size (as.size + i) = bs.extract 0 i := by
|
||||
simp
|
||||
simp only [extract_append, extract_size_left, Nat.sub_self, empty_append]
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[simp, grind =] theorem map_extract {as : Array α} {i j : Nat} :
|
||||
@[simp] theorem map_extract {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).map f = (as.map f).extract i j := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
· simp only [size_map, size_extract] at h₁ h₂
|
||||
simp only [getElem_map, getElem_extract]
|
||||
|
||||
@[simp, grind =] theorem extract_replicate {a : α} {n i j : Nat} :
|
||||
@[simp] theorem extract_replicate {a : α} {n i j : Nat} :
|
||||
(replicate n a).extract i j = replicate (min j n - i) a := by
|
||||
ext l h₁ h₂
|
||||
· simp
|
||||
@@ -299,7 +299,6 @@ theorem set_eq_push_extract_append_extract {as : Array α} {i : Nat} (h : i < as
|
||||
simp at h
|
||||
simp [List.set_eq_take_append_cons_drop, h, List.take_of_length_le]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_reverse {as : Array α} {i j : Nat} :
|
||||
as.reverse.extract i j = (as.extract (as.size - j) (as.size - i)).reverse := by
|
||||
ext l h₁ h₂
|
||||
@@ -310,7 +309,6 @@ theorem extract_reverse {as : Array α} {i j : Nat} :
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_extract {as : Array α} {i j : Nat} :
|
||||
(as.extract i j).reverse = as.reverse.extract (as.size - j) (as.size - i) := by
|
||||
rw [extract_reverse]
|
||||
|
||||
@@ -23,10 +23,10 @@ Examples:
|
||||
-/
|
||||
protected def finRange (n : Nat) : Array (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp, grind =] theorem size_finRange {n} : (Array.finRange n).size = n := by
|
||||
@[simp] theorem size_finRange {n} : (Array.finRange n).size = n := by
|
||||
simp [Array.finRange]
|
||||
|
||||
@[simp, grind =] theorem getElem_finRange {i : Nat} (h : i < (Array.finRange n).size) :
|
||||
@[simp] theorem getElem_finRange {i : Nat} (h : i < (Array.finRange n).size) :
|
||||
(Array.finRange n)[i] = Fin.cast size_finRange ⟨i, h⟩ := by
|
||||
simp [Array.finRange]
|
||||
|
||||
@@ -49,7 +49,6 @@ theorem finRange_succ_last {n} :
|
||||
· simp_all
|
||||
omega
|
||||
|
||||
@[grind _=_]
|
||||
theorem finRange_reverse {n} : (Array.finRange n).reverse = (Array.finRange n).map Fin.rev := by
|
||||
ext i h
|
||||
· simp
|
||||
|
||||
@@ -38,22 +38,11 @@ theorem findSome?_singleton {a : α} {f : α → Option β} : #[a].findSome? f =
|
||||
@[simp] theorem findSomeRev?_push_of_isNone {xs : Array α} (h : (f a).isNone) : (xs.push a).findSomeRev? f = xs.findSomeRev? f := by
|
||||
cases xs; simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem findSomeRev?_push {xs : Array α} {a : α} {f : α → Option β} :
|
||||
(xs.push a).findSomeRev? f = (f a).or (xs.findSomeRev? f) := by
|
||||
match h : f a with
|
||||
| some b =>
|
||||
rw [findSomeRev?_push_of_isSome]
|
||||
all_goals simp_all
|
||||
| none =>
|
||||
rw [findSomeRev?_push_of_isNone]
|
||||
all_goals simp_all
|
||||
|
||||
theorem exists_of_findSome?_eq_some {f : α → Option β} {xs : Array α} (w : xs.findSome? f = some b) :
|
||||
∃ a, a ∈ xs ∧ f a = some b := by
|
||||
cases xs; simp_all [List.exists_of_findSome?_eq_some]
|
||||
|
||||
@[simp, grind =] theorem findSome?_eq_none_iff : findSome? p xs = none ↔ ∀ x ∈ xs, p x = none := by
|
||||
@[simp] theorem findSome?_eq_none_iff : findSome? p xs = none ↔ ∀ x ∈ xs, p x = none := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp] theorem findSome?_isSome_iff {f : α → Option β} {xs : Array α} :
|
||||
@@ -70,39 +59,36 @@ theorem findSome?_eq_some_iff {f : α → Option β} {xs : Array α} {b : β} :
|
||||
· rintro ⟨xs, a, ys, h₀, h₁, h₂⟩
|
||||
exact ⟨xs.toList, a, ys.toList, by simpa using congrArg toList h₀, h₁, by simpa⟩
|
||||
|
||||
@[simp, grind =] theorem findSome?_guard {xs : Array α} : findSome? (Option.guard p) xs = find? p xs := by
|
||||
@[simp] theorem findSome?_guard {xs : Array α} : findSome? (Option.guard fun x => p x) xs = find? p xs := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_eq_findSome?_guard {xs : Array α} : find? p xs = findSome? (Option.guard p) xs :=
|
||||
theorem find?_eq_findSome?_guard {xs : Array α} : find? p xs = findSome? (Option.guard fun x => p x) xs :=
|
||||
findSome?_guard.symm
|
||||
|
||||
@[simp, grind =] theorem getElem?_zero_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f)[0]? = xs.findSome? f := by
|
||||
@[simp] theorem getElem?_zero_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f)[0]? = xs.findSome? f := by
|
||||
cases xs; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp, grind =] theorem getElem_zero_filterMap {f : α → Option β} {xs : Array α} (h) :
|
||||
@[simp] theorem getElem_zero_filterMap {f : α → Option β} {xs : Array α} (h) :
|
||||
(xs.filterMap f)[0] = (xs.findSome? f).get (by cases xs; simpa [List.length_filterMap_eq_countP] using h) := by
|
||||
cases xs; simp [← getElem?_zero_filterMap]
|
||||
cases xs; simp [← List.head_eq_getElem, ← getElem?_zero_filterMap]
|
||||
|
||||
@[simp, grind =] theorem back?_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f).back? = xs.findSomeRev? f := by
|
||||
@[simp] theorem back?_filterMap {f : α → Option β} {xs : Array α} : (xs.filterMap f).back? = xs.findSomeRev? f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =] theorem back!_filterMap [Inhabited β] {f : α → Option β} {xs : Array α} :
|
||||
@[simp] theorem back!_filterMap [Inhabited β] {f : α → Option β} {xs : Array α} :
|
||||
(xs.filterMap f).back! = (xs.findSomeRev? f).getD default := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind _=_] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
@[simp] theorem map_findSome? {f : α → Option β} {g : β → γ} {xs : Array α} :
|
||||
(xs.findSome? f).map g = xs.findSome? (Option.map g ∘ f) := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem findSome?_map {f : β → γ} {xs : Array β} : findSome? p (xs.map f) = xs.findSome? (p ∘ f) := by
|
||||
cases xs; simp [List.findSome?_map]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_append {xs ys : Array α} : (xs ++ ys).findSome? f = (xs.findSome? f).or (ys.findSome? f) := by
|
||||
cases xs; cases ys; simp [List.findSome?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_zero_flatten (xss : Array (Array α)) :
|
||||
(flatten xss)[0]? = xss.findSome? fun xs => xs[0]? := by
|
||||
cases xss using array₂_induction
|
||||
@@ -118,14 +104,12 @@ theorem getElem_zero_flatten.proof {xss : Array (Array α)} (h : 0 < xss.flatten
|
||||
obtain ⟨_, ⟨xs, m, rfl⟩, h⟩ := h
|
||||
exact ⟨xs, m, by simpa using h⟩
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_zero_flatten {xss : Array (Array α)} (h) :
|
||||
(flatten xss)[0] = (xss.findSome? fun xs => xs[0]?).get (getElem_zero_flatten.proof h) := by
|
||||
have t := getElem?_zero_flatten xss
|
||||
simp at t
|
||||
simp [getElem?_eq_getElem, h] at t
|
||||
simp [← t]
|
||||
|
||||
@[grind =]
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
simp [← List.toArray_replicate, List.findSome?_replicate]
|
||||
|
||||
@@ -156,37 +140,21 @@ abbrev findSome?_mkArray_of_isNone := @findSome?_replicate_of_isNone
|
||||
|
||||
/-! ### find? -/
|
||||
|
||||
@[simp, grind =] theorem find?_empty : find? p #[] = none := rfl
|
||||
@[simp] theorem find?_empty : find? p #[] = none := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
@[simp] theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].find? p = if p a then some a else none := by
|
||||
simp
|
||||
simp [singleton_eq_toArray_singleton]
|
||||
|
||||
@[simp] theorem findRev?_push_of_pos {xs : Array α} (h : p a) :
|
||||
findRev? p (xs.push a) = some a := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[simp] theorem findRev?_push_of_neg {xs : Array α} (h : ¬p a) :
|
||||
@[simp] theorem findRev?_cons_of_neg {xs : Array α} (h : ¬p a) :
|
||||
findRev? p (xs.push a) = findRev? p xs := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[deprecated findRev?_push_of_neg (since := "2025-06-12")]
|
||||
abbrev findRev?_cons_of_neg := @findRev?_push_of_neg
|
||||
|
||||
@[grind =]
|
||||
theorem finRev?_push {xs : Array α} :
|
||||
findRev? p (xs.push a) = (Option.guard p a).or (xs.findRev? p) := by
|
||||
cases h : p a
|
||||
· rw [findRev?_push_of_neg, Option.guard_eq_none_iff.mpr h]
|
||||
all_goals simp [h]
|
||||
· rw [findRev?_push_of_pos, Option.guard_eq_some_iff.mpr ⟨rfl, h⟩]
|
||||
all_goals simp [h]
|
||||
|
||||
@[deprecated finRev?_push (since := "2025-06-12")]
|
||||
abbrev findRev?_cons := @finRev?_push
|
||||
|
||||
@[simp, grind =] theorem find?_eq_none : find? p xs = none ↔ ∀ x ∈ xs, ¬ p x := by
|
||||
@[simp] theorem find?_eq_none : find? p xs = none ↔ ∀ x ∈ xs, ¬ p x := by
|
||||
cases xs; simp
|
||||
|
||||
theorem find?_eq_some_iff_append {xs : Array α} :
|
||||
@@ -210,63 +178,60 @@ 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, grind =] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
@[simp] theorem find?_isSome {xs : Array α} {p : α → Bool} : (xs.find? p).isSome ↔ ∃ x, x ∈ xs ∧ p x := by
|
||||
cases xs; simp
|
||||
|
||||
@[grind →]
|
||||
theorem find?_some {xs : Array α} (h : find? p xs = some a) : p a := by
|
||||
cases xs
|
||||
simp at h
|
||||
exact List.find?_some h
|
||||
|
||||
@[grind →]
|
||||
theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ xs := by
|
||||
cases xs
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
@[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, grind =] theorem getElem?_zero_filter {p : α → Bool} {xs : Array α} :
|
||||
@[simp] theorem getElem?_zero_filter {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p)[0]? = xs.find? p := by
|
||||
cases xs; simp [← List.head?_eq_getElem?]
|
||||
|
||||
@[simp, grind =] theorem getElem_zero_filter {p : α → Bool} {xs : Array α} (h) :
|
||||
@[simp] theorem getElem_zero_filter {p : α → Bool} {xs : Array α} (h) :
|
||||
(xs.filter p)[0] =
|
||||
(xs.find? p).get (by cases xs; simpa [← List.countP_eq_length_filter] using h) := by
|
||||
cases xs
|
||||
simp [List.getElem_zero_eq_head]
|
||||
|
||||
@[simp, grind =] theorem back?_filter {p : α → Bool} {xs : Array α} : (xs.filter p).back? = xs.findRev? p := by
|
||||
@[simp] theorem back?_filter {p : α → Bool} {xs : Array α} : (xs.filter p).back? = xs.findRev? p := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =] theorem back!_filter [Inhabited α] {p : α → Bool} {xs : Array α} :
|
||||
@[simp] theorem back!_filter [Inhabited α] {p : α → Bool} {xs : Array α} :
|
||||
(xs.filter p).back! = (xs.findRev? p).get! := by
|
||||
cases xs; simp [Option.get!_eq_getD]
|
||||
|
||||
@[simp, grind =] theorem find?_filterMap {xs : Array α} {f : α → Option β} {p : β → Bool} :
|
||||
@[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, grind =] theorem find?_map {f : β → α} {xs : Array β} :
|
||||
@[simp] theorem find?_map {f : β → α} {xs : Array β} :
|
||||
find? p (xs.map f) = (xs.find? (p ∘ f)).map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind =] theorem find?_append {xs ys : Array α} :
|
||||
@[simp] theorem find?_append {xs ys : Array α} :
|
||||
(xs ++ ys).find? p = (xs.find? p).or (ys.find? p) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
|
||||
@[simp, grind _=_] theorem find?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (find? p) := by
|
||||
@[simp] theorem find?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = xss.findSome? (·.find? p) := by
|
||||
cases xss using array₂_induction
|
||||
simp [List.findSome?_map, Function.comp_def]
|
||||
|
||||
@@ -305,10 +270,10 @@ theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α → Bool} {a
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem find?_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
@[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]
|
||||
simp [List.find?_flatMap, Array.flatMap_toArray]
|
||||
|
||||
theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
@@ -317,7 +282,6 @@ theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β
|
||||
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
|
||||
|
||||
@[grind =]
|
||||
theorem find?_replicate :
|
||||
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [← List.toArray_replicate, List.find?_replicate]
|
||||
@@ -348,7 +312,7 @@ abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [← List.toArray_replicate, Classical.or_iff_not_imp_left]
|
||||
simp [← List.toArray_replicate, List.find?_replicate_eq_none_iff, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
|
||||
@@ -370,7 +334,6 @@ abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkArray := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
(xs.pmap f H).find? p = (xs.attach.find? (fun ⟨a, m⟩ => p (f a (H a m)))).map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
@@ -384,15 +347,11 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
|
||||
|
||||
/-! ### findIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
|
||||
@[grind =]
|
||||
@[simp] theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
@@ -401,8 +360,6 @@ theorem findIdx_getElem {xs : Array α} {w : xs.findIdx p < xs.size} :
|
||||
p xs[xs.findIdx p] :=
|
||||
xs.findIdx_of_getElem?_eq_some (getElem?_eq_getElem w)
|
||||
|
||||
grind_pattern findIdx_getElem => xs[xs.findIdx p]
|
||||
|
||||
theorem findIdx_lt_size_of_exists {xs : Array α} (h : ∃ x ∈ xs, p x) :
|
||||
xs.findIdx p < xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -429,24 +386,18 @@ theorem findIdx_le_size {p : α → Bool} {xs : Array α} : xs.findIdx p ≤ xs.
|
||||
· simp at e
|
||||
exact Nat.le_of_eq (findIdx_eq_size.mpr e)
|
||||
|
||||
grind_pattern findIdx_le_size => xs.findIdx p, xs.size
|
||||
|
||||
@[simp]
|
||||
theorem findIdx_lt_size {p : α → Bool} {xs : Array α} :
|
||||
xs.findIdx p < xs.size ↔ ∃ x ∈ xs, p x := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
grind_pattern findIdx_lt_size => xs.findIdx p, xs.size
|
||||
|
||||
/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/
|
||||
theorem not_of_lt_findIdx {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.findIdx p) :
|
||||
p (xs[i]'(Nat.le_trans h findIdx_le_size)) = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.not_of_lt_findIdx (by simpa using h)
|
||||
|
||||
grind_pattern not_of_lt_findIdx => xs.findIdx p, xs[i]
|
||||
|
||||
/-- If `¬ p xs[j]` for all `j < i`, then `i ≤ xs.findIdx p`. -/
|
||||
theorem le_findIdx_of_not {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
|
||||
(h2 : ∀ j (hji : j < i), p (xs[j]'(Nat.lt_trans hji h)) = false) : i ≤ xs.findIdx p := by
|
||||
@@ -474,7 +425,6 @@ theorem findIdx_eq {p : α → Bool} {xs : Array α} {i : Nat} (h : i < xs.size)
|
||||
simp at h3
|
||||
simp_all [not_of_lt_findIdx h3]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_append {p : α → Bool} {xs ys : Array α} :
|
||||
(xs ++ ys).findIdx p =
|
||||
if xs.findIdx p < xs.size then xs.findIdx p else ys.findIdx p + xs.size := by
|
||||
@@ -482,13 +432,12 @@ theorem findIdx_append {p : α → Bool} {xs ys : Array α} :
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.findIdx_append]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findIdx p = if xs.findIdx p < xs.size then xs.findIdx p else xs.size + if p a then 0 else 1 := by
|
||||
simp only [push_eq_append, findIdx_append]
|
||||
split <;> rename_i h
|
||||
· rfl
|
||||
· simp [Nat.add_comm]
|
||||
· simp [findIdx_singleton, Nat.add_comm]
|
||||
|
||||
theorem findIdx_le_findIdx {xs : Array α} {p q : α → Bool} (h : ∀ x ∈ xs, p x → q x) : xs.findIdx q ≤ xs.findIdx p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -505,7 +454,7 @@ theorem false_of_mem_extract_findIdx {xs : Array α} {p : α → Bool} (h : x
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.false_of_mem_take_findIdx (by simpa using h)
|
||||
|
||||
@[simp, grind =] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
@[simp] theorem findIdx_extract {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
(xs.extract 0 i).findIdx p = min i (xs.findIdx p) := by
|
||||
cases xs
|
||||
simp
|
||||
@@ -517,24 +466,24 @@ theorem false_of_mem_extract_findIdx {xs : Array α} {p : α → Bool} (h : x
|
||||
|
||||
/-! ### findIdx? -/
|
||||
|
||||
@[simp, grind =] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := by simp
|
||||
@[grind =] theorem findIdx?_singleton {a : α} {p : α → Bool} :
|
||||
@[simp] theorem findIdx?_empty : (#[] : Array α).findIdx? p = none := by simp
|
||||
theorem findIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx? p = if p a then some 0 else none := by
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem findIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ ∀ x, x ∈ xs → p x = false := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem findIdx?_isSome {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_isSome]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem findIdx?_isNone {xs : Array α} {p : α → Bool} :
|
||||
(xs.findIdx? p).isNone = xs.all (¬p ·) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -553,7 +502,7 @@ theorem findIdx?_eq_some_of_exists {xs : Array α} {p : α → Bool} (h : ∃ x,
|
||||
theorem findIdx?_eq_none_iff_findIdx_eq {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = none ↔ xs.findIdx p = xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
simp [List.findIdx?_eq_none_iff_findIdx_eq]
|
||||
|
||||
theorem findIdx?_eq_guard_findIdx_lt {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx? p = Option.guard (fun i => i < xs.size) (xs.findIdx p) := by
|
||||
@@ -576,19 +525,18 @@ theorem of_findIdx?_eq_none {xs : Array α} {p : α → Bool} (w : xs.findIdx? p
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.of_findIdx?_eq_none (by simpa using w)
|
||||
|
||||
@[simp, grind =] theorem findIdx?_map {f : β → α} {xs : Array β} {p : α → Bool} :
|
||||
@[simp] theorem findIdx?_map {f : β → α} {xs : Array β} {p : α → Bool} :
|
||||
findIdx? p (xs.map f) = xs.findIdx? (p ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.findIdx?_map]
|
||||
|
||||
@[simp, grind =] theorem findIdx?_append :
|
||||
@[simp] theorem findIdx?_append :
|
||||
(xs ++ ys : Array α).findIdx? p =
|
||||
(xs.findIdx? p).or ((ys.findIdx? p).map fun i => i + xs.size) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.findIdx?_append]
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx?_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findIdx? p = (xs.findIdx? p).or (if p a then some xs.size else none) := by
|
||||
simp only [push_eq_append, findIdx?_append]
|
||||
@@ -604,7 +552,7 @@ theorem findIdx?_flatten {xss : Array (Array α)} {p : α → Bool} :
|
||||
cases xss using array₂_induction
|
||||
simp [List.findIdx?_flatten, Function.comp_def]
|
||||
|
||||
@[simp, grind =] theorem findIdx?_replicate :
|
||||
@[simp] theorem findIdx?_replicate :
|
||||
(replicate n a).findIdx? p = if 0 < n ∧ p a then some 0 else none := by
|
||||
rw [← List.toArray_replicate]
|
||||
simp only [List.findIdx?_toArray]
|
||||
@@ -629,7 +577,6 @@ theorem findIdx?_eq_none_of_findIdx?_eq_none {xs : Array α} {p q : α → Bool}
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.findIdx?_eq_none_of_findIdx?_eq_none (by simpa using w)
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_eq_getD_findIdx? {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx p = (xs.findIdx? p).getD xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -646,17 +593,14 @@ theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : Array α} {p q : α → Bo
|
||||
cases xs
|
||||
simp [hf]
|
||||
|
||||
@[simp, grind =] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
@[simp] theorem findIdx?_take {xs : Array α} {i : Nat} {p : α → Bool} :
|
||||
(xs.take i).findIdx? p = (xs.findIdx? p).bind (Option.guard (fun j => j < i)) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
/-! ### findFinIdx? -/
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p #[] = none := by simp
|
||||
|
||||
@[grind =]
|
||||
@[simp] theorem findFinIdx?_empty {p : α → Bool} : findFinIdx? p #[] = none := by simp
|
||||
theorem findFinIdx?_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findFinIdx? p = if p a then some ⟨0, by simp⟩ else none := by
|
||||
simp
|
||||
@@ -674,7 +618,7 @@ theorem findFinIdx?_eq_pmap_findIdx? {xs : Array α} {p : α → Bool} :
|
||||
(fun i h => h) := by
|
||||
simp [findIdx?_eq_map_findFinIdx?_val, Option.pmap_map]
|
||||
|
||||
@[simp, grind =] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
@[simp] theorem findFinIdx?_eq_none_iff {xs : Array α} {p : α → Bool} :
|
||||
xs.findFinIdx? p = none ↔ ∀ x, x ∈ xs → ¬ p x := by
|
||||
simp [findFinIdx?_eq_pmap_findIdx?]
|
||||
|
||||
@@ -690,14 +634,12 @@ theorem findFinIdx?_eq_some_iff {xs : Array α} {p : α → Bool} {i : Fin xs.si
|
||||
· rintro ⟨h, w⟩
|
||||
exact ⟨i, ⟨i.2, h, fun j hji => w ⟨j, by omega⟩ hji⟩, rfl⟩
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
(xs.push a).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or (if p a then some ⟨xs.size, by simp⟩ else none) := by
|
||||
simp only [findFinIdx?_eq_pmap_findIdx?, findIdx?_push, Option.pmap_or]
|
||||
split <;> rename_i h _ <;> split <;> simp [h]
|
||||
|
||||
@[grind =]
|
||||
theorem findFinIdx?_append {xs ys : Array α} {p : α → Bool} :
|
||||
(xs ++ ys).findFinIdx? p =
|
||||
((xs.findFinIdx? p).map (Fin.castLE (by simp))).or
|
||||
@@ -707,17 +649,17 @@ theorem findFinIdx?_append {xs ys : Array α} {p : α → Bool} :
|
||||
· simp [h, Option.pmap_map, Option.map_pmap, Nat.add_comm]
|
||||
· simp [h]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem isSome_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isSome = xs.any p := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
(xs.findFinIdx? p).isNone = xs.all (fun x => ¬ p x) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
simp
|
||||
|
||||
@[simp] theorem findFinIdx?_subtype {p : α → Prop} {xs : Array { x // p x }}
|
||||
{f : { x // p x } → Bool} {g : α → Bool} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
@@ -725,8 +667,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
|
||||
rw [findFinIdx?_congr List.unattach_toArray]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
|
||||
simp [Array.size]
|
||||
simp [Function.comp_def]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
@@ -734,7 +675,6 @@ The verification API for `idxOf` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
|
||||
-/
|
||||
|
||||
@[grind =]
|
||||
theorem idxOf_append [BEq α] [LawfulBEq α] {xs ys : Array α} {a : α} :
|
||||
(xs ++ ys).idxOf a = if a ∈ xs then xs.idxOf a else ys.idxOf a + xs.size := by
|
||||
rw [idxOf, findIdx_append]
|
||||
@@ -748,23 +688,10 @@ theorem idxOf_eq_size [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∉ xs) : x
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_eq_length (by simpa using h)]
|
||||
|
||||
theorem idxOf_lt_length_of_mem [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∈ xs) : xs.idxOf a < xs.size := by
|
||||
theorem idxOf_lt_length [BEq α] [LawfulBEq α] {xs : Array α} (h : a ∈ xs) : xs.idxOf a < xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_lt_length_of_mem (by simpa using h)]
|
||||
simp [List.idxOf_lt_length (by simpa using h)]
|
||||
|
||||
theorem idxOf_le_size [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf a ≤ xs.size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_le_length]
|
||||
|
||||
grind_pattern idxOf_le_size => xs.idxOf a, xs.size
|
||||
|
||||
theorem idxOf_lt_size_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf a < xs.size ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf_lt_length_iff]
|
||||
|
||||
grind_pattern idxOf_lt_size_iff => xs.idxOf a, xs.size
|
||||
|
||||
/-! ### idxOf?
|
||||
|
||||
@@ -772,24 +699,27 @@ The verification API for `idxOf?` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
|
||||
-/
|
||||
|
||||
@[grind =] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
@[simp] theorem idxOf?_empty [BEq α] : (#[] : Array α).idxOf? a = none := by simp
|
||||
|
||||
@[simp, grind =] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
@[simp] theorem idxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = none ↔ a ∉ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.idxOf?_eq_none_iff]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem isSome_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isSome ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
@[simp]
|
||||
theorem isNone_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.idxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
|
||||
|
||||
/-! ### finIdxOf?
|
||||
|
||||
The verification API for `finIdxOf?` is still incomplete.
|
||||
@@ -798,31 +728,30 @@ The lemmas below should be made consistent with those for `findFinIdx?` (and pro
|
||||
|
||||
theorem idxOf?_eq_map_finIdxOf?_val [BEq α] {xs : Array α} {a : α} :
|
||||
xs.idxOf? a = (xs.finIdxOf? a).map (·.val) := by
|
||||
simp [idxOf?, finIdxOf?]
|
||||
simp [idxOf?, finIdxOf?, findIdx?_eq_map_findFinIdx?_val]
|
||||
|
||||
@[grind =] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
@[simp] theorem finIdxOf?_empty [BEq α] : (#[] : Array α).finIdxOf? a = none := by simp
|
||||
|
||||
@[simp, grind =] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
@[simp] theorem finIdxOf?_eq_none_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
xs.finIdxOf? a = none ↔ a ∉ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.finIdxOf?_eq_none_iff, Array.size]
|
||||
simp [List.finIdxOf?_eq_none_iff]
|
||||
|
||||
@[simp] theorem finIdxOf?_eq_some_iff [BEq α] [LawfulBEq α] {xs : Array α} {a : α} {i : Fin xs.size} :
|
||||
xs.finIdxOf? a = some i ↔ xs[i] = a ∧ ∀ j (_ : j < i), ¬xs[j] = a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
unfold Array.size at i ⊢
|
||||
simp [List.finIdxOf?_eq_some_iff]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isSome_finIdxOf? [BEq α] [PartialEquivBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isSome = xs.contains a := by
|
||||
@[simp]
|
||||
theorem isSome_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isSome ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem isNone_finIdxOf? [BEq α] [PartialEquivBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = !xs.contains a := by
|
||||
@[simp]
|
||||
theorem isNone_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array α} {a : α} :
|
||||
(xs.finIdxOf? a).isNone = ¬ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [Array.size]
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
@@ -44,19 +44,13 @@ theorem insertIdx_zero {xs : Array α} {x : α} : xs.insertIdx 0 x = #[x] ++ xs
|
||||
|
||||
@[simp] theorem size_insertIdx {xs : Array α} (h : i ≤ xs.size) : (xs.insertIdx i a).size = xs.size + 1 := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp at h
|
||||
simp [List.length_insertIdx, h]
|
||||
|
||||
theorem eraseIdx_insertIdx_self {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-15")]
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
|
||||
simp [eraseIdx_insertIdx_self]
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge {as : Array α}
|
||||
(w₁ : i < as.size) (w₂ : j ≤ (as.eraseIdx i).size) (h : i ≤ j) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
@@ -71,18 +65,6 @@ theorem insertIdx_eraseIdx_of_le {as : Array α}
|
||||
cases as
|
||||
simpa using List.insertIdx_eraseIdx_of_le (by simpa) (by simpa)
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_eraseIdx {as : Array α} (h₁ : i < as.size) (h₂ : j ≤ (as.eraseIdx i).size) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
if h : i ≤ j then
|
||||
(as.insertIdx (j + 1) a (by simp_all; omega)).eraseIdx i (by simp_all; omega)
|
||||
else
|
||||
(as.insertIdx j a).eraseIdx (i + 1) (by simp_all) := by
|
||||
split <;> rename_i h'
|
||||
· rw [insertIdx_eraseIdx_of_ge] <;> omega
|
||||
· rw [insertIdx_eraseIdx_of_le] <;> omega
|
||||
|
||||
@[grind =]
|
||||
theorem insertIdx_comm (a b : α) {i j : Nat} {xs : Array α} (_ : i ≤ j) (_ : j ≤ xs.size) :
|
||||
(xs.insertIdx i a).insertIdx (j + 1) b (by simpa) =
|
||||
(xs.insertIdx j b).insertIdx i a (by simp; omega) := by
|
||||
@@ -98,7 +80,6 @@ theorem insertIdx_size_self {xs : Array α} {x : α} : xs.insertIdx xs.size x =
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < (xs.insertIdx i x).size) :
|
||||
(xs.insertIdx i x)[k] =
|
||||
if h₁ : k < i then
|
||||
@@ -109,22 +90,21 @@ theorem getElem_insertIdx {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.siz
|
||||
else
|
||||
xs[k-1]'(by simp [size_insertIdx] at h; omega) := by
|
||||
cases xs
|
||||
simp [List.getElem_insertIdx]
|
||||
simp [List.getElem_insertIdx, w]
|
||||
|
||||
theorem getElem_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < i) :
|
||||
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k] := by
|
||||
simp [getElem_insertIdx, h]
|
||||
simp [getElem_insertIdx, w, h]
|
||||
|
||||
theorem getElem_insertIdx_self {xs : Array α} {x : α} {i : Nat} (w : i ≤ xs.size) :
|
||||
(xs.insertIdx i x)[i]'(by simp; omega) = x := by
|
||||
simp [getElem_insertIdx]
|
||||
simp [getElem_insertIdx, w]
|
||||
|
||||
theorem getElem_insertIdx_of_gt {xs : Array α} {x : α} {i k : Nat} (w : k ≤ xs.size) (h : k > i) :
|
||||
(xs.insertIdx i x)[k]'(by simp; omega) = xs[k - 1]'(by omega) := by
|
||||
simp [getElem_insertIdx]
|
||||
simp [getElem_insertIdx, w, h]
|
||||
rw [dif_neg (by omega), dif_neg (by omega)]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i x)[k]? =
|
||||
if k < i then
|
||||
@@ -135,7 +115,7 @@ theorem getElem?_insertIdx {xs : Array α} {x : α} {i k : Nat} (h : i ≤ xs.si
|
||||
else
|
||||
xs[k-1]? := by
|
||||
cases xs
|
||||
simp [List.getElem?_insertIdx]
|
||||
simp [List.getElem?_insertIdx, h]
|
||||
|
||||
theorem getElem?_insertIdx_of_lt {xs : Array α} {x : α} {i k : Nat} (w : i ≤ xs.size) (h : k < i) :
|
||||
(xs.insertIdx i x)[k]? = xs[k]? := by
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,12 +29,16 @@ protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys
|
||||
Decidable.not_not
|
||||
|
||||
@[simp] theorem lex_empty [BEq α] {lt : α → α → Bool} {xs : Array α} : xs.lex #[] lt = false := by
|
||||
simp [lex]
|
||||
simp [lex, Id.run]
|
||||
|
||||
@[simp] theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[b] lt = lt a b := by
|
||||
simp only [lex, List.getElem_toArray, List.getElem_singleton]
|
||||
cases lt a b <;> cases a != b <;> simp [Id.run]
|
||||
|
||||
private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs ys : Array α} :
|
||||
(#[a] ++ xs).lex (#[b] ++ ys) lt =
|
||||
(lt a b || a == b && xs.lex ys lt) := by
|
||||
simp only [lex]
|
||||
simp only [lex, Id.run]
|
||||
simp only [Std.Range.forIn'_eq_forIn'_range', size_append, List.size_toArray, List.length_singleton,
|
||||
Nat.add_comm 1]
|
||||
simp [Nat.add_min_add_right, List.range'_succ, getElem_append_left, List.range'_succ_left,
|
||||
@@ -47,16 +51,13 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
@[simp, grind =] theorem _root_.List.lex_toArray [BEq α] {lt : α → α → Bool} {l₁ l₂ : List α} :
|
||||
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => cases l₂ <;> simp [lex]
|
||||
| nil => cases l₂ <;> simp [lex, Id.run]
|
||||
| cons x l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp [lex]
|
||||
| nil => simp [lex, Id.run]
|
||||
| cons y l₂ =>
|
||||
rw [List.toArray_cons, List.toArray_cons y, cons_lex_cons, List.lex, ih]
|
||||
|
||||
theorem singleton_lex_singleton [BEq α] {lt : α → α → Bool} : #[a].lex #[b] lt = lt a b := by
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem lex_toList [BEq α] {lt : α → α → Bool} {xs ys : Array α} :
|
||||
xs.toList.lex ys.toList lt = xs.lex ys lt := by
|
||||
cases xs <;> cases ys <;> simp
|
||||
@@ -162,7 +163,7 @@ instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Array α} : lex xs ys = false ↔ ys ≤ xs := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp
|
||||
simp [List.not_lt_iff_ge]
|
||||
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α] : DecidableLT (Array α) :=
|
||||
fun xs ys => decidable_of_iff (lex xs ys = true) lex_eq_true_iff_lt
|
||||
|
||||
@@ -27,7 +27,7 @@ theorem mapFinIdx_induction (xs : Array α) (f : (i : Nat) → α → (h : i < x
|
||||
motive xs.size ∧ ∃ eq : (Array.mapFinIdx xs f).size = xs.size,
|
||||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p i bs[i] h) (hm : motive j) :
|
||||
let as : Array β := Id.run <| Array.mapFinIdxM.map xs (pure <| f · · ·) i j h bs
|
||||
let as : Array β := Array.mapFinIdxM.map (m := Id) xs f i j h bs
|
||||
motive xs.size ∧ ∃ eq : as.size = xs.size, ∀ i h, p i as[i] h := by
|
||||
induction i generalizing j bs with simp [mapFinIdxM.map]
|
||||
| zero =>
|
||||
@@ -51,27 +51,27 @@ theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.siz
|
||||
∀ i h, p i ((Array.mapFinIdx xs f)[i]) h :=
|
||||
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp, grind =] theorem size_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp] theorem size_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
(xs.mapFinIdx f).size = xs.size :=
|
||||
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
|
||||
@[simp, grind =] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
@[simp] theorem size_zipIdx {xs : Array α} {k : Nat} : (xs.zipIdx k).size = xs.size :=
|
||||
Array.size_mapFinIdx
|
||||
|
||||
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
|
||||
|
||||
@[simp, grind =] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
@[simp] theorem getElem_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat}
|
||||
(h : i < (xs.mapFinIdx f).size) :
|
||||
(xs.mapFinIdx f)[i] = f i (xs[i]'(by simp_all)) (by simp_all) :=
|
||||
(mapFinIdx_spec (p := fun i b h => b = f i xs[i] h) fun _ _ => rfl).2 i _
|
||||
|
||||
@[simp, grind =] theorem getElem?_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat} :
|
||||
@[simp] theorem getElem?_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} {i : Nat} :
|
||||
(xs.mapFinIdx f)[i]? =
|
||||
xs[i]?.pbind fun b h => some <| f i b (getElem?_eq_some_iff.1 h).1 := by
|
||||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind =] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@@ -91,20 +91,20 @@ theorem mapIdx_spec {f : Nat → α → β} {xs : Array α}
|
||||
∀ i h, p i ((xs.mapIdx f)[i]) h :=
|
||||
(mapIdx_induction (motive := fun _ => True) trivial fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp, grind =] theorem size_mapIdx {f : Nat → α → β} {xs : Array α} : (xs.mapIdx f).size = xs.size :=
|
||||
@[simp] theorem size_mapIdx {f : Nat → α → β} {xs : Array α} : (xs.mapIdx f).size = xs.size :=
|
||||
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
|
||||
@[simp, grind =] theorem getElem_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat}
|
||||
@[simp] theorem getElem_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat}
|
||||
(h : i < (xs.mapIdx f).size) :
|
||||
(xs.mapIdx f)[i] = f i (xs[i]'(by simp_all)) :=
|
||||
(mapIdx_spec (p := fun i b h => b = f i xs[i]) fun _ _ => rfl).2 i (by simp_all)
|
||||
|
||||
@[simp, grind =] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat} :
|
||||
@[simp] theorem getElem?_mapIdx {f : Nat → α → β} {xs : Array α} {i : Nat} :
|
||||
(xs.mapIdx f)[i]? =
|
||||
xs[i]?.map (f i) := by
|
||||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
|
||||
@[simp, grind =] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||||
@[simp] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||||
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Array
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp, grind =] theorem getElem_zipIdx {xs : Array α} {k : Nat} {i : Nat} (h : i < (xs.zipIdx k).size) :
|
||||
@[simp] theorem getElem_zipIdx {xs : Array α} {k : Nat} {i : Nat} (h : i < (xs.zipIdx k).size) :
|
||||
(xs.zipIdx k)[i] = (xs[i]'(by simp_all), k + i) := by
|
||||
simp [zipIdx]
|
||||
|
||||
@@ -135,12 +135,12 @@ abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
|
||||
@[simp, grind =] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||||
ext i hi₁ hi₂ <;> simp
|
||||
ext i hi₁ hi₂ <;> simp [Nat.add_comm]
|
||||
|
||||
@[deprecated zipIdx_toArray (since := "2025-01-21")]
|
||||
abbrev zipWithIndex_toArray := @zipIdx_toArray
|
||||
|
||||
@[simp, grind =] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
@[simp] theorem toList_zipIdx {xs : Array α} {k : Nat} :
|
||||
(xs.zipIdx k).toList = xs.toList.zipIdx k := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -185,26 +185,24 @@ abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mapFinIdx_empty {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx #[] f = #[] :=
|
||||
rfl
|
||||
|
||||
theorem mapFinIdx_eq_ofFn {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
xs.mapFinIdx f = Array.ofFn fun i : Fin xs.size => f i xs[i] i.2 := by
|
||||
cases xs
|
||||
simp only [List.mapFinIdx_toArray, List.mapFinIdx_eq_ofFn, Fin.getElem_fin, List.getElem_toArray]
|
||||
simp [Array.size]
|
||||
simp [List.mapFinIdx_eq_ofFn]
|
||||
|
||||
@[grind =]
|
||||
theorem mapFinIdx_append {xs ys : Array α} {f : (i : Nat) → α → (h : i < (xs ++ ys).size) → β} :
|
||||
(xs ++ ys).mapFinIdx f =
|
||||
xs.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||||
ys.mapFinIdx (fun i a h => f (i + xs.size) a (by simp; omega)) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp [List.mapFinIdx_append, Array.size]
|
||||
simp [List.mapFinIdx_append]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mapFinIdx_push {xs : Array α} {a : α} {f : (i : Nat) → α → (h : i < (xs.push a).size) → β} :
|
||||
mapFinIdx (xs.push a) f =
|
||||
(mapFinIdx xs (fun i a h => f i a (by simp; omega))).push (f xs.size a (by simp)) := by
|
||||
@@ -238,7 +236,7 @@ theorem exists_of_mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||||
|
||||
@[simp, grind =] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
b ∈ xs.mapFinIdx f ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] h = b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -266,12 +264,12 @@ theorem mapFinIdx_eq_append_iff {xs : Array α} {f : (i : Nat) → α → (h : i
|
||||
toArray_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||||
refine ⟨l₁.toArray, l₂.toArray, by simp_all [Array.size]⟩
|
||||
refine ⟨l₁.toArray, l₂.toArray, by simp_all⟩
|
||||
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
|
||||
simp [← toList_inj] at h₁ h₂
|
||||
obtain rfl := h₁
|
||||
obtain rfl := h₂
|
||||
refine ⟨l₁, l₂, by simp_all [Array.size]⟩
|
||||
refine ⟨l₁, l₂, by simp_all⟩
|
||||
|
||||
theorem mapFinIdx_eq_push_iff {xs : Array α} {b : β} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
xs.mapFinIdx f = ys.push b ↔
|
||||
@@ -291,7 +289,7 @@ theorem mapFinIdx_eq_mapFinIdx_iff {xs : Array α} {f g : (i : Nat) → α → (
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem mapFinIdx_mapFinIdx {xs : Array α}
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {xs : Array α}
|
||||
{f : (i : Nat) → α → (h : i < xs.size) → β}
|
||||
{g : (i : Nat) → β → (h : i < (xs.mapFinIdx f).size) → γ} :
|
||||
(xs.mapFinIdx f).mapFinIdx g = xs.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
|
||||
@@ -306,14 +304,14 @@ theorem mapFinIdx_eq_replicate_iff {xs : Array α} {f : (i : Nat) → α → (h
|
||||
@[deprecated mapFinIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapFinIdx_eq_mkArray_iff := @mapFinIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||||
@[simp] theorem mapFinIdx_reverse {xs : Array α} {f : (i : Nat) → α → (h : i < xs.reverse.size) → β} :
|
||||
xs.reverse.mapFinIdx f = (xs.mapFinIdx (fun i a h => f (xs.size - 1 - i) a (by simp; omega))).reverse := by
|
||||
rcases xs with ⟨l⟩
|
||||
simp [List.mapFinIdx_reverse, Array.size]
|
||||
simp [List.mapFinIdx_reverse]
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #[] = #[] :=
|
||||
rfl
|
||||
|
||||
@@ -333,14 +331,13 @@ theorem mapIdx_eq_zipIdx_map {xs : Array α} {f : Nat → α → β} :
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
@[grind =]
|
||||
theorem mapIdx_append {xs ys : Array α} :
|
||||
(xs ++ ys).mapIdx f = xs.mapIdx f ++ ys.mapIdx (fun i => f (i + xs.size)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp [List.mapIdx_append]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mapIdx_push {xs : Array α} {a : α} :
|
||||
mapIdx f (xs.push a) = (mapIdx f xs).push (f xs.size a) := by
|
||||
simp [← append_singleton, mapIdx_append]
|
||||
@@ -362,7 +359,7 @@ theorem exists_of_mem_mapIdx {b : β} {xs : Array α}
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp, grind =] theorem mem_mapIdx {b : β} {xs : Array α} :
|
||||
@[simp] theorem mem_mapIdx {b : β} {xs : Array α} :
|
||||
b ∈ mapIdx f xs ↔ ∃ (i : Nat) (h : i < xs.size), f i xs[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -416,7 +413,7 @@ theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_eq_mapIdx_iff]
|
||||
|
||||
@[simp, grind =] theorem mapIdx_set {f : Nat → α → β} {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
|
||||
@[simp] theorem mapIdx_set {xs : Array α} {i : Nat} {h : i < xs.size} {a : α} :
|
||||
(xs.set i a).mapIdx f = (xs.mapIdx f).set i (f i a) (by simpa) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_set]
|
||||
@@ -426,17 +423,17 @@ theorem mapIdx_eq_mapIdx_iff {xs : Array α} :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_set]
|
||||
|
||||
@[simp, grind =] theorem back?_mapIdx {xs : Array α} {f : Nat → α → β} :
|
||||
@[simp] theorem back?_mapIdx {xs : Array α} {f : Nat → α → β} :
|
||||
(mapIdx f xs).back? = (xs.back?).map (f (xs.size - 1)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getLast?_mapIdx]
|
||||
|
||||
@[simp, grind =] theorem back_mapIdx {xs : Array α} {f : Nat → α → β} (h) :
|
||||
@[simp] theorem back_mapIdx {xs : Array α} {f : Nat → α → β} (h) :
|
||||
(xs.mapIdx f).back h = f (xs.size - 1) (xs.back (by simpa using h)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.getLast_mapIdx]
|
||||
|
||||
@[simp, grind =] theorem mapIdx_mapIdx {xs : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
@[simp] theorem mapIdx_mapIdx {xs : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(xs.mapIdx f).mapIdx g = xs.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
@@ -449,7 +446,7 @@ theorem mapIdx_eq_replicate_iff {xs : Array α} {f : Nat → α → β} {b : β}
|
||||
@[deprecated mapIdx_eq_replicate_iff (since := "2025-03-18")]
|
||||
abbrev mapIdx_eq_mkArray_iff := @mapIdx_eq_replicate_iff
|
||||
|
||||
@[simp, grind =] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||||
@[simp] theorem mapIdx_reverse {xs : Array α} {f : Nat → α → β} :
|
||||
xs.reverse.mapIdx f = (mapIdx (fun i => f (xs.size - 1 - i)) xs).reverse := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.mapIdx_reverse]
|
||||
@@ -458,7 +455,7 @@ end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[grind =] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
@[grind] theorem mapFinIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
{f : (i : Nat) → α → (h : i < l.length) → m β} :
|
||||
l.toArray.mapFinIdxM f = toArray <$> l.mapFinIdxM f := by
|
||||
let rec go (i : Nat) (acc : Array β) (inv : i + acc.size = l.length) :
|
||||
@@ -479,7 +476,7 @@ namespace List
|
||||
simp only [Array.mapFinIdxM, mapFinIdxM]
|
||||
exact go _ #[] _
|
||||
|
||||
@[grind =] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
@[grind] theorem mapIdxM_toArray [Monad m] [LawfulMonad m] {l : List α}
|
||||
{f : Nat → α → m β} :
|
||||
l.toArray.mapIdxM f = toArray <$> l.mapIdxM f := by
|
||||
let rec go (bs : List α) (acc : Array β) (inv : bs.length + acc.size = l.length) :
|
||||
@@ -489,7 +486,7 @@ namespace List
|
||||
| x :: xs => simp only [mapFinIdxM.go, mapIdxM.go, go]
|
||||
unfold Array.mapIdxM
|
||||
rw [mapFinIdxM_toArray]
|
||||
simp only [mapFinIdxM, mapIdxM, Array.size]
|
||||
simp only [mapFinIdxM, mapIdxM]
|
||||
rw [go]
|
||||
|
||||
end List
|
||||
|
||||
@@ -25,30 +25,16 @@ open Nat
|
||||
|
||||
/-! ## Monadic operations -/
|
||||
|
||||
theorem map_toList_inj [Monad m] [LawfulMonad m]
|
||||
{xs : m (Array α)} {ys : m (Array α)} :
|
||||
toList <$> xs = toList <$> ys ↔ xs = ys := by
|
||||
simp
|
||||
|
||||
/-! ### mapM -/
|
||||
|
||||
@[simp] theorem mapM_pure [Monad m] [LawfulMonad m] {xs : Array α} {f : α → β} :
|
||||
xs.mapM (m := m) (pure <| f ·) = pure (xs.map f) := by
|
||||
induction xs; simp_all
|
||||
|
||||
@[simp, grind =] theorem idRun_mapM {xs : Array α} {f : α → Id β} : (xs.mapM f).run = xs.map (f · |>.run) :=
|
||||
@[simp] theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
mapM_pure
|
||||
|
||||
@[simp, grind =] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
|
||||
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
|
||||
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
|
||||
(xs ++ ys).mapM f = (return (← xs.mapM f) ++ (← ys.mapM f)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
@@ -59,7 +45,7 @@ theorem mapM_eq_foldlM_push [Monad m] [LawfulMonad m] {f : α → m β} {xs : Ar
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.mapM_toArray, bind_pure_comp, List.size_toArray, List.foldlM_toArray']
|
||||
rw [List.mapM_eq_reverse_foldlM_cons]
|
||||
simp only [Functor.map_map]
|
||||
simp only [bind_pure_comp, Functor.map_map]
|
||||
suffices ∀ (l), (fun l' => l'.reverse.toArray) <$> List.foldlM (fun acc a => (fun a => a :: acc) <$> f a) l xs =
|
||||
List.foldlM (fun acc a => acc.push <$> f a) l.reverse.toArray xs by
|
||||
exact this []
|
||||
@@ -143,13 +129,13 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
cases as <;> cases bs
|
||||
simp_all
|
||||
|
||||
@[simp, grind =] theorem forM_append [Monad m] [LawfulMonad m] {xs ys : Array α} {f : α → m PUnit} :
|
||||
@[simp] theorem forM_append [Monad m] [LawfulMonad m] {xs ys : Array α} {f : α → m PUnit} :
|
||||
forM (xs ++ ys) f = (do forM xs f; forM ys f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] {xs : Array α} {g : α → β} {f : β → m PUnit} :
|
||||
@[simp] theorem forM_map [Monad m] [LawfulMonad m] {xs : Array α} {g : α → β} {f : β → m PUnit} :
|
||||
forM (xs.map g) f = forM xs (fun a => f (g a)) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
@@ -195,20 +181,14 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.forIn'_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
theorem idRun_forIn'_yield_eq_foldl
|
||||
{xs : Array α} (f : (a : α) → a ∈ xs → β → Id β) (init : β) :
|
||||
(forIn' xs init (fun a m b => .yield <$> f a m b)).run =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
@[simp] theorem forIn'_yield_eq_foldl
|
||||
{xs : Array α} (f : (a : α) → a ∈ xs → β → β) (init : β) :
|
||||
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_map]
|
||||
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (g : α → β) (f : (b : β) → b ∈ xs.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem h) y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -234,29 +214,23 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
forIn xs init (fun a b => (fun c => .yield (g a b c)) <$> f a b) =
|
||||
xs.foldlM (fun b a => g a b <$> f a b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp
|
||||
simp [List.foldlM_map]
|
||||
|
||||
@[simp] theorem forIn_pure_yield_eq_foldl [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (f : α → β → β) (init : β) :
|
||||
forIn xs init (fun a b => pure (.yield (f a b))) =
|
||||
pure (f := m) (xs.foldl (fun b a => f a b) init) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.forIn_pure_yield_eq_foldl]
|
||||
simp [List.forIn_pure_yield_eq_foldl, List.foldl_map]
|
||||
|
||||
theorem idRun_forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → Id β) (init : β) :
|
||||
(forIn xs init (fun a b => .yield <$> f a b)).run =
|
||||
xs.foldl (fun b a => f a b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
@[simp] theorem forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
|
||||
xs.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
xs.foldl (fun b a => f a b) init := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.foldl_map]
|
||||
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -310,7 +284,7 @@ namespace List
|
||||
@[simp] theorem filterM_toArray' [Monad m] [LawfulMonad m] {l : List α} {p : α → m Bool} (w : stop = l.length) :
|
||||
l.toArray.filterM p 0 stop = toArray <$> l.filterM p := by
|
||||
subst w
|
||||
simp [← filterM_toArray]
|
||||
rw [filterM_toArray]
|
||||
|
||||
@[grind =] theorem filterRevM_toArray [Monad m] [LawfulMonad m] {l : List α} {p : α → m Bool} :
|
||||
l.toArray.filterRevM p = toArray <$> l.filterRevM p := by
|
||||
@@ -322,7 +296,7 @@ namespace List
|
||||
@[simp] theorem filterRevM_toArray' [Monad m] [LawfulMonad m] {l : List α} {p : α → m Bool} (w : start = l.length) :
|
||||
l.toArray.filterRevM p start 0 = toArray <$> l.filterRevM p := by
|
||||
subst w
|
||||
simp [← filterRevM_toArray]
|
||||
rw [filterRevM_toArray]
|
||||
|
||||
@[grind =] theorem filterMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α → m (Option β)} :
|
||||
l.toArray.filterMapM f = toArray <$> l.filterMapM f := by
|
||||
@@ -340,7 +314,7 @@ namespace List
|
||||
@[simp] theorem filterMapM_toArray' [Monad m] [LawfulMonad m] {l : List α} {f : α → m (Option β)} (w : stop = l.length) :
|
||||
l.toArray.filterMapM f 0 stop = toArray <$> l.filterMapM f := by
|
||||
subst w
|
||||
simp [← filterMapM_toArray]
|
||||
rw [filterMapM_toArray]
|
||||
|
||||
@[simp, grind =] theorem flatMapM_toArray [Monad m] [LawfulMonad m] {l : List α} {f : α → m (Array β)} :
|
||||
l.toArray.flatMapM f = toArray <$> l.flatMapM (fun a => Array.toList <$> f a) := by
|
||||
|
||||
@@ -8,9 +8,7 @@ module
|
||||
prelude
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.List.FinRange
|
||||
|
||||
/-!
|
||||
# Theorems about `Array.ofFn`
|
||||
@@ -21,9 +19,7 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace Array
|
||||
|
||||
/-! ### ofFn -/
|
||||
|
||||
@[simp, grind =] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
|
||||
@[simp] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
|
||||
simp [ofFn, ofFn.go]
|
||||
|
||||
theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
@@ -36,29 +32,18 @@ theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
intro h₃
|
||||
simp only [show i = n by omega]
|
||||
|
||||
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
ofFn f = (ofFn (fun i => f (i.castLE (Nat.le_add_right n m)))) ++ (ofFn (fun i => f (i.natAdd n))) := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [ofFn_succ, ih]
|
||||
|
||||
@[simp, grind =] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
|
||||
@[simp] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp, grind =] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
|
||||
@[simp] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
theorem ofFn_succ' {f : Fin (n+1) → α} :
|
||||
ofFn f = #[f 0] ++ ofFn (fun i => f i.succ) := by
|
||||
apply Array.toList_inj.mp
|
||||
simp [List.ofFn_succ]
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
|
||||
rw [← Array.toList_inj]
|
||||
simp
|
||||
|
||||
@[simp 500, grind =]
|
||||
@[simp 500]
|
||||
theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
@@ -67,70 +52,4 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
/-! ### ofFnM -/
|
||||
|
||||
/-- Construct (in a monadic context) an array by applying a monadic function to each index. -/
|
||||
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Array α) :=
|
||||
Fin.foldlM n (fun xs i => xs.push <$> f i) (Array.emptyWithCapacity n)
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : ofFnM f = pure #[] := by
|
||||
simp [ofFnM]
|
||||
|
||||
theorem ofFnM_succ' {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let a ← f 0
|
||||
let as ← ofFnM fun i => f i.succ
|
||||
pure (#[a] ++ as)) := by
|
||||
simp [ofFnM, Fin.foldlM_eq_foldlM_finRange, List.foldlM_push_eq_append, List.finRange_succ, Function.comp_def]
|
||||
|
||||
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i => f i.castSucc
|
||||
let a ← f (Fin.last n)
|
||||
pure (as.push a)) := by
|
||||
simp [ofFnM, Fin.foldlM_succ_last]
|
||||
|
||||
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
|
||||
let bs ← ofFnM fun i : Fin k => f (i.natAdd n)
|
||||
pure (as ++ bs)) := by
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih =>
|
||||
simp only [ofFnM_succ, Nat.add_eq, ih, Fin.castSucc_castLE, Fin.castSucc_natAdd, bind_pure_comp,
|
||||
bind_assoc, bind_map_left, Fin.natAdd_last, map_bind, Functor.map_map]
|
||||
congr 1
|
||||
funext xs
|
||||
congr 1
|
||||
funext ys
|
||||
congr 1
|
||||
funext x
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
|
||||
toList <$> ofFnM f = List.ofFnM f := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ, List.ofFnM_succ_last, ← ih]
|
||||
|
||||
@[simp]
|
||||
theorem ofFnM_pure_comp [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (pure ∘ f) = (pure (ofFn f) : m (Array α)) := by
|
||||
apply Array.map_toList_inj.mp
|
||||
simp
|
||||
|
||||
-- Variant of `ofFnM_pure_comp` using a lambda.
|
||||
-- This is not marked a `@[simp]` as it would match on every occurrence of `ofFnM`.
|
||||
theorem ofFnM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α} :
|
||||
ofFnM (fun i => pure (f i)) = (pure (ofFn f) : m (Array α)) :=
|
||||
ofFnM_pure_comp
|
||||
|
||||
@[simp, grind =] theorem idRun_ofFnM {f : Fin n → Id α} :
|
||||
Id.run (ofFnM f) = ofFn (fun i => Id.run (f i)) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp [ofFnM_succ', ofFn_succ', ih]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -91,26 +91,17 @@ theorem Perm.mem_iff {a : α} {xs ys : Array α} (p : xs ~ ys) : a ∈ xs ↔ a
|
||||
simp only [perm_iff_toList_perm] at p
|
||||
simpa using p.mem_iff
|
||||
|
||||
grind_pattern Perm.mem_iff => xs ~ ys, a ∈ xs
|
||||
grind_pattern Perm.mem_iff => xs ~ ys, a ∈ ys
|
||||
|
||||
theorem Perm.append {xs ys as bs : Array α} (p₁ : xs ~ ys) (p₂ : as ~ bs) :
|
||||
xs ++ as ~ ys ++ bs := by
|
||||
cases xs; cases ys; cases as; cases bs
|
||||
simp only [append_toArray, perm_iff_toList_perm] at p₁ p₂ ⊢
|
||||
exact p₁.append p₂
|
||||
|
||||
grind_pattern Perm.append => xs ~ ys, as ~ bs, xs ++ as
|
||||
grind_pattern Perm.append => xs ~ ys, as ~ bs, ys ++ bs
|
||||
|
||||
theorem Perm.push (x : α) {xs ys : Array α} (p : xs ~ ys) :
|
||||
xs.push x ~ ys.push x := by
|
||||
rw [push_eq_append_singleton]
|
||||
exact p.append .rfl
|
||||
|
||||
grind_pattern Perm.push => xs ~ ys, xs.push x
|
||||
grind_pattern Perm.push => xs ~ ys, ys.push x
|
||||
|
||||
theorem Perm.push_comm (x y : α) {xs ys : Array α} (p : xs ~ ys) :
|
||||
(xs.push x).push y ~ (ys.push y).push x := by
|
||||
cases xs; cases ys
|
||||
|
||||
@@ -27,27 +27,23 @@ Internal implementation of `Array.qsort`.
|
||||
|
||||
It does so by first swapping the elements at indices `lo`, `mid := (lo + hi) / 2`, and `hi`
|
||||
if necessary so that the middle (pivot) element is at index `hi`.
|
||||
We then iterate from `k = lo` to `k = hi`, with a pointer `i` starting at `lo`, and
|
||||
We then iterate from `j = lo` to `j = hi`, with a pointer `i` starting at `lo`, and
|
||||
swapping each element which is less than the pivot to position `i`, and then incrementing `i`.
|
||||
-/
|
||||
def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat) (w : lo ≤ hi := by omega)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {m : Nat // lo ≤ m ∧ m ≤ hi} × Vector α n :=
|
||||
def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) : {m : Nat // lo ≤ m ∧ m < n} × Vector α n :=
|
||||
let mid := (lo + hi) / 2
|
||||
let as := if lt as[mid] as[lo] then as.swap lo mid else as
|
||||
let as := if lt as[hi] as[lo] then as.swap lo hi else as
|
||||
let as := if lt as[mid] as[hi] then as.swap mid hi else as
|
||||
let pivot := as[hi]
|
||||
-- During this loop, elements below in `[lo, i)` are less than `pivot`,
|
||||
-- elements in `[i, k)` are greater than or equal to `pivot`,
|
||||
-- elements in `[k, hi)` are unexamined,
|
||||
-- while `as[hi]` is (by definition) the pivot.
|
||||
let rec loop (as : Vector α n) (i k : Nat)
|
||||
(ilo : lo ≤ i := by omega) (ik : i ≤ k := by omega) (w : k ≤ hi := by omega) :=
|
||||
if h : k < hi then
|
||||
if lt as[k] pivot then
|
||||
loop (as.swap i k) (i+1) (k+1)
|
||||
let rec loop (as : Vector α n) (i j : Nat)
|
||||
(ilo : lo ≤ i := by omega) (jh : j < n := by omega) (w : i ≤ j := by omega) :=
|
||||
if h : j < hi then
|
||||
if lt as[j] pivot then
|
||||
loop (as.swap i j) (i+1) (j+1)
|
||||
else
|
||||
loop as i (k+1)
|
||||
loop as i (j+1)
|
||||
else
|
||||
(⟨i, ilo, by omega⟩, as.swap i hi)
|
||||
loop as lo lo
|
||||
@@ -55,28 +51,25 @@ def qpartition {n} (as : Vector α n) (lt : α → α → Bool) (lo hi : Nat) (w
|
||||
/--
|
||||
In-place quicksort.
|
||||
|
||||
`qsort as lt lo hi` sorts the subarray `as[lo:hi+1]` in-place using `lt` to compare elements.
|
||||
`qsort as lt low high` sorts the subarray `as[low:high+1]` in-place using `lt` to compare elements.
|
||||
-/
|
||||
@[inline] def qsort (as : Array α) (lt : α → α → Bool := by exact (· < ·))
|
||||
(lo := 0) (hi := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat) (w : lo ≤ hi := by omega)
|
||||
(low := 0) (high := as.size - 1) : Array α :=
|
||||
let rec @[specialize] sort {n} (as : Vector α n) (lo hi : Nat)
|
||||
(hlo : lo < n := by omega) (hhi : hi < n := by omega) :=
|
||||
if h₁ : lo < hi then
|
||||
let ⟨⟨mid, hmid⟩, as⟩ := qpartition as lt lo hi
|
||||
if h₂ : mid ≥ hi then
|
||||
-- This only occurs when `hi ≤ lo`,
|
||||
-- and thus `as[lo:hi+1]` is trivially already sorted.
|
||||
as
|
||||
else
|
||||
-- Otherwise, we recursively sort the two subarrays.
|
||||
sort (sort as lo mid) (mid+1) hi
|
||||
else as
|
||||
if h : as.size = 0 then
|
||||
as
|
||||
else
|
||||
let lo := min lo (as.size - 1)
|
||||
let hi := max lo (min hi (as.size - 1))
|
||||
sort as.toVector lo hi |>.toArray
|
||||
let low := min low (as.size - 1)
|
||||
let high := min high (as.size - 1)
|
||||
sort as.toVector low high |>.toArray
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
/--
|
||||
|
||||
@@ -29,7 +29,6 @@ open Nat
|
||||
|
||||
/-! ### range' -/
|
||||
|
||||
@[grind _=_]
|
||||
theorem range'_succ {s n step} : range' s (n + 1) step = #[s] ++ range' (s + step) n step := by
|
||||
rw [← toList_inj]
|
||||
simp [List.range'_succ]
|
||||
@@ -40,17 +39,16 @@ theorem range'_succ {s n step} : range' s (n + 1) step = #[s] ++ range' (s + ste
|
||||
theorem range'_ne_empty_iff : range' s n step ≠ #[] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[simp, grind =] theorem range'_zero : range' s 0 step = #[] := by
|
||||
@[simp] theorem range'_zero : range' s 0 step = #[] := by
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem range'_one {s step : Nat} : range' s 1 step = #[s] := by
|
||||
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = #[s] := by
|
||||
simp [range', ofFn, ofFn.go]
|
||||
|
||||
@[simp] theorem range'_inj : range' s n = range' s' n' ↔ n = n' ∧ (n = 0 ∨ s = s') := by
|
||||
rw [← toList_inj]
|
||||
simp [List.range'_inj]
|
||||
|
||||
@[grind =]
|
||||
theorem mem_range' {n} : m ∈ range' s n step ↔ ∃ i < n, m = s + step * i := by
|
||||
simp [range']
|
||||
constructor
|
||||
@@ -59,7 +57,6 @@ theorem mem_range' {n} : m ∈ range' s n step ↔ ∃ i < n, m = s + step * i :
|
||||
· rintro ⟨i, w, h'⟩
|
||||
exact ⟨⟨i, w⟩, by simp_all⟩
|
||||
|
||||
@[simp, grind =]
|
||||
theorem pop_range' : (range' s n step).pop = range' s (n - 1) step := by
|
||||
ext <;> simp
|
||||
|
||||
@@ -69,7 +66,6 @@ theorem map_add_range' {a} (s n step) : map (a + ·) (range' s n step) = range'
|
||||
theorem range'_succ_left : range' (s + 1) n step = (range' s n step).map (· + 1) := by
|
||||
ext <;> simp <;> omega
|
||||
|
||||
@[grind _=_]
|
||||
theorem range'_append {s m n step : Nat} :
|
||||
range' s m step ++ range' (s + step * m) n step = range' s (m + n) step := by
|
||||
ext i h₁ h₂
|
||||
@@ -81,8 +77,7 @@ theorem range'_append {s m n step : Nat} :
|
||||
have : step * m ≤ step * i := by exact mul_le_mul_left step h
|
||||
omega
|
||||
|
||||
@[simp, grind _=_]
|
||||
theorem range'_append_1 {s m n : Nat} :
|
||||
@[simp] theorem range'_append_1 {s m n : Nat} :
|
||||
range' s m ++ range' (s + m) n = range' s (m + n) := by simpa using range'_append (step := 1)
|
||||
|
||||
theorem range'_concat {s n : Nat} : range' s (n + 1) step = range' s n step ++ #[s + step * n] := by
|
||||
@@ -91,7 +86,7 @@ theorem range'_concat {s n : Nat} : range' s (n + 1) step = range' s n step ++ #
|
||||
theorem range'_1_concat {s n : Nat} : range' s (n + 1) = range' s n ++ #[s + n] := by
|
||||
simp [range'_concat]
|
||||
|
||||
@[simp, grind =] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by
|
||||
@[simp] theorem mem_range'_1 : m ∈ range' s n ↔ s ≤ m ∧ m < s + n := by
|
||||
simp [mem_range']; exact ⟨
|
||||
fun ⟨i, h, e⟩ => e ▸ ⟨Nat.le_add_right .., Nat.add_lt_add_left h _⟩,
|
||||
fun ⟨h₁, h₂⟩ => ⟨m - s, Nat.sub_lt_left_of_lt_add h₁ h₂, (Nat.add_sub_cancel' h₁).symm⟩⟩
|
||||
@@ -121,26 +116,14 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
simp only [List.find?_toArray]
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem erase_range' :
|
||||
(range' s n).erase i =
|
||||
range' s (min n (i - s)) ++ range' (max s (i + 1)) (min s (i + 1) + n - (i + 1)) := by
|
||||
simp only [← List.toArray_range', List.erase_toArray]
|
||||
simp [List.erase_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range' {a s n step} (h : 0 < step := by simp) :
|
||||
count a (range' s n step) = if ∃ i, i < n ∧ a = s + step * i then 1 else 0 := by
|
||||
rw [← List.toArray_range', List.count_toArray, ← List.count_range' h]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range_1' {a s n} :
|
||||
count a (range' s n) = if s ≤ a ∧ a < s + n then 1 else 0 := by
|
||||
rw [← List.toArray_range', List.count_toArray, ← List.count_range_1']
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@[grind _=_]
|
||||
theorem range_eq_range' {n : Nat} : range n = range' 0 n := by
|
||||
simp [range, range']
|
||||
|
||||
@@ -162,7 +145,6 @@ theorem range'_eq_map_range {s n : Nat} : range' s n = map (s + ·) (range n) :=
|
||||
theorem range_ne_empty_iff {n : Nat} : range n ≠ #[] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[grind _=_]
|
||||
theorem range_succ {n : Nat} : range (succ n) = range n ++ #[n] := by
|
||||
ext i h₁ h₂
|
||||
· simp
|
||||
@@ -178,7 +160,7 @@ theorem range_add {n m : Nat} : range (n + m) = range n ++ (range m).map (n + ·
|
||||
theorem reverse_range' {s n : Nat} : reverse (range' s n) = map (s + n - 1 - ·) (range n) := by
|
||||
simp [← toList_inj, List.reverse_range']
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem mem_range {m n : Nat} : m ∈ range n ↔ m < n := by
|
||||
simp only [range_eq_range', mem_range'_1, Nat.zero_le, true_and, Nat.zero_add]
|
||||
|
||||
@@ -186,25 +168,20 @@ theorem not_mem_range_self {n : Nat} : n ∉ range n := by simp
|
||||
|
||||
theorem self_mem_range_succ {n : Nat} : n ∈ range (n + 1) := by simp
|
||||
|
||||
@[simp, grind =] theorem take_range {i n : Nat} : take (range n) i = range (min i n) := by
|
||||
@[simp] theorem take_range {i n : Nat} : take (range n) i = range (min i n) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp, grind =] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[simp, grind =] theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
@[simp] theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp only [← List.toArray_range, List.find?_toArray, List.find?_range_eq_none]
|
||||
|
||||
@[grind =]
|
||||
theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n - (i + 1)) := by
|
||||
simp [range_eq_range', erase_range']
|
||||
|
||||
@[simp, grind =]
|
||||
theorem count_range {a n} :
|
||||
count a (range n) = if a < n then 1 else 0 := by
|
||||
rw [← List.toArray_range, List.count_toArray, ← List.count_range]
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@@ -213,13 +190,13 @@ theorem zipIdx_eq_empty_iff {xs : Array α} {i : Nat} : xs.zipIdx i = #[] ↔ xs
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem getElem?_zipIdx {xs : Array α} {i j} : (zipIdx xs i)[j]? = xs[j]?.map fun a => (a, i + j) := by
|
||||
simp [getElem?_def]
|
||||
|
||||
theorem map_snd_add_zipIdx_eq_zipIdx {xs : Array α} {n k : Nat} :
|
||||
map (Prod.map id (· + n)) (zipIdx xs k) = zipIdx xs (n + k) :=
|
||||
ext_getElem? fun i ↦ by simp [Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
ext_getElem? fun i ↦ by simp [(· ∘ ·), Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
-- Arguments are explicit for parity with `zipIdx_map_fst`.
|
||||
@[simp]
|
||||
@@ -256,7 +233,7 @@ theorem zipIdx_eq_map_add {xs : Array α} {i : Nat} :
|
||||
simp only [zipIdx_toArray, List.map_toArray, mk.injEq]
|
||||
rw [List.zipIdx_eq_map_add]
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem zipIdx_singleton {x : α} {k : Nat} : zipIdx #[x] k = #[(x, k)] :=
|
||||
rfl
|
||||
|
||||
@@ -304,7 +281,6 @@ theorem zipIdx_map {xs : Array α} {k : Nat} {f : α → β} :
|
||||
cases xs
|
||||
simp [List.zipIdx_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipIdx_append {xs ys : Array α} {k : Nat} :
|
||||
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + xs.size) := by
|
||||
cases xs
|
||||
|
||||
@@ -24,7 +24,7 @@ Examples:
|
||||
* `#[0, 1, 2].set 1 5 = #[0, 5, 2]`
|
||||
* `#["orange", "apple"].set 1 "grape" = #["orange", "grape"]`
|
||||
-/
|
||||
@[extern "lean_array_fset", expose]
|
||||
@[extern "lean_array_fset"]
|
||||
def Array.set (xs : Array α) (i : @& Nat) (v : α) (h : i < xs.size := by get_elem_tactic) :
|
||||
Array α where
|
||||
toList := xs.toList.set i v
|
||||
@@ -40,15 +40,17 @@ Examples:
|
||||
* `#["orange", "apple"].setIfInBounds 1 "grape" = #["orange", "grape"]`
|
||||
* `#["orange", "apple"].setIfInBounds 5 "grape" = #["orange", "apple"]`
|
||||
-/
|
||||
@[inline, expose] def Array.setIfInBounds (xs : Array α) (i : Nat) (v : α) : Array α :=
|
||||
@[inline] def Array.setIfInBounds (xs : Array α) (i : Nat) (v : α) : Array α :=
|
||||
dite (LT.lt i xs.size) (fun h => xs.set i v h) (fun _ => xs)
|
||||
|
||||
@[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", expose]
|
||||
@[extern "lean_array_set"]
|
||||
def Array.set! (xs : Array α) (i : @& Nat) (v : α) : Array α :=
|
||||
Array.setIfInBounds xs i v
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Slice.Basic
|
||||
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
set_option linter.missingDocs true
|
||||
@@ -15,9 +14,14 @@ set_option linter.missingDocs true
|
||||
universe u v w
|
||||
|
||||
/--
|
||||
Internal representation of `Subarray`, which is an abbreviation for `Slice SubarrayData`.
|
||||
A region of some underlying array.
|
||||
|
||||
A subarray contains an array together with the start and end indices of a region of interest.
|
||||
Subarrays can be used to avoid copying or allocating space, while being more convenient than
|
||||
tracking the bounds by hand. The region of interest consists of every index that is both greater
|
||||
than or equal to `start` and strictly less than `stop`.
|
||||
-/
|
||||
structure Std.Slice.Internal.SubarrayData (α : Type u) where
|
||||
structure Subarray (α : Type u) where
|
||||
/-- The underlying array. -/
|
||||
array : Array α
|
||||
/-- The starting index of the region of interest (inclusive). -/
|
||||
@@ -38,40 +42,6 @@ structure Std.Slice.Internal.SubarrayData (α : Type u) where
|
||||
-/
|
||||
stop_le_array_size : stop ≤ array.size
|
||||
|
||||
open Std.Slice
|
||||
|
||||
/--
|
||||
A region of some underlying array.
|
||||
|
||||
A subarray contains an array together with the start and end indices of a region of interest.
|
||||
Subarrays can be used to avoid copying or allocating space, while being more convenient than
|
||||
tracking the bounds by hand. The region of interest consists of every index that is both greater
|
||||
than or equal to `start` and strictly less than `stop`.
|
||||
-/
|
||||
abbrev Subarray (α : Type u) := Std.Slice (Internal.SubarrayData α)
|
||||
|
||||
instance {α : Type u} : Self (Std.Slice (Internal.SubarrayData α)) (Subarray α) where
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc Internal.SubarrayData.array]
|
||||
def Subarray.array (xs : Subarray α) : Array α :=
|
||||
xs.internalRepresentation.array
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc Internal.SubarrayData.start]
|
||||
def Subarray.start (xs : Subarray α) : Nat :=
|
||||
xs.internalRepresentation.start
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc Internal.SubarrayData.stop]
|
||||
def Subarray.stop (xs : Subarray α) : Nat :=
|
||||
xs.internalRepresentation.stop
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc Internal.SubarrayData.start_le_stop]
|
||||
def Subarray.start_le_stop (xs : Subarray α) : xs.start ≤ xs.stop :=
|
||||
xs.internalRepresentation.start_le_stop
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc Internal.SubarrayData.stop_le_array_size]
|
||||
def Subarray.stop_le_array_size (xs : Subarray α) : xs.stop ≤ xs.array.size :=
|
||||
xs.internalRepresentation.stop_le_array_size
|
||||
|
||||
namespace Subarray
|
||||
|
||||
/--
|
||||
@@ -81,7 +51,7 @@ def size (s : Subarray α) : Nat :=
|
||||
s.stop - s.start
|
||||
|
||||
theorem size_le_array_size {s : Subarray α} : s.size ≤ s.array.size := by
|
||||
let ⟨{array, start, stop, start_le_stop, stop_le_array_size}⟩ := s
|
||||
let {array, start, stop, start_le_stop, stop_le_array_size} := s
|
||||
simp [size]
|
||||
apply Nat.le_trans (Nat.sub_le stop start)
|
||||
assumption
|
||||
@@ -132,9 +102,7 @@ Examples:
|
||||
-/
|
||||
def popFront (s : Subarray α) : Subarray α :=
|
||||
if h : s.start < s.stop then
|
||||
⟨{ s.internalRepresentation with
|
||||
start := s.start + 1,
|
||||
start_le_stop := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }⟩
|
||||
{ s with start := s.start + 1, start_le_stop := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }
|
||||
else
|
||||
s
|
||||
|
||||
@@ -143,13 +111,12 @@ The empty subarray.
|
||||
|
||||
This empty subarray is backed by an empty array.
|
||||
-/
|
||||
protected def empty : Subarray α := ⟨{
|
||||
array := #[]
|
||||
start := 0
|
||||
stop := 0
|
||||
start_le_stop := Nat.le_refl 0
|
||||
stop_le_array_size := Nat.le_refl 0
|
||||
}⟩
|
||||
protected def empty : Subarray α where
|
||||
array := #[]
|
||||
start := 0
|
||||
stop := 0
|
||||
start_le_stop := Nat.le_refl 0
|
||||
stop_le_array_size := Nat.le_refl 0
|
||||
|
||||
instance : EmptyCollection (Subarray α) :=
|
||||
⟨Subarray.empty⟩
|
||||
@@ -323,7 +290,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
Id.run <| as.foldlM (pure <| f · ·) (init := init)
|
||||
Id.run <| as.foldlM f (init := init)
|
||||
|
||||
/--
|
||||
Folds an operation from right to left over the elements in a subarray.
|
||||
@@ -337,7 +304,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Subarray α) : β :=
|
||||
Id.run <| as.foldrM (pure <| f · ·) (init := init)
|
||||
Id.run <| as.foldrM f (init := init)
|
||||
|
||||
/--
|
||||
Checks whether any of the elements in a subarray satisfy a Boolean predicate.
|
||||
@@ -347,7 +314,7 @@ an element that satisfies the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
def any {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.anyM (pure <| p ·)
|
||||
Id.run <| as.anyM p
|
||||
|
||||
/--
|
||||
Checks whether all of the elements in a subarray satisfy a Boolean predicate.
|
||||
@@ -357,7 +324,7 @@ an element that does not satisfy the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
def all {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.allM (pure <| p ·)
|
||||
Id.run <| as.allM p
|
||||
|
||||
/--
|
||||
Applies a monadic function to each element in a subarray in reverse order, stopping at the first
|
||||
@@ -427,7 +394,7 @@ Examples:
|
||||
-/
|
||||
@[inline]
|
||||
def findRev? {α : Type} (as : Subarray α) (p : α → Bool) : Option α :=
|
||||
Id.run <| as.findRevM? (pure <| p ·)
|
||||
Id.run <| as.findRevM? p
|
||||
|
||||
end Subarray
|
||||
|
||||
@@ -443,24 +410,24 @@ Additionally, the starting index is clamped to the ending index.
|
||||
def toSubarray (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Subarray α :=
|
||||
if h₂ : stop ≤ as.size then
|
||||
if h₁ : start ≤ stop then
|
||||
⟨{ array := as, start := start, stop := stop,
|
||||
start_le_stop := h₁, stop_le_array_size := h₂ }⟩
|
||||
{ array := as, start := start, stop := stop,
|
||||
start_le_stop := h₁, stop_le_array_size := h₂ }
|
||||
else
|
||||
⟨{ array := as, start := stop, stop := stop,
|
||||
start_le_stop := Nat.le_refl _, stop_le_array_size := h₂ }⟩
|
||||
{ array := as, start := stop, stop := stop,
|
||||
start_le_stop := Nat.le_refl _, stop_le_array_size := h₂ }
|
||||
else
|
||||
if h₁ : start ≤ as.size then
|
||||
⟨{ array := as,
|
||||
start := start,
|
||||
stop := as.size,
|
||||
start_le_stop := h₁,
|
||||
stop_le_array_size := Nat.le_refl _ }⟩
|
||||
{ array := as,
|
||||
start := start,
|
||||
stop := as.size,
|
||||
start_le_stop := h₁,
|
||||
stop_le_array_size := Nat.le_refl _ }
|
||||
else
|
||||
⟨{ array := as,
|
||||
start := as.size,
|
||||
stop := as.size,
|
||||
start_le_stop := Nat.le_refl _,
|
||||
stop_le_array_size := Nat.le_refl _ }⟩
|
||||
{ array := as,
|
||||
start := as.size,
|
||||
stop := as.size,
|
||||
start_le_stop := Nat.le_refl _,
|
||||
stop_le_array_size := Nat.le_refl _ }
|
||||
|
||||
/--
|
||||
Allocates a new array that contains the contents of the subarray.
|
||||
|
||||
@@ -21,24 +21,44 @@ set_option linter.listVariables true -- Enforce naming conventions for `List`/`A
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
namespace Subarray
|
||||
/--
|
||||
Splits a subarray into two parts, the first of which contains the first `i` elements and the second
|
||||
of which contains the remainder.
|
||||
-/
|
||||
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 : 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 omega
|
||||
}
|
||||
let post := {s with
|
||||
start := s.start + i'
|
||||
start_le_stop := by assumption
|
||||
}
|
||||
(pre, post)
|
||||
|
||||
/--
|
||||
Removes the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
|
||||
subarray is empty.
|
||||
-/
|
||||
def drop (arr : Subarray α) (i : Nat) : Subarray α := ⟨{
|
||||
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 omega
|
||||
stop_le_array_size := arr.stop_le_array_size
|
||||
}⟩
|
||||
|
||||
/--
|
||||
Keeps only the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
|
||||
subarray is empty.
|
||||
-/
|
||||
def take (arr : Subarray α) (i : Nat) : Subarray α := ⟨{
|
||||
def take (arr : Subarray α) (i : Nat) : Subarray α where
|
||||
array := arr.array
|
||||
start := arr.start
|
||||
stop := min (arr.start + i) arr.stop
|
||||
@@ -48,11 +68,3 @@ def take (arr : Subarray α) (i : Nat) : Subarray α := ⟨{
|
||||
stop_le_array_size := by
|
||||
have := arr.stop_le_array_size
|
||||
omega
|
||||
}⟩
|
||||
|
||||
/--
|
||||
Splits a subarray into two parts, the first of which contains the first `i` elements and the second
|
||||
of which contains the remainder.
|
||||
-/
|
||||
def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α) :=
|
||||
(s.take i, s.drop i)
|
||||
|
||||
@@ -45,7 +45,6 @@ theorem zipWith_self {f : α → α → δ} {xs : Array α} : zipWith f xs xs =
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
using `Option.map` and `Option.bind` rather than a `match`.
|
||||
-/
|
||||
@[grind =]
|
||||
theorem getElem?_zipWith {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
@@ -77,35 +76,31 @@ theorem getElem?_zip_eq_some {as : Array α} {bs : Array β} {z : α × β} {i :
|
||||
· rintro ⟨h₀, h₁⟩
|
||||
exact ⟨_, _, h₀, h₁, rfl⟩
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem zipWith_map {μ} {f : γ → δ → μ} {g : α → γ} {h : β → δ} {as : Array α} {bs : Array β} :
|
||||
zipWith f (as.map g) (bs.map h) = zipWith (fun a b => f (g a) (h b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_left {as : Array α} {bs : Array β} {f : α → α'} {g : α' → β → γ} :
|
||||
zipWith g (as.map f) bs = zipWith (fun a b => g (f a) b) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map_left]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_map_right {as : Array α} {bs : Array β} {f : β → β'} {g : α → β' → γ} :
|
||||
zipWith g as (bs.map f) = zipWith (fun a b => g a (f b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_map_right]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} {i : δ} :
|
||||
(zipWith f as bs).foldr g i = (zip as bs).foldr (fun p r => g (f p.1 p.2) r) i := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWith_foldr_eq_zip_foldr]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} :
|
||||
(zipWith f as bs).foldl g i = (zip as bs).foldl (fun r p => g r (f p.1 p.2)) i := by
|
||||
cases as
|
||||
@@ -116,26 +111,22 @@ theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} {i : δ} :
|
||||
theorem zipWith_eq_empty_iff {f : α → β → γ} {as : Array α} {bs : Array β} : zipWith f as bs = #[] ↔ as = #[] ∨ bs = #[] := by
|
||||
cases as <;> cases bs <;> simp
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWith {δ : Type _} {f : α → β} {g : γ → δ → α} {cs : Array γ} {ds : Array δ} :
|
||||
map f (zipWith g cs ds) = zipWith (fun x y => f (g x y)) cs ds := by
|
||||
cases cs
|
||||
cases ds
|
||||
simp [List.map_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem take_zipWith : (zipWith f as bs).take i = zipWith f (as.take i) (bs.take i) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.take_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem extract_zipWith : (zipWith f as bs).extract i j = zipWith f (as.extract i j) (bs.extract i j) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.drop_zipWith, List.take_zipWith]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWith_append {f : α → β → γ} {as as' : Array α} {bs bs' : Array β}
|
||||
(h : as.size = bs.size) :
|
||||
zipWith f (as ++ as') (bs ++ bs') = zipWith f as bs ++ zipWith f as' bs' := by
|
||||
@@ -161,7 +152,7 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {as : Array α} {bs : Array
|
||||
· rintro ⟨⟨ws⟩, ⟨xs⟩, ⟨ys⟩, ⟨zs⟩, h, rfl, rfl, h₁, h₂⟩
|
||||
exact ⟨ws, xs, ys, zs, by simp_all⟩
|
||||
|
||||
@[simp, grind =] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||||
@[simp] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -193,7 +184,6 @@ theorem zipWith_eq_zipWith_take_min (as : Array α) (bs : Array β) :
|
||||
simp
|
||||
rw [List.zipWith_eq_zipWith_take_min]
|
||||
|
||||
@[grind =]
|
||||
theorem reverse_zipWith (h : as.size = bs.size) :
|
||||
(zipWith f as bs).reverse = zipWith f as.reverse bs.reverse := by
|
||||
cases as
|
||||
@@ -210,7 +200,7 @@ theorem lt_size_right_of_zip {i : Nat} {as : Array α} {bs : Array β} (h : i <
|
||||
i < bs.size :=
|
||||
lt_size_right_of_zipWith h
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem getElem_zip {as : Array α} {bs : Array β} {i : Nat} {h : i < (zip as bs).size} :
|
||||
(zip as bs)[i] =
|
||||
(as[i]'(lt_size_left_of_zip h), bs[i]'(lt_size_right_of_zip h)) :=
|
||||
@@ -221,22 +211,18 @@ theorem zip_eq_zipWith {as : Array α} {bs : Array β} : zip as bs = zipWith Pro
|
||||
cases bs
|
||||
simp [List.zip_eq_zipWith]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map {f : α → γ} {g : β → δ} {as : Array α} {bs : Array β} :
|
||||
zip (as.map f) (bs.map g) = (zip as bs).map (Prod.map f g) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zip_map]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_left {f : α → γ} {as : Array α} {bs : Array β} :
|
||||
zip (as.map f) bs = (zip as bs).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind _=_]
|
||||
theorem zip_map_right {f : β → γ} {as : Array α} {bs : Array β} :
|
||||
zip as (bs.map f) = (zip as bs).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size) :
|
||||
zip (as ++ bs) (cs ++ ds) = zip as cs ++ zip bs ds := by
|
||||
cases as
|
||||
@@ -245,7 +231,6 @@ theorem zip_append {as bs : Array α} {cs ds : Array β} (_h : as.size = cs.size
|
||||
cases ds
|
||||
simp_all [List.zip_append]
|
||||
|
||||
@[grind =]
|
||||
theorem zip_map' {f : α → β} {g : α → γ} {xs : Array α} :
|
||||
zip (xs.map f) (xs.map g) = xs.map fun a => (f a, g a) := by
|
||||
cases xs
|
||||
@@ -291,7 +276,7 @@ theorem zip_eq_append_iff {as : Array α} {bs : Array β} :
|
||||
∃ as₁ as₂ bs₁ bs₂, as₁.size = bs₁.size ∧ as = as₁ ++ as₂ ∧ bs = bs₁ ++ bs₂ ∧ xs = zip as₁ bs₁ ∧ ys = zip as₂ bs₂ := by
|
||||
simp [zip_eq_zipWith, zipWith_eq_append_iff]
|
||||
|
||||
@[simp, grind =] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||||
@[simp] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -308,7 +293,6 @@ theorem zip_eq_zip_take_min {as : Array α} {bs : Array β} :
|
||||
|
||||
/-! ### zipWithAll -/
|
||||
|
||||
@[grind =]
|
||||
theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
(zipWithAll f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
@@ -317,35 +301,31 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
simp [List.getElem?_zipWithAll]
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map {μ} {f : Option γ → Option δ → μ} {g : α → γ} {h : β → δ} {as : Array α} {bs : Array β} :
|
||||
zipWithAll f (as.map g) (bs.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_left {as : Array α} {bs : Array β} {f : α → α'} {g : Option α' → Option β → γ} :
|
||||
zipWithAll g (as.map f) bs = zipWithAll (fun a b => g (f <$> a) b) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map_left]
|
||||
|
||||
@[grind =]
|
||||
theorem zipWithAll_map_right {as : Array α} {bs : Array β} {f : β → β'} {g : Option α → Option β' → γ} :
|
||||
zipWithAll g as (bs.map f) = zipWithAll (fun a b => g a (f <$> b)) as bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.zipWithAll_map_right]
|
||||
|
||||
@[grind =]
|
||||
theorem map_zipWithAll {δ : Type _} {f : α → β} {g : Option γ → Option δ → α} {cs : Array γ} {ds : Array δ} :
|
||||
map f (zipWithAll g cs ds) = zipWithAll (fun x y => f (g x y)) cs ds := by
|
||||
cases cs
|
||||
cases ds
|
||||
simp [List.map_zipWithAll]
|
||||
|
||||
@[simp, grind =] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
zipWithAll f (replicate n a) (replicate n b) = replicate n (f (some a) (some b)) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@@ -354,15 +334,12 @@ abbrev zipWithAll_mkArray := @zipWithAll_replicate
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[deprecated fst_unzip (since := "2025-05-26")]
|
||||
theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
simp
|
||||
@[simp] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[deprecated snd_unzip (since := "2025-05-26")]
|
||||
theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
simp
|
||||
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[grind =]
|
||||
theorem unzip_eq_map {xs : Array (α × β)} : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
|
||||
cases xs
|
||||
simp [List.unzip_eq_map]
|
||||
@@ -394,13 +371,11 @@ theorem unzip_zip {as : Array α} {bs : Array β} (h : as.size = bs.size) :
|
||||
|
||||
theorem zip_of_prod {as : Array α} {bs : Array β} {xs : Array (α × β)} (hl : xs.map Prod.fst = as)
|
||||
(hr : xs.map Prod.snd = bs) : xs = as.zip bs := by
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← fst_unzip, ← snd_unzip, zip_unzip, zip_unzip]
|
||||
rw [← hl, ← hr, ← zip_unzip xs, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp, grind =] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
@[simp] theorem unzip_replicate {n : Nat} {a : α} {b : β} :
|
||||
unzip (replicate n (a, b)) = (replicate n a, replicate n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
@[deprecated unzip_replicate (since := "2025-03-18")]
|
||||
abbrev unzip_mkArray := @unzip_replicate
|
||||
|
||||
end Array
|
||||
|
||||
@@ -27,7 +27,7 @@ class EquivBEq (α) [BEq α] : Prop extends PartialEquivBEq α, ReflBEq α
|
||||
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||
PartialEquivBEq.symm
|
||||
|
||||
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
@[grind] theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
||||
|
||||
theorem bne_comm [BEq α] [PartialEquivBEq α] {a b : α} : (a != b) = (b != a) := by
|
||||
|
||||
@@ -6,10 +6,7 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.BasicAux
|
||||
import Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
import Init.Data.BitVec.Bitblast
|
||||
import Init.Data.BitVec.Decidable
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Folds
|
||||
import Init.Data.BitVec.Lemmas
|
||||
|
||||
@@ -37,7 +37,7 @@ instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||
|
||||
/-- Theorem for normalizing the bitvector literal representation. -/
|
||||
-- TODO: This needs more usage data to assess which direction the simp should go.
|
||||
@[simp, bitvec_to_nat, grind =] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
|
||||
@[simp, bitvec_to_nat] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
|
||||
|
||||
-- Note. Mathlib would like this to go the other direction.
|
||||
@[simp] theorem natCast_eq_ofNat (w x : Nat) : @Nat.cast (BitVec w) _ x = .ofNat w x := rfl
|
||||
@@ -61,7 +61,7 @@ end subsingleton
|
||||
section zero_allOnes
|
||||
|
||||
/-- Returns a bitvector of size `n` where all bits are `0`. -/
|
||||
@[expose] protected def zero (n : Nat) : BitVec n := .ofNatLT 0 (Nat.two_pow_pos n)
|
||||
protected def zero (n : Nat) : BitVec n := .ofNatLT 0 (Nat.two_pow_pos n)
|
||||
instance : Inhabited (BitVec n) where default := .zero n
|
||||
|
||||
/-- Returns a bitvector of size `n` where all bits are `1`. -/
|
||||
@@ -74,30 +74,28 @@ section getXsb
|
||||
|
||||
/--
|
||||
Returns the `i`th least significant bit.
|
||||
-/
|
||||
@[inline, expose] def getLsb (x : BitVec w) (i : Fin w) : Bool := x.toNat.testBit i
|
||||
|
||||
@[deprecated getLsb (since := "2025-06-17"), inherit_doc getLsb]
|
||||
abbrev getLsb' := @getLsb
|
||||
This will be renamed `getLsb` after the existing deprecated alias is removed.
|
||||
-/
|
||||
@[inline] def getLsb' (x : BitVec w) (i : Fin w) : Bool := x.toNat.testBit i
|
||||
|
||||
/-- Returns the `i`th least significant bit, or `none` if `i ≥ w`. -/
|
||||
@[inline, expose] def getLsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getLsb x ⟨i, h⟩) else none
|
||||
@[inline] def getLsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getLsb' x ⟨i, h⟩) else none
|
||||
|
||||
/--
|
||||
Returns the `i`th most significant bit.
|
||||
-/
|
||||
@[inline] def getMsb (x : BitVec w) (i : Fin w) : Bool := x.getLsb ⟨w-1-i, by omega⟩
|
||||
|
||||
@[deprecated getMsb (since := "2025-06-17"), inherit_doc getMsb]
|
||||
abbrev getMsb' := @getMsb
|
||||
This will be renamed `BitVec.getMsb` after the existing deprecated alias is removed.
|
||||
-/
|
||||
@[inline] def getMsb' (x : BitVec w) (i : Fin w) : Bool := x.getLsb' ⟨w-1-i, by omega⟩
|
||||
|
||||
/-- Returns the `i`th most significant bit or `none` if `i ≥ w`. -/
|
||||
@[inline] def getMsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getMsb x ⟨i, h⟩) else none
|
||||
if h : i < w then some (getMsb' x ⟨i, h⟩) else none
|
||||
|
||||
/-- Returns the `i`th least significant bit or `false` if `i ≥ w`. -/
|
||||
@[inline, expose] def getLsbD (x : BitVec w) (i : Nat) : Bool :=
|
||||
@[inline] def getLsbD (x : BitVec w) (i : Nat) : Bool :=
|
||||
x.toNat.testBit i
|
||||
|
||||
/-- Returns the `i`th most significant bit, or `false` if `i ≥ w`. -/
|
||||
@@ -112,21 +110,20 @@ end getXsb
|
||||
section getElem
|
||||
|
||||
instance : GetElem (BitVec w) Nat Bool fun _ i => i < w where
|
||||
getElem xs i h := xs.getLsb ⟨i, h⟩
|
||||
getElem xs i h := xs.getLsb' ⟨i, h⟩
|
||||
|
||||
/-- We prefer `x[i]` as the simp normal form for `getLsb'` -/
|
||||
@[simp, grind =] theorem getLsb_eq_getElem (x : BitVec w) (i : Fin w) :
|
||||
x.getLsb i = x[i] := rfl
|
||||
@[simp] theorem getLsb'_eq_getElem (x : BitVec w) (i : Fin w) :
|
||||
x.getLsb' i = x[i] := rfl
|
||||
|
||||
/-- We prefer `x[i]?` as the simp normal form for `getLsb?` -/
|
||||
@[simp, grind =] theorem getLsb?_eq_getElem? (x : BitVec w) (i : Nat) :
|
||||
@[simp] theorem getLsb?_eq_getElem? (x : BitVec w) (i : Nat) :
|
||||
x.getLsb? i = x[i]? := rfl
|
||||
|
||||
@[grind =_] -- Activate when we see `x.toNat.testBit i`.
|
||||
theorem getElem_eq_testBit_toNat (x : BitVec w) (i : Nat) (h : i < w) :
|
||||
x[i] = x.toNat.testBit i := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp]
|
||||
theorem getLsbD_eq_getElem {x : BitVec w} {i : Nat} (h : i < w) :
|
||||
x.getLsbD i = x[i] := rfl
|
||||
|
||||
@@ -137,7 +134,6 @@ section Int
|
||||
/--
|
||||
Interprets the bitvector as an integer stored in two's complement form.
|
||||
-/
|
||||
@[expose]
|
||||
protected def toInt (x : BitVec n) : Int :=
|
||||
if 2 * x.toNat < 2^n then
|
||||
x.toNat
|
||||
@@ -151,7 +147,6 @@ over- and underflowing as needed.
|
||||
The underlying `Nat` is `(2^n + (i mod 2^n)) mod 2^n`. Converting the bitvector back to an `Int`
|
||||
with `BitVec.toInt` results in the value `i.bmod (2^n)`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def ofInt (n : Nat) (i : Int) : BitVec n := .ofNatLT (i % (Int.ofNat (2^n))).toNat (by
|
||||
apply (Int.toNat_lt _).mpr
|
||||
· apply Int.emod_lt_of_pos
|
||||
@@ -177,7 +172,7 @@ recommended_spelling "zero" for "0#n" in [BitVec.ofNat, «term__#__»]
|
||||
recommended_spelling "one" for "1#n" in [BitVec.ofNat, «term__#__»]
|
||||
|
||||
/-- Unexpander for bitvector literals. -/
|
||||
@[app_unexpander BitVec.ofNat] meta def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
||||
@[app_unexpander BitVec.ofNat] def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $n $i:num) => `($i:num#$n)
|
||||
| _ => throw ()
|
||||
|
||||
@@ -186,7 +181,7 @@ scoped syntax:max term:max noWs "#'" noWs term:max : term
|
||||
macro_rules | `($i#'$p) => `(BitVec.ofNatLT $i $p)
|
||||
|
||||
/-- Unexpander for bitvector literals without truncation. -/
|
||||
@[app_unexpander BitVec.ofNatLT] meta def unexpandBitVecOfNatLt : Lean.PrettyPrinter.Unexpander
|
||||
@[app_unexpander BitVec.ofNatLT] def unexpandBitVecOfNatLt : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $i $p) => `($i#'$p)
|
||||
| _ => throw ()
|
||||
|
||||
@@ -223,14 +218,12 @@ Usually accessed via the `-` prefix operator.
|
||||
|
||||
SMT-LIB name: `bvneg`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def neg (x : BitVec n) : BitVec n := .ofNat n (2^n - x.toNat)
|
||||
instance : Neg (BitVec n) := ⟨.neg⟩
|
||||
|
||||
/--
|
||||
Returns the absolute value of a signed bitvector.
|
||||
-/
|
||||
@[expose]
|
||||
protected def abs (x : BitVec n) : BitVec n := if x.msb then .neg x else x
|
||||
|
||||
/--
|
||||
@@ -239,7 +232,6 @@ modulo `2^n`. Usually accessed via the `*` operator.
|
||||
|
||||
SMT-LIB name: `bvmul`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def mul (x y : BitVec n) : BitVec n := BitVec.ofNat n (x.toNat * y.toNat)
|
||||
instance : Mul (BitVec n) := ⟨.mul⟩
|
||||
|
||||
@@ -250,7 +242,6 @@ Note that this is currently an inefficient implementation,
|
||||
and should be replaced via an `@[extern]` with a native implementation.
|
||||
See https://github.com/leanprover/lean4/issues/7887.
|
||||
-/
|
||||
@[expose]
|
||||
protected def pow (x : BitVec n) (y : Nat) : BitVec n :=
|
||||
match y with
|
||||
| 0 => 1
|
||||
@@ -262,7 +253,6 @@ instance : Pow (BitVec n) Nat where
|
||||
Unsigned division of bitvectors using the Lean convention where division by zero returns zero.
|
||||
Usually accessed via the `/` operator.
|
||||
-/
|
||||
@[expose]
|
||||
def udiv (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat / y.toNat)#'(Nat.lt_of_le_of_lt (Nat.div_le_self _ _) x.isLt)
|
||||
instance : Div (BitVec n) := ⟨.udiv⟩
|
||||
@@ -272,7 +262,6 @@ Unsigned modulo for bitvectors. Usually accessed via the `%` operator.
|
||||
|
||||
SMT-LIB name: `bvurem`.
|
||||
-/
|
||||
@[expose]
|
||||
def umod (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat % y.toNat)#'(Nat.lt_of_le_of_lt (Nat.mod_le _ _) x.isLt)
|
||||
instance : Mod (BitVec n) := ⟨.umod⟩
|
||||
@@ -284,7 +273,6 @@ where division by zero returns `BitVector.allOnes n`.
|
||||
|
||||
SMT-LIB name: `bvudiv`.
|
||||
-/
|
||||
@[expose]
|
||||
def smtUDiv (x y : BitVec n) : BitVec n := if y = 0 then allOnes n else udiv x y
|
||||
|
||||
/--
|
||||
@@ -354,11 +342,10 @@ end arithmetic
|
||||
section bool
|
||||
|
||||
/-- Turns a `Bool` into a bitvector of length `1`. -/
|
||||
@[expose]
|
||||
def ofBool (b : Bool) : BitVec 1 := cond b 1 0
|
||||
|
||||
@[simp, grind =] theorem ofBool_false : ofBool false = 0 := by trivial
|
||||
@[simp, grind =] theorem ofBool_true : ofBool true = 1 := by trivial
|
||||
@[simp] theorem ofBool_false : ofBool false = 0 := by trivial
|
||||
@[simp] theorem ofBool_true : ofBool true = 1 := by trivial
|
||||
|
||||
/-- Fills a bitvector with `w` copies of the bit `b`. -/
|
||||
def fill (w : Nat) (b : Bool) : BitVec w := bif b then -1 else 0
|
||||
@@ -372,7 +359,6 @@ Unsigned less-than for bitvectors.
|
||||
|
||||
SMT-LIB name: `bvult`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def ult (x y : BitVec n) : Bool := x.toNat < y.toNat
|
||||
|
||||
/--
|
||||
@@ -380,7 +366,6 @@ Unsigned less-than-or-equal-to for bitvectors.
|
||||
|
||||
SMT-LIB name: `bvule`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def ule (x y : BitVec n) : Bool := x.toNat ≤ y.toNat
|
||||
|
||||
/--
|
||||
@@ -392,7 +377,6 @@ Examples:
|
||||
* `BitVec.slt 6#4 7 = true`
|
||||
* `BitVec.slt 7#4 8 = false`
|
||||
-/
|
||||
@[expose]
|
||||
protected def slt (x y : BitVec n) : Bool := x.toInt < y.toInt
|
||||
|
||||
/--
|
||||
@@ -400,7 +384,6 @@ Signed less-than-or-equal-to for bitvectors.
|
||||
|
||||
SMT-LIB name: `bvsle`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def sle (x y : BitVec n) : Bool := x.toInt ≤ y.toInt
|
||||
|
||||
end relations
|
||||
@@ -414,23 +397,22 @@ width `m`.
|
||||
Using `x.cast eq` should be preferred over `eq ▸ x` because there are special-purpose `simp` lemmas
|
||||
that can more consistently simplify `BitVec.cast` away.
|
||||
-/
|
||||
@[inline, expose] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLT x.toNat (eq ▸ x.isLt)
|
||||
@[inline] protected def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLT x.toNat (eq ▸ x.isLt)
|
||||
|
||||
@[simp, grind =] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
||||
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
||||
(BitVec.ofNat n x).cast h = BitVec.ofNat m x := by
|
||||
subst h; rfl
|
||||
|
||||
@[simp, grind =] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
|
||||
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
|
||||
(x.cast h₁).cast h₂ = x.cast (h₁ ▸ h₂) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
|
||||
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : x.cast h = x := rfl
|
||||
|
||||
/--
|
||||
Extracts the bits `start` to `start + len - 1` from a bitvector of size `n` to yield a
|
||||
new bitvector of size `len`. If `start + len > n`, then the bitvector is zero-extended.
|
||||
-/
|
||||
@[expose]
|
||||
def extractLsb' (start len : Nat) (x : BitVec n) : BitVec len := .ofNat _ (x.toNat >>> start)
|
||||
|
||||
/--
|
||||
@@ -441,7 +423,6 @@ The resulting bitvector has size `hi - lo + 1`.
|
||||
|
||||
SMT-LIB name: `extract`.
|
||||
-/
|
||||
@[expose]
|
||||
def extractLsb (hi lo : Nat) (x : BitVec n) : BitVec (hi - lo + 1) := extractLsb' lo _ x
|
||||
|
||||
/--
|
||||
@@ -450,7 +431,6 @@ Increases the width of a bitvector to one that is at least as large by zero-exte
|
||||
This is a constant-time operation because the underlying `Nat` is unmodified; because the new width
|
||||
is at least as large as the old one, no overflow is possible.
|
||||
-/
|
||||
@[expose]
|
||||
def setWidth' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
||||
x.toNat#'(by
|
||||
apply Nat.lt_of_lt_of_le x.isLt
|
||||
@@ -459,7 +439,6 @@ def setWidth' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
||||
/--
|
||||
Returns `zeroExtend (w+n) x <<< n` without needing to compute `x % 2^(2+n)`.
|
||||
-/
|
||||
@[expose]
|
||||
def shiftLeftZeroExtend (msbs : BitVec w) (m : Nat) : BitVec (w + m) :=
|
||||
let shiftLeftLt {x : Nat} (p : x < 2^w) (m : Nat) : x <<< m < 2^(w + m) := by
|
||||
simp [Nat.shiftLeft_eq, Nat.pow_add]
|
||||
@@ -516,7 +495,6 @@ SMT-LIB name: `bvand`.
|
||||
Example:
|
||||
* `0b1010#4 &&& 0b0110#4 = 0b0010#4`
|
||||
-/
|
||||
@[expose]
|
||||
protected def and (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat &&& y.toNat)#'(Nat.and_lt_two_pow x.toNat y.isLt)
|
||||
instance : AndOp (BitVec w) := ⟨.and⟩
|
||||
@@ -529,7 +507,6 @@ SMT-LIB name: `bvor`.
|
||||
Example:
|
||||
* `0b1010#4 ||| 0b0110#4 = 0b1110#4`
|
||||
-/
|
||||
@[expose]
|
||||
protected def or (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat ||| y.toNat)#'(Nat.or_lt_two_pow x.isLt y.isLt)
|
||||
instance : OrOp (BitVec w) := ⟨.or⟩
|
||||
@@ -542,7 +519,6 @@ SMT-LIB name: `bvxor`.
|
||||
Example:
|
||||
* `0b1010#4 ^^^ 0b0110#4 = 0b1100#4`
|
||||
-/
|
||||
@[expose]
|
||||
protected def xor (x y : BitVec n) : BitVec n :=
|
||||
(x.toNat ^^^ y.toNat)#'(Nat.xor_lt_two_pow x.isLt y.isLt)
|
||||
instance : Xor (BitVec w) := ⟨.xor⟩
|
||||
@@ -555,7 +531,6 @@ SMT-LIB name: `bvnot`.
|
||||
Example:
|
||||
* `~~~(0b0101#4) == 0b1010`
|
||||
-/
|
||||
@[expose]
|
||||
protected def not (x : BitVec n) : BitVec n := allOnes n ^^^ x
|
||||
instance : Complement (BitVec w) := ⟨.not⟩
|
||||
|
||||
@@ -565,7 +540,6 @@ equivalent to `x * 2^s`, modulo `2^n`.
|
||||
|
||||
SMT-LIB name: `bvshl` except this operator uses a `Nat` shift value.
|
||||
-/
|
||||
@[expose]
|
||||
protected def shiftLeft (x : BitVec n) (s : Nat) : BitVec n := BitVec.ofNat n (x.toNat <<< s)
|
||||
instance : HShiftLeft (BitVec w) Nat (BitVec w) := ⟨.shiftLeft⟩
|
||||
|
||||
@@ -577,7 +551,6 @@ As a numeric operation, this is equivalent to `x / 2^s`, rounding down.
|
||||
|
||||
SMT-LIB name: `bvlshr` except this operator uses a `Nat` shift value.
|
||||
-/
|
||||
@[expose]
|
||||
def ushiftRight (x : BitVec n) (s : Nat) : BitVec n :=
|
||||
(x.toNat >>> s)#'(by
|
||||
let ⟨x, lt⟩ := x
|
||||
@@ -595,7 +568,6 @@ As a numeric operation, this is equivalent to `x.toInt >>> s`.
|
||||
|
||||
SMT-LIB name: `bvashr` except this operator uses a `Nat` shift value.
|
||||
-/
|
||||
@[expose]
|
||||
def sshiftRight (x : BitVec n) (s : Nat) : BitVec n := .ofInt n (x.toInt >>> s)
|
||||
|
||||
instance {n} : HShiftLeft (BitVec m) (BitVec n) (BitVec m) := ⟨fun x y => x <<< y.toNat⟩
|
||||
@@ -609,12 +581,10 @@ As a numeric operation, this is equivalent to `a.toInt >>> s.toNat`.
|
||||
|
||||
SMT-LIB name: `bvashr`.
|
||||
-/
|
||||
@[expose]
|
||||
def sshiftRight' (a : BitVec n) (s : BitVec m) : BitVec n := a.sshiftRight s.toNat
|
||||
|
||||
/-- Auxiliary function for `rotateLeft`, which does not take into account the case where
|
||||
the rotation amount is greater than the bitvector width. -/
|
||||
@[expose]
|
||||
def rotateLeftAux (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
x <<< n ||| x >>> (w - n)
|
||||
|
||||
@@ -629,7 +599,6 @@ SMT-LIB name: `rotate_left`, except this operator uses a `Nat` shift amount.
|
||||
Example:
|
||||
* `(0b0011#4).rotateLeft 3 = 0b1001`
|
||||
-/
|
||||
@[expose]
|
||||
def rotateLeft (x : BitVec w) (n : Nat) : BitVec w := rotateLeftAux x (n % w)
|
||||
|
||||
|
||||
@@ -637,7 +606,6 @@ def rotateLeft (x : BitVec w) (n : Nat) : BitVec w := rotateLeftAux x (n % w)
|
||||
Auxiliary function for `rotateRight`, which does not take into account the case where
|
||||
the rotation amount is greater than the bitvector width.
|
||||
-/
|
||||
@[expose]
|
||||
def rotateRightAux (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
x >>> n ||| x <<< (w - n)
|
||||
|
||||
@@ -652,7 +620,6 @@ SMT-LIB name: `rotate_right`, except this operator uses a `Nat` shift amount.
|
||||
Example:
|
||||
* `rotateRight 0b01001#5 1 = 0b10100`
|
||||
-/
|
||||
@[expose]
|
||||
def rotateRight (x : BitVec w) (n : Nat) : BitVec w := rotateRightAux x (n % w)
|
||||
|
||||
/--
|
||||
@@ -664,7 +631,6 @@ SMT-LIB name: `concat`.
|
||||
Example:
|
||||
* `0xAB#8 ++ 0xCD#8 = 0xABCD#16`.
|
||||
-/
|
||||
@[expose]
|
||||
def append (msbs : BitVec n) (lsbs : BitVec m) : BitVec (n+m) :=
|
||||
shiftLeftZeroExtend msbs m ||| setWidth' (Nat.le_add_left m n) lsbs
|
||||
|
||||
@@ -687,7 +653,6 @@ result of appending a single bit to the front in the naive implementation).
|
||||
|
||||
/-- Append a single bit to the end of a bitvector, using big endian order (see `append`).
|
||||
That is, the new bit is the least significant bit. -/
|
||||
@[expose]
|
||||
def concat {n} (msbs : BitVec n) (lsb : Bool) : BitVec (n+1) := msbs ++ (ofBool lsb)
|
||||
|
||||
/--
|
||||
@@ -695,7 +660,6 @@ Shifts all bits of `x` to the left by `1` and sets the least significant bit to
|
||||
|
||||
This is a non-dependent version of `BitVec.concat` that does not change the total bitwidth.
|
||||
-/
|
||||
@[expose]
|
||||
def shiftConcat (x : BitVec n) (b : Bool) : BitVec n :=
|
||||
(x.concat b).truncate n
|
||||
|
||||
@@ -704,16 +668,13 @@ Prepends a single bit to the front of a bitvector, using big-endian order (see `
|
||||
|
||||
The new bit is the most significant bit.
|
||||
-/
|
||||
@[expose]
|
||||
def cons {n} (msb : Bool) (lsbs : BitVec n) : BitVec (n+1) :=
|
||||
((ofBool msb) ++ lsbs).cast (Nat.add_comm ..)
|
||||
|
||||
@[grind =]
|
||||
theorem append_ofBool (msbs : BitVec w) (lsb : Bool) :
|
||||
msbs ++ ofBool lsb = concat msbs lsb :=
|
||||
rfl
|
||||
|
||||
@[grind =]
|
||||
theorem ofBool_append (msb : Bool) (lsbs : BitVec w) :
|
||||
ofBool msb ++ lsbs = (cons msb lsbs).cast (Nat.add_comm ..) :=
|
||||
rfl
|
||||
@@ -728,12 +689,6 @@ def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
|
||||
|
||||
end bitwise
|
||||
|
||||
/-- The bitvector of width `w` that has the smallest value when interpreted as an integer. -/
|
||||
def intMin (w : Nat) := twoPow w (w - 1)
|
||||
|
||||
/-- The bitvector of width `w` that has the largest value when interpreted as an integer. -/
|
||||
def intMax (w : Nat) := (twoPow w (w - 1)) - 1
|
||||
|
||||
/--
|
||||
Computes a hash of a bitvector, combining 64-bit words using `mixHash`.
|
||||
-/
|
||||
@@ -748,20 +703,20 @@ instance : Hashable (BitVec n) where
|
||||
|
||||
section normalization_eqs
|
||||
/-! We add simp-lemmas that rewrite bitvector operations into the equivalent notation -/
|
||||
@[simp, grind =] theorem append_eq (x : BitVec w) (y : BitVec v) : BitVec.append x y = x ++ y := rfl
|
||||
@[simp, grind =] theorem shiftLeft_eq (x : BitVec w) (n : Nat) : BitVec.shiftLeft x n = x <<< n := rfl
|
||||
@[simp, grind =] theorem ushiftRight_eq (x : BitVec w) (n : Nat) : BitVec.ushiftRight x n = x >>> n := rfl
|
||||
@[simp, grind =] theorem not_eq (x : BitVec w) : BitVec.not x = ~~~x := rfl
|
||||
@[simp, grind =] theorem and_eq (x y : BitVec w) : BitVec.and x y = x &&& y := rfl
|
||||
@[simp, grind =] theorem or_eq (x y : BitVec w) : BitVec.or x y = x ||| y := rfl
|
||||
@[simp, grind =] theorem xor_eq (x y : BitVec w) : BitVec.xor x y = x ^^^ y := rfl
|
||||
@[simp, grind =] theorem neg_eq (x : BitVec w) : BitVec.neg x = -x := rfl
|
||||
@[simp, grind =] theorem add_eq (x y : BitVec w) : BitVec.add x y = x + y := rfl
|
||||
@[simp, grind =] theorem sub_eq (x y : BitVec w) : BitVec.sub x y = x - y := rfl
|
||||
@[simp, grind =] theorem mul_eq (x y : BitVec w) : BitVec.mul x y = x * y := rfl
|
||||
@[simp, grind =] theorem udiv_eq (x y : BitVec w) : BitVec.udiv x y = x / y := rfl
|
||||
@[simp, grind =] theorem umod_eq (x y : BitVec w) : BitVec.umod x y = x % y := rfl
|
||||
@[simp, grind =] theorem zero_eq : BitVec.zero n = 0#n := rfl
|
||||
@[simp] theorem append_eq (x : BitVec w) (y : BitVec v) : BitVec.append x y = x ++ y := rfl
|
||||
@[simp] theorem shiftLeft_eq (x : BitVec w) (n : Nat) : BitVec.shiftLeft x n = x <<< n := rfl
|
||||
@[simp] theorem ushiftRight_eq (x : BitVec w) (n : Nat) : BitVec.ushiftRight x n = x >>> n := rfl
|
||||
@[simp] theorem not_eq (x : BitVec w) : BitVec.not x = ~~~x := rfl
|
||||
@[simp] theorem and_eq (x y : BitVec w) : BitVec.and x y = x &&& y := rfl
|
||||
@[simp] theorem or_eq (x y : BitVec w) : BitVec.or x y = x ||| y := rfl
|
||||
@[simp] theorem xor_eq (x y : BitVec w) : BitVec.xor x y = x ^^^ y := rfl
|
||||
@[simp] theorem neg_eq (x : BitVec w) : BitVec.neg x = -x := rfl
|
||||
@[simp] theorem add_eq (x y : BitVec w) : BitVec.add x y = x + y := rfl
|
||||
@[simp] theorem sub_eq (x y : BitVec w) : BitVec.sub x y = x - y := rfl
|
||||
@[simp] theorem mul_eq (x y : BitVec w) : BitVec.mul x y = x * y := rfl
|
||||
@[simp] theorem udiv_eq (x y : BitVec w) : BitVec.udiv x y = x / y := rfl
|
||||
@[simp] theorem umod_eq (x y : BitVec w) : BitVec.umod x y = x % y := rfl
|
||||
@[simp] theorem zero_eq : BitVec.zero n = 0#n := rfl
|
||||
end normalization_eqs
|
||||
|
||||
/-- Converts a list of `Bool`s into a big-endian `BitVec`. -/
|
||||
@@ -797,7 +752,6 @@ Checks whether subtraction of `x` and `y` results in *unsigned* overflow.
|
||||
|
||||
SMT-Lib name: `bvusubo`.
|
||||
-/
|
||||
@[expose]
|
||||
def usubOverflow {w : Nat} (x y : BitVec w) : Bool := x.toNat < y.toNat
|
||||
|
||||
/--
|
||||
@@ -806,7 +760,6 @@ Checks whether the subtraction of `x` and `y` results in *signed* overflow, trea
|
||||
|
||||
SMT-Lib name: `bvssubo`.
|
||||
-/
|
||||
@[expose]
|
||||
def ssubOverflow {w : Nat} (x y : BitVec w) : Bool :=
|
||||
(x.toInt - y.toInt ≥ 2 ^ (w - 1)) || (x.toInt - y.toInt < - 2 ^ (w - 1))
|
||||
|
||||
@@ -817,7 +770,6 @@ For a bitvector `x` with nonzero width, this only happens if `x = intMin`.
|
||||
|
||||
SMT-Lib name: `bvnego`.
|
||||
-/
|
||||
@[expose]
|
||||
def negOverflow {w : Nat} (x : BitVec w) : Bool :=
|
||||
x.toInt == - 2 ^ (w - 1)
|
||||
|
||||
@@ -827,7 +779,6 @@ For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` an
|
||||
|
||||
SMT-LIB name: `bvsdivo`.
|
||||
-/
|
||||
@[expose]
|
||||
def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
|
||||
(2 ^ (w - 1) ≤ x.toInt / y.toInt) || (x.toInt / y.toInt < - 2 ^ (w - 1))
|
||||
|
||||
@@ -853,15 +804,4 @@ treating `x` and `y` as 2's complement signed bitvectors.
|
||||
def smulOverflow {w : Nat} (x y : BitVec w) : Bool :=
|
||||
(x.toInt * y.toInt ≥ 2 ^ (w - 1)) || (x.toInt * y.toInt < - 2 ^ (w - 1))
|
||||
|
||||
/-- Count the number of leading zeros downward from the `n`-th bit to the `0`-th bit for the bitblaster.
|
||||
This builds a tree of `if-then-else` lookups whose length is linear in the bitwidth,
|
||||
and an efficient circuit for bitblasting `clz`. -/
|
||||
def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
match n with
|
||||
| 0 => if x.getLsbD 0 then BitVec.ofNat w (w - 1) else BitVec.ofNat w w
|
||||
| n' + 1 => if x.getLsbD n then BitVec.ofNat w (w - 1 - n) else clzAuxRec x n'
|
||||
|
||||
/-- Count the number of leading zeros. -/
|
||||
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -24,15 +24,13 @@ The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.ofNat (2^n) i
|
||||
toFin := Fin.ofNat' (2^n) i
|
||||
|
||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||
|
||||
/-- Return the bound in terms of toNat. -/
|
||||
theorem isLt (x : BitVec w) : x.toNat < 2^w := x.toFin.isLt
|
||||
|
||||
grind_pattern isLt => x.toNat, 2^w
|
||||
|
||||
end Nat
|
||||
|
||||
section arithmetic
|
||||
@@ -43,7 +41,6 @@ Usually accessed via the `+` operator.
|
||||
|
||||
SMT-LIB name: `bvadd`.
|
||||
-/
|
||||
@[expose]
|
||||
protected def add (x y : BitVec n) : BitVec n := .ofNat n (x.toNat + y.toNat)
|
||||
instance : Add (BitVec n) := ⟨BitVec.add⟩
|
||||
|
||||
@@ -52,7 +49,6 @@ Subtracts one bitvector from another. This can be interpreted as either signed o
|
||||
modulo `2^n`. Usually accessed via the `-` operator.
|
||||
|
||||
-/
|
||||
@[expose]
|
||||
protected def sub (x y : BitVec n) : BitVec n := .ofNat n ((2^n - y.toNat) + x.toNat)
|
||||
instance : Sub (BitVec n) := ⟨BitVec.sub⟩
|
||||
|
||||
|
||||
@@ -6,14 +6,12 @@ Authors: Harun Khan, Abdalrhman M Mohamed, Joe Hendrix, Siddharth Bhat
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.Folds
|
||||
import all Init.Data.Nat.Bitwise.Basic
|
||||
import Init.Data.Nat.Mod
|
||||
import all Init.Data.Int.DivMod
|
||||
import Init.Data.Int.LemmasAux
|
||||
import all Init.Data.BitVec.Basic
|
||||
import Init.Data.BitVec.Decidable
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.BitVec.Folds
|
||||
import all Init.Data.BitVec.Lemmas
|
||||
|
||||
/-!
|
||||
# Bit blasting of bitvectors
|
||||
@@ -240,7 +238,7 @@ theorem toNat_add_of_and_eq_zero {x y : BitVec w} (h : x &&& y = 0#w) :
|
||||
simp only [decide_eq_true_eq] at this
|
||||
omega
|
||||
rw [← carry_width]
|
||||
simp [carry_of_and_eq_zero h]
|
||||
simp [not_eq_true, carry_of_and_eq_zero h]
|
||||
|
||||
/-- Carry function for bitwise addition. -/
|
||||
def adcb (x y c : Bool) : Bool × Bool := (atLeastTwo x y c, x ^^ (y ^^ c))
|
||||
@@ -254,7 +252,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
|
||||
(getLsbD x i ^^ (getLsbD y i ^^ carry i x y c)) := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
let ⟨y, y_lt⟩ := y
|
||||
simp only [getLsbD, toNat_add, toNat_setWidth, toNat_ofFin, toNat_ofBool,
|
||||
simp only [getLsbD, toNat_add, toNat_setWidth, i_lt, toNat_ofFin, toNat_ofBool,
|
||||
Nat.mod_add_mod, Nat.add_mod_mod]
|
||||
apply Eq.trans
|
||||
rw [← Nat.div_add_mod x (2^i), ← Nat.div_add_mod y (2^i)]
|
||||
@@ -297,7 +295,7 @@ theorem adc_spec (x y : BitVec w) (c : Bool) :
|
||||
simp [carry, Nat.mod_one]
|
||||
cases c <;> rfl
|
||||
case step =>
|
||||
simp [adcb, carry_succ, getElem_add_add_bool]
|
||||
simp [adcb, Prod.mk.injEq, carry_succ, getElem_add_add_bool]
|
||||
|
||||
theorem add_eq_adc (w : Nat) (x y : BitVec w) : x + y = (adc x y false).snd := by
|
||||
simp [adc_spec]
|
||||
@@ -314,7 +312,7 @@ theorem msb_add {w : Nat} {x y: BitVec w} :
|
||||
Bool.xor x.msb (Bool.xor y.msb (carry (w - 1) x y false)) := by
|
||||
simp only [BitVec.msb, BitVec.getMsbD]
|
||||
by_cases h : w ≤ 0
|
||||
· simp [show w = 0 by omega]
|
||||
· simp [h, show w = 0 by omega]
|
||||
· rw [getLsbD_add (x := x)]
|
||||
simp [show w > 0 by omega]
|
||||
omega
|
||||
@@ -334,15 +332,15 @@ theorem add_eq_or_of_and_eq_zero {w : Nat} (x y : BitVec w)
|
||||
(h : x &&& y = 0#w) : x + y = x ||| y := by
|
||||
rw [add_eq_adc, adc, iunfoldr_replace (fun _ => false) (x ||| y)]
|
||||
· rfl
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false,
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false, getLsbD_or,
|
||||
Prod.mk.injEq, and_eq_false_imp]
|
||||
intros i
|
||||
replace h : (x &&& y).getLsbD i = (0#w).getLsbD i := by rw [h]
|
||||
simp only [getLsbD_and, getLsbD_zero, and_eq_false_imp] at h
|
||||
constructor
|
||||
· intros hx
|
||||
simp_all
|
||||
· by_cases hx : x.getLsbD i <;> simp_all
|
||||
simp_all [hx]
|
||||
· by_cases hx : x.getLsbD i <;> simp_all [hx]
|
||||
|
||||
/-! ### Sub-/
|
||||
|
||||
@@ -379,7 +377,7 @@ theorem bit_not_add_self (x : BitVec w) :
|
||||
simp only [add_eq_adc]
|
||||
apply iunfoldr_replace_snd (fun _ => false) (-1) false rfl
|
||||
intro i; simp only [adcb, Fin.is_lt, getLsbD_eq_getElem, atLeastTwo_false_right, bne_false,
|
||||
ofNat_eq_ofNat, Prod.mk.injEq, and_eq_false_imp]
|
||||
ofNat_eq_ofNat, Fin.getElem_fin, Prod.mk.injEq, and_eq_false_imp]
|
||||
rw [iunfoldr_replace_snd (fun _ => ()) (((iunfoldr (fun i c => (c, !(x[i.val])))) ()).snd)]
|
||||
<;> simp [bit_not_testBit, neg_one_eq_allOnes, getElem_allOnes]
|
||||
|
||||
@@ -411,7 +409,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
· rw [getLsbD_add hi]
|
||||
have : 0 < w := by omega
|
||||
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
not_eq_eq_eq_not]
|
||||
_root_.true_and, not_eq_eq_eq_not]
|
||||
cases i with
|
||||
| zero =>
|
||||
have carry_zero : carry 0 ?x ?y false = false := by
|
||||
@@ -426,7 +424,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
· rintro h j hj; exact And.right <| h j (by omega)
|
||||
· rintro h j hj; exact ⟨by omega, h j (by omega)⟩
|
||||
· have h_ge : w ≤ i := by omega
|
||||
simp [h_ge, hi]
|
||||
simp [getLsbD_of_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
|
||||
@@ -435,7 +433,7 @@ theorem getElem_neg {i : Nat} {x : BitVec w} (h : i < w) :
|
||||
theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
getMsbD (-x) i =
|
||||
(getMsbD x i ^^ decide (∃ j < w, i < j ∧ getMsbD x j = true)) := by
|
||||
simp only [getMsbD, getLsbD_neg, Bool.and_eq_true, decide_eq_true_eq]
|
||||
simp only [getMsbD, getLsbD_neg, Bool.decide_and, Bool.and_eq_true, decide_eq_true_eq]
|
||||
by_cases hi : i < w
|
||||
case neg =>
|
||||
simp [hi]; omega
|
||||
@@ -520,11 +518,14 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
rw [(show w = w - 1 + 1 by omega), Int.pow_succ] at this
|
||||
omega
|
||||
|
||||
@[simp] theorem setWidth_neg_of_le {x : BitVec v} (h : w ≤ v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
|
||||
simp [← BitVec.signExtend_eq_setWidth_of_le _ h, BitVec.signExtend_neg_of_le h]
|
||||
|
||||
/-! ### abs -/
|
||||
|
||||
theorem msb_abs {w : Nat} {x : BitVec w} :
|
||||
x.abs.msb = (decide (x = intMin w) && decide (0 < w)) := by
|
||||
simp only [BitVec.abs]
|
||||
simp only [BitVec.abs, getMsbD_neg, ne_eq, decide_not, Bool.not_bne]
|
||||
by_cases h₀ : 0 < w
|
||||
· by_cases h₁ : x = intMin w
|
||||
· simp [h₁, msb_intMin]
|
||||
@@ -547,14 +548,54 @@ theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true :=
|
||||
rw [Nat.mod_eq_of_lt (by omega)]
|
||||
omega
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
simp [BitVec.ule, BitVec.ult, ← decide_not]
|
||||
|
||||
theorem ule_eq_carry (x y : BitVec w) : x.ule y = carry w y (~~~x) true := by
|
||||
simp [ule_eq_not_ult, ult_eq_not_carry]
|
||||
|
||||
/-- If two bitvectors have the same `msb`, then signed and unsigned comparisons coincide -/
|
||||
theorem slt_eq_ult_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) :
|
||||
x.slt y = x.ult y := by
|
||||
simp only [BitVec.slt, toInt_eq_msb_cond, BitVec.ult, decide_eq_decide, h]
|
||||
cases y.msb <;> simp
|
||||
|
||||
/-- If two bitvectors have different `msb`s, then unsigned comparison is determined by this bit -/
|
||||
theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
x.ult y = y.msb := by
|
||||
simp only [BitVec.ult, msb_eq_decide, ne_eq, decide_eq_decide] at *
|
||||
omega
|
||||
|
||||
/-- If two bitvectors have different `msb`s, then signed and unsigned comparisons are opposites -/
|
||||
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||
x.slt y = !x.ult y := by
|
||||
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
|
||||
cases y.msb <;> (simp [-Int.natCast_pow]; omega)
|
||||
|
||||
theorem slt_eq_ult {x y : BitVec w} :
|
||||
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
|
||||
by_cases h : x.msb = y.msb
|
||||
· simp [h, slt_eq_ult_of_msb_eq]
|
||||
· have h' : x.msb != y.msb := by simp_all
|
||||
simp [slt_eq_not_ult_of_msb_neq h, h']
|
||||
|
||||
theorem slt_eq_not_carry {x y : BitVec w} :
|
||||
x.slt y = (x.msb == y.msb).xor (carry w x (~~~y) true) := by
|
||||
simp only [slt_eq_ult, bne, ult_eq_not_carry]
|
||||
cases x.msb == y.msb <;> simp
|
||||
|
||||
theorem sle_eq_not_slt {x y : BitVec w} : x.sle y = !y.slt x := by
|
||||
simp only [BitVec.sle, BitVec.slt, ← decide_not, decide_eq_decide]; omega
|
||||
|
||||
theorem zero_sle_eq_not_msb {w : Nat} {x : BitVec w} : BitVec.sle 0#w x = !x.msb := by
|
||||
rw [sle_eq_not_slt, BitVec.slt_zero_eq_msb]
|
||||
|
||||
theorem zero_sle_iff_msb_eq_false {w : Nat} {x : BitVec w} : BitVec.sle 0#w x ↔ x.msb = false := by
|
||||
simp [zero_sle_eq_not_msb]
|
||||
|
||||
theorem toNat_toInt_of_sle {w : Nat} {x : BitVec w} (hx : BitVec.sle 0#w x) : x.toInt.toNat = x.toNat :=
|
||||
toNat_toInt_of_msb x (zero_sle_iff_msb_eq_false.1 hx)
|
||||
|
||||
theorem sle_eq_carry {x y : BitVec w} :
|
||||
x.sle y = !((x.msb == y.msb).xor (carry w y (~~~x) true)) := by
|
||||
rw [sle_eq_not_slt, slt_eq_not_carry, beq_comm]
|
||||
@@ -577,6 +618,12 @@ theorem neg_sle_zero (h : 0 < w) {x : BitVec w} :
|
||||
rw [sle_eq_slt_or_eq, neg_slt_zero h, sle_eq_slt_or_eq]
|
||||
simp [Bool.beq_eq_decide_eq (-x), Bool.beq_eq_decide_eq _ x, Eq.comm (a := x), Bool.or_assoc]
|
||||
|
||||
theorem sle_eq_ule {x y : BitVec w} : x.sle y = (x.msb != y.msb ^^ x.ule y) := by
|
||||
rw [sle_eq_not_slt, slt_eq_ult, ← Bool.xor_not, ← ule_eq_not_ult, bne_comm]
|
||||
|
||||
theorem sle_eq_ule_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) : x.sle y = x.ule y := by
|
||||
simp [BitVec.sle_eq_ule, h]
|
||||
|
||||
/-! ### mul recurrence for bit blasting -/
|
||||
|
||||
/--
|
||||
@@ -584,7 +631,6 @@ A recurrence that describes multiplication as repeated addition.
|
||||
|
||||
This function is useful for bit blasting multiplication.
|
||||
-/
|
||||
@[expose]
|
||||
def mulRec (x y : BitVec w) (s : Nat) : BitVec w :=
|
||||
let cur := if y.getLsbD s then (x <<< s) else 0
|
||||
match s with
|
||||
@@ -611,7 +657,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
getElem_twoPow]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
simp [h]
|
||||
· by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
@@ -620,8 +666,8 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
simp [hik', hik'']
|
||||
omega
|
||||
· ext k
|
||||
simp only [and_twoPow,
|
||||
]
|
||||
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
|
||||
|
||||
/--
|
||||
@@ -778,7 +824,7 @@ private theorem Nat.div_add_eq_left_of_lt {x y z : Nat} (hx : z ∣ x) (hy : y <
|
||||
· apply Nat.le_trans
|
||||
· exact div_mul_le_self x z
|
||||
· omega
|
||||
· simp only [Nat.add_mul, Nat.one_mul]
|
||||
· simp only [succ_eq_add_one, Nat.add_mul, Nat.one_mul]
|
||||
apply Nat.add_lt_add_of_le_of_lt
|
||||
· apply Nat.le_of_eq
|
||||
exact (Nat.div_eq_iff_eq_mul_left hz hx).mp rfl
|
||||
@@ -891,10 +937,10 @@ def DivModState.lawful_init {w : Nat} (args : DivModArgs w) (hd : 0#w < args.d)
|
||||
hwrn := by simp only; omega,
|
||||
hdPos := by assumption
|
||||
hrLtDivisor := by simp [BitVec.lt_def] at hd ⊢; assumption
|
||||
hrWidth := by simp,
|
||||
hqWidth := by simp,
|
||||
hrWidth := by simp [DivModState.init],
|
||||
hqWidth := by simp [DivModState.init],
|
||||
hdiv := by
|
||||
simp only [toNat_ofNat, zero_mod, Nat.mul_zero, Nat.add_zero];
|
||||
simp only [DivModState.init, toNat_ofNat, zero_mod, Nat.mul_zero, Nat.add_zero];
|
||||
rw [Nat.shiftRight_eq_div_pow]
|
||||
apply Nat.div_eq_of_lt args.n.isLt
|
||||
}
|
||||
@@ -922,7 +968,7 @@ theorem DivModState.umod_eq_of_lawful {qr : DivModState w}
|
||||
n % d = qr.r := by
|
||||
apply umod_eq_of_mul_add_toNat h.hrLtDivisor
|
||||
have hdiv := h.hdiv
|
||||
simp only at hdiv
|
||||
simp only [shiftRight_zero] at hdiv
|
||||
simp only [h_final] at *
|
||||
exact hdiv.symm
|
||||
|
||||
@@ -976,7 +1022,7 @@ theorem DivModState.toNat_shiftRight_sub_one_eq
|
||||
{args : DivModArgs w} {qr : DivModState w} (h : qr.Poised args) :
|
||||
args.n.toNat >>> (qr.wn - 1)
|
||||
= (args.n.toNat >>> qr.wn) * 2 + (args.n.getLsbD (qr.wn - 1)).toNat := by
|
||||
change BitVec.toNat (args.n >>> (qr.wn - 1)) = _
|
||||
show BitVec.toNat (args.n >>> (qr.wn - 1)) = _
|
||||
have {..} := h -- break the structure down for `omega`
|
||||
rw [shiftRight_sub_one_eq_shiftConcat args.n h.hwn_lt]
|
||||
rw [toNat_shiftConcat_eq_of_lt (k := w - qr.wn)]
|
||||
@@ -1000,7 +1046,7 @@ obeys the division equation. -/
|
||||
theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
|
||||
DivModState.Lawful args (divSubtractShift args qr) := by
|
||||
rcases args with ⟨n, d⟩
|
||||
simp only [divSubtractShift]
|
||||
simp only [divSubtractShift, decide_eq_true_eq]
|
||||
-- We add these hypotheses for `omega` to find them later.
|
||||
have ⟨⟨hrwn, hd, hrd, hr, hn, hrnd⟩, hwn_lt⟩ := h
|
||||
have : d.toNat * (qr.q.toNat * 2) = d.toNat * qr.q.toNat * 2 := by rw [Nat.mul_assoc]
|
||||
@@ -1045,7 +1091,6 @@ theorem lawful_divSubtractShift (qr : DivModState w) (h : qr.Poised args) :
|
||||
/-! ### Core division algorithm circuit -/
|
||||
|
||||
/-- A recursive definition of division for bit blasting, in terms of a shift-subtraction circuit. -/
|
||||
@[expose]
|
||||
def divRec {w : Nat} (m : Nat) (args : DivModArgs w) (qr : DivModState w) :
|
||||
DivModState w :=
|
||||
match m with
|
||||
@@ -1137,7 +1182,7 @@ theorem getLsbD_udiv (n d : BitVec w) (hy : 0#w < d) (i : Nat) :
|
||||
|
||||
theorem getMsbD_udiv (n d : BitVec w) (hd : 0#w < d) (i : Nat) :
|
||||
(n / d).getMsbD i = (decide (i < w) && (divRec w {n, d} (DivModState.init w)).q.getMsbD i) := by
|
||||
simp [getMsbD_eq_getLsbD, udiv_eq_divRec (by assumption)]
|
||||
simp [getMsbD_eq_getLsbD, getLsbD_udiv, udiv_eq_divRec (by assumption)]
|
||||
|
||||
/- ### Arithmetic shift right (sshiftRight) recurrence -/
|
||||
|
||||
@@ -1304,7 +1349,7 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
|
||||
(negOverflow x) = (decide (0 < w) && (x == intMin w)) := by
|
||||
simp only [negOverflow]
|
||||
rcases w with _|w
|
||||
· simp [toInt_of_zero_length]
|
||||
· simp [toInt_of_zero_length, Int.min_eq_right]
|
||||
· suffices - 2 ^ w = (intMin (w + 1)).toInt by simp [beq_eq_decide_eq, ← toInt_inj, this]
|
||||
simp only [toInt_intMin, Nat.add_one_sub_one, Int.natCast_emod, Int.neg_inj]
|
||||
rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
|
||||
@@ -1346,7 +1391,7 @@ theorem umulOverflow_eq {w : Nat} (x y : BitVec w) :
|
||||
(0 < w && BitVec.twoPow (w * 2) w ≤ x.zeroExtend (w * 2) * y.zeroExtend (w * 2)) := by
|
||||
simp only [umulOverflow, toNat_twoPow, le_def, toNat_mul, toNat_setWidth, mod_mul_mod]
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· simp [of_length_zero, toInt_zero, mul_mod_mod]
|
||||
· simp only [ge_iff_le, show 0 < w + 1 by omega, decide_true, mul_mod_mod, Bool.true_and,
|
||||
decide_eq_decide]
|
||||
rw [Nat.mod_eq_of_lt BitVec.toNat_mul_toNat_lt, Nat.mod_eq_of_lt]
|
||||
@@ -1582,11 +1627,11 @@ theorem toInt_sdiv_of_ne_or_ne (a b : BitVec w) (h : a ≠ intMin w ∨ b ≠ -1
|
||||
have := Nat.two_pow_pos (w - 1)
|
||||
|
||||
by_cases hbintMin : b = intMin w
|
||||
· simp only at hbintMin
|
||||
· simp only [ne_eq, Decidable.not_not] at hbintMin
|
||||
subst hbintMin
|
||||
have toIntA_lt := @BitVec.toInt_lt w a; norm_cast at toIntA_lt
|
||||
have le_toIntA := @BitVec.le_toInt w a; norm_cast at le_toIntA
|
||||
simp only [sdiv_intMin, toInt_intMin, wpos,
|
||||
simp only [sdiv_intMin, h, ↓reduceIte, toInt_zero, toInt_intMin, wpos,
|
||||
Nat.two_pow_pred_mod_two_pow, Int.tdiv_neg]
|
||||
· by_cases ha_intMin : a = intMin w
|
||||
· simp only [ha_intMin, ↓reduceIte, show 1 < w by omega, toInt_one, toInt_intMin, wpos,
|
||||
@@ -1662,120 +1707,6 @@ theorem toInt_sdiv (a b : BitVec w) : (a.sdiv b).toInt = (a.toInt.tdiv b.toInt).
|
||||
· rw [← toInt_bmod_cancel]
|
||||
rw [BitVec.toInt_sdiv_of_ne_or_ne _ _ (by simpa only [Decidable.not_and_iff_not_or_not] using h)]
|
||||
|
||||
private theorem neg_udiv_eq_intMin_iff_eq_intMin_eq_one_of_msb_eq_true
|
||||
{x y : BitVec w} (hx : x.msb = true) (hy : y.msb = false) :
|
||||
-x / y = intMin w ↔ (x = intMin w ∧ y = 1#w) := by
|
||||
constructor
|
||||
· intros h
|
||||
rcases w with _ | w; decide +revert
|
||||
have : (-x / y).msb = true := by simp [h, msb_intMin]
|
||||
rw [msb_udiv] at this
|
||||
simp only [bool_to_prop] at this
|
||||
obtain ⟨hx, hy⟩ := this
|
||||
simp only [beq_iff_eq] at hy
|
||||
subst hy
|
||||
simp only [udiv_one, neg_eq_intMin] at h
|
||||
simp [h]
|
||||
· rintro ⟨hx, hy⟩
|
||||
subst hx hy
|
||||
simp
|
||||
|
||||
theorem getElem_sdiv {x y : BitVec w} (h : i < w) :
|
||||
(x.sdiv y)[i] =
|
||||
(match x.msb, y.msb with
|
||||
| false, false => (x / y)[i]
|
||||
| false, true => (-(x / -y))[i]
|
||||
| true, false => (-(-x / y))[i]
|
||||
| true, true => (-x / -y)[i]) := by
|
||||
simp only [sdiv, udiv_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem getLsbD_sdiv {x y : BitVec w} :
|
||||
(x.sdiv y).getLsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x / y).getLsbD i
|
||||
| false, true =>( -(x / -y)).getLsbD i
|
||||
| true, false => (-(-x / y)).getLsbD i
|
||||
| true, true => (-x / -y).getLsbD i := by
|
||||
simp only [sdiv, udiv_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem getMsbD_sdiv {x y : BitVec w} :
|
||||
(x.sdiv y).getMsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x / y).getMsbD i
|
||||
| false, true =>( -(x / -y)).getMsbD i
|
||||
| true, false => (-(-x / y)).getMsbD i
|
||||
| true, true => (-x / -y).getMsbD i := by
|
||||
simp only [sdiv, udiv_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
/--
|
||||
the most significant bit of the signed division `x.sdiv y` can be computed
|
||||
by the following cases:
|
||||
(1) x nonneg, y nonneg: never neg.
|
||||
(2) x nonneg, y neg: neg when result nonzero.
|
||||
We know that y is nonzero since it is negative, so we only check `|x| ≥ |y|`.
|
||||
(3) x neg, y nonneg: neg when result nonzero.
|
||||
We check that `y ≠ 0` and `|x| ≥ |y|`.
|
||||
(4) x neg, y neg: neg when `x = intMin, `y = -1`, since `intMin / -1 = intMin`.
|
||||
|
||||
The proof strategy is to perform a case analysis on the sign of `x` and `y`,
|
||||
followed by unfolding the `sdiv` into `udiv`.
|
||||
-/
|
||||
theorem msb_sdiv_eq_decide {x y : BitVec w} :
|
||||
(x.sdiv y).msb = (decide (0 < w) &&
|
||||
(!x.msb && y.msb && decide (-y ≤ x)) ||
|
||||
(x.msb && !y.msb && decide (y ≤ -x) && !decide (y = 0#w)) ||
|
||||
(x.msb && y.msb && decide (x = intMin w) && decide (y = -1#w)))
|
||||
:= by
|
||||
rcases w; decide +revert
|
||||
case succ w =>
|
||||
simp only [sdiv_eq, udiv_eq]
|
||||
rcases hxmsb : x.msb <;> rcases hymsb : y.msb
|
||||
· simp [hxmsb, msb_udiv_eq_false_of, Bool.not_false, Bool.and_false, Bool.false_and,
|
||||
Bool.and_true, Bool.or_self, Bool.and_self]
|
||||
· simp only [hxmsb, hymsb, msb_neg, msb_udiv_eq_false_of, bne_false, Bool.not_false,
|
||||
Bool.and_self, ne_zero_of_msb_true, decide_false, Bool.and_true, Bool.true_and, Bool.not_true,
|
||||
Bool.false_and, Bool.or_false, bool_to_prop]
|
||||
have : x / -y ≠ intMin (w + 1) := by
|
||||
intros h
|
||||
have : (x / -y).msb = (intMin (w + 1)).msb := by simp only [h]
|
||||
simp only [msb_udiv, msb_intMin, show 0 < w + 1 by omega, decide_true, and_eq_true, beq_iff_eq] at this
|
||||
obtain ⟨hcontra, _⟩ := this
|
||||
simp only [hcontra, true_eq_false] at hxmsb
|
||||
simp [this, hymsb, udiv_ne_zero_iff_ne_zero_and_le]
|
||||
· simp only [Bool.not_true, Bool.and_self, Bool.false_and, Bool.not_false,
|
||||
Bool.true_and, Bool.false_or, Bool.and_false, Bool.or_false]
|
||||
by_cases hx₁ : x = 0#(w + 1)
|
||||
· simp [hx₁, neg_zero, zero_udiv, msb_zero, le_zero_iff, Bool.and_not_self]
|
||||
· by_cases hy₁ : y = 0#(w + 1)
|
||||
· simp [hy₁, udiv_zero, neg_zero, msb_zero, decide_true, Bool.not_true, Bool.and_false]
|
||||
· simp only [hy₁, decide_false, Bool.not_false, Bool.and_true]
|
||||
by_cases hxy₁ : (- x / y) = 0#(w + 1)
|
||||
· simp only [hxy₁, neg_zero, msb_zero, false_eq_decide_iff, BitVec.not_le,
|
||||
BitVec.not_le]
|
||||
simp only [udiv_eq_zero_iff_eq_zero_or_lt, hy₁, _root_.false_or] at hxy₁
|
||||
bv_omega
|
||||
· simp only [udiv_eq_zero_iff_eq_zero_or_lt, _root_.not_or, BitVec.not_lt,
|
||||
hy₁, not_false_eq_true, _root_.true_and] at hxy₁
|
||||
simp only [decide_true, msb_neg, bne_iff_ne, ne_eq,
|
||||
bool_to_prop,
|
||||
bne_iff_ne, ne_eq, udiv_eq_zero_iff_eq_zero_or_lt, hy₁, _root_.false_or,
|
||||
BitVec.not_lt, hxy₁, _root_.true_and, decide_not, not_eq_eq_eq_not, not_eq_not,
|
||||
msb_udiv, msb_neg]
|
||||
simp only [hx₁, not_false_eq_true, _root_.true_and, decide_not, hxmsb, not_eq_eq_eq_not,
|
||||
Bool.not_true, decide_eq_false_iff_not, Decidable.not_not, beq_iff_eq]
|
||||
rw [neg_udiv_eq_intMin_iff_eq_intMin_eq_one_of_msb_eq_true hxmsb hymsb]
|
||||
· simp only [msb_udiv, msb_neg, hxmsb, bne_true, Bool.not_and, Bool.not_true, Bool.and_true,
|
||||
Bool.false_and, Bool.and_false, hymsb, ne_zero_of_msb_true, decide_false, Bool.not_false,
|
||||
Bool.or_self, Bool.and_self, Bool.true_and, Bool.false_or]
|
||||
simp only [bool_to_prop]
|
||||
simp [BitVec.ne_zero_of_msb_true (x := x) hxmsb, neg_eq_iff_eq_neg]
|
||||
|
||||
theorem msb_umod_eq_false_of_left {x : BitVec w} (hx : x.msb = false) (y : BitVec w) : (x % y).msb = false := by
|
||||
rw [msb_eq_false_iff_two_mul_lt] at hx ⊢
|
||||
rw [toNat_umod]
|
||||
@@ -1791,44 +1722,11 @@ theorem msb_umod_of_le_of_ne_zero_of_le {x y : BitVec w}
|
||||
rw [← intMin_le_iff_msb_eq_true (length_pos_of_ne hy)] at h
|
||||
rwa [BitVec.le_antisymm hx h]
|
||||
|
||||
theorem getElem_srem {x y : BitVec w} (h : i < w) :
|
||||
(x.srem y)[i] =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y)[i]
|
||||
| false, true => (x % -y)[i]
|
||||
| true, false => (-(-x % y))[i]
|
||||
| true, true => (-(-x % -y))[i] := by
|
||||
simp only [srem, umod_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem getLsbD_srem {x y : BitVec w} :
|
||||
(x.srem y).getLsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y).getLsbD i
|
||||
| false, true => (x % -y).getLsbD i
|
||||
| true, false => (-(-x % y)).getLsbD i
|
||||
| true, true => (-(-x % -y)).getLsbD i := by
|
||||
simp only [srem, umod_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem getMsbD_srem {x y : BitVec w} :
|
||||
(x.srem y).getMsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y).getMsbD i
|
||||
| false, true => (x % -y).getMsbD i
|
||||
| true, false => (-(-x % y)).getMsbD i
|
||||
| true, true => (-(-x % -y)).getMsbD i := by
|
||||
simp only [srem, umod_eq, neg_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
@[simp]
|
||||
theorem toInt_srem (x y : BitVec w) : (x.srem y).toInt = x.toInt.tmod y.toInt := by
|
||||
rw [srem_eq]
|
||||
by_cases hyz : y = 0#w
|
||||
· simp only [hyz, msb_zero, umod_zero, neg_zero, neg_neg, toInt_zero, Int.tmod_zero]
|
||||
· simp only [hyz, ofNat_eq_ofNat, msb_zero, umod_zero, neg_zero, neg_neg, toInt_zero, Int.tmod_zero]
|
||||
cases x.msb <;> rfl
|
||||
cases h : x.msb
|
||||
· cases h' : y.msb
|
||||
@@ -1852,214 +1750,6 @@ theorem toInt_srem (x y : BitVec w) : (x.srem y).toInt = x.toInt.tmod y.toInt :=
|
||||
((not_congr neg_eq_zero_iff).mpr hyz)]
|
||||
exact neg_le_intMin_of_msb_eq_true h'
|
||||
|
||||
@[simp]
|
||||
theorem msb_intMin_umod_neg_of_msb_true {y : BitVec w} (hy : y.msb = true) :
|
||||
(intMin w % -y).msb = false := by
|
||||
by_cases hyintmin : y = intMin w
|
||||
· simp [hyintmin]
|
||||
· rw [msb_umod_of_msb_false_of_ne_zero (by simp [hyintmin, hy])]
|
||||
simp [hy]
|
||||
|
||||
@[simp]
|
||||
theorem msb_neg_umod_neg_of_msb_true_of_msb_true {x y : BitVec w} (hx : x.msb = true) (hy : y.msb = true) :
|
||||
(-x % -y).msb = false := by
|
||||
by_cases hx' : x = intMin w
|
||||
· simp only [hx', neg_intMin, msb_intMin_umod_neg_of_msb_true hy]
|
||||
· simp [show (-x).msb = false by simp [hx, hx']]
|
||||
|
||||
theorem toInt_dvd_toInt_iff {x y : BitVec w} :
|
||||
y.toInt ∣ x.toInt ↔ (if x.msb then -x else x) % (if y.msb then -y else y) = 0#w := by
|
||||
constructor
|
||||
<;> by_cases hxmsb : x.msb <;> by_cases hymsb: y.msb
|
||||
<;> intros h
|
||||
<;> simp only [hxmsb, hymsb, reduceIte, false_eq_true, toNat_eq, toNat_umod, toNat_ofNat,
|
||||
zero_mod, toInt_eq_neg_toNat_neg_of_msb_true, Int.dvd_neg, Int.neg_dvd,
|
||||
toInt_eq_toNat_of_msb] at h
|
||||
<;> simp only [hxmsb, hymsb, toInt_eq_neg_toNat_neg_of_msb_true, toInt_eq_toNat_of_msb,
|
||||
Int.dvd_neg, Int.neg_dvd, toNat_eq, toNat_umod, reduceIte, toNat_ofNat, zero_mod]
|
||||
<;> norm_cast
|
||||
<;> norm_cast at h
|
||||
<;> simp only [dvd_of_mod_eq_zero, h, dvd_iff_mod_eq_zero.mp, reduceIte]
|
||||
|
||||
theorem toInt_dvd_toInt_iff_of_msb_true_msb_false {x y : BitVec w} (hx : x.msb = true) (hy : y.msb = false) :
|
||||
y.toInt ∣ x.toInt ↔ (-x) % y = 0#w := by
|
||||
simpa [hx, hy] using toInt_dvd_toInt_iff (x := x) (y := y)
|
||||
|
||||
theorem toInt_dvd_toInt_iff_of_msb_false_msb_true {x y : BitVec w} (hx : x.msb = false) (hy : y.msb = true) :
|
||||
y.toInt ∣ x.toInt ↔ x % (-y) = 0#w := by
|
||||
simpa [hx, hy] using toInt_dvd_toInt_iff (x := x) (y := y)
|
||||
|
||||
@[simp]
|
||||
theorem neg_toInt_neg_umod_eq_of_msb_true_msb_true {x y : BitVec w} (hx : x.msb = true) (hy : y.msb = true) :
|
||||
-(-(-x % -y)).toInt = (-x % -y).toNat := by
|
||||
rw [neg_toInt_neg]
|
||||
by_cases h : -x % -y = 0#w
|
||||
· simp [h]
|
||||
· rw [msb_neg_umod_neg_of_msb_true_of_msb_true hx hy]
|
||||
|
||||
@[simp]
|
||||
theorem toInt_umod_neg_add {x y : BitVec w} (hymsb : y.msb = true) (hxmsb : x.msb = false) (hdvd : ¬y.toInt ∣ x.toInt) :
|
||||
(x % -y + y).toInt = x.toInt % y.toInt + y.toInt := by
|
||||
rcases w with _|w ; simp [of_length_zero]
|
||||
have hypos : 0 < y.toNat := toNat_pos_of_ne_zero (by simp [hymsb])
|
||||
have hxnonneg := toInt_nonneg_of_msb_false hxmsb
|
||||
have hynonpos := toInt_neg_of_msb_true hymsb
|
||||
have hylt : (-y).toNat ≤ 2 ^ (w) := toNat_neg_lt_of_msb y hymsb
|
||||
have hmodlt := Nat.mod_lt x.toNat (y := (-y).toNat)
|
||||
(by rw [toNat_neg, Nat.mod_eq_of_lt (by omega)]; omega)
|
||||
simp only [toInt_add]
|
||||
rw [toInt_umod, toInt_eq_neg_toNat_neg_of_msb_true hymsb, Int.bmod_add_bmod,
|
||||
Int.bmod_eq_of_le (by omega) (by omega),
|
||||
toInt_eq_toNat_of_msb hxmsb, Int.emod_neg]
|
||||
|
||||
@[simp]
|
||||
theorem toInt_sub_neg_umod {x y : BitVec w} (hxmsb : x.msb = true) (hymsb : y.msb = false) (hdvd : ¬y.toInt ∣ x.toInt) :
|
||||
(y - -x % y).toInt = x.toInt % y.toInt := by
|
||||
rcases w with _|w
|
||||
· simp [of_length_zero]
|
||||
· have : y.toNat < 2 ^ w := toNat_lt_of_msb_false hymsb
|
||||
by_cases hyzero : y = 0#(w+1)
|
||||
· subst hyzero; simp
|
||||
· simp only [toNat_eq, toNat_ofNat, zero_mod] at hyzero
|
||||
have hypos : 0 < y.toNat := by omega
|
||||
simp only [toInt_sub, toInt_eq_toNat_of_msb hymsb, toInt_umod,
|
||||
Int.sub_bmod_bmod, toInt_eq_neg_toNat_neg_of_msb_true hxmsb, Int.neg_emod]
|
||||
have hmodlt := Nat.mod_lt (x := (-x).toNat) (y := y.toNat) hypos
|
||||
rw [Int.bmod_eq_of_le (by omega) (by omega)]
|
||||
simp only [toInt_eq_toNat_of_msb hymsb, BitVec.toInt_eq_neg_toNat_neg_of_msb_true hxmsb,
|
||||
Int.dvd_neg] at hdvd
|
||||
simp only [hdvd, ↓reduceIte, Int.natAbs_cast]
|
||||
|
||||
theorem srem_zero_of_dvd {x y : BitVec w} (h : y.toInt ∣ x.toInt) :
|
||||
x.srem y = 0#w := by
|
||||
have := toInt_dvd_toInt_iff (x := x) (y := y)
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp only [h, hx, reduceIte, hy, false_eq_true, true_iff] at this
|
||||
<;> simp [srem, hx, hy, this]
|
||||
|
||||
/--
|
||||
The remainder for `srem`, i.e. division with rounding to zero is negative
|
||||
iff `x` is negative and `y` does not divide `x`.
|
||||
|
||||
We can eventually build fast circuits for the divisibility test `x.srem y = 0`.
|
||||
-/
|
||||
theorem msb_srem {x y : BitVec w} : (x.srem y).msb =
|
||||
(x.msb && decide (x.srem y ≠ 0)) := by
|
||||
rw [msb_eq_toInt]
|
||||
by_cases hx : x.msb
|
||||
· by_cases hsrem : x.srem y = 0#w
|
||||
· simp [hsrem]
|
||||
· have := toInt_neg_of_msb_true hx
|
||||
by_cases hdvd : y.toInt ∣ x.toInt
|
||||
· simp [BitVec.srem_zero_of_dvd hdvd] at hsrem
|
||||
· simp only [toInt_srem, Int.tmod_eq_emod, show ¬0 ≤ x.toInt by omega, hdvd, _root_.or_self,
|
||||
reduceIte, hx, ofNat_eq_ofNat, ne_eq, hsrem, not_false_eq_true, decide_true, Bool.and_self,
|
||||
decide_eq_true_eq, gt_iff_lt]
|
||||
have hlt := Int.emod_lt (a := x.toInt) (b := y.toInt)
|
||||
by_cases hy0 : y = 0#w
|
||||
· simp only [hy0, toInt_zero, Int.emod_zero, Int.natAbs_zero, Int.cast_ofNat_Int,
|
||||
Int.sub_zero, gt_iff_lt]
|
||||
exact toInt_neg_of_msb_true hx
|
||||
· simp only [← toInt_inj, toInt_zero] at hy0
|
||||
simp only [ne_eq, hy0, not_false_eq_true, forall_const] at hlt
|
||||
have := Int.le_natAbs (a := y.toInt)
|
||||
omega
|
||||
· simp only [toInt_srem, hx, ofNat_eq_ofNat, ne_eq, decide_not, Bool.false_and,
|
||||
decide_eq_false_iff_not, Int.not_lt]
|
||||
apply Int.tmod_nonneg y.toInt (by exact toInt_nonneg_of_msb_false (by simp at hx; exact hx))
|
||||
|
||||
theorem toInt_smod {x y : BitVec w} :
|
||||
(x.smod y).toInt = x.toInt.fmod y.toInt := by
|
||||
rcases w with _|w
|
||||
· decide +revert
|
||||
· by_cases hyzero : y = 0#(w + 1)
|
||||
· simp [hyzero]
|
||||
· rw [smod_eq]
|
||||
cases hxmsb : x.msb <;> cases hymsb : y.msb
|
||||
<;> simp only [umod_eq]
|
||||
· have : 0 < y.toNat := by simp [toNat_eq] at hyzero; omega
|
||||
have : y.toNat < 2 ^ w := toNat_lt_of_msb_false hymsb
|
||||
have : x.toNat % y.toNat < y.toNat := Nat.mod_lt x.toNat (by omega)
|
||||
rw [toInt_umod, Int.fmod_eq_emod_of_nonneg x.toInt (toInt_nonneg_of_msb_false hymsb),
|
||||
toInt_eq_toNat_of_msb hxmsb, toInt_eq_toNat_of_msb hymsb,
|
||||
Int.bmod_eq_of_le_mul_two (by omega) (by omega)]
|
||||
· have := toInt_dvd_toInt_iff_of_msb_false_msb_true hxmsb hymsb
|
||||
by_cases hx_dvd_y : y.toInt ∣ x.toInt
|
||||
· simp [show x % -y = 0#(w + 1) by simp_all, hx_dvd_y, Int.fmod_eq_zero_of_dvd]
|
||||
· have hynonpos := toInt_neg_of_msb_true hymsb
|
||||
simp only [show ¬x % -y = 0#(w + 1) by simp_all, ↓reduceIte,
|
||||
toInt_umod_neg_add hymsb hxmsb hx_dvd_y, Int.fmod_eq_emod, show ¬0 ≤ y.toInt by omega,
|
||||
hx_dvd_y, _root_.or_self]
|
||||
· have hynonneg := toInt_nonneg_of_msb_false hymsb
|
||||
rw [Int.fmod_eq_emod_of_nonneg x.toInt (b := y.toInt) (by omega)]
|
||||
have hdvd := toInt_dvd_toInt_iff_of_msb_true_msb_false hxmsb hymsb
|
||||
by_cases hx_dvd_y : y.toInt ∣ x.toInt
|
||||
· simp [show -x % y = 0#(w + 1) by simp_all, hx_dvd_y, Int.emod_eq_zero_of_dvd]
|
||||
· simp [show ¬-x % y = 0#(w + 1) by simp_all, toInt_sub_neg_umod hxmsb hymsb hx_dvd_y]
|
||||
· rw [←Int.neg_inj, neg_toInt_neg_umod_eq_of_msb_true_msb_true hxmsb hymsb]
|
||||
simp [BitVec.toInt_eq_neg_toNat_neg_of_msb_true, hxmsb, hymsb,
|
||||
Int.fmod_eq_emod_of_nonneg _]
|
||||
|
||||
theorem getElem_smod {x y : BitVec w} (h : i < w) :
|
||||
(x.smod y)[i] =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y)[i]
|
||||
| false, true => (if x % -y = 0#w then (x % -y) else (x % -y + y))[i]
|
||||
| true, false => (if -x % y = 0#w then (-x % y) else (y - -x % y))[i]
|
||||
| true, true => (-(-x % -y))[i] := by
|
||||
simp only [smod, umod_eq, neg_eq, zero_eq, add_eq, sub_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem getLsbD_smod {x y : BitVec w} :
|
||||
(x.smod y).getLsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y).getLsbD i
|
||||
| false, true => if x % -y = 0#w then false else (x % -y + y).getLsbD i
|
||||
| true, false => if -x % y = 0#w then false else (y - -x % y).getLsbD i
|
||||
| true, true => (-(-x % -y)).getLsbD i := by
|
||||
simp only [smod, umod_eq, neg_eq, zero_eq, add_eq, sub_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
· simp [hx, hy]
|
||||
· by_cases hxy : -x % y = 0#w <;> simp [hx, hy, hxy]
|
||||
· by_cases hxy : x % -y = 0#w <;> simp [hx, hy, hxy]
|
||||
· simp [hx, hy]
|
||||
|
||||
theorem getMsbD_smod {x y : BitVec w} :
|
||||
(x.smod y).getMsbD i =
|
||||
match x.msb, y.msb with
|
||||
| false, false => (x % y).getMsbD i
|
||||
| false, true => (if x % -y = 0#w then (x % -y) else (x % -y + y)).getMsbD i
|
||||
| true, false => (if -x % y = 0#w then (-x % y) else (y - -x % y)).getMsbD i
|
||||
| true, true => (-(-x % -y)).getMsbD i := by
|
||||
simp only [smod, umod_eq, neg_eq, zero_eq, add_eq, sub_eq]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
<;> simp [hx, hy]
|
||||
|
||||
theorem msb_smod {x y : BitVec w} :
|
||||
(x.smod y).msb = (x.msb && y = 0) || (y.msb && (x.smod y) ≠ 0) := by
|
||||
rw [msb_eq_toInt]
|
||||
by_cases hx : x.msb <;> by_cases hy : y.msb
|
||||
· by_cases hsmod : x.smod y = 0#w <;> simp [hx, hy, hsmod]
|
||||
· simp only [hx, ofNat_eq_ofNat, Bool.true_and, decide_eq_decide, decide_iff_dist, hy, ne_eq,
|
||||
decide_not, Bool.false_and, Bool.or_false, beq_iff_eq]
|
||||
constructor
|
||||
· intro h
|
||||
apply Classical.byContradiction
|
||||
intro hcontra
|
||||
rw [toInt_smod] at h
|
||||
have := toInt_nonneg_of_msb_false (by simp at hy; exact hy)
|
||||
have := Int.fmod_nonneg_of_pos (a := x.toInt) (b := y.toInt) (by simp [← toInt_inj] at hcontra; omega)
|
||||
omega
|
||||
· intro h
|
||||
simp only [h, smod_zero]
|
||||
exact toInt_neg_of_msb_true hx
|
||||
· by_cases hsmod : x.smod y = 0#w <;> simp [hx, hy, hsmod]
|
||||
· simp only [toInt_smod, hx, ofNat_eq_ofNat, Bool.false_and, decide_eq_false_iff_not, Int.not_lt,
|
||||
hy, ne_eq, decide_not, Bool.or_false, decide_eq_true_eq]
|
||||
simp only [not_eq_true] at hx hy
|
||||
apply Int.fmod_nonneg (by exact toInt_nonneg_of_msb_false hx) (by exact toInt_nonneg_of_msb_false hy)
|
||||
|
||||
/-! ### Lemmas that use bit blasting circuits -/
|
||||
|
||||
theorem add_sub_comm {x y : BitVec w} : x + y - z = x - z + y := by
|
||||
@@ -2092,7 +1782,7 @@ theorem carry_extractLsb'_eq_carry {w i len : Nat} (hi : i < len)
|
||||
{x y : BitVec w} {b : Bool}:
|
||||
(carry i (extractLsb' 0 len x) (extractLsb' 0 len y) b)
|
||||
= (carry i x y b) := by
|
||||
simp only [carry, extractLsb'_toNat, shiftRight_zero, ge_iff_le,
|
||||
simp only [carry, extractLsb'_toNat, shiftRight_zero, toNat_false, Nat.add_zero, ge_iff_le,
|
||||
decide_eq_decide]
|
||||
have : 2 ^ i ∣ 2^len := by
|
||||
apply Nat.pow_dvd_pow
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth Bhat
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import all Init.Data.BitVec.Basic
|
||||
|
||||
namespace BitVec
|
||||
|
||||
theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
|
||||
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
simp only [getLsbD_ofFin]
|
||||
apply Nat.testBit_lt_two_pow
|
||||
have p : 2^w ≤ 2^i := Nat.pow_le_pow_right (by omega) ge
|
||||
omega
|
||||
|
||||
/-- Prove equality of bitvectors in terms of nat operations. -/
|
||||
theorem eq_of_toNat_eq {n} : ∀ {x y : BitVec n}, x.toNat = y.toNat → x = y
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
|
||||
theorem eq_of_getLsbD_eq {x y : BitVec w}
|
||||
(pred : ∀ i, i < w → x.getLsbD i = y.getLsbD i) : x = y := by
|
||||
apply eq_of_toNat_eq
|
||||
apply Nat.eq_of_testBit_eq
|
||||
intro i
|
||||
if i_lt : i < w then
|
||||
exact pred i i_lt
|
||||
else
|
||||
have p : i ≥ w := Nat.le_of_not_gt i_lt
|
||||
simp [testBit_toNat, getLsbD_of_ge _ _ p]
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_ofNat (x w : Nat) : (BitVec.ofNat w x).toNat = x % 2^w := by
|
||||
simp [BitVec.toNat, BitVec.ofNat, Fin.ofNat]
|
||||
|
||||
@[ext, grind ext] theorem eq_of_getElem_eq {x y : BitVec n} :
|
||||
(∀ i (hi : i < n), x[i] = y[i]) → x = y :=
|
||||
fun h => BitVec.eq_of_getLsbD_eq (h ↑·)
|
||||
|
||||
@[simp, grind =] theorem toNat_append (x : BitVec m) (y : BitVec n) :
|
||||
(x ++ y).toNat = x.toNat <<< n ||| y.toNat :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem toNat_ofBool (b : Bool) : (ofBool b).toNat = b.toNat := by
|
||||
cases b <;> rfl
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_cast (h : w = v) (x : BitVec w) : (x.cast h).toNat = x.toNat := rfl
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_ofFin (x : Fin (2^n)) : (BitVec.ofFin x).toNat = x.val := rfl
|
||||
|
||||
@[simp, grind =] theorem toNat_ofNatLT (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||||
|
||||
@[simp, grind =] theorem toNat_cons (b : Bool) (x : BitVec w) :
|
||||
(cons b x).toNat = (b.toNat <<< w) ||| x.toNat := by
|
||||
let ⟨x, _⟩ := x
|
||||
simp only [cons, toNat_cast, toNat_append, toNat_ofBool, toNat_ofFin]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||||
(cons b x)[i] = if h : i = n then b else x[i] := by
|
||||
simp only [getElem_eq_testBit_toNat, toNat_cons, Nat.testBit_or]
|
||||
rw [Nat.testBit_shiftLeft]
|
||||
rcases Nat.lt_trichotomy i n with i_lt_n | i_eq_n | n_lt_i
|
||||
· have p1 : ¬(n ≤ i) := by omega
|
||||
have p2 : i ≠ n := by omega
|
||||
simp [p1, p2]
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
|
||||
Bool.true_and, testBit_toNat, getLsbD_of_ge, Bool.or_false]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
have p2 : i - n ≠ 0 := by omega
|
||||
simp [p1, p2, Nat.testBit_bool_toNat]
|
||||
|
||||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_right (by trivial : 0 < 2) le)
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_setWidth' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
(setWidth' p x).toNat = x.toNat := by
|
||||
simp only [setWidth', toNat_ofNatLT]
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_setWidth (i : Nat) (x : BitVec n) :
|
||||
(setWidth i x).toNat = x.toNat % 2^i := by
|
||||
let ⟨x, lt_n⟩ := x
|
||||
simp only [setWidth]
|
||||
if n_le_i : n ≤ i then
|
||||
have x_lt_two_i : x < 2 ^ i := lt_two_pow_of_le lt_n n_le_i
|
||||
simp [n_le_i, Nat.mod_eq_of_lt, x_lt_two_i]
|
||||
else
|
||||
simp [n_le_i, toNat_ofNat]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ofNat_toNat (m : Nat) (x : BitVec n) : BitVec.ofNat m x.toNat = setWidth m x := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_ofNat, toNat_setWidth]
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_setWidth' (x : BitVec w) (i : Nat) (h : w ≤ v) (hi : i < v) :
|
||||
(setWidth' h x)[i] = x.getLsbD i := by
|
||||
rw [getElem_eq_testBit_toNat, toNat_setWidth', getLsbD]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem getElem_setWidth (m : Nat) (x : BitVec n) (i : Nat) (h : i < m) :
|
||||
(setWidth m x)[i] = x.getLsbD i := by
|
||||
rw [setWidth]
|
||||
split
|
||||
· rw [getElem_setWidth']
|
||||
· simp only [ofNat_toNat, getElem_eq_testBit_toNat, toNat_setWidth, Nat.testBit_mod_two_pow,
|
||||
getLsbD, Bool.and_eq_right_iff_imp, decide_eq_true_eq]
|
||||
omega
|
||||
|
||||
-- Later this is provable by `grind`, so doesn't need an annotation.
|
||||
@[simp] theorem cons_msb_setWidth (x : BitVec (w+1)) : (cons x.msb (x.setWidth w)) = x := by
|
||||
ext i
|
||||
simp only [getElem_cons]
|
||||
split <;> rename_i h
|
||||
· simp [BitVec.msb, getMsbD, h]
|
||||
· by_cases h' : i < w
|
||||
· simp_all only [getElem_setWidth, getLsbD_eq_getElem]
|
||||
· omega
|
||||
|
||||
@[simp, bitvec_to_nat, grind =]
|
||||
theorem toNat_neg (x : BitVec n) : (- x).toNat = (2^n - x.toNat) % 2^n := by
|
||||
simp [Neg.neg, BitVec.neg]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem setWidth_neg_of_le {x : BitVec v} (h : w ≤ v) : BitVec.setWidth w (-x) = -BitVec.setWidth w x := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
simp only [toNat_setWidth, toNat_neg]
|
||||
rw [Nat.mod_mod_of_dvd _ (Nat.pow_dvd_pow 2 h)]
|
||||
rw [Nat.mod_eq_mod_iff]
|
||||
rw [Nat.mod_def]
|
||||
refine ⟨1 + x.toNat / 2^w, 2^(v-w), ?_⟩
|
||||
rw [← Nat.pow_add]
|
||||
have : v - w + w = v := by omega
|
||||
rw [this]
|
||||
rw [Nat.add_mul, Nat.one_mul, Nat.mul_comm (2^w)]
|
||||
have sub_sub : ∀ (a : Nat) {b c : Nat} (h : c ≤ b), a - (b - c) = a + c - b := by omega
|
||||
rw [sub_sub _ (Nat.div_mul_le_self x.toNat (2 ^ w))]
|
||||
have : x.toNat / 2 ^ w * 2 ^ w ≤ x.toNat := Nat.div_mul_le_self x.toNat (2 ^ w)
|
||||
have : x.toNat < 2 ^w ∨ x.toNat - 2 ^ w < x.toNat / 2 ^ w * 2 ^ w := by
|
||||
have := Nat.lt_div_mul_add (a := x.toNat) (b := 2 ^ w) (Nat.two_pow_pos w)
|
||||
omega
|
||||
omega
|
||||
|
||||
end BitVec
|
||||
@@ -1,79 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joe Hendrix, Harun Khan, Alex Keizer, Abdalrhman M Mohamed, Siddharth Bhat
|
||||
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
namespace BitVec
|
||||
|
||||
/-! ### Decidable quantifiers -/
|
||||
|
||||
theorem forall_zero_iff {P : BitVec 0 → Prop} :
|
||||
(∀ v, P v) ↔ P 0#0 := by
|
||||
constructor
|
||||
· intro h
|
||||
apply h
|
||||
· intro h v
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
apply h
|
||||
|
||||
theorem forall_cons_iff {P : BitVec (n + 1) → Prop} :
|
||||
(∀ v : BitVec (n + 1), P v) ↔ (∀ (x : Bool) (v : BitVec n), P (v.cons x)) := by
|
||||
constructor
|
||||
· intro h _ _
|
||||
apply h
|
||||
· intro h v
|
||||
have w : v = (v.setWidth n).cons v.msb := by simp only [cons_msb_setWidth]
|
||||
rw [w]
|
||||
apply h
|
||||
|
||||
instance instDecidableForallBitVecZero (P : BitVec 0 → Prop) :
|
||||
∀ [Decidable (P 0#0)], Decidable (∀ v, P v)
|
||||
| .isTrue h => .isTrue fun v => by
|
||||
obtain (rfl : v = 0#0) := (by ext i ⟨⟩)
|
||||
exact h
|
||||
| .isFalse h => .isFalse (fun w => h (w _))
|
||||
|
||||
instance instDecidableForallBitVecSucc (P : BitVec (n+1) → Prop) [DecidablePred P]
|
||||
[Decidable (∀ (x : Bool) (v : BitVec n), P (v.cons x))] : Decidable (∀ v, P v) :=
|
||||
decidable_of_iff' (∀ x (v : BitVec n), P (v.cons x)) forall_cons_iff
|
||||
|
||||
instance instDecidableExistsBitVecZero (P : BitVec 0 → Prop) [Decidable (P 0#0)] :
|
||||
Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
|
||||
instance instDecidableExistsBitVecSucc (P : BitVec (n+1) → Prop) [DecidablePred P]
|
||||
[Decidable (∀ (x : Bool) (v : BitVec n), ¬ P (v.cons x))] : Decidable (∃ v, P v) :=
|
||||
decidable_of_iff (¬ ∀ v, ¬ P v) Classical.not_forall_not
|
||||
|
||||
/--
|
||||
For small numerals this isn't necessary (as typeclass search can use the above two instances),
|
||||
but for large numerals this provides a shortcut.
|
||||
Note, however, that for large numerals the decision procedure may be very slow,
|
||||
and you should use `bv_decide` if possible.
|
||||
-/
|
||||
instance instDecidableForallBitVec :
|
||||
∀ (n : Nat) (P : BitVec n → Prop) [DecidablePred P], Decidable (∀ v, P v)
|
||||
| 0, _, _ => inferInstance
|
||||
| n + 1, _, _ =>
|
||||
have := instDecidableForallBitVec n
|
||||
inferInstance
|
||||
|
||||
/--
|
||||
For small numerals this isn't necessary (as typeclass search can use the above two instances),
|
||||
but for large numerals this provides a shortcut.
|
||||
Note, however, that for large numerals the decision procedure may be very slow.
|
||||
-/
|
||||
instance instDecidableExistsBitVec :
|
||||
∀ (n : Nat) (P : BitVec n → Prop) [DecidablePred P], Decidable (∃ v, P v)
|
||||
| 0, _, _ => inferInstance
|
||||
| _ + 1, _, _ => inferInstance
|
||||
|
||||
end BitVec
|
||||
@@ -82,9 +82,9 @@ theorem iunfoldr_getLsbD' {f : Fin w → α → α × Bool} (state : Nat → α)
|
||||
simp only [getLsbD_cons]
|
||||
have hj2 : j.val ≤ w := by simp
|
||||
cases (Nat.lt_or_eq_of_le (Nat.lt_succ.mp i.isLt)) with
|
||||
| inl h3 => simp [(Nat.ne_of_lt h3)]
|
||||
| inl h3 => simp [if_neg, (Nat.ne_of_lt h3)]
|
||||
exact (ih hj2).1 ⟨i.val, h3⟩
|
||||
| inr h3 => simp [h3]
|
||||
| inr h3 => simp [h3, if_pos]
|
||||
cases (Nat.eq_zero_or_pos j.val) with
|
||||
| inl hj3 => congr
|
||||
rw [← (ih hj2).2]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -434,9 +434,9 @@ Converts `true` to `1` and `false` to `0`.
|
||||
-/
|
||||
@[expose] def toNat (b : Bool) : Nat := cond b 1 0
|
||||
|
||||
@[simp, bitvec_to_nat, grind =] theorem toNat_false : false.toNat = 0 := rfl
|
||||
@[simp, bitvec_to_nat] theorem toNat_false : false.toNat = 0 := rfl
|
||||
|
||||
@[simp, bitvec_to_nat, grind =] theorem toNat_true : true.toNat = 1 := rfl
|
||||
@[simp, bitvec_to_nat] theorem toNat_true : true.toNat = 1 := rfl
|
||||
|
||||
theorem toNat_le (c : Bool) : c.toNat ≤ 1 := by
|
||||
cases c <;> trivial
|
||||
@@ -455,11 +455,11 @@ theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
||||
/--
|
||||
Converts `true` to `1` and `false` to `0`.
|
||||
-/
|
||||
@[expose] def toInt (b : Bool) : Int := cond b 1 0
|
||||
def toInt (b : Bool) : Int := cond b 1 0
|
||||
|
||||
@[simp, grind =] theorem toInt_false : false.toInt = 0 := rfl
|
||||
@[simp] theorem toInt_false : false.toInt = 0 := rfl
|
||||
|
||||
@[simp, grind =] theorem toInt_true : true.toInt = 1 := rfl
|
||||
@[simp] theorem toInt_true : true.toInt = 1 := rfl
|
||||
|
||||
/-! ### ite -/
|
||||
|
||||
@@ -488,7 +488,7 @@ Converts `true` to `1` and `false` to `0`.
|
||||
|
||||
@[simp] theorem ite_eq_true_else_eq_false {q : Prop} :
|
||||
(if b = true then q else b = false) ↔ (b = true → q) := by
|
||||
cases b <;> simp
|
||||
cases b <;> simp [not_eq_self]
|
||||
|
||||
/-
|
||||
`not_ite_eq_true_eq_true` and related theorems below are added for
|
||||
|
||||
@@ -205,7 +205,7 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
|
||||
|
||||
@[inline]
|
||||
def foldl {β : Type v} (f : β → UInt8 → β) (init : β) (as : ByteArray) (start := 0) (stop := as.size) : β :=
|
||||
Id.run <| as.foldlM (pure <| f · ·) init start stop
|
||||
Id.run <| as.foldlM f init start stop
|
||||
|
||||
/-- Iterator over the bytes (`UInt8`) of a `ByteArray`.
|
||||
|
||||
|
||||
@@ -46,12 +46,15 @@ Returns `a` modulo `n` as a `Fin n`.
|
||||
|
||||
The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
-/
|
||||
@[expose] protected def ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
@[expose] protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
@[deprecated Fin.ofNat (since := "2025-05-28")]
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
Fin.ofNat n a
|
||||
/--
|
||||
Returns `a` modulo `n + 1` as a `Fin n.succ`.
|
||||
-/
|
||||
@[deprecated Fin.ofNat' (since := "2024-11-27")]
|
||||
protected def ofNat {n : Nat} (a : Nat) : Fin (n + 1) :=
|
||||
⟨a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)⟩
|
||||
|
||||
-- We provide this because other similar types have a `toNat` function, but `simp` rewrites
|
||||
-- `i.toNat` to `i.val`.
|
||||
@@ -81,7 +84,7 @@ Examples:
|
||||
* `(2 : Fin 3) + (2 : Fin 3) = (1 : Fin 3)`
|
||||
-/
|
||||
protected def add : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Multiplication modulo `n`, usually invoked via the `*` operator.
|
||||
@@ -92,7 +95,7 @@ Examples:
|
||||
* `(3 : Fin 10) * (7 : Fin 10) = (1 : Fin 10)`
|
||||
-/
|
||||
protected def mul : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a * b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a * b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Subtraction modulo `n`, usually invoked via the `-` operator.
|
||||
@@ -119,7 +122,7 @@ protected def sub : Fin n → Fin n → Fin n
|
||||
using recursion on the second argument.
|
||||
See issue #4413.
|
||||
-/
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, mlt h⟩
|
||||
|
||||
/-!
|
||||
Remark: land/lor can be defined without using (% n), but
|
||||
@@ -161,19 +164,19 @@ def modn : Fin n → Nat → Fin n
|
||||
Bitwise and.
|
||||
-/
|
||||
def land : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.land a b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.land a b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Bitwise or.
|
||||
-/
|
||||
def lor : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.lor a b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.lor a b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Bitwise xor (“exclusive or”).
|
||||
-/
|
||||
def xor : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.xor a b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(Nat.xor a b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Bitwise left shift of bounded numbers, with wraparound on overflow.
|
||||
@@ -184,7 +187,7 @@ Examples:
|
||||
* `(1 : Fin 10) <<< (4 : Fin 10) = (6 : Fin 10)`
|
||||
-/
|
||||
def shiftLeft : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a <<< b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a <<< b) % n, mlt h⟩
|
||||
|
||||
/--
|
||||
Bitwise right shift of bounded numbers.
|
||||
@@ -198,7 +201,7 @@ Examples:
|
||||
* `(15 : Fin 17) >>> (2 : Fin 17) = (3 : Fin 17)`
|
||||
-/
|
||||
def shiftRight : Fin n → Fin n → Fin n
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a >>> b) % n, by exact mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a >>> b) % n, mlt h⟩
|
||||
|
||||
instance : Add (Fin n) where
|
||||
add := Fin.add
|
||||
@@ -227,7 +230,7 @@ instance : ShiftRight (Fin n) where
|
||||
shiftRight := Fin.shiftRight
|
||||
|
||||
instance instOfNat {n : Nat} [NeZero n] {i : Nat} : OfNat (Fin n) i where
|
||||
ofNat := Fin.ofNat n i
|
||||
ofNat := Fin.ofNat' n i
|
||||
|
||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||
protected theorem pos (i : Fin n) : 0 < n :=
|
||||
|
||||
@@ -100,11 +100,6 @@ Fin.foldrM n f xₙ = do
|
||||
|
||||
/-! ### foldlM -/
|
||||
|
||||
@[congr] theorem foldlM_congr [Monad m] {n k : Nat} (w : n = k) (f : α → Fin n → m α) :
|
||||
foldlM n f = foldlM k (fun x i => f x (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
|
||||
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
|
||||
rw [foldlM.loop, dif_pos h]
|
||||
@@ -125,49 +120,14 @@ theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1)
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) : foldlM 0 f = pure := by
|
||||
funext x
|
||||
exact foldlM_loop_eq ..
|
||||
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) (x) : foldlM 0 f x = pure x :=
|
||||
foldlM_loop_eq ..
|
||||
|
||||
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) :
|
||||
foldlM (n+1) f = fun x => f x 0 >>= foldlM n (fun x j => f x j.succ) := by
|
||||
funext x
|
||||
exact foldlM_loop ..
|
||||
|
||||
/-- Variant of `foldlM_succ` that splits off `Fin.last n` rather than `0`. -/
|
||||
theorem foldlM_succ_last [Monad m] [LawfulMonad m] (f : α → Fin (n+1) → m α) :
|
||||
foldlM (n+1) f = fun x => foldlM n (fun x j => f x j.castSucc) x >>= (f · (Fin.last n)) := by
|
||||
funext x
|
||||
induction n generalizing x with
|
||||
| zero =>
|
||||
simp [foldlM_succ]
|
||||
| succ n ih =>
|
||||
rw [foldlM_succ]
|
||||
conv => rhs; rw [foldlM_succ]
|
||||
simp only [castSucc_zero, castSucc_succ, bind_assoc]
|
||||
congr 1
|
||||
funext x
|
||||
rw [ih]
|
||||
simp
|
||||
|
||||
theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
|
||||
foldlM (n + k) f =
|
||||
fun x => foldlM n (fun x i => f x (i.castLE (Nat.le_add_right n k))) x >>= foldlM k (fun x i => f x (i.natAdd n)) := by
|
||||
induction k with
|
||||
| zero =>
|
||||
funext x
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldlM_succ_last, ← Nat.add_assoc, ih]
|
||||
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) (x) :
|
||||
foldlM (n+1) f x = f x 0 >>= foldlM n (fun x j => f x j.succ) := foldlM_loop ..
|
||||
|
||||
/-! ### foldrM -/
|
||||
|
||||
@[congr] theorem foldrM_congr [Monad m] {n k : Nat} (w : n = k) (f : Fin n → α → m α) :
|
||||
foldrM n f = foldrM k (fun i => f (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
|
||||
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
|
||||
rw [foldrM.loop]
|
||||
@@ -183,47 +143,21 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
|
||||
| zero =>
|
||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
rfl
|
||||
congr
|
||||
funext
|
||||
try simp only [foldrM.loop] -- the try makes this proof work with and without opaque wf rec
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
|
||||
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) : foldrM 0 f = pure := by
|
||||
funext x
|
||||
exact foldrM_loop_zero ..
|
||||
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) (x) : foldrM 0 f x = pure x :=
|
||||
foldrM_loop_zero ..
|
||||
|
||||
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
|
||||
foldrM (n+1) f = fun x => foldrM n (fun i => f i.succ) x >>= f 0 := by
|
||||
funext x
|
||||
exact foldrM_loop ..
|
||||
|
||||
theorem foldrM_succ_last [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
|
||||
foldrM (n+1) f = fun x => f (Fin.last n) x >>= foldrM n (fun i => f i.castSucc) := by
|
||||
funext x
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldrM_succ]
|
||||
| succ n ih =>
|
||||
rw [foldrM_succ]
|
||||
conv => rhs; rw [foldrM_succ]
|
||||
simp [ih]
|
||||
|
||||
theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
|
||||
foldrM (n + k) f =
|
||||
fun x => foldrM k (fun i => f (i.natAdd n)) x >>= foldrM n (fun i => f (i.castLE (Nat.le_add_right n k))) := by
|
||||
induction k with
|
||||
| zero =>
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldrM_succ_last, ← Nat.add_assoc, ih]
|
||||
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) :
|
||||
foldrM (n+1) f x = foldrM n (fun i => f i.succ) x >>= f 0 := foldrM_loop ..
|
||||
|
||||
/-! ### foldl -/
|
||||
|
||||
@[congr] theorem foldl_congr {n k : Nat} (w : n = k) (f : α → Fin n → α) :
|
||||
foldl n f = foldl k (fun x i => f x (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
|
||||
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
|
||||
rw [foldl.loop, dif_pos h]
|
||||
@@ -252,35 +186,15 @@ theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) :
|
||||
foldl (n+1) f x = f (foldl n (f · ·.castSucc) x) (last n) := by
|
||||
rw [foldl_succ]
|
||||
induction n generalizing x with
|
||||
| zero => simp [Fin.last]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp
|
||||
|
||||
theorem foldl_add (f : α → Fin (n + m) → α) (x) :
|
||||
foldl (n + m) f x =
|
||||
foldl m (fun x i => f x (i.natAdd n))
|
||||
(foldl n (fun x i => f x (i.castLE (Nat.le_add_right n m))) x):= by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldl_succ_last, ih, ← Nat.add_assoc]
|
||||
| zero => simp [foldl_succ, Fin.last]
|
||||
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc]
|
||||
|
||||
theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
|
||||
foldl n f x = (foldlM (m := Id) n (pure <| f · ·) x).run := by
|
||||
foldl n f x = foldlM (m:=Id) n f x := by
|
||||
induction n generalizing x <;> simp [foldl_succ, foldlM_succ, *]
|
||||
|
||||
-- This is not marked `@[simp]` as it would match on every occurrence of `foldlM`.
|
||||
theorem foldlM_pure [Monad m] [LawfulMonad m] {n} {f : α → Fin n → α} :
|
||||
foldlM n (fun x i => pure (f x i)) x = (pure (foldl n f x) : m α) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => simp [foldlM_succ, foldl_succ, ih]
|
||||
|
||||
/-! ### foldr -/
|
||||
|
||||
@[congr] theorem foldr_congr {n k : Nat} (w : n = k) (f : Fin n → α → α) :
|
||||
foldr n f = foldr k (fun i => f (i.cast w.symm)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
|
||||
foldr.loop n f 0 (Nat.zero_le _) x = x := by
|
||||
rw [foldr.loop]
|
||||
@@ -306,18 +220,10 @@ theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) :
|
||||
foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp [foldr_succ, Fin.last]
|
||||
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp
|
||||
|
||||
theorem foldr_add (f : Fin (n + m) → α → α) (x) :
|
||||
foldr (n + m) f x =
|
||||
foldr n (fun i => f (i.castLE (Nat.le_add_right n m)))
|
||||
(foldr m (fun i => f (i.natAdd n)) x) := by
|
||||
induction m generalizing x with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldr_succ_last, ih, ← Nat.add_assoc]
|
||||
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc]
|
||||
|
||||
theorem foldr_eq_foldrM (f : Fin n → α → α) (x) :
|
||||
foldr n f x = (foldrM (m := Id) n (pure <| f · ·) x).run := by
|
||||
foldr n f x = foldrM (m:=Id) n f x := by
|
||||
induction n <;> simp [foldr_succ, foldrM_succ, *]
|
||||
|
||||
theorem foldl_rev (f : Fin n → α → α) (x) :
|
||||
@@ -332,11 +238,4 @@ theorem foldr_rev (f : α → Fin n → α) (x) :
|
||||
| zero => simp
|
||||
| succ n ih => rw [foldl_succ_last, foldr_succ, ← ih]; simp [rev_succ]
|
||||
|
||||
-- This is not marked `@[simp]` as it would match on every occurrence of `foldrM`.
|
||||
theorem foldrM_pure [Monad m] [LawfulMonad m] {n} {f : Fin n → α → α} :
|
||||
foldrM n (fun i x => pure (f i x)) x = (pure (foldr n f x) : m α) := by
|
||||
induction n generalizing x with
|
||||
| zero => simp
|
||||
| succ n ih => simp [foldrM_succ, foldr_succ, ih]
|
||||
|
||||
end Fin
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user