mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-18 19:04:07 +00:00
Compare commits
1 Commits
sofia/pars
...
ExtHashMap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
921472c67e |
38
.github/workflows/awaiting-manual.yml
vendored
38
.github/workflows/awaiting-manual.yml
vendored
@@ -1,38 +0,0 @@
|
||||
name: Check awaiting-manual label
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
check-awaiting-manual:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check awaiting-manual label
|
||||
id: check-awaiting-manual-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-manual");
|
||||
const hasBreaks = labels.some(label => label.name == "breaks-manual");
|
||||
const hasBuilds = labels.some(label => label.name == "builds-manual");
|
||||
|
||||
if (hasAwaiting && hasBreaks) {
|
||||
core.setFailed('PR has both "awaiting-manual" and "breaks-manual" labels.');
|
||||
} else if (hasAwaiting && !hasBreaks && !hasBuilds) {
|
||||
core.info('PR is marked "awaiting-manual" but neither "breaks-manual" nor "builds-manual" labels are present.');
|
||||
core.setOutput('awaiting', 'true');
|
||||
}
|
||||
|
||||
- name: Wait for manual compatibility
|
||||
if: github.event_name == 'pull_request' && steps.check-awaiting-manual-label.outputs.awaiting == 'true'
|
||||
run: |
|
||||
echo "::notice title=Awaiting manual::PR is marked 'awaiting-manual' but neither 'breaks-manual' nor 'builds-manual' labels are present."
|
||||
echo "This check will remain in progress until the PR is updated with appropriate manual 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
|
||||
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
|
||||
|
||||
29
.github/workflows/build-template.yml
vendored
29
.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,13 +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/**/*.ir
|
||||
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
|
||||
@@ -128,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 }}
|
||||
@@ -197,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:
|
||||
@@ -214,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
|
||||
@@ -228,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
|
||||
@@ -246,10 +242,9 @@ 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/**/*.ir
|
||||
build/stage1/**/*.c
|
||||
build/stage1/**/*.c.o*' || '' }}
|
||||
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
|
||||
|
||||
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 }}
|
||||
235
.github/workflows/pr-release.yml
vendored
235
.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
|
||||
@@ -154,7 +114,7 @@ jobs:
|
||||
uses: dcarbone/install-jq-action@v3.1.1
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD for Mathlib/Batteries
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: ready
|
||||
run: |
|
||||
@@ -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."
|
||||
@@ -183,6 +143,7 @@ jobs:
|
||||
echo "... but Batteries does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE="- ❗ Batteries CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Batteries CI should run now."
|
||||
fi
|
||||
|
||||
else
|
||||
echo "The most recently nightly tag on this branch has SHA: $NIGHTLY_SHA"
|
||||
echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA"
|
||||
@@ -264,108 +225,6 @@ jobs:
|
||||
echo "mathlib_ready=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD for reference manual
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: reference-manual-ready
|
||||
run: |
|
||||
echo "Most recent nightly release in your branch: $MOST_RECENT_NIGHTLY"
|
||||
NIGHTLY_SHA=$(git -C lean4.git rev-parse "nightly-$MOST_RECENT_NIGHTLY^{commit}")
|
||||
echo "SHA of most recent nightly release: $NIGHTLY_SHA"
|
||||
MERGE_BASE_SHA=$(git -C lean4.git merge-base origin/master "${{ steps.workflow-info.outputs.sourceHeadSha }}")
|
||||
echo "SHA of merge-base: $MERGE_BASE_SHA"
|
||||
if [ "$NIGHTLY_SHA" = "$MERGE_BASE_SHA" ]; then
|
||||
echo "The merge base of this PR coincides with the nightly release"
|
||||
|
||||
MANUAL_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover/reference-manual.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
if [[ -n "$MANUAL_REMOTE_TAGS" ]]; then
|
||||
echo "... and the reference manual has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE=""
|
||||
else
|
||||
echo "... but the reference manual does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE="- ❗ Reference manual CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-manual\`, reference manual CI should run now."
|
||||
fi
|
||||
else
|
||||
echo "The most recently nightly tag on this branch has SHA: $NIGHTLY_SHA"
|
||||
echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA"
|
||||
git -C lean4.git log -10 origin/master
|
||||
|
||||
git -C lean4.git fetch origin nightly-with-manual
|
||||
NIGHTLY_WITH_MANUAL_SHA="$(git -C lean4.git rev-parse "origin/nightly-with-manual")"
|
||||
MESSAGE="- ❗ Reference manual CI will not be attempted unless your PR branches off the \`nightly-with-manual\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_WITH_MANUAL_SHA\`."
|
||||
fi
|
||||
|
||||
if [[ -n "$MESSAGE" ]]; then
|
||||
# Check if force-manual-ci label is present
|
||||
LABELS="$(curl --retry 3 --location --silent \
|
||||
-H "Authorization: token ${{ secrets.MANUAL_COMMENT_BOT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/labels" \
|
||||
| jq -r '.[].name')"
|
||||
|
||||
if echo "$LABELS" | grep -q "^force-manual-ci$"; then
|
||||
echo "force-manual-ci label detected, forcing CI despite issues"
|
||||
MESSAGE="Forcing reference manual CI because the \`force-manual-ci\` label is present, despite problem: $MESSAGE"
|
||||
FORCE_CI=true
|
||||
else
|
||||
MESSAGE="$MESSAGE You can force reference manual CI using the \`force-manual-ci\` label."
|
||||
fi
|
||||
|
||||
echo "Checking existing messages"
|
||||
|
||||
# The code for updating comments is duplicated in the reference manual's
|
||||
# scripts/lean-pr-testing-comments.sh
|
||||
# so keep in sync
|
||||
|
||||
# Use GitHub API to check if a comment already exists
|
||||
existing_comment="$(curl --retry 3 --location --silent \
|
||||
-H "Authorization: token ${{ secrets.MANUAL_COMMENT_BOT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" \
|
||||
| jq 'first(.[] | select(.body | test("^- . Manual") or startswith("Reference manual CI status")) | select(.user.login == "leanprover-bot"))')"
|
||||
existing_comment_id="$(echo "$existing_comment" | jq -r .id)"
|
||||
existing_comment_body="$(echo "$existing_comment" | jq -r .body)"
|
||||
|
||||
if [[ "$existing_comment_body" != *"$MESSAGE"* ]]; then
|
||||
MESSAGE="$MESSAGE ($(date "+%Y-%m-%d %H:%M:%S"))"
|
||||
|
||||
echo "Posting message to the comments: $MESSAGE"
|
||||
|
||||
# Append new result to the existing comment or post a new comment
|
||||
# It's essential we use the MANUAL_COMMENT_BOT token here, so that reference manual CI can subsequently edit the comment.
|
||||
if [ -z "$existing_comment_id" ]; then
|
||||
INTRO="Reference manual CI status:"
|
||||
# Post new comment with a bullet point
|
||||
echo "Posting as new comment at leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments"
|
||||
curl -L -s \
|
||||
-X POST \
|
||||
-H "Authorization: token ${{ secrets.MANUAL_COMMENT_BOT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-d "$(jq --null-input --arg intro "$INTRO" --arg val "$MESSAGE" '{"body":($intro + "\n" + $val)}')" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments"
|
||||
else
|
||||
# Append new result to the existing comment
|
||||
echo "Appending to existing comment at leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments"
|
||||
curl -L -s \
|
||||
-X PATCH \
|
||||
-H "Authorization: token ${{ secrets.MANUAL_COMMENT_BOT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-d "$(jq --null-input --arg existing "$existing_comment_body" --arg message "$MESSAGE" '{"body":($existing + "\n" + $message)}')" \
|
||||
"https://api.github.com/repos/leanprover/lean4/issues/comments/$existing_comment_id"
|
||||
fi
|
||||
else
|
||||
echo "The message already exists in the comment body."
|
||||
fi
|
||||
|
||||
if [[ "$FORCE_CI" == "true" ]]; then
|
||||
echo "manual_ready=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "manual_ready=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
else
|
||||
echo "manual_ready=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
|
||||
- name: Report mathlib base
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' }}
|
||||
uses: actions/github-script@v7
|
||||
@@ -423,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
|
||||
@@ -456,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.
|
||||
@@ -489,86 +346,24 @@ 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
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
run: |
|
||||
git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
|
||||
# We next automatically create a reference manual branch using this toolchain.
|
||||
# Reference manual CI will be responsible for reporting back success or failure
|
||||
# to the PR comments asynchronously (and thus transitively SubVerso/Verso).
|
||||
- name: Cleanup workspace
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
run: |
|
||||
sudo rm -rf ./*
|
||||
|
||||
# Checkout the reference manual repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: leanprover/reference-manual
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
ref: nightly-testing
|
||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||
|
||||
- name: Check if tag in reference manual exists
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
id: check_manual_tag
|
||||
run: |
|
||||
git config user.name "leanprover-bot"
|
||||
git config user.email "leanprover-bot@lean-fro.org"
|
||||
|
||||
if git ls-remote --heads --tags --exit-code origin "nightly-testing-${MOST_RECENT_NIGHTLY}" >/dev/null; then
|
||||
BASE="nightly-testing-${MOST_RECENT_NIGHTLY}"
|
||||
else
|
||||
echo "Couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' branch in the reference manual. Falling back to 'nightly-testing'."
|
||||
BASE=nightly-testing
|
||||
fi
|
||||
|
||||
echo "Using base tag: $BASE"
|
||||
|
||||
EXISTS="$(git ls-remote --heads origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} | wc -l)"
|
||||
echo "Branch exists: $EXISTS"
|
||||
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
|
||||
git add lean-toolchain
|
||||
git add lakefile.lean lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
else
|
||||
echo "Branch already exists, updating lean-toolchain."
|
||||
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# The reference manual's `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
|
||||
git add lake-manifest.json
|
||||
git commit -m "Update lean-toolchain for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||
fi
|
||||
|
||||
- name: Push changes
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
run: |
|
||||
git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
|
||||
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'
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
lake-manifest.json
|
||||
/build
|
||||
/src/lakefile.toml
|
||||
/tests/lakefile.toml
|
||||
/lakefile.toml
|
||||
GPATH
|
||||
GRTAGS
|
||||
@@ -31,4 +32,3 @@ fwOut.txt
|
||||
wdErr.txt
|
||||
wdIn.txt
|
||||
wdOut.txt
|
||||
downstream_releases/
|
||||
|
||||
@@ -16,7 +16,7 @@ foreach(var ${vars})
|
||||
list(APPEND STAGE1_ARGS "-D${CMAKE_MATCH_1}=${${var}}")
|
||||
elseif("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
|
||||
list(APPEND CL_ARGS "-D${var}=${${var}}")
|
||||
if("${var}" MATCHES "USE_GMP|CHECK_OLEAN_VERSION|LEAN_VERSION_.*|LEAN_SPECIAL_VERSION_DESC")
|
||||
if("${var}" MATCHES "USE_GMP|CHECK_OLEAN_VERSION")
|
||||
# must forward options that generate incompatible .olean format
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
elseif("${var}" MATCHES "LLVM*|PKG_CONFIG|USE_LAKE|USE_MIMALLOC")
|
||||
|
||||
@@ -68,7 +68,7 @@ The memory order of the fields is derived from the types and order of the fields
|
||||
* Fields of type `USize`
|
||||
* Other scalar fields, in decreasing order by size
|
||||
|
||||
Within each group the fields are ordered in declaration order. Trivial wrapper types count as their underlying wrapped type for this purpose.
|
||||
Within each group the fields are ordered in declaration order. **Warning**: Trivial wrapper types still count toward a field being treated as non-scalar for this purpose.
|
||||
|
||||
* To access fields of the first kind, use `lean_ctor_get(val, i)` to get the `i`th non-scalar field.
|
||||
* To access `USize` fields, use `lean_ctor_get_usize(val, n+i)` to get the `i`th usize field and `n` is the total number of fields of the first kind.
|
||||
@@ -80,32 +80,32 @@ structure S where
|
||||
ptr_1 : Array Nat
|
||||
usize_1 : USize
|
||||
sc64_1 : UInt64
|
||||
sc64_2 : { x : UInt64 // x > 0 } -- wrappers of scalars count as scalars
|
||||
sc64_3 : Float -- `Float` is 64 bit
|
||||
ptr_2 : { x : UInt64 // x > 0 } -- wrappers don't count as scalars
|
||||
sc64_2 : Float -- `Float` is 64 bit
|
||||
sc8_1 : Bool
|
||||
sc16_1 : UInt16
|
||||
sc8_2 : UInt8
|
||||
sc64_4 : UInt64
|
||||
sc64_3 : UInt64
|
||||
usize_2 : USize
|
||||
sc32_1 : Char -- trivial wrapper around `UInt32`
|
||||
sc32_2 : UInt32
|
||||
ptr_3 : Char -- trivial wrapper around `UInt32`
|
||||
sc32_1 : UInt32
|
||||
sc16_2 : UInt16
|
||||
```
|
||||
would get re-sorted into the following memory order:
|
||||
|
||||
* `S.ptr_1` - `lean_ctor_get(val, 0)`
|
||||
* `S.usize_1` - `lean_ctor_get_usize(val, 1)`
|
||||
* `S.usize_2` - `lean_ctor_get_usize(val, 2)`
|
||||
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*3)`
|
||||
* `S.sc64_2` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 8)`
|
||||
* `S.sc64_3` - `lean_ctor_get_float(val, sizeof(void*)*3 + 16)`
|
||||
* `S.sc64_4` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 24)`
|
||||
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 32)`
|
||||
* `S.sc32_2` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 36)`
|
||||
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 40)`
|
||||
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 42)`
|
||||
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 44)`
|
||||
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 45)`
|
||||
* `S.ptr_2` - `lean_ctor_get(val, 1)`
|
||||
* `S.ptr_3` - `lean_ctor_get(val, 2)`
|
||||
* `S.usize_1` - `lean_ctor_get_usize(val, 3)`
|
||||
* `S.usize_2` - `lean_ctor_get_usize(val, 4)`
|
||||
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*5)`
|
||||
* `S.sc64_2` - `lean_ctor_get_float(val, sizeof(void*)*5 + 8)`
|
||||
* `S.sc64_3` - `lean_ctor_get_uint64(val, sizeof(void*)*5 + 16)`
|
||||
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*5 + 24)`
|
||||
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 28)`
|
||||
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 30)`
|
||||
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 32)`
|
||||
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 33)`
|
||||
|
||||
### Borrowing
|
||||
|
||||
@@ -131,21 +131,14 @@ Thus `[init]` functions are run iff their module is imported, regardless of whet
|
||||
|
||||
The initializer for module `A.B` is called `initialize_A_B` and will automatically initialize any imported modules.
|
||||
Module initializers are idempotent (when run with the same `builtin` flag), but not thread-safe.
|
||||
|
||||
**Important for process-related functionality**: If your application needs to use process-related functions from libuv, such as `Std.Internal.IO.Process.getProcessTitle` and `Std.Internal.IO.Process.setProcessTitle`, you must call `lean_setup_args(argc, argv)` (which returns a potentially modified `argv` that must be used in place of the original) **before** calling `lean_initialize()` or `lean_initialize_runtime_module()`. This sets up process handling capabilities correctly, which is essential for certain system-level operations that Lean's runtime may depend on.
|
||||
|
||||
Together with initialization of the Lean runtime, you should execute code like the following exactly once before accessing any Lean declarations:
|
||||
|
||||
```c
|
||||
void lean_initialize_runtime_module();
|
||||
void lean_initialize();
|
||||
char ** lean_setup_args(int argc, char ** argv);
|
||||
|
||||
lean_object * initialize_A_B(uint8_t builtin, lean_object *);
|
||||
lean_object * initialize_C(uint8_t builtin, lean_object *);
|
||||
...
|
||||
|
||||
argv = lean_setup_args(argc, argv); // if using process-related functionality
|
||||
lean_initialize_runtime_module();
|
||||
//lean_initialize(); // necessary (and replaces `lean_initialize_runtime_module`) if you (indirectly) access the `Lean` package
|
||||
|
||||
|
||||
@@ -85,13 +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.
|
||||
|
||||
### Testing against the Lean Language Reference
|
||||
You can test a Lean PR against the reference manual by rebasing your PR
|
||||
on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
|
||||
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
|
||||
and will report back to the Lean PR with results from Mathlib CI.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# The Lean standard library
|
||||
|
||||
This directory contains development information about the Lean standard library. The user-facing documentation of the standard library
|
||||
is part of the [Lean Language Reference](https://lean-lang.org/doc/reference/latest/).
|
||||
|
||||
Here you will find
|
||||
* the [standard library vision document](./vision.md), including the call for contributions,
|
||||
* the [standard library style guide](./style.md), and
|
||||
* the [standard library naming conventions](./naming.md).
|
||||
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,14 +0,0 @@
|
||||
import Grove.Framework
|
||||
import GroveStdlib.Generated.«associative-query-operations»
|
||||
|
||||
/-
|
||||
This file is autogenerated by grove. You can manually edit it, for example to resolve merge
|
||||
conflicts, but be careful.
|
||||
-/
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Generated
|
||||
|
||||
def restoreState : RestoreStateM Unit := do
|
||||
«associative-query-operations».restoreState
|
||||
@@ -1,486 +0,0 @@
|
||||
import Grove.Framework
|
||||
|
||||
/-
|
||||
This file is autogenerated by grove. You can manually edit it, for example to resolve merge
|
||||
conflicts, but be careful.
|
||||
-/
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Generated.«associative-query-operations»
|
||||
|
||||
def «01f88623-fa5f-4380-9772-b30f2fec5c94» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "01f88623-fa5f-4380-9772-b30f2fec5c94"
|
||||
rowId := "01f88623-fa5f-4380-9772-b30f2fec5c94"
|
||||
rowState := #[⟨"Std.DHashMap", "Std.DHashMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DHashMap.isEmpty,
|
||||
renderedStatement := "Std.DHashMap.isEmpty.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.DHashMap α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DHashMap.Raw.isEmpty,
|
||||
renderedStatement := "Std.DHashMap.Raw.isEmpty.{u, v} {α : Type u} {β : α → Type v} (m : Std.DHashMap.Raw α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtDHashMap.isEmpty,
|
||||
renderedStatement := "Std.ExtDHashMap.isEmpty.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α]\n [LawfulHashable α] (m : Std.ExtDHashMap α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.DTreeMap", "Std.DTreeMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.isEmpty,
|
||||
renderedStatement := "Std.DTreeMap.isEmpty.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap α β cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.Raw.isEmpty,
|
||||
renderedStatement := "Std.DTreeMap.Raw.isEmpty.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap.Raw α β cmp) :\n Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtDTreeMap.isEmpty,
|
||||
renderedStatement := "Std.ExtDTreeMap.isEmpty.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.ExtDTreeMap α β cmp) :\n Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashMap", "Std.HashMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashMap.isEmpty,
|
||||
renderedStatement := "Std.HashMap.isEmpty.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashMap α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashMap.Raw.isEmpty,
|
||||
renderedStatement := "Std.HashMap.Raw.isEmpty.{u, v} {α : Type u} {β : Type v} (m : Std.HashMap.Raw α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtHashMap.isEmpty,
|
||||
renderedStatement := "Std.ExtHashMap.isEmpty.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashMap α β) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap", "Std.TreeMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.isEmpty,
|
||||
renderedStatement := "Std.TreeMap.isEmpty.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap α β cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.Raw.isEmpty,
|
||||
renderedStatement := "Std.TreeMap.Raw.isEmpty.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap.Raw α β cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeMap.isEmpty,
|
||||
renderedStatement := "Std.ExtTreeMap.isEmpty.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.ExtTreeMap α β cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet", "Std.HashSet.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.isEmpty,
|
||||
renderedStatement := "Std.HashSet.isEmpty.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashSet α) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.Raw.isEmpty,
|
||||
renderedStatement := "Std.HashSet.Raw.isEmpty.{u} {α : Type u} (m : Std.HashSet.Raw α) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtHashSet.isEmpty,
|
||||
renderedStatement := "Std.ExtHashSet.isEmpty.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashSet α) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet", "Std.TreeSet.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.isEmpty,
|
||||
renderedStatement := "Std.TreeSet.isEmpty.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.Raw.isEmpty,
|
||||
renderedStatement := "Std.TreeSet.Raw.isEmpty.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.isEmpty", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeSet.isEmpty,
|
||||
renderedStatement := "Std.ExtTreeSet.isEmpty.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.ExtTreeSet α cmp) : Bool",
|
||||
isDeprecated := false })⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «f084f852-af71-45b6-8ab3-d251a8144f72» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "f084f852-af71-45b6-8ab3-d251a8144f72"
|
||||
rowId := "f084f852-af71-45b6-8ab3-d251a8144f72"
|
||||
rowState := #[⟨"Std.DHashMap", "Std.DHashMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DHashMap.size,
|
||||
renderedStatement := "Std.DHashMap.size.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.DHashMap α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DHashMap.Raw.size,
|
||||
renderedStatement := "Std.DHashMap.Raw.size.{u, v} {α : Type u} {β : α → Type v} (self : Std.DHashMap.Raw α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtDHashMap.size,
|
||||
renderedStatement := "Std.ExtDHashMap.size.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α]\n [LawfulHashable α] (m : Std.ExtDHashMap α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.DTreeMap", "Std.DTreeMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.size,
|
||||
renderedStatement := "Std.DTreeMap.size.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.Raw.size,
|
||||
renderedStatement := "Std.DTreeMap.Raw.size.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap.Raw α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtDTreeMap.size,
|
||||
renderedStatement := "Std.ExtDTreeMap.size.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.ExtDTreeMap α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.HashMap", "Std.HashMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashMap.size,
|
||||
renderedStatement := "Std.HashMap.size.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashMap α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashMap.Raw.size,
|
||||
renderedStatement := "Std.HashMap.Raw.size.{u, v} {α : Type u} {β : Type v} (m : Std.HashMap.Raw α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtHashMap.size,
|
||||
renderedStatement := "Std.ExtHashMap.size.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashMap α β) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap", "Std.TreeMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.size,
|
||||
renderedStatement := "Std.TreeMap.size.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.Raw.size,
|
||||
renderedStatement := "Std.TreeMap.Raw.size.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap.Raw α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeMap.size,
|
||||
renderedStatement := "Std.ExtTreeMap.size.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.ExtTreeMap α β cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet", "Std.HashSet.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.size,
|
||||
renderedStatement := "Std.HashSet.size.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashSet α) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.Raw.size,
|
||||
renderedStatement := "Std.HashSet.Raw.size.{u} {α : Type u} (m : Std.HashSet.Raw α) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtHashSet.size,
|
||||
renderedStatement := "Std.ExtHashSet.size.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashSet α) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet", "Std.TreeSet.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.size,
|
||||
renderedStatement := "Std.TreeSet.size.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.Raw.size,
|
||||
renderedStatement := "Std.TreeSet.Raw.size.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) : Nat",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.size", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeSet.size,
|
||||
renderedStatement := "Std.ExtTreeSet.size.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.ExtTreeSet α cmp) : Nat",
|
||||
isDeprecated := false })⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «f4e6fa70-5aed-439d-aaad-5f4ced65bf7b» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "f4e6fa70-5aed-439d-aaad-5f4ced65bf7b"
|
||||
rowId := "f4e6fa70-5aed-439d-aaad-5f4ced65bf7b"
|
||||
rowState := #[⟨"Std.DTreeMap", "Std.DTreeMap.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.any,
|
||||
renderedStatement := "Std.DTreeMap.any.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap α β cmp)\n (p : (a : α) → β a → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.DTreeMap.Raw.any,
|
||||
renderedStatement := "Std.DTreeMap.Raw.any.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap.Raw α β cmp)\n (p : (a : α) → β a → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtDTreeMap.any,
|
||||
renderedStatement := "Std.ExtDTreeMap.any.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n (t : Std.ExtDTreeMap α β cmp) (p : (a : α) → β a → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap", "Std.TreeMap.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.any,
|
||||
renderedStatement := "Std.TreeMap.any.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap α β cmp) (p : α → β → Bool) :\n Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeMap.Raw.any,
|
||||
renderedStatement := "Std.TreeMap.Raw.any.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap.Raw α β cmp)\n (p : α → β → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeMap.any,
|
||||
renderedStatement := "Std.ExtTreeMap.any.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n (t : Std.ExtTreeMap α β cmp) (p : α → β → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet", "Std.HashSet.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.any,
|
||||
renderedStatement := "Std.HashSet.any.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashSet α) (p : α → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.HashSet.Raw.any,
|
||||
renderedStatement := "Std.HashSet.Raw.any.{u} {α : Type u} (m : Std.HashSet.Raw α) (p : α → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet", "Std.TreeSet.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.any,
|
||||
renderedStatement := "Std.TreeSet.any.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) (p : α → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.TreeSet.Raw.any,
|
||||
renderedStatement := "Std.TreeSet.Raw.any.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) (p : α → Bool) : Bool",
|
||||
isDeprecated := false })⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.any", Grove.Framework.Subexpression.State.declaration
|
||||
(Grove.Framework.Declaration.def
|
||||
{ name := `Std.ExtTreeSet.any,
|
||||
renderedStatement := "Std.ExtTreeSet.any.{u} {α : Type u} {cmp : α → α → Ordering} [Std.TransCmp cmp] (t : Std.ExtTreeSet α cmp)\n (p : α → Bool) : Bool",
|
||||
isDeprecated := false })⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing for some containers"
|
||||
}
|
||||
def «c1d181f6-3204-4956-946f-e81619f9feb4» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "c1d181f6-3204-4956-946f-e81619f9feb4"
|
||||
rowId := "c1d181f6-3204-4956-946f-e81619f9feb4"
|
||||
rowState := #[⟨"Std.DTreeMap", "Std.DTreeMap.all", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.all
|
||||
renderedStatement := "Std.DTreeMap.all.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap α β cmp)\n (p : (a : α) → β a → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.all", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.Raw.all
|
||||
renderedStatement := "Std.DTreeMap.Raw.all.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} (t : Std.DTreeMap.Raw α β cmp)\n (p : (a : α) → β a → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.all", .declaration (Declaration.def {
|
||||
name := `Std.ExtDTreeMap.all
|
||||
renderedStatement := "Std.ExtDTreeMap.all.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n (t : Std.ExtDTreeMap α β cmp) (p : (a : α) → β a → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeMap", "Std.TreeMap.all", .declaration (Declaration.def {
|
||||
name := `Std.TreeMap.all
|
||||
renderedStatement := "Std.TreeMap.all.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap α β cmp) (p : α → β → Bool) :\n Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.all", .declaration (Declaration.def {
|
||||
name := `Std.TreeMap.Raw.all
|
||||
renderedStatement := "Std.TreeMap.Raw.all.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap.Raw α β cmp)\n (p : α → β → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.all", .declaration (Declaration.def {
|
||||
name := `Std.ExtTreeMap.all
|
||||
renderedStatement := "Std.ExtTreeMap.all.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n (t : Std.ExtTreeMap α β cmp) (p : α → β → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashSet", "Std.HashSet.all", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.all
|
||||
renderedStatement := "Std.HashSet.all.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashSet α) (p : α → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.all", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.Raw.all
|
||||
renderedStatement := "Std.HashSet.Raw.all.{u} {α : Type u} (m : Std.HashSet.Raw α) (p : α → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet", "Std.TreeSet.all", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.all
|
||||
renderedStatement := "Std.TreeSet.all.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) (p : α → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.all", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.Raw.all
|
||||
renderedStatement := "Std.TreeSet.Raw.all.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) (p : α → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.all", .declaration (Declaration.def {
|
||||
name := `Std.ExtTreeSet.all
|
||||
renderedStatement := "Std.ExtTreeSet.all.{u} {α : Type u} {cmp : α → α → Ordering} [Std.TransCmp cmp] (t : Std.ExtTreeSet α cmp)\n (p : α → Bool) : Bool"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing for some containers"
|
||||
}
|
||||
def «efe57f41-7db7-4303-b3a6-5216a70c43ce» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "efe57f41-7db7-4303-b3a6-5216a70c43ce"
|
||||
rowId := "efe57f41-7db7-4303-b3a6-5216a70c43ce"
|
||||
rowState := #[⟨"Std.DHashMap", "Std.DHashMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.DHashMap.getD
|
||||
renderedStatement := "Std.DHashMap.getD.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [LawfulBEq α]\n (m : Std.DHashMap α β) (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.DHashMap.Raw.getD
|
||||
renderedStatement := "Std.DHashMap.Raw.getD.{u, v} {α : Type u} {β : α → Type v} [BEq α] [Hashable α] [LawfulBEq α] (m : Std.DHashMap.Raw α β)\n (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtDHashMap.getD
|
||||
renderedStatement := "Std.ExtDHashMap.getD.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [LawfulBEq α]\n (m : Std.ExtDHashMap α β) (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DTreeMap", "Std.DTreeMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.getD
|
||||
renderedStatement := "Std.DTreeMap.getD.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.LawfulEqCmp cmp]\n (t : Std.DTreeMap α β cmp) (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.Raw.getD
|
||||
renderedStatement := "Std.DTreeMap.Raw.getD.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.LawfulEqCmp cmp]\n (t : Std.DTreeMap.Raw α β cmp) (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtDTreeMap.getD
|
||||
renderedStatement := "Std.ExtDTreeMap.getD.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n [Std.LawfulEqCmp cmp] (t : Std.ExtDTreeMap α β cmp) (a : α) (fallback : β a) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashMap", "Std.HashMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.HashMap.getD
|
||||
renderedStatement := "Std.HashMap.getD.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} (m : Std.HashMap α β) (a : α)\n (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.HashMap.Raw.getD
|
||||
renderedStatement := "Std.HashMap.Raw.getD.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α] (m : Std.HashMap.Raw α β) (a : α)\n (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtHashMap.getD
|
||||
renderedStatement := "Std.ExtHashMap.getD.{u, v} {α : Type u} {β : Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashMap α β) (a : α) (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeMap", "Std.TreeMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.TreeMap.getD
|
||||
renderedStatement := "Std.TreeMap.getD.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap α β cmp) (a : α)\n (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.TreeMap.Raw.getD
|
||||
renderedStatement := "Std.TreeMap.Raw.getD.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} (t : Std.TreeMap.Raw α β cmp) (a : α)\n (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtTreeMap.getD
|
||||
renderedStatement := "Std.ExtTreeMap.getD.{u, v} {α : Type u} {β : Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n (t : Std.ExtTreeMap α β cmp) (a : α) (fallback : β) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashSet", "Std.HashSet.getD", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.getD
|
||||
renderedStatement := "Std.HashSet.getD.{u} {α : Type u} [BEq α] [Hashable α] (m : Std.HashSet α) (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.Raw.getD
|
||||
renderedStatement := "Std.HashSet.Raw.getD.{u} {α : Type u} [BEq α] [Hashable α] (m : Std.HashSet.Raw α) (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtHashSet.getD
|
||||
renderedStatement := "Std.ExtHashSet.getD.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashSet α) (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet", "Std.TreeSet.getD", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.getD
|
||||
renderedStatement := "Std.TreeSet.getD.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.getD", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.Raw.getD
|
||||
renderedStatement := "Std.TreeSet.Raw.getD.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.getD", .declaration (Declaration.def {
|
||||
name := `Std.ExtTreeSet.getD
|
||||
renderedStatement := "Std.ExtTreeSet.getD.{u} {α : Type u} {cmp : α → α → Ordering} [Std.TransCmp cmp] (t : Std.ExtTreeSet α cmp)\n (a fallback : α) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «e23b1119-3b57-433e-a68d-68fd70b9943d» : AssociationTable.Fact .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
factId := "e23b1119-3b57-433e-a68d-68fd70b9943d"
|
||||
rowId := "e23b1119-3b57-433e-a68d-68fd70b9943d"
|
||||
rowState := #[⟨"Std.DHashMap", "Std.DHashMap.get", .declaration (Declaration.def {
|
||||
name := `Std.DHashMap.get
|
||||
renderedStatement := "Std.DHashMap.get.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [LawfulBEq α]\n (m : Std.DHashMap α β) (a : α) (h : a ∈ m) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.Const.get", .declaration (Declaration.def {
|
||||
name := `Std.DHashMap.Raw.Const.get
|
||||
renderedStatement := "Std.DHashMap.Raw.Const.get.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α] (m : Std.DHashMap.Raw α fun x => β)\n (a : α) (h : a ∈ m) : β"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.get", .declaration (Declaration.def {
|
||||
name := `Std.ExtDHashMap.get
|
||||
renderedStatement := "Std.ExtDHashMap.get.{u, v} {α : Type u} {β : α → Type v} {x✝ : BEq α} {x✝¹ : Hashable α} [LawfulBEq α]\n (m : Std.ExtDHashMap α β) (a : α) (h : a ∈ m) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DTreeMap", "Std.DTreeMap.get", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.get
|
||||
renderedStatement := "Std.DTreeMap.get.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.LawfulEqCmp cmp]\n (t : Std.DTreeMap α β cmp) (a : α) (h : a ∈ t) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.get", .declaration (Declaration.def {
|
||||
name := `Std.DTreeMap.Raw.get
|
||||
renderedStatement := "Std.DTreeMap.Raw.get.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.LawfulEqCmp cmp]\n (t : Std.DTreeMap.Raw α β cmp) (a : α) (h : a ∈ t) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.get", .declaration (Declaration.def {
|
||||
name := `Std.ExtDTreeMap.get
|
||||
renderedStatement := "Std.ExtDTreeMap.get.{u, v} {α : Type u} {β : α → Type v} {cmp : α → α → Ordering} [Std.TransCmp cmp]\n [Std.LawfulEqCmp cmp] (t : Std.ExtDTreeMap α β cmp) (a : α) (h : a ∈ t) : β a"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashMap", "app (GetElem.getElem) (Std.HashMap*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.HashMap*)", displayShort := "Std.HashMap[·]" }⟩,⟨"Std.HashMap.Raw", "app (GetElem.getElem) (Std.HashMap.Raw*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.HashMap.Raw*)", displayShort := "Std.HashMap.Raw[·]" }⟩,⟨"Std.ExtHashMap", "app (GetElem.getElem) (Std.ExtHashMap*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.ExtHashMap*)", displayShort := "Std.ExtHashMap[·]" }⟩,⟨"Std.TreeMap", "app (GetElem.getElem) (Std.TreeMap*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.TreeMap*)", displayShort := "Std.TreeMap[·]" }⟩,⟨"Std.TreeMap.Raw", "app (GetElem.getElem) (Std.TreeMap.Raw*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.TreeMap.Raw*)", displayShort := "Std.TreeMap.Raw[·]" }⟩,⟨"Std.ExtTreeMap", "app (GetElem.getElem) (Std.ExtTreeMap*)", Grove.Framework.Subexpression.State.predicate
|
||||
{ key := "app (GetElem.getElem) (Std.ExtTreeMap*)", displayShort := "Std.ExtTreeMap[·]" }⟩,⟨"Std.HashSet", "Std.HashSet.get", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.get
|
||||
renderedStatement := "Std.HashSet.get.{u} {α : Type u} [BEq α] [Hashable α] (m : Std.HashSet α) (a : α) (h : a ∈ m) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.get", .declaration (Declaration.def {
|
||||
name := `Std.HashSet.Raw.get
|
||||
renderedStatement := "Std.HashSet.Raw.get.{u} {α : Type u} [BEq α] [Hashable α] (m : Std.HashSet.Raw α) (a : α) (h : a ∈ m) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.get", .declaration (Declaration.def {
|
||||
name := `Std.ExtHashSet.get
|
||||
renderedStatement := "Std.ExtHashSet.get.{u} {α : Type u} {x✝ : BEq α} {x✝¹ : Hashable α} [EquivBEq α] [LawfulHashable α]\n (m : Std.ExtHashSet α) (a : α) (h : a ∈ m) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet", "Std.TreeSet.get", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.get
|
||||
renderedStatement := "Std.TreeSet.get.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet α cmp) (a : α) (h : a ∈ t) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.get", .declaration (Declaration.def {
|
||||
name := `Std.TreeSet.Raw.get
|
||||
renderedStatement := "Std.TreeSet.Raw.get.{u} {α : Type u} {cmp : α → α → Ordering} (t : Std.TreeSet.Raw α cmp) (a : α) (h : a ∈ t) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.get", .declaration (Declaration.def {
|
||||
name := `Std.ExtTreeSet.get
|
||||
renderedStatement := "Std.ExtTreeSet.get.{u} {α : Type u} {cmp : α → α → Ordering} [Std.TransCmp cmp] (t : Std.ExtTreeSet α cmp) (a : α)\n (h : a ∈ t) : α"
|
||||
isDeprecated := false
|
||||
}
|
||||
)⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Should *Set have GetElem?"
|
||||
}
|
||||
|
||||
def table : AssociationTable.Data .subexpression where
|
||||
widgetId := "associative-query-operations"
|
||||
rows := #[
|
||||
⟨"01f88623-fa5f-4380-9772-b30f2fec5c94", "isEmpty", #[⟨"Std.DHashMap", "Std.DHashMap.isEmpty"⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.isEmpty"⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.isEmpty"⟩,⟨"Std.DTreeMap", "Std.DTreeMap.isEmpty"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.isEmpty"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.isEmpty"⟩,⟨"Std.HashMap", "Std.HashMap.isEmpty"⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.isEmpty"⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.isEmpty"⟩,⟨"Std.TreeMap", "Std.TreeMap.isEmpty"⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.isEmpty"⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.isEmpty"⟩,⟨"Std.HashSet", "Std.HashSet.isEmpty"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.isEmpty"⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.isEmpty"⟩,⟨"Std.TreeSet", "Std.TreeSet.isEmpty"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.isEmpty"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.isEmpty"⟩,]⟩,
|
||||
⟨"f084f852-af71-45b6-8ab3-d251a8144f72", "size", #[⟨"Std.DHashMap", "Std.DHashMap.size"⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.size"⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.size"⟩,⟨"Std.DTreeMap", "Std.DTreeMap.size"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.size"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.size"⟩,⟨"Std.HashMap", "Std.HashMap.size"⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.size"⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.size"⟩,⟨"Std.TreeMap", "Std.TreeMap.size"⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.size"⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.size"⟩,⟨"Std.HashSet", "Std.HashSet.size"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.size"⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.size"⟩,⟨"Std.TreeSet", "Std.TreeSet.size"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.size"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.size"⟩,]⟩,
|
||||
⟨"f4e6fa70-5aed-439d-aaad-5f4ced65bf7b", "any", #[⟨"Std.DTreeMap", "Std.DTreeMap.any"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.any"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.any"⟩,⟨"Std.TreeMap", "Std.TreeMap.any"⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.any"⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.any"⟩,⟨"Std.HashSet", "Std.HashSet.any"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.any"⟩,⟨"Std.TreeSet", "Std.TreeSet.any"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.any"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.any"⟩,]⟩,
|
||||
⟨"c1d181f6-3204-4956-946f-e81619f9feb4", "all", #[⟨"Std.DTreeMap", "Std.DTreeMap.all"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.all"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.all"⟩,⟨"Std.TreeMap", "Std.TreeMap.all"⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.all"⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.all"⟩,⟨"Std.HashSet", "Std.HashSet.all"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.all"⟩,⟨"Std.TreeSet", "Std.TreeSet.all"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.all"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.all"⟩,]⟩,
|
||||
⟨"efe57f41-7db7-4303-b3a6-5216a70c43ce", "getD", #[⟨"Std.DHashMap", "Std.DHashMap.getD"⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.getD"⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.getD"⟩,⟨"Std.DTreeMap", "Std.DTreeMap.getD"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.getD"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.getD"⟩,⟨"Std.HashMap", "Std.HashMap.getD"⟩,⟨"Std.HashMap.Raw", "Std.HashMap.Raw.getD"⟩,⟨"Std.ExtHashMap", "Std.ExtHashMap.getD"⟩,⟨"Std.TreeMap", "Std.TreeMap.getD"⟩,⟨"Std.TreeMap.Raw", "Std.TreeMap.Raw.getD"⟩,⟨"Std.ExtTreeMap", "Std.ExtTreeMap.getD"⟩,⟨"Std.HashSet", "Std.HashSet.getD"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.getD"⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.getD"⟩,⟨"Std.TreeSet", "Std.TreeSet.getD"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.getD"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.getD"⟩,]⟩,
|
||||
⟨"e23b1119-3b57-433e-a68d-68fd70b9943d", "getElem", #[⟨"Std.DHashMap", "Std.DHashMap.get"⟩,⟨"Std.DHashMap.Raw", "Std.DHashMap.Raw.Const.get"⟩,⟨"Std.ExtDHashMap", "Std.ExtDHashMap.get"⟩,⟨"Std.DTreeMap", "Std.DTreeMap.get"⟩,⟨"Std.DTreeMap.Raw", "Std.DTreeMap.Raw.get"⟩,⟨"Std.ExtDTreeMap", "Std.ExtDTreeMap.get"⟩,⟨"Std.HashMap", "app (GetElem.getElem) (Std.HashMap*)"⟩,⟨"Std.HashMap.Raw", "app (GetElem.getElem) (Std.HashMap.Raw*)"⟩,⟨"Std.ExtHashMap", "app (GetElem.getElem) (Std.ExtHashMap*)"⟩,⟨"Std.TreeMap", "app (GetElem.getElem) (Std.TreeMap*)"⟩,⟨"Std.TreeMap.Raw", "app (GetElem.getElem) (Std.TreeMap.Raw*)"⟩,⟨"Std.ExtTreeMap", "app (GetElem.getElem) (Std.ExtTreeMap*)"⟩,⟨"Std.HashSet", "Std.HashSet.get"⟩,⟨"Std.HashSet.Raw", "Std.HashSet.Raw.get"⟩,⟨"Std.ExtHashSet", "Std.ExtHashSet.get"⟩,⟨"Std.TreeSet", "Std.TreeSet.get"⟩,⟨"Std.TreeSet.Raw", "Std.TreeSet.Raw.get"⟩,⟨"Std.ExtTreeSet", "Std.ExtTreeSet.get"⟩,]⟩,
|
||||
]
|
||||
facts := #[
|
||||
«01f88623-fa5f-4380-9772-b30f2fec5c94»,
|
||||
«f084f852-af71-45b6-8ab3-d251a8144f72»,
|
||||
«f4e6fa70-5aed-439d-aaad-5f4ced65bf7b»,
|
||||
«c1d181f6-3204-4956-946f-e81619f9feb4»,
|
||||
«efe57f41-7db7-4303-b3a6-5216a70c43ce»,
|
||||
«e23b1119-3b57-433e-a68d-68fd70b9943d»,
|
||||
]
|
||||
|
||||
def restoreState : RestoreStateM Unit := do
|
||||
addAssociationTable table
|
||||
@@ -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,58 +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
|
||||
|
||||
namespace SequentialContainers
|
||||
|
||||
end SequentialContainers
|
||||
|
||||
def sequentialContainers : Node :=
|
||||
.section "sequential-containers" "Sequential containers" #[]
|
||||
|
||||
namespace AssociativeContainers
|
||||
|
||||
def associativeQueryOperations : AssociationTable .subexpression
|
||||
[`Std.DHashMap, `Std.DHashMap.Raw, `Std.ExtDHashMap, `Std.DTreeMap, `Std.DTreeMap.Raw, `Std.ExtDTreeMap, `Std.HashMap,
|
||||
`Std.HashMap.Raw, `Std.ExtHashMap, `Std.TreeMap, `Std.TreeMap.Raw, `Std.ExtTreeMap, `Std.HashSet, `Std.HashSet.Raw, `Std.ExtHashSet,
|
||||
`Std.TreeSet, `Std.TreeSet.Raw, `Std.ExtTreeSet] where
|
||||
id := "associative-query-operations"
|
||||
title := "Associative query operations"
|
||||
description := "Operations that take as input an associative container and return a 'single' piece of information (e.g., `GetElem` or `isEmpty`, but not `toList`)."
|
||||
dataSources n :=
|
||||
(DataSource.declarationsInNamespace n .definitionsOnly)
|
||||
|>.map Subexpression.declaration
|
||||
|>.or (DataSource.getElem n)
|
||||
|
||||
end AssociativeContainers
|
||||
|
||||
def associativeContainers : Node :=
|
||||
.section "associative-containers" "Associative containers" #[
|
||||
.associationTable AssociativeContainers.associativeQueryOperations
|
||||
]
|
||||
|
||||
namespace PersistentDataStructures
|
||||
|
||||
end PersistentDataStructures
|
||||
|
||||
def persistentDataStructures : Node :=
|
||||
.section "persistent-data-structures" "Persistent data structures" #[]
|
||||
|
||||
end Containers
|
||||
|
||||
def containers : Node :=
|
||||
.section "containers" "Containers" #[
|
||||
Containers.sequentialContainers,
|
||||
Containers.associativeContainers,
|
||||
Containers.persistentDataStructures
|
||||
]
|
||||
|
||||
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": "e8127fc6554b99fb988ecdceb770a5e112afbe24",
|
||||
"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
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 68 KiB |
@@ -1,260 +0,0 @@
|
||||
# Standard library naming conventions
|
||||
|
||||
The easiest way to access a result in the standard library is to correctly guess the name of the declaration (possibly with the help of identifier autocompletion). This is faster and has lower friction than more sophisticated search tools, so easily guessable names (which are still reasonably short) make Lean users more productive.
|
||||
|
||||
The guide that follows contains very few hard rules, many heuristics and a selection of examples. It cannot and does not present a deterministic algorithm for choosing good names in all situations. It is intended as a living document that gets clarified and expanded as situations arise during code reviews for the standard library. If applying one of the suggestions in this guide leads to nonsensical results in a certain situation, it is
|
||||
probably safe to ignore the suggestion (or even better, suggest a way to improve the suggestion).
|
||||
|
||||
## Prelude
|
||||
|
||||
Identifiers use a mix of `UpperCamelCase`, `lowerCamelCase` and `snake_case`, used for types, data, and theorems, respectively.
|
||||
|
||||
Structure fields should be named such that the projections have the correct names.
|
||||
|
||||
## Naming convention for types
|
||||
|
||||
When defining a type, i.e., a (possibly 0-ary) function whose codomain is Sort u for some u, it should be named in UpperCamelCase. Examples include `List`, and `List.IsPrefix`.
|
||||
|
||||
When defining a predicate, prefix the name by `Is`, like in `List.IsPrefix`. The `Is` prefix may be omitted if
|
||||
* the resulting name would be ungrammatical, or
|
||||
* the predicate depends on additional data in a way where the `Is` prefix would be confusing (like `List.Pairwise`), or
|
||||
* the name is an adjective (like `Std.Time.Month.Ordinal.Valid`)
|
||||
|
||||
## Namespaces and generalized projection notation
|
||||
|
||||
Almost always, definitions and theorems relating to a type should be placed in a namespace with the same name as the type. For example, operations and theorems about lists should be placed in the `List` namespace, and operations and theorems about `Std.Time.PlainDate` should be placed in the `Std.Time.PlainDate` namespace.
|
||||
|
||||
Declarations in the root namespace will be relatively rare. The most common type of declaration in the root namespace are declarations about data and properties exported by notation type classes, as long as they are not about a specific type implementing that type class. For example, we have
|
||||
|
||||
```lean
|
||||
theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b ↔ a = b := sorry
|
||||
```
|
||||
|
||||
in the root namespace, but
|
||||
|
||||
```lean
|
||||
theorem List.cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
|
||||
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
|
||||
```
|
||||
|
||||
belongs in the `List` namespace.
|
||||
|
||||
Subtleties arise when multiple namespaces are in play. Generally, place your theorem in the most specific namespace that appears in one of the hypotheses of the theorem. The following names are both correct according to this convention:
|
||||
|
||||
```lean
|
||||
theorem List.Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse := sorry
|
||||
theorem List.reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := sorry
|
||||
```
|
||||
|
||||
Notice that the second theorem does not have a hypothesis of type `List.Sublist l` for some `l`, so the name `List.Sublist.reverse_iff` would be incorrect.
|
||||
|
||||
The advantage of placing results in a namespace like `List.Sublist` is that it enables generalized projection notation, i.e., given `h : l₁ <+ l₂`,
|
||||
one can write `h.reverse` to obtain a proof of `l₁.reverse <+ l₂.reverse`. Thinking about which dot notations are convenient can act as a guideline
|
||||
for deciding where to place a theorem, and is, on occasion, a good reason to duplicate a theorem into multiple namespaces.
|
||||
|
||||
### The `Std` namespace
|
||||
|
||||
New types that are added will usually be placed in the `Std` namespace and in the `Std/` source directory, unless there are good reasons to place
|
||||
them elsewhere.
|
||||
|
||||
Inside the `Std` namespace, all internal declarations should be `private` or else have a name component that clearly marks them as internal, preferably
|
||||
`Internal`.
|
||||
|
||||
|
||||
## Naming convention for data
|
||||
|
||||
When defining data, i.e., a (possibly 0-ary) function whose codomain is not Sort u, but has type Type u for some u, it should be named in lowerCamelCase. Examples include `List.append` and `List.isPrefixOf`.
|
||||
If your data is morally fully specified by its type, then use the naming procedure for theorems described below and convert the result to lower camel case.
|
||||
|
||||
If your function returns an `Option`, consider adding `?` as a suffix. If your function may panic, consider adding `!` as a suffix. In many cases, there will be multiple variants of a function; one returning an option, one that may panic and possibly one that takes a proof argument.
|
||||
|
||||
## Naming algorithm for theorems and some definitions
|
||||
|
||||
There is, in principle, a general algorithm for naming a theorem. The problem with this algorithm is that it produces very long and unwieldy names which need to be shortened. So choosing a name for a declaration can be thought of as consisting of a mechanical part and a creative part.
|
||||
|
||||
Usually the first part is to decide which namespace the result should live in, according to the guidelines described above.
|
||||
|
||||
Next, consider the type of your declaration as a tree. Inner nodes of this tree are function types or function applications. Leaves of the tree are 0-ary functions or bound variables.
|
||||
|
||||
As an example, consider the following result from the standard library:
|
||||
|
||||
```lean
|
||||
example {α : Type u} {β : Type v} [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α]
|
||||
[Inhabited β] {m : Std.HashMap α β} {a : α} {h' : a ∈ m} : m[a]? = some (m[a]'h') :=
|
||||
sorry
|
||||
```
|
||||
|
||||
The correct namespace is clearly `Std.HashMap`. The corresponding tree looks like this:
|
||||
|
||||

|
||||
|
||||
The preferred spelling of a notation can be looked up by hovering over the notation.
|
||||
|
||||
Now traverse the tree and build a name according to the following rules:
|
||||
|
||||
* When encountering a function type, first turn the result type into a name, then all of the argument types from left to right, and join the names using `_of_`.
|
||||
* When encountering a function that is neither an infix notation nor a structure projection, first put the function name and then the arguments, joined by an underscore.
|
||||
* When encountering an infix notation, join the arguments using the name of the notation, separated by underscores.
|
||||
* When encountering a structure projection, proceed as for normal functions, but put the name of the projection last.
|
||||
* When encountering a name, put it in lower camel case.
|
||||
* Skip bound variables and proofs.
|
||||
* Type class arguments are also generally skipped.
|
||||
|
||||
When encountering namespaces names, concatenate them in lower camel case.
|
||||
|
||||
Applying this algorithm to our example yields the name `Std.HashMap.getElem?_eq_optionSome_getElem_of_mem`.
|
||||
|
||||
From there, the name should be shortened, using the following heuristics:
|
||||
|
||||
* The namespace of functions can be omitted if it is clear from context or if the namespace is the current one. This is almost always the case.
|
||||
* For infix operators, it is possible to leave out the RHS or the name of the notation and the RHS if they are clear from context.
|
||||
* Hypotheses can be left out if it is clear that they are required or if they appear in the conclusion.
|
||||
|
||||
Based on this, here are some possible names for our example:
|
||||
|
||||
1. `Std.HashMap.getElem?_eq`
|
||||
2. `Std.HashMap.getElem?_eq_of_mem`
|
||||
3. `Std.HashMap.getElem?_eq_some`
|
||||
4. `Std.HashMap.getElem?_eq_some_of_mem`
|
||||
5. `Std.HashMap.getElem?_eq_some_getElem`
|
||||
6. `Std.Hashmap.getElem?_eq_some_getElem_of_mem`
|
||||
|
||||
Choosing a good name among these then requires considering the context of the lemma. In this case it turns out that the first four options are underspecified as there is also a lemma relating `m[a]?` and `m[a]!` which could have the same name. This leaves the last two options, the first of which is shorter, and this is how the lemma is called in the Lean standard library.
|
||||
|
||||
Here are some additional examples:
|
||||
|
||||
```lean
|
||||
example {x y : List α} (h : x <+: y) (hx : x ≠ []) :
|
||||
x.head hx = y.head (h.ne_nil hx) := sorry
|
||||
```
|
||||
|
||||
Since we have an `IsPrefix` parameter, this should live in the `List.IsPrefix` namespace, and the algorithm suggests `List.IsPrefix.head_eq_head_of_ne_nil`, which is shortened to `List.IsPrefix.head`. Note here the difference between the namespace name (`IsPrefix`) and the recommended spelling of the corresponding notation (`prefix`).
|
||||
|
||||
```lean
|
||||
example : l₁ <+: l₂ → reverse l₁ <:+ reverse l₂ := sorry
|
||||
```
|
||||
|
||||
Again, this result should be in the `List.IsPrefix` namespace; the algorithm suggests `List.IsPrefix.reverse_prefix_reverse`, which becomes `List.IsPrefix.reverse`.
|
||||
|
||||
The following examples show how the traversal order often matters.
|
||||
|
||||
```lean
|
||||
theorem Nat.mul_zero (n : Nat) : n * 0 = 0 := sorry
|
||||
theorem Nat.zero_mul (n : Nat) : 0 * n = 0 := sorry
|
||||
```
|
||||
|
||||
Here we see that one name may be a prefix of another name:
|
||||
|
||||
```lean
|
||||
theorem Int.mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 := sorry
|
||||
theorem Int.mul_ne_zero_iff {a b : Int} : a * b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := sorry
|
||||
```
|
||||
|
||||
It is usually a good idea to include the `iff` in a theorem name even if the name would still be unique without the name. For example,
|
||||
|
||||
```lean
|
||||
theorem List.head?_eq_none_iff : l.head? = none ↔ l = [] := sorry
|
||||
```
|
||||
|
||||
is a good name: if the lemma was simply called `List.head?_eq_none`, users might try to `apply` it when the goal is `l.head? = none`, leading
|
||||
to confusion.
|
||||
|
||||
The more common you expect (or want) a theorem to be, the shorter you should try to make the name. For example, we have both
|
||||
|
||||
```lean
|
||||
theorem Std.HashMap.getElem?_eq_none_of_contains_eq_false {a : α} : m.contains a = false → m[a]? = none := sorry
|
||||
theorem Std.HashMap.getElem?_eq_none {a : α} : ¬a ∈ m → m[a]? = none := sorry
|
||||
```
|
||||
|
||||
As users of the hash map are encouraged to use ∈ rather than contains, the second lemma gets the shorter name.
|
||||
|
||||
## Special cases
|
||||
|
||||
There are certain special “keywords” that may appear in identifiers.
|
||||
|
||||
| Keyword | Meaning | Example |
|
||||
| :---- | :---- | :---- |
|
||||
| `def` | Unfold a definition. Avoid this for public APIs. | `Nat.max_def` |
|
||||
| `refl` | Theorems of the form `a R a`, where R is a reflexive relation and `a` is an explicit parameter | `Nat.le_refl` |
|
||||
| `rfl` | Like `refl`, but with `a` implicit | `Nat.le_rfl` |
|
||||
| `irrefl` | Theorems of the form `¬a R a`, where R is an irreflexive relation | `Nat.lt_irrefl` |
|
||||
| `symm` | Theorems of the form `a R b → b R a`, where R is a symmetric relation (compare `comm` below) | `Eq.symm` |
|
||||
| `trans` | Theorems of the form `a R b → b R c → a R c`, where R is a transitive relation (R may carry data) | `Eq.trans` |
|
||||
| `antisymmm` | Theorems of the form `a R b → b R a → a = b`, where R is an antisymmetric relation | `Nat.le_antisymm` |
|
||||
| `congr` | Theorems of the form `a R b → f a S f b`, where R and S are usually equivalence relations | `Std.HashMap.mem_congr` |
|
||||
| `comm` | Theorems of the form `f a b = f b a` (compare `symm` above) | `Eq.comm`, `Nat.add_comm` |
|
||||
| `assoc` | Theorems of the form `g (f a b) c = f a (g b c)` (note the order! In most cases, we have f = g) | `Nat.add_sub_assoc` |
|
||||
| `distrib` | Theorems of the form `f (g a b) = g (f a) (f b)` | `Nat.add_left_distrib` |
|
||||
| `self` | May be used if a variable appears multiple times in the conclusion | `List.mem_cons_self` |
|
||||
| `inj` | Theorems of the form `f a = f b ↔ a = b`. | `Int.neg_inj`, `Nat.add_left_inj` |
|
||||
| `cancel` | Theorems which have one of the forms `f a = f b → a = b` or `g (f a) = a`, where `f` and `g` usually involve a binary operator | `Nat.add_sub_cancel` |
|
||||
| `cancel_iff` | Same as `inj`, but with different conventions for left and right (see below) | `Nat.add_right_cancel_iff` |
|
||||
| `ext` | Theorems of the form `f a = f b → a = b`, where `f` usually involves some kind of projection | `List.ext_getElem`
|
||||
| `mono` | Theorems of the form `a R b → f a R f b`, where `R` is a transitive relation | `List.countP_mono_left`
|
||||
|
||||
### Left and right
|
||||
|
||||
The keywords left and right are useful to disambiguate symmetric variants of theorems.
|
||||
|
||||
```lean
|
||||
theorem imp_congr_left (h : a ↔ b) : (a → c) ↔ (b → c) := sorry
|
||||
theorem imp_congr_right (h : a → (b ↔ c)) : (a → b) ↔ (a → c) := sorry
|
||||
```
|
||||
|
||||
It is not always obvious which version of a theorem should be “left” and which should be “right”.
|
||||
Heuristically, the theorem should name the side which is “more variable”, but there are exceptions. For some of the special keywords discussed in this section, there are conventions which should be followed, as laid out in the following examples:
|
||||
|
||||
```lean
|
||||
theorem Nat.left_distrib (n m k : Nat) : n * (m + k) = n * m + n * k := sorry
|
||||
theorem Nat.right_distrib (n m k : Nat) : (n + m) * k = n * k + m * k := sorry
|
||||
theorem Nat.add_left_cancel {n m k : Nat} : n + m = n + k → m = k := sorry
|
||||
theorem Nat.add_right_cancel {n m k : Nat} : n + m = k + m → n = k := sorry
|
||||
theorem Nat.add_left_cancel_iff {m k n : Nat} : n + m = n + k ↔ m = k := sorry
|
||||
theorem Nat.add_right_cancel_iff {m k n : Nat} : m + n = k + n ↔ m = k := sorry
|
||||
theorem Nat.add_left_inj {m k n : Nat} : m + n = k + n ↔ m = k := sorry
|
||||
theorem Nat.add_right_inj {m k n : Nat} : n + m = n + k ↔ m = k := sorry
|
||||
```
|
||||
|
||||
Note in particular that the convention is opposite for `cancel_iff` and `inj`.
|
||||
|
||||
```lean
|
||||
theorem Nat.add_sub_self_left (a b : Nat) : (a + b) - a = b := sorry
|
||||
theorem Nat.add_sub_self_right (a b : Nat) : (a + b) - b = a := sorry
|
||||
theorem Nat.add_sub_cancel (n m : Nat) : (n + m) - m = n := sorry
|
||||
```
|
||||
|
||||
## Primed names
|
||||
|
||||
Avoid disambiguating variants of a concept by appending the `'` character (e.g., introducing both `BitVec.sshiftRight` and `BitVec.sshiftRight'`), as it is impossible to tell the difference without looking at the type signature, the documentation or even the code, and even if you know what the two variants are there is no way to tell which is which. Prefer descriptive pairs `BitVec.sshiftRightNat`/`BitVec.sshiftRight`.
|
||||
|
||||
## Acronyms
|
||||
|
||||
For acronyms which are three letters or shorter, all letters should use the same case as dictated by the convention. For example, `IO` is a correct name for a type and the name `IO.Ref` may become `IORef` when used as part of a definition name and `ioRef` when used as part of a theorem name.
|
||||
|
||||
For acronyms which are at least four letters long, switch to lower case starting from the second letter. For example, `Json` is a correct name for a type, as is `JsonRPC`.
|
||||
|
||||
If an acronym is typically spelled using mixed case, this mixed spelling may be used in identifiers (for example `Std.Net.IPv4Addr`).
|
||||
|
||||
## Simp sets
|
||||
|
||||
Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to
|
||||
`Nat`, should be called `bitvec_to_nat`.
|
||||
|
||||
## Variable names
|
||||
|
||||
We make the following recommendations for variable names, but without insisting on them:
|
||||
* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc.
|
||||
* Another common name for a simple hypothesis is `w` (for "witness").
|
||||
* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc.
|
||||
(Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.)
|
||||
`xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`.
|
||||
A list of lists may be named `L`.
|
||||
* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`.
|
||||
An array of arrays may be named `xss`.
|
||||
* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`.
|
||||
A vector of vectors may be named `xss`.
|
||||
* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function.
|
||||
* `i`, `j`, `k` are preferred for numerical indices.
|
||||
Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability.
|
||||
* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`.
|
||||
* `w` is preferred for the width of a `BitVec`.
|
||||
522
doc/std/style.md
522
doc/std/style.md
@@ -1,522 +0,0 @@
|
||||
# Standard library style
|
||||
|
||||
Please take some time to familiarize yourself with the stylistic conventions of
|
||||
the project and the specific part of the library you are planning to contribute
|
||||
to. While the Lean compiler may not enforce strict formatting rules,
|
||||
consistently formatted code is much easier for others to read and maintain.
|
||||
Attention to formatting is more than a cosmetic concern—it reflects the same
|
||||
level of precision and care required to meet the deeper standards of the Lean 4
|
||||
standard library.
|
||||
|
||||
Below we will give specific formatting prescriptions for various language constructs. Note that this style guide only applies to the Lean standard library, even though some examples in the guide are taken from other parts of the Lean code base.
|
||||
|
||||
## Basic whitespace rules
|
||||
|
||||
Syntactic elements (like `:`, `:=`, `|`, `::`) are surrounded by single spaces, with the exception of `,` and `;`, which are followed by a space but not preceded by one. Delimiters (like `()`, `{}`) do not have spaces on the inside, with the exceptions of subtype notation and structure instance notation.
|
||||
|
||||
Examples of correctly formatted function parameters:
|
||||
|
||||
* `{α : Type u}`
|
||||
* `[BEq α]`
|
||||
* `(cmp : α → α → Ordering)`
|
||||
* `(hab : a = b)`
|
||||
* `{d : { l : List ((n : Nat) × Vector Nat n) // l.length % 2 = 0 }}`
|
||||
|
||||
Examples of correctly formatted terms:
|
||||
|
||||
* `1 :: [2, 3]`
|
||||
* `letI : Ord α := ⟨cmp⟩; True`
|
||||
* `(⟨2, 3⟩ : Nat × Nat)`
|
||||
* `((2, 3) : Nat × Nat)`
|
||||
* `{ x with fst := f (4 + f 0), snd := 4, .. }`
|
||||
* `match 1 with | 0 => 0 | _ => 0`
|
||||
* `fun ⟨a, b⟩ _ _ => by cases hab <;> apply id; rw [hbc]`
|
||||
|
||||
Configure your editor to remove trailing whitespace. If you have set up Visual Studio Code for Lean development in the recommended way then the correct setting is applied automatically.
|
||||
|
||||
## Splitting terms across multiple lines
|
||||
|
||||
When splitting a term across multiple lines, increase indentation by two spaces starting from the second line. When splitting a function application, try to split at argument boundaries. If an argument itself needs to be split, increase indentation further as appropriate.
|
||||
|
||||
When splitting at an infix operator, the operator goes at the end of the first line, not at the beginning of the second line. When splitting at an infix operator, you may or may not increase indentation depth, depending on what is more readable.
|
||||
|
||||
When splitting an `if`-`then`-`else` expression, the `then` keyword wants to stay with the condition and the `else` keyword wants to stay with the alternative term. Otherwise, indent as if the `if` and `else` keywords were arguments to the same function.
|
||||
|
||||
When splitting a comma-separated bracketed sequence (i.e., anonymous constructor application, list/array/vector literal, tuple) it is allowed to indent subsequent lines for alignment, but indenting by two spaces is also allowed.
|
||||
|
||||
Do not orphan parentheses.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def MacroScopesView.isPrefixOf (v₁ v₂ : MacroScopesView) : Bool :=
|
||||
v₁.name.isPrefixOf v₂.name &&
|
||||
v₁.scopes == v₂.scopes &&
|
||||
v₁.mainModule == v₂.mainModule &&
|
||||
v₁.imported == v₂.imported
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eraseP_eq_iff {p} {l : List α} :
|
||||
l.eraseP p = l' ↔
|
||||
((∀ a ∈ l, ¬ p a) ∧ l = l') ∨
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧
|
||||
l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ :=
|
||||
sorry
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat :=
|
||||
functionWithAVeryLongNameSoThatSomeArgumentsWillNotFit firstArgument secondArgument
|
||||
(firstArgumentWithAnEquallyLongNameAndThatFunctionDoesHaveMoreArguments firstArgument
|
||||
secondArgument)
|
||||
secondArgument
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem size_alter [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} (h : m.WF) :
|
||||
(m.alter k f).size =
|
||||
if m.contains k && (f (m.get? k)).isNone then
|
||||
m.size - 1
|
||||
else if !m.contains k && (f (m.get? k)).isSome then
|
||||
m.size + 1
|
||||
else
|
||||
m.size := by
|
||||
simp_to_raw using Raw₀.size_alter
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem get?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} (h : m.WF) :
|
||||
(m.alter k f).get? k' =
|
||||
if h : k == k' then
|
||||
cast (congrArg (Option ∘ β) (eq_of_beq h)) (f (m.get? k))
|
||||
else m.get? k' := by
|
||||
simp_to_raw using Raw₀.get?_alter
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat × Nat :=
|
||||
⟨imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Nat × Nat :=
|
||||
⟨imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
example : Vector Nat :=
|
||||
#v[imagineThisWasALongTerm,
|
||||
imagineThisWasAnotherLongTerm]
|
||||
```
|
||||
|
||||
## Basic file structure
|
||||
|
||||
Every file should start with a copyright header, imports (in the standard library, this always includes a `prelude` declaration) and a module documentation string. There should not be a blank line between the copyright header and the imports. There should be a blank line between the imports and the module documentation string.
|
||||
|
||||
If you explicitly declare universe variables, do so at the top of the file, after the module documentation.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro,
|
||||
Yury Kudryashov
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Pairwise
|
||||
import Init.Data.List.Find
|
||||
|
||||
/-!
|
||||
**# Lemmas about `List.eraseP` and `List.erase`.**
|
||||
-/
|
||||
|
||||
universe u u'
|
||||
```
|
||||
|
||||
Syntax that is not supposed to be user-facing must be scoped. New public syntax must always be discussed explicitly in an RFC.
|
||||
|
||||
## Top-level commands and declarations
|
||||
|
||||
All top-level commands are unindented. Sectioning commands like `section` and `namespace` do not increase the indentation level.
|
||||
|
||||
Attributes may be placed on the same line as the rest of the command or on a separate line.
|
||||
|
||||
Multi-line declaration headers are indented by four spaces starting from the second line. The colon that indicates the type of a declaration may not be placed at the start of a line or on its own line.
|
||||
|
||||
Declaration bodies are indented by two spaces. Short declaration bodies may be placed on the same line as the declaration type.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eraseP_eq_iff {p} {l : List α} :
|
||||
l.eraseP p = l' ↔
|
||||
((∀ a ∈ l, ¬ p a) ∧ l = l') ∨
|
||||
∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧
|
||||
l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ :=
|
||||
sorry
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp]
|
||||
theorem eraseP_nil : [].eraseP p = [] := rfl
|
||||
```
|
||||
|
||||
### Documentation comments
|
||||
|
||||
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
|
||||
|
||||
Declarations should be documented as required by the `docBlame` linter, which may be activated in a file using
|
||||
`set_option linter.missingDocs true` (we allow these to stay in the file).
|
||||
|
||||
Single-line documentation comments should go on the same line as `/--`/`-/`, while multi-line documentation strings
|
||||
should have these delimiters on their own line, with the documentation comment itself unindented.
|
||||
|
||||
Documentation comments must be written in the indicative mood. Use American orthography.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/-- Carries out a monadic action on each mapping in the hash map in some order. -/
|
||||
@[inline] def forM (f : (a : α) → β a → m PUnit) (b : Raw α β) : m PUnit :=
|
||||
b.buckets.forM (AssocList.forM f)
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
/--
|
||||
Monadically computes a value by folding the given function over the mappings in the hash
|
||||
map in some order.
|
||||
-/
|
||||
@[inline] def foldM (f : δ → (a : α) → β a → m δ) (init : δ) (b : Raw α β) : m δ :=
|
||||
b.buckets.foldlM (fun acc l => l.foldlM f acc) init
|
||||
```
|
||||
|
||||
### Where clauses
|
||||
|
||||
The `where` keyword should be unindented, and all declarations bound by it should be indented with two spaces.
|
||||
|
||||
Blank lines before and after `where` and between declarations bound by `where` are optional and should be chosen
|
||||
to maximize readability.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[simp] theorem partition_eq_filter_filter (p : α → Bool) (l : List α) :
|
||||
partition p l = (filter p l, filter (not ∘ p) l) := by
|
||||
simp [partition, aux]
|
||||
where
|
||||
aux (l) {as bs} : partition.loop p l (as, bs) =
|
||||
(as.reverse ++ filter p l, bs.reverse ++ filter (not ∘ p) l) :=
|
||||
match l with
|
||||
| [] => by simp [partition.loop, filter]
|
||||
| a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc]
|
||||
```
|
||||
|
||||
### Termination arguments
|
||||
|
||||
The `termination_by`, `decreasing_by`, `partial_fixpoint` keywords should be unindented. The associated terms should be indented like declaration bodies.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
@[inline] def multiShortOption (handle : Char → m PUnit) (opt : String) : m PUnit := do
|
||||
let rec loop (p : String.Pos) := do
|
||||
if h : opt.atEnd p then
|
||||
return
|
||||
else
|
||||
handle (opt.get' p h)
|
||||
loop (opt.next' p h)
|
||||
termination_by opt.utf8ByteSize - p.byteIdx
|
||||
decreasing_by
|
||||
simp [String.atEnd] at h
|
||||
apply Nat.sub_lt_sub_left h
|
||||
simp [String.lt_next opt p]
|
||||
loop ⟨1⟩
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool :=
|
||||
off1.byteIdx + sz ≤ s1.endPos.byteIdx && off2.byteIdx + sz ≤ s2.endPos.byteIdx && loop off1 off2 { byteIdx := off1.byteIdx + sz }
|
||||
where
|
||||
loop (off1 off2 stop1 : Pos) :=
|
||||
if _h : off1.byteIdx < stop1.byteIdx then
|
||||
let c₁ := s1.get off1
|
||||
let c₂ := s2.get off2
|
||||
c₁ == c₂ && loop (off1 + c₁) (off2 + c₂) stop1
|
||||
else true
|
||||
termination_by stop1.1 - off1.1
|
||||
decreasing_by
|
||||
have := Nat.sub_lt_sub_left _h (Nat.add_lt_add_left c₁.utf8Size_pos off1.1)
|
||||
decreasing_tactic
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by
|
||||
rw [div_eq, mod_eq]
|
||||
have h : Decidable (0 < n ∧ n ≤ m) := inferInstance
|
||||
cases h with
|
||||
| isFalse h => simp [h]
|
||||
| isTrue h =>
|
||||
simp [h]
|
||||
have ih := div_add_mod (m - n) n
|
||||
rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2]
|
||||
decreasing_by apply div_rec_lemma; assumption
|
||||
```
|
||||
|
||||
### Deriving
|
||||
|
||||
The `deriving` clause should be unindented.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
structure Iterator where
|
||||
array : ByteArray
|
||||
idx : Nat
|
||||
deriving Inhabited
|
||||
```
|
||||
|
||||
## Notation and Unicode
|
||||
|
||||
We generally prefer to use notation as available. We usually prefer the Unicode versions of notations over non-Unicode alternatives.
|
||||
|
||||
There are some rules and exceptions regarding specific notations which are listed below:
|
||||
|
||||
* Sigma types: use `(a : α) × β a` instead of `Σ a, β a` or `Sigma β`.
|
||||
* Function arrows: use `fun a => f x` instead of `fun x ↦ f x` or `λ x => f x` or any other variant.
|
||||
|
||||
## Language constructs
|
||||
|
||||
### Pattern matching, induction etc.
|
||||
|
||||
Match arms are indented at the indentation level that the match statement would have if it was on its own line. If the match is implicit, then the arms should be indented as if the match was explicitly given. The content of match arms is indented two spaces, so that it appears on the same level as the match pattern.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def alter [BEq α] {β : Type v} (a : α) (f : Option β → Option β) :
|
||||
AssocList α (fun _ => β) → AssocList α (fun _ => β)
|
||||
| nil => match f none with
|
||||
| none => nil
|
||||
| some b => AssocList.cons a b nil
|
||||
| cons k v l =>
|
||||
if k == a then
|
||||
match f v with
|
||||
| none => l
|
||||
| some b => cons a b l
|
||||
else
|
||||
cons k v (alter a f l)
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
|
||||
∃ as bs, xs = as ++ a :: bs ∧ a ∉ as := by
|
||||
induction xs with
|
||||
| nil => cases h
|
||||
| cons x xs ih =>
|
||||
simp at h
|
||||
cases h with
|
||||
| inl h => exact ⟨[], xs, by simp_all⟩
|
||||
| inr h =>
|
||||
by_cases h' : a = x
|
||||
· subst h'
|
||||
exact ⟨[], xs, by simp⟩
|
||||
· obtain ⟨as, bs, rfl, h⟩ := ih h
|
||||
exact ⟨x :: as, bs, rfl, by simp_all⟩
|
||||
```
|
||||
|
||||
Aligning match arms is allowed, but not required.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) :=
|
||||
match h₁?, h₂? with
|
||||
| none, none => return none
|
||||
| none, some h => return h
|
||||
| some h, none => return h
|
||||
| some h₁, some h₂ => mkEqTrans h₁ h₂
|
||||
```
|
||||
|
||||
### Structures
|
||||
|
||||
Note to external contributors: this is a section where the Lean style and the mathlib style are different.
|
||||
|
||||
When using structure instance syntax over multiple lines, the opening brace should go on the preceding line, while the closing brace should go on its own line. The rest of the syntax should be indented by one level. During structure updates, the `with` clause goes on the same line as the opening brace. Aligning at the assignment symbol is allowed but not required.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true) :
|
||||
IO AddConstAsyncResult := do
|
||||
let sigPromise ← IO.Promise.new
|
||||
let infoPromise ← IO.Promise.new
|
||||
let extensionsPromise ← IO.Promise.new
|
||||
let checkedEnvPromise ← IO.Promise.new
|
||||
let asyncConst := {
|
||||
constInfo := {
|
||||
name := constName
|
||||
kind
|
||||
sig := sigPromise.result
|
||||
constInfo := infoPromise.result
|
||||
}
|
||||
exts? := guard reportExts *> some extensionsPromise.result
|
||||
}
|
||||
return {
|
||||
constName, kind
|
||||
mainEnv := { env with
|
||||
asyncConsts := env.asyncConsts.add asyncConst
|
||||
checked := checkedEnvPromise.result }
|
||||
asyncEnv := { env with
|
||||
asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes }
|
||||
}
|
||||
sigPromise, infoPromise, extensionsPromise, checkedEnvPromise
|
||||
}
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
instance [Inhabited α] : Inhabited (Descr α β σ) where
|
||||
default := {
|
||||
name := default
|
||||
mkInitial := default
|
||||
ofOLeanEntry := default
|
||||
toOLeanEntry := default
|
||||
addEntry := fun s _ => s
|
||||
}
|
||||
```
|
||||
|
||||
### Declaring structures
|
||||
|
||||
When defining structure types, do not parenthesize structure fields.
|
||||
|
||||
When declaring a structure type with a custom constructor name, put the custom name on its own line, indented like the
|
||||
structure fields, and add a documentation comment.
|
||||
|
||||
Correct:
|
||||
|
||||
```lean
|
||||
/--
|
||||
A bitvector of the specified width.
|
||||
|
||||
This is represented as the underlying `Nat` number in both the runtime
|
||||
and the kernel, inheriting all the special support for `Nat`.
|
||||
-/
|
||||
structure BitVec (w : Nat) where
|
||||
/--
|
||||
Constructs a `BitVec w` from a number less than `2^w`.
|
||||
O(1), because we use `Fin` as the internal representation of a bitvector.
|
||||
-/
|
||||
ofFin ::
|
||||
/--
|
||||
Interprets a bitvector as a number less than `2^w`.
|
||||
O(1), because we use `Fin` as the internal representation of a bitvector.
|
||||
-/
|
||||
toFin : Fin (2 ^ w)
|
||||
```
|
||||
|
||||
## Tactic proofs
|
||||
|
||||
Tactic proofs are the most common thing to break during any kind of upgrade, so it is important to write them in a way that minimizes the likelihood of proofs breaking and that makes it easy to debug breakages if they do occur.
|
||||
|
||||
If there are multiple goals, either use a tactic combinator (like `all_goals`) to operate on all of them or a clearly specified subset, or use focus dots to work on goals one at a time. Using structured proofs (e.g., `induction … with`) is encouraged but not mandatory.
|
||||
|
||||
Squeeze non-terminal `simp`s (i.e., calls to `simp` which do not close the goal). Squeezing terminal `simp`s is generally discouraged, although there are exceptions (for example if squeezing yields a noticeable performance improvement).
|
||||
|
||||
Do not over-golf proofs in ways that are likely to lead to hard-to-debug breakage. Examples of things to avoid include complex multi-goal manipulation using lots of tactic combinators, complex uses of the substitution operator (`▸`) and clever point-free expressions (possibly involving anonymous function notation for multiple arguments).
|
||||
|
||||
Do not under-golf proofs: for routine tasks, use the most powerful tactics available.
|
||||
|
||||
Do not use `erw`. Avoid using `rfl` after `simp` or `rw`, as this usually indicates a missing lemma that should be used instead of `rfl`.
|
||||
|
||||
Use `(d)simp` or `rw` instead of `delta` or `unfold`. Use `refine` instead of `refine’`. Use `haveI` and `letI` only if they are actually required.
|
||||
|
||||
Prefer highly automated tactics (like `grind` and `omega`) over low-level proofs, unless the automated tactic requires unacceptable additional imports or has bad performance. If you decide against using a highly automated tactic, leave a comment explaining the decision.
|
||||
|
||||
## `do` notation
|
||||
|
||||
The `do` keyword goes on the same line as the corresponding `:=` (or `=>`, or similar). `Id.run do` should be treated as if it was a bare `do`.
|
||||
|
||||
Use early `return` statements to reduce nesting depth and make the non-exceptional control flow of a function easier to see.
|
||||
|
||||
Alternatives for `let` matches may be placed in the same line or in the next line, indented by two spaces. If the term that is
|
||||
being matched on is itself more than one line and there is an alternative present, consider breaking immediately after `←` and indent
|
||||
as far as necessary to ensure readability.
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ← findFunDecl? fvarId | throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ←
|
||||
findFunDecl? fvarId
|
||||
| throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do
|
||||
let some decl ← findFunDecl?
|
||||
fvarId
|
||||
| throwError "unknown local function {fvarId.name}"
|
||||
return decl
|
||||
```
|
||||
|
||||
Correct:
|
||||
```lean
|
||||
def tagUntaggedGoals (parentTag : Name) (newSuffix : Name) (newGoals : List MVarId) : TacticM Unit := do
|
||||
let mctx ← getMCtx
|
||||
let mut numAnonymous := 0
|
||||
for g in newGoals do
|
||||
if mctx.isAnonymousMVar g then
|
||||
numAnonymous := numAnonymous + 1
|
||||
modifyMCtx fun mctx => Id.run do
|
||||
let mut mctx := mctx
|
||||
let mut idx := 1
|
||||
for g in newGoals do
|
||||
if mctx.isAnonymousMVar g then
|
||||
if numAnonymous == 1 then
|
||||
mctx := mctx.setMVarUserName g parentTag
|
||||
else
|
||||
mctx := mctx.setMVarUserName g (parentTag ++ newSuffix.appendIndexAfter idx)
|
||||
idx := idx + 1
|
||||
pure mctx
|
||||
```
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
# The Lean 4 standard library
|
||||
|
||||
Maintainer team (in alphabetical order): Henrik Böving, Markus Himmel
|
||||
(community contact & external contribution coordinator), Kim Morrison, Paul
|
||||
Reichert, Sofia Rodrigues.
|
||||
|
||||
The Lean 4 standard library is a core part of the Lean distribution, providing
|
||||
essential building blocks for functional programming, verified software
|
||||
development, and software verification. Unlike the standard libraries of most
|
||||
other languages, many of its components are formally verified and can be used
|
||||
as part of verified applications.
|
||||
|
||||
The standard library is a public API that contains the components listed in the
|
||||
standard library outline below. Not all public APIs in the Lean distribution
|
||||
are part of the standard library, and the standard library does not correspond
|
||||
to a certain directory within the Lean source repository (like `Std`). For
|
||||
example, the metaprogramming framework is not part of the standard library, but
|
||||
basic types like `True` and `Nat` are.
|
||||
|
||||
The standard library is under active development. Our guiding principles are:
|
||||
|
||||
* Provide comprehensive, verified building blocks for real-world software.
|
||||
* Build a public API of the highest quality with excellent internal consistency.
|
||||
* Carefully optimize components that may be used in performance-critical software.
|
||||
* Ensure smooth adoption and maintenance for users.
|
||||
* Offer excellent documentation, example projects, and guides.
|
||||
* Provide a reliable and extensible basis that libraries for software
|
||||
development, software verification and mathematics can build on.
|
||||
|
||||
The standard library is principally developed by the Lean FRO. Community
|
||||
contributions are welcome. If you would like to contribute, please refer to the
|
||||
call for contributions below.
|
||||
|
||||
### Standard library outline
|
||||
|
||||
1. Core types and operations
|
||||
1. Basic types
|
||||
2. Numeric types, including floating point numbers
|
||||
3. Containers
|
||||
4. Strings and formatting
|
||||
2. Language constructs
|
||||
1. Ranges and iterators
|
||||
2. Comparison, ordering, hashing and related type classes
|
||||
3. Basic monad infrastructure
|
||||
3. Libraries
|
||||
1. Random numbers
|
||||
2. Dates and times
|
||||
4. Operating system abstractions
|
||||
1. Concurrency and parallelism primitives
|
||||
2. Asynchronous I/O
|
||||
3. FFI helpers
|
||||
4. Environment, file system, processes
|
||||
5. Locales
|
||||
|
||||
The material covered in the first three sections (core types and operations,
|
||||
language constructs and libraries) will be verified, with the exception of
|
||||
floating point numbers and the parts of the libraries that interface with the
|
||||
operating system (e.g., sources of operating system randomness or time zone
|
||||
database access).
|
||||
|
||||
### Call for contributions
|
||||
|
||||
Thank you for taking interest in contributing to the Lean standard library\!
|
||||
There are two main ways for community members to contribute to the Lean
|
||||
standard library: by contributing experience reports or by contributing code
|
||||
and lemmas.
|
||||
|
||||
**If you are using Lean for software verification or verified software
|
||||
development:** hearing about your experiences using Lean and its standard
|
||||
library for software verification is extremely valuable to us. We are committed
|
||||
to building a standard library suitable for real-world applications and your
|
||||
input will directly influence the continued evolution of the Lean standard
|
||||
library. Please reach out to the standard library maintainer team via Zulip
|
||||
(either in a public thread in the \#lean4 channel or via direct message). Even
|
||||
just a link to your code helps. Thanks\!
|
||||
|
||||
**If you have code that you believe could enhance the Lean 4 standard
|
||||
library:** we encourage you to initiate a discussion in the \#lean4 channel on
|
||||
Zulip. This is the most effective way to receive preliminary feedback on your
|
||||
contribution. The Lean standard library has a very precise scope and it has
|
||||
very high quality standards, so at the moment we are mostly interested in
|
||||
contributions that expand upon existing material rather than introducing novel
|
||||
concepts.
|
||||
|
||||
**If you would like to contribute code to the standard library but don’t know
|
||||
what to work on:** we are always excited to meet motivated community members
|
||||
who would like to contribute, and there is always impactful work that is
|
||||
suitable for new contributors. Please reach out to Markus Himmel on Zulip to
|
||||
discuss possible contributions.
|
||||
|
||||
As laid out in the [project-wide External Contribution
|
||||
Guidelines](../../CONTRIBUTING.md),
|
||||
PRs are much more likely to be merged if they are preceded by an RFC or if you
|
||||
discussed your planned contribution with a member of the standard library
|
||||
maintainer team. When in doubt, introducing yourself is always a good idea.
|
||||
|
||||
All code in the standard library is expected to strictly adhere to the
|
||||
[standard library coding conventions](./style.md).
|
||||
@@ -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=''"
|
||||
|
||||
@@ -3,32 +3,6 @@ import sys
|
||||
import subprocess
|
||||
import requests
|
||||
|
||||
def check_gh_auth():
|
||||
"""Check if GitHub CLI is properly authenticated."""
|
||||
try:
|
||||
result = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
return False, result.stderr
|
||||
return True, None
|
||||
except FileNotFoundError:
|
||||
return False, "GitHub CLI (gh) is not installed. Please install it first."
|
||||
except Exception as e:
|
||||
return False, f"Error checking authentication: {e}"
|
||||
|
||||
def handle_gh_error(error_output):
|
||||
"""Handle GitHub CLI errors and provide helpful messages."""
|
||||
if "Not Found (HTTP 404)" in error_output:
|
||||
return "Repository not found or access denied. Please check:\n" \
|
||||
"1. The repository name is correct\n" \
|
||||
"2. You have access to the repository\n" \
|
||||
"3. Your GitHub CLI authentication is valid"
|
||||
elif "Bad credentials" in error_output or "invalid" in error_output.lower():
|
||||
return "Authentication failed. Please run 'gh auth login' to re-authenticate."
|
||||
elif "rate limit" in error_output.lower():
|
||||
return "GitHub API rate limit exceeded. Please try again later."
|
||||
else:
|
||||
return f"GitHub API error: {error_output}"
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
print("Usage: ./push_repo_release_tag.py <repo> <branch> <version_tag>")
|
||||
@@ -40,13 +14,6 @@ def main():
|
||||
print(f"Error: Branch '{branch}' is not 'master' or 'main'.")
|
||||
sys.exit(1)
|
||||
|
||||
# Check GitHub CLI authentication first
|
||||
auth_ok, auth_error = check_gh_auth()
|
||||
if not auth_ok:
|
||||
print(f"Authentication error: {auth_error}")
|
||||
print("\nTo fix this, run: gh auth login")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the `lean-toolchain` file content
|
||||
lean_toolchain_url = f"https://raw.githubusercontent.com/{repo}/{branch}/lean-toolchain"
|
||||
try:
|
||||
@@ -76,23 +43,12 @@ def main():
|
||||
for tag in existing_tags:
|
||||
print(tag.replace("refs/tags/", ""))
|
||||
sys.exit(1)
|
||||
elif list_tags_output.returncode != 0:
|
||||
# Handle API errors when listing tags
|
||||
error_msg = handle_gh_error(list_tags_output.stderr)
|
||||
print(f"Error checking existing tags: {error_msg}")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the SHA of the branch
|
||||
get_sha_cmd = [
|
||||
"gh", "api", f"repos/{repo}/git/ref/heads/{branch}", "--jq", ".object.sha"
|
||||
]
|
||||
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True)
|
||||
|
||||
if sha_result.returncode != 0:
|
||||
error_msg = handle_gh_error(sha_result.stderr)
|
||||
print(f"Error getting branch SHA: {error_msg}")
|
||||
sys.exit(1)
|
||||
|
||||
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True, check=True)
|
||||
sha = sha_result.stdout.strip()
|
||||
|
||||
# Create the tag
|
||||
@@ -102,20 +58,11 @@ def main():
|
||||
"-F", f"ref=refs/tags/{version_tag}",
|
||||
"-F", f"sha={sha}"
|
||||
]
|
||||
create_result = subprocess.run(create_tag_cmd, capture_output=True, text=True)
|
||||
|
||||
if create_result.returncode != 0:
|
||||
error_msg = handle_gh_error(create_result.stderr)
|
||||
print(f"Error creating tag: {error_msg}")
|
||||
sys.exit(1)
|
||||
subprocess.run(create_tag_cmd, capture_output=True, text=True, check=True)
|
||||
|
||||
print(f"Successfully created and pushed tag '{version_tag}' to {repo}.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = handle_gh_error(e.stderr.strip() if e.stderr else str(e))
|
||||
print(f"Error while creating/pushing tag: {error_msg}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
print(f"Error while creating/pushing tag: {e.stderr.strip() if e.stderr else e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -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 {}
|
||||
@@ -231,43 +214,6 @@ def get_next_version(version):
|
||||
# Next version is always .0
|
||||
return f"v{major}.{minor + 1}.0"
|
||||
|
||||
def get_latest_nightly_tag(github_token):
|
||||
"""Get the most recent nightly tag from leanprover/lean4-nightly."""
|
||||
api_url = "https://api.github.com/repos/leanprover/lean4-nightly/tags"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
if response.status_code != 200:
|
||||
return None
|
||||
tags = response.json()
|
||||
if not tags:
|
||||
return None
|
||||
# Return the most recent tag name
|
||||
return tags[0]['name']
|
||||
|
||||
def update_lean_toolchain_in_branch(org_repo, branch, toolchain_content, github_token):
|
||||
"""Update the lean-toolchain file in a specific branch."""
|
||||
api_url = f"https://api.github.com/repos/{org_repo}/contents/lean-toolchain"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
|
||||
# First get the current file to get its SHA
|
||||
response = requests.get(f"{api_url}?ref={branch}", headers=headers)
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
current_file = response.json()
|
||||
file_sha = current_file['sha']
|
||||
|
||||
# Update the file
|
||||
update_data = {
|
||||
"message": f"chore: update lean-toolchain to {toolchain_content}",
|
||||
"content": base64.b64encode(toolchain_content.encode('utf-8')).decode('utf-8'),
|
||||
"sha": file_sha,
|
||||
"branch": branch
|
||||
}
|
||||
|
||||
response = requests.put(api_url, json=update_data, headers=headers)
|
||||
return response.status_code in [200, 201]
|
||||
|
||||
def check_bump_branch_toolchain(url, bump_branch, github_token):
|
||||
"""Check if the lean-toolchain file in bump branch starts with either 'leanprover/lean4:nightly-' or the next version."""
|
||||
content = get_branch_content(url, bump_branch, "lean-toolchain", github_token)
|
||||
@@ -299,61 +245,6 @@ def pr_exists_with_title(repo_url, title, github_token):
|
||||
return pr['number'], pr['html_url']
|
||||
return None
|
||||
|
||||
def check_proofwidgets4_release(repo_url, target_toolchain, github_token):
|
||||
"""Check if ProofWidgets4 has a release tag that uses the target toolchain."""
|
||||
api_base = repo_url.replace("https://github.com/", "https://api.github.com/repos/")
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
|
||||
# Get all tags matching v0.0.* pattern
|
||||
response = requests.get(f"{api_base}/git/matching-refs/tags/v0.0.", headers=headers)
|
||||
if response.status_code != 200:
|
||||
print(f" ❌ Could not fetch ProofWidgets4 tags")
|
||||
return False
|
||||
|
||||
tags = response.json()
|
||||
if not tags:
|
||||
print(f" ❌ No v0.0.* tags found for ProofWidgets4")
|
||||
return False
|
||||
|
||||
# Extract tag names and sort by version number (descending)
|
||||
tag_names = []
|
||||
for tag in tags:
|
||||
ref = tag['ref']
|
||||
if ref.startswith('refs/tags/v0.0.'):
|
||||
tag_name = ref.replace('refs/tags/', '')
|
||||
try:
|
||||
# Extract the number after v0.0.
|
||||
version_num = int(tag_name.split('.')[-1])
|
||||
tag_names.append((version_num, tag_name))
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
if not tag_names:
|
||||
print(f" ❌ No valid v0.0.* tags found for ProofWidgets4")
|
||||
return False
|
||||
|
||||
# Sort by version number (descending) and take the most recent 10
|
||||
tag_names.sort(reverse=True)
|
||||
recent_tags = tag_names[:10]
|
||||
|
||||
# Check each recent tag to see if it uses the target toolchain
|
||||
for version_num, tag_name in recent_tags:
|
||||
toolchain_content = get_branch_content(repo_url, tag_name, "lean-toolchain", github_token)
|
||||
if toolchain_content is None:
|
||||
continue
|
||||
|
||||
if is_version_gte(toolchain_content.strip(), target_toolchain):
|
||||
print(f" ✅ Found release {tag_name} using compatible toolchain (>= {target_toolchain})")
|
||||
return True
|
||||
|
||||
# If we get here, no recent release uses the target toolchain
|
||||
# Find the highest version number to suggest the next one
|
||||
highest_version = max(version_num for version_num, _ in recent_tags)
|
||||
next_version = highest_version + 1
|
||||
print(f" ❌ No recent ProofWidgets4 release uses toolchain >= {target_toolchain}")
|
||||
print(f" You will need to create and push a tag v0.0.{next_version}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Check release status of Lean4 repositories")
|
||||
parser.add_argument("toolchain", help="The toolchain version to check (e.g., v4.6.0)")
|
||||
@@ -395,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")
|
||||
@@ -478,12 +361,6 @@ def main():
|
||||
continue
|
||||
print(f" ✅ On compatible toolchain (>= {toolchain})")
|
||||
|
||||
# Special handling for ProofWidgets4
|
||||
if name == "ProofWidgets4":
|
||||
if not check_proofwidgets4_release(url, toolchain, github_token):
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
if check_tag:
|
||||
tag_exists_initially = tag_exists(url, toolchain, github_token)
|
||||
if not tag_exists_initially:
|
||||
@@ -492,7 +369,7 @@ def main():
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ⮕ Tag {toolchain} does not exist. Running `script/push_repo_release_tag.py {org_repo} {branch} {toolchain}`...")
|
||||
print(f" … Tag {toolchain} does not exist. Running `script/push_repo_release_tag.py {org_repo} {branch} {toolchain}`...")
|
||||
|
||||
# Run the script to create the tag
|
||||
subprocess.run(["script/push_repo_release_tag.py", org_repo, branch, toolchain])
|
||||
@@ -515,7 +392,7 @@ def main():
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ⮕ Tag {toolchain} is not merged into stable. Running `script/merge_remote.py {org_repo} stable {toolchain}`...")
|
||||
print(f" … Tag {toolchain} is not merged into stable. Running `script/merge_remote.py {org_repo} stable {toolchain}`...")
|
||||
|
||||
# Run the script to merge the tag
|
||||
subprocess.run(["script/merge_remote.py", org_repo, "stable", toolchain])
|
||||
@@ -532,49 +409,19 @@ def main():
|
||||
if check_bump:
|
||||
next_version = get_next_version(toolchain)
|
||||
bump_branch = f"bump/{next_version}"
|
||||
|
||||
# For mathlib4, use the nightly-testing fork for bump branches
|
||||
bump_org_repo = org_repo
|
||||
bump_url = url
|
||||
if name == "mathlib4":
|
||||
bump_org_repo = "leanprover-community/mathlib4-nightly-testing"
|
||||
bump_url = "https://github.com/leanprover-community/mathlib4-nightly-testing"
|
||||
|
||||
branch_created = False
|
||||
if not branch_exists(bump_url, bump_branch, github_token):
|
||||
if not branch_exists(url, bump_branch, github_token):
|
||||
if args.dry_run:
|
||||
latest_nightly = get_latest_nightly_tag(github_token)
|
||||
nightly_note = f" (will set lean-toolchain to {latest_nightly})" if name in ["batteries", "mathlib4"] and latest_nightly else ""
|
||||
print(f" ❌ Bump branch {bump_branch} does not exist. Run `gh api -X POST /repos/{bump_org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)` to create it{nightly_note}.")
|
||||
print(f" ❌ Bump branch {bump_branch} does not exist. Run `gh api -X POST /repos/{org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)` to create it.")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
print(f" ⮕ Bump branch {bump_branch} does not exist. Creating it...")
|
||||
result = run_command(f"gh api -X POST /repos/{bump_org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)", check=False)
|
||||
print(f" … Bump branch {bump_branch} does not exist. Creating it...")
|
||||
result = run_command(f"gh api -X POST /repos/{org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)", check=False)
|
||||
if result.returncode != 0:
|
||||
print(f" ❌ Failed to create bump branch {bump_branch}")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
branch_created = True
|
||||
|
||||
print(f" ✅ Bump branch {bump_branch} exists")
|
||||
|
||||
# For batteries and mathlib4, update the lean-toolchain to the latest nightly
|
||||
if branch_created and name in ["batteries", "mathlib4"]:
|
||||
latest_nightly = get_latest_nightly_tag(github_token)
|
||||
if latest_nightly:
|
||||
nightly_toolchain = f"leanprover/lean4:{latest_nightly}"
|
||||
print(f" ⮕ Updating lean-toolchain to {nightly_toolchain}...")
|
||||
if update_lean_toolchain_in_branch(bump_org_repo, bump_branch, nightly_toolchain, github_token):
|
||||
print(f" ✅ Updated lean-toolchain to {nightly_toolchain}")
|
||||
else:
|
||||
print(f" ❌ Failed to update lean-toolchain to {nightly_toolchain}")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ❌ Could not fetch latest nightly tag")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
if not check_bump_branch_toolchain(bump_url, bump_branch, github_token):
|
||||
if not check_bump_branch_toolchain(url, bump_branch, github_token):
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Execute release steps for Lean4 repositories.
|
||||
Generate release steps script for Lean4 repositories.
|
||||
|
||||
This script helps automate the release process for Lean4 and its dependent repositories
|
||||
by actually executing the step-by-step instructions for updating toolchains, creating tags,
|
||||
by generating step-by-step instructions for updating toolchains, creating tags,
|
||||
and managing branches.
|
||||
|
||||
Usage:
|
||||
@@ -12,11 +12,11 @@ Usage:
|
||||
|
||||
Arguments:
|
||||
version: The version to set in the lean-toolchain file (e.g., v4.6.0)
|
||||
repo: The repository name as specified in release_repos.yml
|
||||
repo: A substring of the repository name as specified in release_repos.yml
|
||||
|
||||
Example:
|
||||
python3 release_steps.py v4.6.0 mathlib4
|
||||
python3 release_steps.py v4.6.0 batteries
|
||||
python3 release_steps.py v4.6.0 mathlib
|
||||
python3 release_steps.py v4.6.0 batt
|
||||
|
||||
The script reads repository configurations from release_repos.yml in the same directory.
|
||||
Each repository may have specific requirements for:
|
||||
@@ -32,124 +32,23 @@ import yaml
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Color functions for terminal output
|
||||
def blue(text):
|
||||
"""Blue text for 'I'm doing something' messages."""
|
||||
return f"\033[94m{text}\033[0m"
|
||||
|
||||
def green(text):
|
||||
"""Green text for 'successful step' messages."""
|
||||
return f"\033[92m{text}\033[0m"
|
||||
|
||||
def red(text):
|
||||
"""Red text for 'this looks bad' messages."""
|
||||
return f"\033[91m{text}\033[0m"
|
||||
|
||||
def yellow(text):
|
||||
"""Yellow text for warnings."""
|
||||
return f"\033[93m{text}\033[0m"
|
||||
|
||||
def run_command(cmd, cwd=None, check=True, stream_output=False):
|
||||
"""Run a shell command and return the result."""
|
||||
print(blue(f"Running: {cmd}"))
|
||||
try:
|
||||
if stream_output:
|
||||
# Stream output in real-time for long-running commands
|
||||
result = subprocess.run(cmd, shell=True, cwd=cwd, check=check, text=True)
|
||||
return result
|
||||
else:
|
||||
# Capture output for commands where we need to process the result
|
||||
result = subprocess.run(cmd, shell=True, cwd=cwd, check=check,
|
||||
capture_output=True, text=True)
|
||||
if result.stdout:
|
||||
# Command output in plain white (default terminal color)
|
||||
print(result.stdout)
|
||||
return result
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red(f"Error running command: {cmd}"))
|
||||
print(red(f"Exit code: {e.returncode}"))
|
||||
if not stream_output:
|
||||
print(f"Stdout: {e.stdout}")
|
||||
print(f"Stderr: {e.stderr}")
|
||||
raise
|
||||
|
||||
def load_repos_config(file_path):
|
||||
with open(file_path, "r") as f:
|
||||
return yaml.safe_load(f)["repositories"]
|
||||
|
||||
def find_repo(repo_name, config):
|
||||
matching_repos = [r for r in config if r["name"] == repo_name]
|
||||
def find_repo(repo_substring, config):
|
||||
pattern = re.compile(re.escape(repo_substring), re.IGNORECASE)
|
||||
matching_repos = [r for r in config if pattern.search(r["name"])]
|
||||
if not matching_repos:
|
||||
print(red(f"Error: No repository named '{repo_name}' found in configuration."))
|
||||
available_repos = [r["name"] for r in config]
|
||||
print(yellow(f"Available repositories: {', '.join(available_repos)}"))
|
||||
print(f"Error: No repository matching '{repo_substring}' found in configuration.")
|
||||
sys.exit(1)
|
||||
if len(matching_repos) > 1:
|
||||
print(f"Error: Multiple repositories matching '{repo_substring}' found in configuration: {', '.join(r['name'] for r in matching_repos)}")
|
||||
sys.exit(1)
|
||||
return matching_repos[0]
|
||||
|
||||
def setup_downstream_releases_dir():
|
||||
"""Create the downstream_releases directory if it doesn't exist."""
|
||||
downstream_dir = Path("downstream_releases")
|
||||
if not downstream_dir.exists():
|
||||
print(blue(f"Creating {downstream_dir} directory..."))
|
||||
downstream_dir.mkdir()
|
||||
print(green(f"Created {downstream_dir} directory"))
|
||||
return downstream_dir
|
||||
|
||||
def clone_or_update_repo(repo_url, repo_dir, downstream_dir):
|
||||
"""Clone the repository if it doesn't exist, or update it if it does."""
|
||||
repo_path = downstream_dir / repo_dir
|
||||
|
||||
if repo_path.exists():
|
||||
print(blue(f"Repository {repo_dir} already exists, updating..."))
|
||||
run_command("git fetch", cwd=repo_path)
|
||||
print(green(f"Updated repository {repo_dir}"))
|
||||
else:
|
||||
print(blue(f"Cloning {repo_url} to {repo_path}..."))
|
||||
run_command(f"git clone {repo_url}", cwd=downstream_dir)
|
||||
print(green(f"Cloned repository {repo_dir}"))
|
||||
|
||||
return repo_path
|
||||
|
||||
def get_remotes_for_repo(repo_name):
|
||||
"""Get the appropriate remotes for bump and nightly-testing branches based on repository."""
|
||||
if repo_name == "mathlib4":
|
||||
return "nightly-testing", "nightly-testing"
|
||||
else:
|
||||
return "origin", "origin"
|
||||
|
||||
def check_and_abort_merge(repo_path):
|
||||
"""Check if repository is in the middle of a merge and abort it if so."""
|
||||
merge_head_file = repo_path / ".git" / "MERGE_HEAD"
|
||||
|
||||
if merge_head_file.exists():
|
||||
print(yellow(f"Repository {repo_path.name} is in the middle of a merge. Aborting merge..."))
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
print(green("Merge aborted successfully"))
|
||||
return True
|
||||
|
||||
# Also check git status for other merge-related states
|
||||
try:
|
||||
result = run_command("git status --porcelain=v1", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
# Check for unmerged paths (indicated by 'UU', 'AA', etc. in git status)
|
||||
for line in result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
print(yellow(f"Repository {repo_path.name} has unmerged paths. Aborting merge..."))
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
print(green("Merge aborted successfully"))
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
# If git status fails, we'll let the main process handle it
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def execute_release_steps(repo, version, config):
|
||||
def generate_script(repo, version, config):
|
||||
repo_config = find_repo(repo, config)
|
||||
repo_name = repo_config['name']
|
||||
repo_url = repo_config['url']
|
||||
@@ -160,481 +59,91 @@ def execute_release_steps(repo, version, config):
|
||||
requires_tagging = repo_config.get("toolchain-tag", True)
|
||||
has_stable_branch = repo_config.get("stable-branch", True)
|
||||
|
||||
# Setup downstream releases directory
|
||||
downstream_dir = setup_downstream_releases_dir()
|
||||
|
||||
# Clone or update the repository
|
||||
repo_path = clone_or_update_repo(repo_url, repo_dir, downstream_dir)
|
||||
|
||||
# Special remote setup for mathlib4
|
||||
if repo_name == "mathlib4":
|
||||
print(blue("Setting up special remotes for mathlib4..."))
|
||||
try:
|
||||
# Check if nightly-testing remote already exists
|
||||
result = run_command("git remote get-url nightly-testing", cwd=repo_path, check=False)
|
||||
if result.returncode != 0:
|
||||
# Add the nightly-testing remote
|
||||
run_command("git remote add nightly-testing https://github.com/leanprover-community/mathlib4-nightly-testing.git", cwd=repo_path)
|
||||
print(green("Added nightly-testing remote"))
|
||||
else:
|
||||
print(green("nightly-testing remote already exists"))
|
||||
|
||||
# Fetch from the nightly-testing remote
|
||||
run_command("git fetch nightly-testing", cwd=repo_path)
|
||||
print(green("Fetched from nightly-testing remote"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red(f"Error setting up mathlib4 remotes: {e}"))
|
||||
print(yellow("Continuing with default remote setup..."))
|
||||
|
||||
print(blue(f"\n=== Executing release steps for {repo_name} ==="))
|
||||
|
||||
# Check if repository is in the middle of a merge and abort it if necessary
|
||||
check_and_abort_merge(repo_path)
|
||||
|
||||
# Execute the release steps
|
||||
run_command(f"git checkout {default_branch} && git pull", cwd=repo_path)
|
||||
|
||||
# Special rc1 safety check for batteries and mathlib4 (before creating any branches)
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"] and version.endswith('-rc1'):
|
||||
print(blue("This repo has nightly-testing infrastructure"))
|
||||
print(blue(f"Checking if nightly-testing can be safely merged into bump/{version.split('-rc')[0]}..."))
|
||||
|
||||
# Get the base version (e.g., v4.6.0 from v4.6.0-rc1)
|
||||
base_version = version.split('-rc')[0]
|
||||
bump_branch = f"bump/{base_version}"
|
||||
|
||||
# Determine which remote to use for bump and nightly-testing branches
|
||||
bump_remote, nightly_remote = get_remotes_for_repo(repo_name)
|
||||
|
||||
try:
|
||||
# Fetch latest changes from the appropriate remote
|
||||
run_command(f"git fetch {bump_remote}", cwd=repo_path)
|
||||
|
||||
# Check if the bump branch exists
|
||||
result = run_command(f"git show-ref --verify --quiet refs/remotes/{bump_remote}/{bump_branch}", cwd=repo_path, check=False)
|
||||
if result.returncode != 0:
|
||||
print(red(f"Bump branch {bump_remote}/{bump_branch} does not exist. Cannot perform safety check."))
|
||||
print(yellow("Please ensure the bump branch exists before proceeding."))
|
||||
return
|
||||
|
||||
# Create a temporary branch for testing the merge
|
||||
temp_branch = f"temp-merge-test-{base_version}"
|
||||
|
||||
# Clean up any existing temp branch from previous runs
|
||||
result = run_command(f"git show-ref --verify --quiet refs/heads/{temp_branch}", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
print(blue(f"Cleaning up existing temp branch {temp_branch}..."))
|
||||
# Make sure we're not on the temp branch before deleting it
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
print(green(f"Deleted existing temp branch {temp_branch}"))
|
||||
|
||||
run_command(f"git checkout -b {temp_branch} {bump_remote}/{bump_branch}", cwd=repo_path)
|
||||
|
||||
# Try to merge nightly-testing
|
||||
try:
|
||||
run_command(f"git merge {nightly_remote}/nightly-testing", cwd=repo_path)
|
||||
|
||||
# Check what files have changed compared to the bump branch
|
||||
changed_files = run_command(f"git diff --name-only {bump_remote}/{bump_branch}..HEAD", cwd=repo_path)
|
||||
|
||||
# Filter out allowed changes
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in changed_files.stdout.strip().split('\n'):
|
||||
if file.strip(): # Skip empty lines
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
# Clean up temporary branch and return to default branch
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
|
||||
if problematic_files:
|
||||
print(red("❌ Safety check failed!"))
|
||||
print(red(f"Merging nightly-testing into {bump_branch} would result in changes to:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(yellow("\nYou need to make a PR merging the changes from nightly-testing into the bump branch first."))
|
||||
print(yellow(f"Create a PR from nightly-testing targeting {bump_branch} to resolve these changes."))
|
||||
return
|
||||
else:
|
||||
print(green("✅ Safety check passed - only lean-toolchain and/or lake-manifest.json would change"))
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge failed, checking which files are affected..."))
|
||||
|
||||
# Get all changed files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
changed_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if line.strip(): # Skip empty lines
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
changed_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in changed_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are changes in non-allowed files - fail the safety check
|
||||
# First abort the merge to clean up the conflicted state
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
print(red("❌ Safety check failed!"))
|
||||
print(red(f"Merging nightly-testing into {bump_branch} would result in changes to:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(yellow("\nYou need to make a PR merging the changes from nightly-testing into the bump branch first."))
|
||||
print(yellow(f"Create a PR from nightly-testing targeting {bump_branch} to resolve these changes."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are changed - resolve them and continue
|
||||
print(green(f"✅ Only allowed files changed: {', '.join(changed_files)}"))
|
||||
print(blue("Resolving conflicts by taking nightly-testing version..."))
|
||||
|
||||
# For each changed allowed file, take the nightly-testing version
|
||||
for file in changed_files:
|
||||
run_command(f"git checkout --theirs {file}", cwd=repo_path)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Safety check passed - changes only in allowed files"))
|
||||
|
||||
# Clean up temporary branch and return to default branch
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Ensure we're back on the default branch even if setup failed
|
||||
try:
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
except subprocess.CalledProcessError:
|
||||
print(red(f"Cannot return to {default_branch} branch. Repository is in an inconsistent state."))
|
||||
print(red("Please manually check the repository state and fix any issues."))
|
||||
return
|
||||
print(red(f"Error during safety check: {e}"))
|
||||
print(yellow("Skipping safety check and proceeding with normal merge..."))
|
||||
|
||||
# Check if the branch already exists
|
||||
branch_name = f"bump_to_{version}"
|
||||
try:
|
||||
# Check if branch exists locally
|
||||
result = run_command(f"git show-ref --verify --quiet refs/heads/{branch_name}", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
print(blue(f"Branch {branch_name} already exists, checking it out..."))
|
||||
run_command(f"git checkout {branch_name}", cwd=repo_path)
|
||||
print(green(f"Checked out existing branch {branch_name}"))
|
||||
else:
|
||||
print(blue(f"Creating new branch {branch_name}..."))
|
||||
run_command(f"git checkout -b {branch_name}", cwd=repo_path)
|
||||
print(green(f"Created new branch {branch_name}"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(blue(f"Creating new branch {branch_name}..."))
|
||||
run_command(f"git checkout -b {branch_name}", cwd=repo_path)
|
||||
print(green(f"Created new branch {branch_name}"))
|
||||
|
||||
# Update lean-toolchain
|
||||
print(blue("Updating lean-toolchain file..."))
|
||||
toolchain_file = repo_path / "lean-toolchain"
|
||||
with open(toolchain_file, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated lean-toolchain to leanprover/lean4:{version}"))
|
||||
script_lines = [
|
||||
f"cd {repo_dir}",
|
||||
"git fetch",
|
||||
f"git checkout {default_branch} && git pull",
|
||||
f"git checkout -b bump_to_{version}",
|
||||
f"echo leanprover/lean4:{version} > lean-toolchain",
|
||||
]
|
||||
|
||||
# Special cases for specific repositories
|
||||
if repo_name == "repl":
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
mathlib_test_dir = repo_path / "test" / "Mathlib"
|
||||
run_command(f'perl -pi -e \'s/rev = "v\\d+\\.\\d+\\.\\d+(-rc\\d+)?"/rev = "{version}"/g\' lakefile.toml', cwd=mathlib_test_dir)
|
||||
|
||||
# Update lean-toolchain in test/Mathlib
|
||||
print(blue("Updating test/Mathlib/lean-toolchain..."))
|
||||
mathlib_toolchain = mathlib_test_dir / "lean-toolchain"
|
||||
with open(mathlib_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated test/Mathlib/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=mathlib_test_dir, stream_output=True)
|
||||
try:
|
||||
result = run_command("./test.sh", cwd=repo_path, stream_output=True, check=False)
|
||||
if result.returncode == 0:
|
||||
print(green("Tests completed successfully"))
|
||||
else:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test exit code: {result.returncode}"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
script_lines.extend([
|
||||
"lake update",
|
||||
"cd test/Mathlib",
|
||||
f"perl -pi -e 's/rev = \"v\\d+\\.\\d+\\.\\d+(-rc\\d+)?\"/rev = \"{version}\"/g' lakefile.toml",
|
||||
f"echo leanprover/lean4:{version} > lean-toolchain",
|
||||
"lake update",
|
||||
"cd ../..",
|
||||
"./test.sh"
|
||||
])
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
script_lines.append('perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*')
|
||||
script_lines.append("lake update")
|
||||
|
||||
# Commit changes (only if there are changes)
|
||||
print(blue("Checking for changes to commit..."))
|
||||
try:
|
||||
# Check if there are any changes to commit (staged or unstaged)
|
||||
result = run_command("git status --porcelain", cwd=repo_path, check=False)
|
||||
if result.stdout.strip(): # There are changes
|
||||
print(blue("Committing changes..."))
|
||||
run_command(f'git commit -am "chore: bump toolchain to {version}"', cwd=repo_path)
|
||||
print(green(f"Committed changes: chore: bump toolchain to {version}"))
|
||||
else:
|
||||
print(green("No changes to commit - toolchain already up to date"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(yellow("Failed to check for changes, attempting commit anyway..."))
|
||||
try:
|
||||
run_command(f'git commit -am "chore: bump toolchain to {version}"', cwd=repo_path)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if "nothing to commit" in e.stderr:
|
||||
print(green("No changes to commit - toolchain already up to date"))
|
||||
else:
|
||||
raise
|
||||
script_lines.append("")
|
||||
|
||||
script_lines.extend([
|
||||
f'git commit -am "chore: bump toolchain to {version}"',
|
||||
""
|
||||
])
|
||||
|
||||
# Handle special merging cases
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"]:
|
||||
print(blue("This repo uses `bump/v4.X.0` branches for reviewed content from nightly-testing."))
|
||||
|
||||
# Determine which remote to use for bump branches
|
||||
bump_remote, nightly_remote = get_remotes_for_repo(repo_name)
|
||||
|
||||
# Fetch latest changes to ensure we have the most up-to-date bump branch
|
||||
print(blue(f"Fetching latest changes from {bump_remote}..."))
|
||||
run_command(f"git fetch {bump_remote}", cwd=repo_path)
|
||||
|
||||
try:
|
||||
print(blue(f"Merging {bump_remote}/bump/{version.split('-rc')[0]}..."))
|
||||
run_command(f"git merge {bump_remote}/bump/{version.split('-rc')[0]}", cwd=repo_path)
|
||||
print(green("Merge completed successfully"))
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge conflicts detected, checking which files are affected..."))
|
||||
|
||||
# Get conflicted files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
conflicted_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
conflicted_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in conflicted_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are conflicts in non-allowed files - fail
|
||||
print(red("❌ Merge failed!"))
|
||||
print(red(f"Merging {bump_remote}/bump/{version.split('-rc')[0]} resulted in conflicts in:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(red("Please resolve these conflicts manually."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are conflicted - resolve them automatically
|
||||
print(green(f"✅ Only allowed files conflicted: {', '.join(conflicted_files)}"))
|
||||
print(blue("Resolving conflicts automatically..."))
|
||||
|
||||
# Overwrite lean-toolchain with our target version
|
||||
if 'lean-toolchain' in conflicted_files:
|
||||
print(blue(f"Overwriting lean-toolchain with target version {version}"))
|
||||
toolchain_file = repo_path / "lean-toolchain"
|
||||
with open(toolchain_file, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
|
||||
# For other allowed files, take our version (since we want our changes)
|
||||
for file in conflicted_files:
|
||||
if file != 'lean-toolchain':
|
||||
run_command(f"git checkout --ours {file}", cwd=repo_path)
|
||||
|
||||
# Run lake update to rebuild lake-manifest.json
|
||||
print(blue("Running lake update to rebuild lake-manifest.json..."))
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Merge completed successfully with automatic conflict resolution"))
|
||||
|
||||
elif re.search(r'rc\d+$', version):
|
||||
# For all other repos with rc versions, merge nightly-testing
|
||||
if repo_name in ["verso", "reference-manual"]:
|
||||
print(yellow("This repo does development on nightly-testing: remember to rebase merge the PR."))
|
||||
|
||||
# Fetch latest changes to ensure we have the most up-to-date nightly-testing branch
|
||||
print(blue("Fetching latest changes from origin..."))
|
||||
run_command("git fetch origin", cwd=repo_path)
|
||||
|
||||
try:
|
||||
print(blue("Merging origin/nightly-testing..."))
|
||||
run_command("git merge origin/nightly-testing", cwd=repo_path)
|
||||
print(green("Merge completed successfully"))
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge conflicts detected, checking which files are affected..."))
|
||||
|
||||
# Get conflicted files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
conflicted_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
conflicted_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in conflicted_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are conflicts in non-allowed files - fail
|
||||
print(red("❌ Merge failed!"))
|
||||
print(red(f"Merging nightly-testing resulted in conflicts in:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(red("Please resolve these conflicts manually."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are conflicted - resolve them automatically
|
||||
print(green(f"✅ Only allowed files conflicted: {', '.join(conflicted_files)}"))
|
||||
print(blue("Resolving conflicts automatically..."))
|
||||
|
||||
# For lean-toolchain and lake-manifest.json, keep our versions
|
||||
for file in conflicted_files:
|
||||
print(blue(f"Keeping our version of {file}"))
|
||||
run_command(f"git checkout --ours {file}", cwd=repo_path)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Merge completed successfully with automatic conflict resolution"))
|
||||
script_lines.extend([
|
||||
"echo 'This repo has nightly-testing infrastructure'",
|
||||
f"git merge origin/bump/{version.split('-rc')[0]}",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
""
|
||||
])
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
|
||||
script_lines.extend([
|
||||
"echo 'This repo does development on nightly-testing: remember to rebase merge the PR.'",
|
||||
f"git merge origin/nightly-testing",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
""
|
||||
])
|
||||
if repo_name != "Mathlib":
|
||||
script_lines.extend([
|
||||
"lake build && if lake check-test; then lake test; fi",
|
||||
""
|
||||
])
|
||||
|
||||
# Build and test (skip for Mathlib)
|
||||
if repo_name not in ["mathlib4"]:
|
||||
print(blue("Building project..."))
|
||||
|
||||
# Clean lake cache for a fresh build
|
||||
print(blue("Cleaning lake cache..."))
|
||||
run_command("rm -rf .lake", cwd=repo_path)
|
||||
|
||||
try:
|
||||
run_command("lake build", cwd=repo_path, stream_output=True)
|
||||
print(green("Build completed successfully"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Build failed, but continuing with PR creation..."))
|
||||
print(red(f"Build error: {e}"))
|
||||
|
||||
# Check if lake check-test exists before running tests
|
||||
print(blue("Running tests..."))
|
||||
check_test_result = run_command("lake check-test", cwd=repo_path, check=False)
|
||||
if check_test_result.returncode == 0:
|
||||
try:
|
||||
run_command("lake test", cwd=repo_path, stream_output=True)
|
||||
print(green("Tests completed successfully"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
else:
|
||||
print(yellow("lake check-test reports that there is no test suite"))
|
||||
script_lines.extend([
|
||||
'gh pr create --title "chore: bump toolchain to ' + version + '" --body ""',
|
||||
"echo 'Please review the PR and merge or rebase it.'",
|
||||
""
|
||||
])
|
||||
|
||||
# Push the branch to remote before creating PR
|
||||
print(blue("Checking remote branch status..."))
|
||||
try:
|
||||
# Check if branch exists on remote
|
||||
result = run_command(f"git ls-remote --heads origin {branch_name}", cwd=repo_path, check=False)
|
||||
if not result.stdout.strip():
|
||||
print(blue(f"Pushing branch {branch_name} to remote..."))
|
||||
run_command(f"git push -u origin {branch_name}", cwd=repo_path)
|
||||
print(green(f"Successfully pushed branch {branch_name} to remote"))
|
||||
else:
|
||||
print(blue(f"Branch {branch_name} already exists on remote, pushing any new commits..."))
|
||||
run_command(f"git push", cwd=repo_path)
|
||||
print(green("Successfully pushed commits to remote"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(red("Failed to push branch to remote. Please check your permissions and network connection."))
|
||||
print(yellow(f"You may need to run: git push -u origin {branch_name}"))
|
||||
return
|
||||
|
||||
# Create pull request (only if one doesn't already exist)
|
||||
print(blue("Checking for existing pull request..."))
|
||||
try:
|
||||
# Check if PR already exists for this branch
|
||||
result = run_command(f'gh pr list --head {branch_name} --json number', cwd=repo_path, check=False)
|
||||
if result.returncode == 0 and result.stdout.strip() != "[]":
|
||||
print(green(f"Pull request already exists for branch {branch_name}"))
|
||||
# Get the PR URL
|
||||
pr_result = run_command(f'gh pr view {branch_name} --json url', cwd=repo_path, check=False)
|
||||
if pr_result.returncode == 0:
|
||||
pr_data = json.loads(pr_result.stdout)
|
||||
print(green(f"PR URL: {pr_data.get('url', 'N/A')}"))
|
||||
else:
|
||||
# Create new PR
|
||||
print(blue("Creating new pull request..."))
|
||||
run_command(f'gh pr create --title "chore: bump toolchain to {version}" --body ""', cwd=repo_path)
|
||||
print(green("Pull request created successfully!"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(red("Failed to check for existing PR or create new PR."))
|
||||
print(yellow("This could be due to:"))
|
||||
print(yellow("1. GitHub CLI not authenticated"))
|
||||
print(yellow("2. No push permissions to the repository"))
|
||||
print(yellow("3. Network issues"))
|
||||
print(f"Branch: {branch_name}")
|
||||
print(f"Title: chore: bump toolchain to {version}")
|
||||
print(yellow("Please create the PR manually if needed."))
|
||||
return "\n".join(script_lines)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Execute release steps for Lean4 repositories.",
|
||||
description="Generate release steps script for Lean4 repositories.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
%(prog)s v4.6.0 mathlib4 Execute steps for updating Mathlib to v4.6.0
|
||||
%(prog)s v4.6.0 batteries Execute steps for updating Batteries to v4.6.0
|
||||
%(prog)s v4.6.0 mathlib Generate steps for updating Mathlib to v4.6.0
|
||||
%(prog)s v4.6.0 batt Generate steps for updating Batteries to v4.6.0
|
||||
|
||||
The script will:
|
||||
1. Create a downstream_releases/ directory
|
||||
2. Clone or update the target repository
|
||||
3. Update the lean-toolchain file
|
||||
4. Create appropriate branches and commits
|
||||
5. Build and test the project
|
||||
6. Create pull requests
|
||||
The script will generate shell commands to:
|
||||
1. Update the lean-toolchain file
|
||||
2. Create appropriate branches and commits
|
||||
3. Create pull requests
|
||||
|
||||
(Note that the steps of creating toolchain version tags, and merging these into `stable` branches,
|
||||
are handled by `script/release_checklist.py`.)
|
||||
"""
|
||||
)
|
||||
parser.add_argument("version", help="The version to set in the lean-toolchain file (e.g., v4.6.0)")
|
||||
parser.add_argument("repo", help="The repository name as specified in release_repos.yml")
|
||||
parser.add_argument("repo", help="A substring of the repository name as specified in release_repos.yml")
|
||||
args = parser.parse_args()
|
||||
|
||||
config_path = os.path.join(os.path.dirname(__file__), "release_repos.yml")
|
||||
config = load_repos_config(config_path)
|
||||
|
||||
execute_release_steps(args.repo, args.version, config)
|
||||
script = generate_script(args.repo, args.version, config)
|
||||
print(script)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 23)
|
||||
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")
|
||||
|
||||
|
||||
@@ -6,41 +6,40 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Notation
|
||||
public import Init.Tactics
|
||||
public import Init.TacticsExtra
|
||||
public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Core
|
||||
public import Init.Control
|
||||
public import Init.Data.Basic
|
||||
public import Init.WF
|
||||
public import Init.WFTactics
|
||||
public import Init.Data
|
||||
public import Init.System
|
||||
public import Init.Util
|
||||
public import Init.Dynamic
|
||||
public import Init.ShareCommon
|
||||
public import Init.MetaTypes
|
||||
public import Init.Meta
|
||||
public import Init.NotationExtra
|
||||
public import Init.SimpLemmas
|
||||
public import Init.PropLemmas
|
||||
public import Init.Hints
|
||||
public import Init.Conv
|
||||
public import Init.Guard
|
||||
public import Init.Simproc
|
||||
public import Init.SizeOfLemmas
|
||||
public import Init.BinderPredicates
|
||||
public import Init.Ext
|
||||
public import Init.Omega
|
||||
public import Init.MacroTrace
|
||||
public import Init.Grind
|
||||
public import Init.GrindInstances
|
||||
public import Init.While
|
||||
public import Init.Syntax
|
||||
public import Init.Internal
|
||||
public import Init.Try
|
||||
public import Init.BinderNameHint
|
||||
public import Init.Task
|
||||
import Init.Prelude
|
||||
import Init.Notation
|
||||
import Init.Tactics
|
||||
import Init.TacticsExtra
|
||||
import Init.ByCases
|
||||
import Init.RCases
|
||||
import Init.Core
|
||||
import Init.Control
|
||||
import Init.Data.Basic
|
||||
import Init.WF
|
||||
import Init.WFTactics
|
||||
import Init.Data
|
||||
import Init.System
|
||||
import Init.Util
|
||||
import Init.Dynamic
|
||||
import Init.ShareCommon
|
||||
import Init.MetaTypes
|
||||
import Init.Meta
|
||||
import Init.NotationExtra
|
||||
import Init.SimpLemmas
|
||||
import Init.PropLemmas
|
||||
import Init.Hints
|
||||
import Init.Conv
|
||||
import Init.Guard
|
||||
import Init.Simproc
|
||||
import Init.SizeOfLemmas
|
||||
import Init.BinderPredicates
|
||||
import Init.Ext
|
||||
import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
import Init.Internal
|
||||
import Init.Try
|
||||
import Init.BinderNameHint
|
||||
import Init.Task
|
||||
|
||||
@@ -7,10 +7,8 @@ Authors: Joachim Breitner
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Tactics
|
||||
|
||||
public section
|
||||
import Init.Prelude
|
||||
import Init.Tactics
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
/--
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Gabriel Ebner
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
|
||||
public section
|
||||
import Init.NotationExtra
|
||||
|
||||
namespace Lean
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Classical
|
||||
|
||||
public section
|
||||
import Init.Classical
|
||||
|
||||
/-! # by_cases tactic and if-then-else support -/
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.PropLemmas
|
||||
|
||||
public section
|
||||
import Init.PropLemmas
|
||||
|
||||
universe u v
|
||||
|
||||
@@ -47,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 =>
|
||||
@@ -109,8 +107,8 @@ noncomputable def epsilon {α : Sort u} [h : Nonempty α] (p : α → Prop) : α
|
||||
theorem epsilon_spec_aux {α : Sort u} (h : Nonempty α) (p : α → Prop) : (∃ y, p y) → p (@epsilon α h p) :=
|
||||
(strongIndefiniteDescription p h).property
|
||||
|
||||
theorem epsilon_spec {α : Sort u} {p : α → Prop} (hex : ∃ y, p y) : p (@epsilon α hex.nonempty p) :=
|
||||
epsilon_spec_aux hex.nonempty p hex
|
||||
theorem epsilon_spec {α : Sort u} {p : α → Prop} (hex : ∃ y, p y) : p (@epsilon α (nonempty_of_exists hex) p) :=
|
||||
epsilon_spec_aux (nonempty_of_exists hex) p hex
|
||||
|
||||
theorem epsilon_singleton {α : Sort u} (x : α) : @epsilon α ⟨x⟩ (fun y => y = x) = x :=
|
||||
@epsilon_spec α (fun y => y = x) ⟨x, rfl⟩
|
||||
|
||||
@@ -6,10 +6,7 @@ Authors: Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public meta import Init.Prelude
|
||||
|
||||
public section
|
||||
import Init.Prelude
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
/-!
|
||||
|
||||
@@ -6,15 +6,13 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Basic
|
||||
public import Init.Control.State
|
||||
public import Init.Control.StateRef
|
||||
public import Init.Control.Id
|
||||
public import Init.Control.Except
|
||||
public import Init.Control.Reader
|
||||
public import Init.Control.Option
|
||||
public import Init.Control.Lawful
|
||||
public import Init.Control.StateCps
|
||||
public import Init.Control.ExceptCps
|
||||
|
||||
public section
|
||||
import Init.Control.Basic
|
||||
import Init.Control.State
|
||||
import Init.Control.StateRef
|
||||
import Init.Control.Id
|
||||
import Init.Control.Except
|
||||
import Init.Control.Reader
|
||||
import Init.Control.Option
|
||||
import Init.Control.Lawful
|
||||
import Init.Control.StateCps
|
||||
import Init.Control.ExceptCps
|
||||
|
||||
@@ -6,10 +6,8 @@ Author: Leonardo de Moura, Sebastian Ullrich
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.BinderNameHint
|
||||
|
||||
public section
|
||||
import Init.Core
|
||||
import Init.BinderNameHint
|
||||
|
||||
universe u v w
|
||||
|
||||
@@ -51,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
|
||||
|
||||
@@ -6,11 +6,9 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.State
|
||||
public import Init.Control.Except
|
||||
public import Init.Data.ToString.Basic
|
||||
|
||||
public section
|
||||
import Init.Control.State
|
||||
import Init.Control.Except
|
||||
import Init.Data.ToString.Basic
|
||||
universe u v
|
||||
|
||||
namespace EStateM
|
||||
|
||||
@@ -8,11 +8,9 @@ The Except monad transformer.
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Basic
|
||||
public import Init.Control.Id
|
||||
public import Init.Coe
|
||||
|
||||
public section
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Coe
|
||||
|
||||
namespace Except
|
||||
variable {ε : Type u}
|
||||
@@ -138,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
|
||||
|
||||
/--
|
||||
@@ -146,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
|
||||
@@ -156,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)
|
||||
@@ -172,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)
|
||||
@@ -188,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
|
||||
|
||||
@@ -199,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)
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
|
||||
public section
|
||||
import Init.Control.Lawful.Basic
|
||||
|
||||
/-!
|
||||
The Exception monad transformer using CPS style.
|
||||
@@ -27,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))
|
||||
|
||||
@@ -45,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
|
||||
|
||||
@@ -65,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
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ The identity Monad.
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
|
||||
public section
|
||||
import Init.Core
|
||||
|
||||
universe u
|
||||
|
||||
@@ -64,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
|
||||
|
||||
@@ -6,9 +6,6 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.Control.Lawful.Instances
|
||||
public import Init.Control.Lawful.Lemmas
|
||||
public import Init.Control.Lawful.MonadLift
|
||||
|
||||
public section
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.Control.Lawful.Instances
|
||||
import Init.Control.Lawful.Lemmas
|
||||
|
||||
@@ -6,11 +6,8 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Ext
|
||||
public import Init.SimpLemmas
|
||||
public import Init.Meta
|
||||
|
||||
public section
|
||||
import Init.SimpLemmas
|
||||
import Init.Meta
|
||||
|
||||
open Function
|
||||
|
||||
@@ -52,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.
|
||||
@@ -150,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]
|
||||
|
||||
/--
|
||||
@@ -244,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 -/
|
||||
|
||||
@@ -6,13 +6,11 @@ Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import all Init.Control.Except
|
||||
public import all Init.Control.State
|
||||
public import Init.Control.StateRef
|
||||
public import Init.Ext
|
||||
|
||||
public section
|
||||
import Init.Control.Lawful.Basic
|
||||
import all Init.Control.Except
|
||||
import all Init.Control.State
|
||||
import Init.Control.StateRef
|
||||
import Init.Ext
|
||||
|
||||
open Function
|
||||
|
||||
@@ -60,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]
|
||||
@@ -69,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]
|
||||
@@ -208,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
|
||||
|
||||
@@ -6,11 +6,9 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.RCases
|
||||
public import Init.ByCases
|
||||
|
||||
public section
|
||||
import Init.Control.Lawful.Basic
|
||||
import Init.RCases
|
||||
import Init.ByCases
|
||||
|
||||
-- Mapping by a function with a left inverse is injective.
|
||||
theorem map_inj_of_left_inverse [Functor m] [LawfulFunctor m] {f : α → β}
|
||||
|
||||
@@ -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: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.MonadLift.Basic
|
||||
public import Init.Control.Lawful.MonadLift.Lemmas
|
||||
public import Init.Control.Lawful.MonadLift.Instances
|
||||
|
||||
public section
|
||||
@@ -1,54 +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
|
||||
public import Init.Control.Basic
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
# 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,148 +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
|
||||
public import all Init.Control.Option
|
||||
public import all Init.Control.Except
|
||||
public import all Init.Control.ExceptCps
|
||||
public import all Init.Control.StateRef
|
||||
public import all Init.Control.StateCps
|
||||
public import all Init.Control.Id
|
||||
public import Init.Control.Lawful.MonadLift.Lemmas
|
||||
public import Init.Control.Lawful.Instances
|
||||
|
||||
public section
|
||||
|
||||
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,65 +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
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.Control.Lawful.MonadLift.Basic
|
||||
|
||||
public section
|
||||
|
||||
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 _ _
|
||||
@@ -6,11 +6,9 @@ Authors: Leonardo de Moura, Sebastian Ullrich
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Option.Basic
|
||||
public import Init.Control.Basic
|
||||
public import Init.Control.Except
|
||||
|
||||
public section
|
||||
import Init.Data.Option.Basic
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Except
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
|
||||
@@ -8,11 +8,9 @@ The Reader monad transformer for passing immutable State.
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Basic
|
||||
public import Init.Control.Id
|
||||
public import Init.Control.Except
|
||||
|
||||
public section
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Control.Except
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
|
||||
@@ -8,11 +8,9 @@ The State monad transformer.
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Basic
|
||||
public import Init.Control.Id
|
||||
public import Init.Control.Except
|
||||
|
||||
public section
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Control.Except
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@@ -31,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
|
||||
|
||||
@@ -39,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
|
||||
|
||||
@@ -68,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)
|
||||
|
||||
@@ -116,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')
|
||||
|
||||
@@ -135,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)
|
||||
|
||||
@@ -145,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)
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Lawful.Basic
|
||||
|
||||
public section
|
||||
import Init.Control.Lawful.Basic
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@@ -30,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
|
||||
|
||||
@@ -41,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))
|
||||
|
||||
@@ -49,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)
|
||||
|
||||
@@ -74,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)
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ The State monad transformer using IO references.
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.System.ST
|
||||
|
||||
public section
|
||||
import Init.System.ST
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ Notation for operators defined at Prelude.lean
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Tactics
|
||||
public meta import Init.Meta
|
||||
|
||||
public section
|
||||
import Init.Tactics
|
||||
import Init.Meta
|
||||
|
||||
namespace Lean.Parser.Tactic.Conv
|
||||
|
||||
@@ -323,7 +321,7 @@ macro_rules
|
||||
| `(conv| repeat $seq) => `(conv| first | ($seq); repeat $seq | skip)
|
||||
|
||||
/--
|
||||
Extracts `let` and `have` expressions from within the target expression.
|
||||
Extracts `let` and `let_fun` expressions from within the target expression.
|
||||
This is the conv mode version of the `extract_lets` tactic.
|
||||
|
||||
- `extract_lets` extracts all the lets from the target.
|
||||
@@ -336,17 +334,11 @@ See also `lift_lets`, which does not extract lets as local declarations.
|
||||
syntax (name := extractLets) "extract_lets " optConfig (ppSpace colGt (ident <|> hole))* : conv
|
||||
|
||||
/--
|
||||
Lifts `let` and `have` expressions within the target expression as far out as possible.
|
||||
Lifts `let` and `let_fun` expressions within the target expression as far out as possible.
|
||||
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,10 +8,8 @@ notation, basic datatypes and type classes
|
||||
module
|
||||
|
||||
prelude
|
||||
public meta import Init.Prelude
|
||||
public import Init.SizeOf
|
||||
|
||||
public section
|
||||
import Init.Prelude
|
||||
import Init.SizeOf
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
@[expose] section
|
||||
@@ -45,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
|
||||
@@ -97,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
|
||||
|
||||
@@ -120,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.
|
||||
@@ -904,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
|
||||
@@ -949,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
|
||||
|
||||
/--
|
||||
@@ -957,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
|
||||
|
||||
/--
|
||||
@@ -967,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
|
||||
|
||||
/--
|
||||
@@ -984,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₂
|
||||
@@ -992,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}
|
||||
@@ -1021,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
|
||||
@@ -1055,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)
|
||||
@@ -1214,7 +1212,10 @@ abbrev noConfusionEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f :
|
||||
instance : Inhabited Prop where
|
||||
default := True
|
||||
|
||||
deriving instance Inhabited for NonScalar, PNonScalar, True
|
||||
deriving instance Inhabited for NonScalar, PNonScalar, True, ForInStep
|
||||
|
||||
theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : Exists (fun x => p x) → Nonempty α
|
||||
| ⟨w, _⟩ => ⟨w⟩
|
||||
|
||||
/-! # Subsingleton -/
|
||||
|
||||
@@ -1241,7 +1242,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
|
||||
@@ -1388,7 +1389,16 @@ instance Sum.nonemptyLeft [h : Nonempty α] : Nonempty (Sum α β) :=
|
||||
instance Sum.nonemptyRight [h : Nonempty β] : Nonempty (Sum α β) :=
|
||||
Nonempty.elim h (fun b => ⟨Sum.inr b⟩)
|
||||
|
||||
deriving instance DecidableEq for Sum
|
||||
instance {α : Type u} {β : Type v} [DecidableEq α] [DecidableEq β] : DecidableEq (Sum α β) := fun a b =>
|
||||
match a, b with
|
||||
| Sum.inl a, Sum.inl b =>
|
||||
if h : a = b then isTrue (h ▸ rfl)
|
||||
else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h
|
||||
| Sum.inr a, Sum.inr b =>
|
||||
if h : a = b then isTrue (h ▸ rfl)
|
||||
else isFalse fun h' => Sum.noConfusion h' fun h' => absurd h' h
|
||||
| Sum.inr _, Sum.inl _ => isFalse fun h => Sum.noConfusion h
|
||||
| Sum.inl _, Sum.inr _ => isFalse fun h => Sum.noConfusion h
|
||||
|
||||
end
|
||||
|
||||
@@ -1692,7 +1702,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 -/
|
||||
|
||||
@@ -1892,7 +1902,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))
|
||||
|
||||
@@ -2090,7 +2100,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
|
||||
@@ -2254,7 +2264,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)
|
||||
|
||||
/--
|
||||
|
||||
@@ -6,48 +6,43 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Basic
|
||||
public import Init.Data.Nat
|
||||
public import Init.Data.Bool
|
||||
public import Init.Data.BitVec
|
||||
public import Init.Data.Cast
|
||||
public import Init.Data.Char
|
||||
public import Init.Data.String
|
||||
public import Init.Data.List
|
||||
public import Init.Data.Int
|
||||
public import Init.Data.Array
|
||||
public import Init.Data.Array.Subarray.Split
|
||||
public import Init.Data.ByteArray
|
||||
public import Init.Data.FloatArray
|
||||
public import Init.Data.Fin
|
||||
public import Init.Data.UInt
|
||||
public import Init.Data.SInt
|
||||
public import Init.Data.Float
|
||||
public import Init.Data.Float32
|
||||
public import Init.Data.Option
|
||||
public import Init.Data.Ord
|
||||
public import Init.Data.Random
|
||||
public import Init.Data.ToString
|
||||
public import Init.Data.Range
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.OfScientific
|
||||
public import Init.Data.Format
|
||||
public import Init.Data.Stream
|
||||
public import Init.Data.Prod
|
||||
public import Init.Data.AC
|
||||
public import Init.Data.Queue
|
||||
public import Init.Data.Sum
|
||||
public import Init.Data.BEq
|
||||
public import Init.Data.Subtype
|
||||
public import Init.Data.ULift
|
||||
public import Init.Data.PLift
|
||||
public import Init.Data.Zero
|
||||
public import Init.Data.NeZero
|
||||
public import Init.Data.Function
|
||||
public import Init.Data.RArray
|
||||
public import Init.Data.Vector
|
||||
public import Init.Data.Iterators
|
||||
public import Init.Data.Range.Polymorphic
|
||||
public import Init.Data.Slice
|
||||
|
||||
public section
|
||||
import Init.Data.Basic
|
||||
import Init.Data.Nat
|
||||
import Init.Data.Bool
|
||||
import Init.Data.BitVec
|
||||
import Init.Data.Cast
|
||||
import Init.Data.Char
|
||||
import Init.Data.String
|
||||
import Init.Data.List
|
||||
import Init.Data.Int
|
||||
import Init.Data.Array
|
||||
import Init.Data.Array.Subarray.Split
|
||||
import Init.Data.ByteArray
|
||||
import Init.Data.FloatArray
|
||||
import Init.Data.Fin
|
||||
import Init.Data.UInt
|
||||
import Init.Data.SInt
|
||||
import Init.Data.Float
|
||||
import Init.Data.Float32
|
||||
import Init.Data.Option
|
||||
import Init.Data.Ord
|
||||
import Init.Data.Random
|
||||
import Init.Data.ToString
|
||||
import Init.Data.Range
|
||||
import Init.Data.Hashable
|
||||
import Init.Data.OfScientific
|
||||
import Init.Data.Format
|
||||
import Init.Data.Stream
|
||||
import Init.Data.Prod
|
||||
import Init.Data.AC
|
||||
import Init.Data.Queue
|
||||
import Init.Data.Sum
|
||||
import Init.Data.BEq
|
||||
import Init.Data.Subtype
|
||||
import Init.Data.ULift
|
||||
import Init.Data.PLift
|
||||
import Init.Data.Zero
|
||||
import Init.Data.NeZero
|
||||
import Init.Data.Function
|
||||
import Init.Data.RArray
|
||||
import Init.Data.Vector
|
||||
|
||||
@@ -7,10 +7,8 @@ Authors: Dany Fabian
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Classical
|
||||
public import Init.ByCases
|
||||
|
||||
public section
|
||||
import Init.Classical
|
||||
import Init.ByCases
|
||||
|
||||
namespace Lean.Data.AC
|
||||
inductive Expr
|
||||
@@ -211,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 =>
|
||||
@@ -284,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 α}
|
||||
@@ -330,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)
|
||||
|
||||
@@ -6,29 +6,27 @@ Authors: Gabriel Ebner
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.QSort
|
||||
public import Init.Data.Array.BinSearch
|
||||
public import Init.Data.Array.InsertionSort
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.Attach
|
||||
public import Init.Data.Array.BasicAux
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.TakeDrop
|
||||
public import Init.Data.Array.Bootstrap
|
||||
public import Init.Data.Array.GetLit
|
||||
public import Init.Data.Array.MapIdx
|
||||
public import Init.Data.Array.Set
|
||||
public import Init.Data.Array.Monadic
|
||||
public import Init.Data.Array.FinRange
|
||||
public import Init.Data.Array.Perm
|
||||
public import Init.Data.Array.Find
|
||||
public import Init.Data.Array.Lex
|
||||
public import Init.Data.Array.Range
|
||||
public import Init.Data.Array.Erase
|
||||
public import Init.Data.Array.Zip
|
||||
public import Init.Data.Array.InsertIdx
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Array.QSort
|
||||
import Init.Data.Array.BinSearch
|
||||
import Init.Data.Array.InsertionSort
|
||||
import Init.Data.Array.DecidableEq
|
||||
import Init.Data.Array.Mem
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.Array.BasicAux
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.TakeDrop
|
||||
import Init.Data.Array.Bootstrap
|
||||
import Init.Data.Array.GetLit
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Array.Set
|
||||
import Init.Data.Array.Monadic
|
||||
import Init.Data.Array.FinRange
|
||||
import Init.Data.Array.Perm
|
||||
import Init.Data.Array.Find
|
||||
import Init.Data.Array.Lex
|
||||
import Init.Data.Array.Range
|
||||
import Init.Data.Array.Erase
|
||||
import Init.Data.Array.Zip
|
||||
import Init.Data.Array.InsertIdx
|
||||
import Init.Data.Array.Extract
|
||||
|
||||
@@ -6,12 +6,10 @@ Authors: Joachim Breitner, Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Mem
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Count
|
||||
public import all Init.Data.List.Attach
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Mem
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Count
|
||||
import all Init.Data.List.Attach
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -24,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
|
||||
|
||||
@@ -41,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)⟩
|
||||
|
||||
@@ -56,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
|
||||
@@ -70,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]
|
||||
|
||||
@@ -94,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) =
|
||||
@@ -124,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
|
||||
@@ -146,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
|
||||
@@ -193,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
|
||||
|
||||
@@ -257,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] =
|
||||
@@ -271,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
|
||||
@@ -344,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
|
||||
@@ -363,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
|
||||
@@ -402,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
|
||||
@@ -410,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
|
||||
@@ -420,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
|
||||
@@ -428,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 =
|
||||
@@ -437,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
|
||||
@@ -445,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)) ++
|
||||
@@ -460,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
|
||||
@@ -468,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
|
||||
@@ -541,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⟩
|
||||
@@ -550,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]
|
||||
@@ -589,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]
|
||||
@@ -705,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]
|
||||
|
||||
@@ -6,17 +6,15 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.WFTactics
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.GetElem
|
||||
public import all Init.Data.List.ToArrayImpl
|
||||
public import all Init.Data.Array.Set
|
||||
|
||||
public section
|
||||
import Init.WFTactics
|
||||
import Init.Data.Nat.Basic
|
||||
import Init.Data.Fin.Basic
|
||||
import Init.Data.UInt.BasicAux
|
||||
import Init.Data.Repr
|
||||
import Init.Data.ToString.Basic
|
||||
import Init.GetElem
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.Array.Set
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -93,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
|
||||
@@ -115,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
|
||||
@@ -170,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]
|
||||
|
||||
@@ -193,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
|
||||
|
||||
@@ -212,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
|
||||
|
||||
@@ -240,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]
|
||||
@@ -248,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]
|
||||
|
||||
@@ -263,13 +256,15 @@ Examples:
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]`
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]`
|
||||
-/
|
||||
@[extern "lean_array_swap", grind]
|
||||
@[extern "lean_array_swap"]
|
||||
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
|
||||
if h₁ : i < xs.size then
|
||||
if h₂ : j < xs.size then swap xs i j
|
||||
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
|
||||
@@ -291,7 +286,6 @@ Examples:
|
||||
* `#[1, 2].isEmpty = false`
|
||||
* `#[()].isEmpty = false`
|
||||
-/
|
||||
@[expose]
|
||||
def isEmpty (xs : Array α) : Bool :=
|
||||
xs.size = 0
|
||||
|
||||
@@ -333,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.
|
||||
@@ -377,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.
|
||||
@@ -406,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
|
||||
|
||||
@@ -420,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')
|
||||
@@ -435,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
|
||||
@@ -548,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.
|
||||
/--
|
||||
@@ -581,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
|
||||
@@ -648,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
|
||||
@@ -713,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
|
||||
@@ -768,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
|
||||
@@ -790,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
|
||||
|
||||
@@ -836,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
|
||||
@@ -917,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.
|
||||
@@ -1059,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
|
||||
@@ -1076,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.
|
||||
@@ -1087,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
|
||||
|
||||
@@ -1099,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
|
||||
|
||||
@@ -1111,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
|
||||
|
||||
@@ -1124,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
|
||||
@@ -1139,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,
|
||||
@@ -1150,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`.
|
||||
@@ -1161,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)
|
||||
|
||||
@@ -1175,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
|
||||
@@ -1199,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
|
||||
@@ -1235,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
|
||||
@@ -1247,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
|
||||
@@ -1257,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) :=
|
||||
@@ -1311,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.
|
||||
@@ -1365,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`.
|
||||
|
||||
@@ -1380,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`.
|
||||
@@ -1400,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.
|
||||
@@ -1411,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 == ·)
|
||||
|
||||
@@ -1460,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
|
||||
|
||||
@@ -1498,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
|
||||
|
||||
@@ -1511,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
|
||||
|
||||
/--
|
||||
@@ -1524,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
|
||||
@@ -1557,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
|
||||
@@ -1650,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
|
||||
@@ -1670,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
|
||||
@@ -1790,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']
|
||||
@@ -1808,7 +1800,6 @@ Examples:
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
|
||||
-/
|
||||
@[grind]
|
||||
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
|
||||
if h : i < xs.size then xs.eraseIdx i h else xs
|
||||
|
||||
@@ -1884,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.
|
||||
@@ -1904,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.
|
||||
@@ -1919,7 +1914,6 @@ Examples:
|
||||
* `#["tues", "thur", "sat"].insertIdxIfInBounds 3 "wed" = #["tues", "thur", "sat", "wed"]`
|
||||
* `#["tues", "thur", "sat"].insertIdxIfInBounds 4 "wed" = #["tues", "thur", "sat"]`
|
||||
-/
|
||||
@[grind]
|
||||
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertIdx as i a
|
||||
@@ -2027,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.
|
||||
|
||||
@@ -6,11 +6,9 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Nat.Linear
|
||||
public import Init.NotationExtra
|
||||
|
||||
public section
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Linear
|
||||
import Init.NotationExtra
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -90,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
|
||||
|
||||
@@ -6,11 +6,9 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
public import Init.Omega
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Omega
|
||||
universe u v
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
@@ -131,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
|
||||
|
||||
@@ -7,10 +7,8 @@ Authors: Mario Carneiro
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.TakeDrop
|
||||
public import all Init.Data.Array.Basic
|
||||
|
||||
public section
|
||||
import Init.Data.List.TakeDrop
|
||||
import all Init.Data.Array.Basic
|
||||
|
||||
/-!
|
||||
## Bootstrapping theorems about arrays
|
||||
@@ -42,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
|
||||
|
||||
@@ -80,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 α} :
|
||||
@@ -92,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]
|
||||
|
||||
@@ -121,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
|
||||
@@ -145,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
|
||||
|
||||
@@ -6,11 +6,9 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.Count
|
||||
|
||||
public section
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.Count
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.countP` and `Array.count`.
|
||||
@@ -54,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
|
||||
@@ -76,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
|
||||
@@ -107,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 α} :
|
||||
@@ -152,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]
|
||||
|
||||
@@ -179,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
|
||||
@@ -192,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
|
||||
|
||||
@@ -222,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 α]
|
||||
|
||||
@@ -233,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
|
||||
|
||||
@@ -294,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 =
|
||||
|
||||
@@ -6,12 +6,10 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.BEq
|
||||
public import Init.Data.List.Nat.BEq
|
||||
public import Init.ByCases
|
||||
|
||||
public section
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.BEq
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.ByCases
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -25,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'
|
||||
@@ -71,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
|
||||
@@ -102,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
|
||||
|
||||
|
||||
@@ -6,12 +6,10 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Nat.Basic
|
||||
|
||||
public section
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Nat.Basic
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.eraseP`, `Array.erase`, and `Array.eraseIdx`.
|
||||
@@ -26,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⟩
|
||||
@@ -67,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
|
||||
@@ -85,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
|
||||
|
||||
@@ -98,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⟩
|
||||
@@ -127,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⟩
|
||||
@@ -135,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]
|
||||
@@ -175,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⟩
|
||||
@@ -208,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
|
||||
@@ -219,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]
|
||||
@@ -234,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)
|
||||
|
||||
@@ -247,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⟩
|
||||
@@ -265,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⟩
|
||||
@@ -273,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]
|
||||
@@ -285,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⟩
|
||||
@@ -308,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
|
||||
@@ -329,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⟩
|
||||
@@ -340,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⟩
|
||||
@@ -354,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]
|
||||
@@ -382,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)
|
||||
@@ -394,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
|
||||
@@ -465,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
|
||||
|
||||
@@ -6,10 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.TakeDrop
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.extract`
|
||||
@@ -31,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
|
||||
@@ -48,47 +46,17 @@ theorem size_extract_of_le {as : Array α} {i j : Nat} (h : j ≤ as.size) :
|
||||
simp
|
||||
omega
|
||||
|
||||
@[grind =]
|
||||
theorem extract_push {as : Array α} {b : α} {start stop : Nat} :
|
||||
(as.push b).extract start stop =
|
||||
if stop ≤ as.size then
|
||||
as.extract start stop
|
||||
else if start ≤ as.size then
|
||||
(as.extract start as.size).push b
|
||||
else #[] := by
|
||||
split
|
||||
· ext i h₁ h₂
|
||||
· simp
|
||||
omega
|
||||
· simp only [size_extract, size_push] at h₁ h₂
|
||||
simp only [getElem_extract, getElem_push]
|
||||
rw [dif_pos (by omega)]
|
||||
· split
|
||||
· ext i h₁ h₂
|
||||
· simp
|
||||
omega
|
||||
· simp only [size_extract, size_push] at h₁ h₂
|
||||
simp only [getElem_extract, getElem_push]
|
||||
split <;> rename_i h₃
|
||||
· split
|
||||
· rfl
|
||||
· simp_all
|
||||
omega
|
||||
· split <;> rename_i h₄
|
||||
· simp at h₄
|
||||
omega
|
||||
· rfl
|
||||
· ext i h₁ h₂
|
||||
· simp
|
||||
omega
|
||||
· simp at h₂
|
||||
@[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₂
|
||||
· simp
|
||||
omega
|
||||
· simp only [size_extract, size_push] at h₁ h₂
|
||||
simp only [getElem_extract, getElem_push]
|
||||
rw [dif_pos (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem extract_push_of_le {as : Array α} {b : α} {start stop : Nat} (h : stop ≤ as.size) :
|
||||
(as.push b).extract start stop = as.extract start stop := by
|
||||
rw [extract_push, if_pos h]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem extract_eq_pop {as : Array α} {stop : Nat} (h : stop = as.size - 1) :
|
||||
as.extract 0 stop = as.pop := by
|
||||
ext i h₁ h₂
|
||||
@@ -97,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₂
|
||||
@@ -194,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
|
||||
@@ -217,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
|
||||
@@ -244,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₂
|
||||
@@ -272,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
|
||||
@@ -331,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₂
|
||||
@@ -342,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]
|
||||
|
||||
@@ -6,10 +6,8 @@ Authors: François G. Dorais
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.FinRange
|
||||
public import Init.Data.Array.OfFn
|
||||
|
||||
public section
|
||||
import Init.Data.List.FinRange
|
||||
import Init.Data.Array.OfFn
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
@@ -25,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]
|
||||
|
||||
@@ -51,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
|
||||
|
||||
@@ -6,13 +6,11 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Nat.Find
|
||||
public import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Array.Attach
|
||||
public import Init.Data.Array.Range
|
||||
|
||||
public section
|
||||
import Init.Data.List.Nat.Find
|
||||
import all Init.Data.Array.Basic
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.Array.Range
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.findSome?`, `Array.find?, `Array.findIdx`, `Array.findIdx?`, `Array.idxOf`.
|
||||
@@ -40,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 α} :
|
||||
@@ -72,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
|
||||
@@ -120,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]
|
||||
|
||||
@@ -158,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 α} :
|
||||
@@ -212,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]
|
||||
|
||||
@@ -307,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
|
||||
@@ -319,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]
|
||||
@@ -350,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
|
||||
@@ -372,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
|
||||
@@ -386,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)
|
||||
@@ -403,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⟩
|
||||
@@ -431,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
|
||||
@@ -476,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
|
||||
@@ -484,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⟩
|
||||
@@ -507,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
|
||||
@@ -519,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⟩
|
||||
@@ -555,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
|
||||
@@ -578,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]
|
||||
@@ -606,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]
|
||||
@@ -631,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⟩
|
||||
@@ -648,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
|
||||
@@ -676,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?]
|
||||
|
||||
@@ -692,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
|
||||
@@ -709,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) :
|
||||
@@ -727,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
|
||||
|
||||
@@ -736,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]
|
||||
@@ -750,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?
|
||||
|
||||
@@ -774,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.
|
||||
@@ -800,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
|
||||
|
||||
@@ -7,9 +7,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Basic
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
@@ -6,10 +6,8 @@ Authors: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.List.Nat.InsertIdx
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.InsertIdx
|
||||
|
||||
/-!
|
||||
# insertIdx
|
||||
@@ -46,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 =
|
||||
@@ -73,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
|
||||
@@ -100,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
|
||||
@@ -111,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
|
||||
@@ -137,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
|
||||
|
||||
@@ -6,9 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Basic
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,5 @@ Author: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Array.Lex.Lemmas
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Lex.Basic
|
||||
import Init.Data.Array.Lex.Lemmas
|
||||
|
||||
@@ -6,11 +6,9 @@ Author: Kim Morrison
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range
|
||||
|
||||
public section
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Range
|
||||
|
||||
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
|
||||
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user