mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 20:04:23 +00:00
Compare commits
3 Commits
replace_fi
...
cycle
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72e5528758 | ||
|
|
fb01c650c2 | ||
|
|
e0cbb4d7b7 |
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v1
|
||||
with:
|
||||
|
||||
120
.github/workflows/ci.yml
vendored
120
.github/workflows/ci.yml
vendored
@@ -9,17 +9,6 @@ on:
|
||||
merge_group:
|
||||
schedule:
|
||||
- cron: '0 7 * * *' # 8AM CET/11PM PT
|
||||
# for manual re-release of a nightly
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
action:
|
||||
description: 'Action'
|
||||
required: true
|
||||
default: 'release nightly'
|
||||
type: choice
|
||||
options:
|
||||
- release nightly
|
||||
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||
@@ -52,11 +41,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
# don't schedule nightlies on forks
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4'
|
||||
- name: Set Nightly
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4'
|
||||
id: set-nightly
|
||||
run: |
|
||||
if [[ -n '${{ secrets.PUSH_NIGHTLY_TOKEN }}' ]]; then
|
||||
@@ -133,8 +122,9 @@ jobs:
|
||||
script: |
|
||||
const level = ${{ steps.set-level.outputs.check-level }};
|
||||
console.log(`level: ${level}`);
|
||||
// use large runners where available (original repo)
|
||||
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||
// use large runners outside PRs where available (original repo)
|
||||
// disabled for now as this mostly just speeds up the test suite which is not a bottleneck
|
||||
// let large = ${{ github.event_name != 'pull_request' && github.repository == 'leanprover/lean4' }} ? "-large" : "";
|
||||
let matrix = [
|
||||
{
|
||||
// portable release build: use channel with older glibc (2.27)
|
||||
@@ -153,7 +143,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux release",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"os": "ubuntu-latest",
|
||||
"release": true,
|
||||
"check-level": 0,
|
||||
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
||||
@@ -165,7 +155,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||
"os": "ubuntu-latest",
|
||||
"check-stage3": level >= 2,
|
||||
"test-speedcenter": level >= 2,
|
||||
"check-level": 1,
|
||||
@@ -291,8 +281,16 @@ jobs:
|
||||
CXX: c++
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
uses: cachix/install-nix-action@v18
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.12.0/install
|
||||
if: runner.os == 'Linux' && !matrix.cmultilib
|
||||
- name: Install MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
@@ -305,20 +303,6 @@ jobs:
|
||||
run: |
|
||||
brew install ccache tree zstd coreutils gmp
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
# Do check out some CI-relevant files from virtual merge commit to accommodate CI changes on
|
||||
# master (as the workflow files themselves are always taken from the merge)
|
||||
# (needs to be after "Install *" to use the right shell)
|
||||
- name: CI Merge Checkout
|
||||
run: |
|
||||
git fetch --depth=1 origin ${{ github.sha }}
|
||||
git checkout FETCH_HEAD flake.nix flake.lock
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overriden)
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
with:
|
||||
@@ -334,14 +318,20 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
|
||||
key: ${{ matrix.name }}-build-v3-${{ github.sha }}
|
||||
# fall back to (latest) previous cache
|
||||
restore-keys: |
|
||||
${{ matrix.name }}-build-v3
|
||||
# open nix-shell once for initial setup
|
||||
- name: Setup
|
||||
run: |
|
||||
ccache --zero-stats
|
||||
# open nix-shell once for initial setup
|
||||
true
|
||||
if: runner.os == 'Linux'
|
||||
- name: Set up core dumps
|
||||
run: |
|
||||
mkdir -p $PWD/coredumps
|
||||
# store in current directory, for easy uploading together with binary
|
||||
echo $PWD/coredumps/%e.%p.%t | sudo tee /proc/sys/kernel/core_pattern
|
||||
if: runner.os == 'Linux'
|
||||
- name: Set up NPROC
|
||||
run: |
|
||||
@@ -350,6 +340,7 @@ jobs:
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
ulimit -c unlimited # coredumps
|
||||
# arguments passed to `cmake`
|
||||
# this also enables githash embedding into stage 1 library
|
||||
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
|
||||
@@ -376,10 +367,8 @@ jobs:
|
||||
fi
|
||||
# contortion to support empty OPTIONS with old macOS bash
|
||||
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
|
||||
time make -j$NPROC
|
||||
- name: Install
|
||||
run: |
|
||||
make -C build install
|
||||
make -j$NPROC
|
||||
make install
|
||||
- name: Check Binaries
|
||||
run: ${{ matrix.binary-check }} lean-*/bin/* || true
|
||||
- name: List Install Tree
|
||||
@@ -397,7 +386,7 @@ jobs:
|
||||
else
|
||||
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
|
||||
fi
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: matrix.release
|
||||
with:
|
||||
name: build-${{ matrix.name }}
|
||||
@@ -409,7 +398,8 @@ jobs:
|
||||
- name: Test
|
||||
id: test
|
||||
run: |
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
ulimit -c unlimited # coredumps
|
||||
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) && needs.configure.outputs.check-level >= 1
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
@@ -422,28 +412,51 @@ jobs:
|
||||
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
|
||||
- name: Build Stage 2
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
make -C build -j$NPROC stage2
|
||||
if: matrix.test-speedcenter
|
||||
- name: Check Stage 3
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
make -C build -j$NPROC stage3
|
||||
if: matrix.test-speedcenter
|
||||
- name: Test Speedcenter Benchmarks
|
||||
run: |
|
||||
# Necessary for some timing metrics but does not work on Namespace runners
|
||||
# and we just want to test that the benchmarks run at all here
|
||||
#echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
|
||||
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
|
||||
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
|
||||
cd tests/bench
|
||||
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
|
||||
if: matrix.test-speedcenter
|
||||
- name: Check rebootstrap
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
# clean rebuild in case of Makefile changes
|
||||
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
|
||||
if: matrix.name == 'Linux' && needs.configure.outputs.check-level >= 1
|
||||
- name: CCache stats
|
||||
run: ccache -s
|
||||
- name: Show stacktrace for coredumps
|
||||
if: ${{ failure() && runner.os == 'Linux' }}
|
||||
run: |
|
||||
for c in coredumps/*; do
|
||||
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
|
||||
echo bt | $GDB/bin/gdb -q $progbin $c || true
|
||||
done
|
||||
# has not been used in a long while, would need to be adapted to new
|
||||
# shared libs
|
||||
#- name: Upload coredumps
|
||||
# uses: actions/upload-artifact@v3
|
||||
# if: ${{ failure() && runner.os == 'Linux' }}
|
||||
# with:
|
||||
# name: coredumps-${{ matrix.name }}
|
||||
# path: |
|
||||
# ./coredumps
|
||||
# ./build/stage0/bin/lean
|
||||
# ./build/stage0/lib/lean/libleanshared.so
|
||||
# ./build/stage1/bin/lean
|
||||
# ./build/stage1/lib/lean/libleanshared.so
|
||||
# ./build/stage2/bin/lean
|
||||
# ./build/stage2/lib/lean/libleanshared.so
|
||||
|
||||
# This job collects results from all the matrix jobs
|
||||
# This can be made the “required” job, instead of listing each
|
||||
@@ -470,7 +483,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
@@ -478,14 +491,8 @@ jobs:
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-rc') }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update release.lean-lang.org
|
||||
run: |
|
||||
gh workflow -R leanprover/release-index run update-index.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_INDEX_TOKEN }}
|
||||
|
||||
# This job creates nightly releases during the cron job.
|
||||
# It is responsible for creating the tag, and automatically generating a changelog.
|
||||
@@ -495,12 +502,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
@@ -528,8 +535,3 @@ jobs:
|
||||
repository: ${{ github.repository_owner }}/lean4-nightly
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- name: Update release.lean-lang.org
|
||||
run: |
|
||||
gh workflow -R leanprover/release-index run update-index.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_INDEX_TOKEN }}
|
||||
|
||||
30
.github/workflows/nix-ci.yml
vendored
30
.github/workflows/nix-ci.yml
vendored
@@ -13,36 +13,18 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# see ci.yml
|
||||
configure:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.result }}
|
||||
steps:
|
||||
- name: Configure build matrix
|
||||
id: set-matrix
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||
let matrix = [
|
||||
{
|
||||
"name": "Nix Linux",
|
||||
"os": large ? "nscloud-ubuntu-22.04-amd64-8x8" : "ubuntu-latest",
|
||||
}
|
||||
];
|
||||
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`);
|
||||
return matrix;
|
||||
|
||||
Build:
|
||||
needs: [configure]
|
||||
runs-on: ${{ matrix.os }}
|
||||
defaults:
|
||||
run:
|
||||
shell: nix run .#ciShell -- bash -euxo pipefail {0}
|
||||
strategy:
|
||||
matrix:
|
||||
include: ${{fromJson(needs.configure.outputs.matrix)}}
|
||||
include:
|
||||
- name: Nix Linux
|
||||
os: ubuntu-latest
|
||||
#- name: Nix macOS
|
||||
# os: macos-latest
|
||||
# complete all jobs
|
||||
fail-fast: false
|
||||
name: ${{ matrix.name }}
|
||||
@@ -50,7 +32,7 @@ jobs:
|
||||
NIX_BUILD_ARGS: --print-build-logs --fallback
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
6
.github/workflows/pr-release.yml
vendored
6
.github/workflows/pr-release.yml
vendored
@@ -234,7 +234,7 @@ jobs:
|
||||
# Checkout the Batteries repository with all branches
|
||||
- name: Checkout Batteries repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -291,7 +291,7 @@ jobs:
|
||||
# Checkout the mathlib4 repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: leanprover-community/mathlib4
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -328,7 +328,7 @@ jobs:
|
||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||
git add lean-toolchain
|
||||
sed -i 's,require "leanprover-community" / "batteries" @ ".\+",require "leanprover-community" / "batteries" @ "git#nightly-testing-'"${MOST_RECENT_NIGHTLY}"'",' lakefile.lean
|
||||
sed -i "s/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \".\+\"/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \"nightly-testing-${MOST_RECENT_NIGHTLY}\"/" 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 }}"
|
||||
|
||||
6
.github/workflows/restart-on-label.yml
vendored
6
.github/workflows/restart-on-label.yml
vendored
@@ -20,12 +20,10 @@ jobs:
|
||||
gh run view "$run_id"
|
||||
echo "Cancelling (just in case)"
|
||||
gh run cancel "$run_id" || echo "(failed)"
|
||||
echo "Waiting for 30s"
|
||||
sleep 30
|
||||
gh run view "$run_id"
|
||||
echo "Waiting for 10s"
|
||||
sleep 10
|
||||
echo "Rerunning"
|
||||
gh run rerun "$run_id"
|
||||
gh run view "$run_id"
|
||||
shell: bash
|
||||
env:
|
||||
head_ref: ${{ github.head_ref }}
|
||||
|
||||
2
.github/workflows/update-stage0.yml
vendored
2
.github/workflows/update-stage0.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
# https://stackoverflow.com/a/76135647/946226
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,10 +4,8 @@
|
||||
*.lock
|
||||
.lake
|
||||
lake-manifest.json
|
||||
/build
|
||||
/src/lakefile.toml
|
||||
/tests/lakefile.toml
|
||||
/lakefile.toml
|
||||
build
|
||||
!/src/lake/Lake/Build
|
||||
GPATH
|
||||
GRTAGS
|
||||
GSYMS
|
||||
|
||||
@@ -42,4 +42,4 @@
|
||||
/src/Lean/Elab/Tactic/Guard.lean @digama0
|
||||
/src/Init/Guard.lean @digama0
|
||||
/src/Lean/Server/CodeActions/ @digama0
|
||||
/src/Std/ @TwoFX
|
||||
|
||||
|
||||
317
RELEASES.md
317
RELEASES.md
@@ -8,326 +8,13 @@ This file contains work-in-progress notes for the upcoming release, as well as p
|
||||
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
|
||||
of each version.
|
||||
|
||||
v4.11.0
|
||||
v4.10.0
|
||||
----------
|
||||
Development in progress.
|
||||
|
||||
v4.10.0
|
||||
----------
|
||||
Release candidate, release notes will be copied from branch `releases/v4.10.0` once completed.
|
||||
|
||||
v4.9.0
|
||||
----------
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* **Definition transparency**
|
||||
* [#4053](https://github.com/leanprover/lean4/pull/4053) adds the `seal` and `unseal` commands, which make definitions locally be irreducible or semireducible.
|
||||
* [#4061](https://github.com/leanprover/lean4/pull/4061) marks functions defined by well-founded recursion with `@[irreducible]` by default,
|
||||
which should prevent the expensive and often unfruitful unfolding of such definitions (see breaking changes below).
|
||||
* **Incrementality**
|
||||
* [#3940](https://github.com/leanprover/lean4/pull/3940) extends incremental elaboration into various steps inside of declarations:
|
||||
definition headers, bodies, and tactics.
|
||||
.
|
||||
* [250994](https://github.com/leanprover/lean4/commit/250994166ce036ab8644e459129f51ea79c1c2d2)
|
||||
and [67338b](https://github.com/leanprover/lean4/commit/67338bac2333fa39a8656e8f90574784e4c23d3d)
|
||||
add `@[incremental]` attribute to mark an elaborator as supporting incremental elaboration.
|
||||
* [#4259](https://github.com/leanprover/lean4/pull/4259) improves resilience by ensuring incremental commands and tactics are reached only in supported ways.
|
||||
* [#4268](https://github.com/leanprover/lean4/pull/4268) adds special handling for `:= by` so that stray tokens in tactic blocks do not inhibit incrementality.
|
||||
* [#4308](https://github.com/leanprover/lean4/pull/4308) adds incremental `have` tactic.
|
||||
* [#4340](https://github.com/leanprover/lean4/pull/4340) fixes incorrect info tree reuse.
|
||||
* [#4364](https://github.com/leanprover/lean4/pull/4364) adds incrementality for careful command macros such as `set_option in theorem`, `theorem foo.bar`, and `lemma`.
|
||||
* [#4395](https://github.com/leanprover/lean4/pull/4395) adds conservative fix for whitespace handling to avoid incremental reuse leading to goals in front of the text cursor being shown.
|
||||
* [#4407](https://github.com/leanprover/lean4/pull/4407) fixes non-incremental commands in macros blocking further incremental reporting.
|
||||
* [#4436](https://github.com/leanprover/lean4/pull/4436) fixes incremental reporting when there are nested tactics in terms.
|
||||
* **Functional induction**
|
||||
* [#4135](https://github.com/leanprover/lean4/pull/4135) ensures that the names used for functional induction are reserved.
|
||||
* [#4327](https://github.com/leanprover/lean4/pull/4327) adds support for structural recursion on reflexive types.
|
||||
For example,
|
||||
```lean4
|
||||
inductive Many (α : Type u) where
|
||||
| none : Many α
|
||||
| more : α → (Unit → Many α) → Many α
|
||||
|
||||
def Many.map {α β : Type u} (f : α → β) : Many α → Many β
|
||||
| .none => .none
|
||||
| .more x xs => .more (f x) (fun _ => (xs ()).map f)
|
||||
|
||||
#check Many.map.induct
|
||||
/-
|
||||
Many.map.induct {α β : Type u} (f : α → β) (motive : Many α → Prop)
|
||||
(case1 : motive Many.none)
|
||||
(case2 : ∀ (x : α) (xs : Unit → Many α), motive (xs ()) → motive (Many.more x xs)) :
|
||||
∀ (a : Many α), motive a
|
||||
-/
|
||||
```
|
||||
* [#3903](https://github.com/leanprover/lean4/pull/3903) makes the Lean frontend normalize all line endings to LF before processing.
|
||||
This lets Lean be insensitive to CRLF vs LF line endings, improving the cross-platform experience and making Lake hashes be faithful to what Lean processes.
|
||||
* [#4130](https://github.com/leanprover/lean4/pull/4130) makes the tactic framework be able to recover from runtime errors (for example, deterministic timeouts or maximum recursion depth errors).
|
||||
* `split` tactic
|
||||
* [#4211](https://github.com/leanprover/lean4/pull/4211) fixes `split at h` when `h` has forward dependencies.
|
||||
* [#4349](https://github.com/leanprover/lean4/pull/4349) allows `split` for `if`-expressions to work on non-propositional goals.
|
||||
* `apply` tactic
|
||||
* [#3929](https://github.com/leanprover/lean4/pull/3929) makes error message for `apply` show implicit arguments in unification errors as needed.
|
||||
Modifies `MessageData` type (see breaking changes below).
|
||||
* `cases` tactic
|
||||
* [#4224](https://github.com/leanprover/lean4/pull/4224) adds support for unification of offsets such as `x + 20000 = 20001` in `cases` tactic.
|
||||
* `omega` tactic
|
||||
* [#4073](https://github.com/leanprover/lean4/pull/4073) lets `omega` fall back to using classical `Decidable` instances when setting up contradiction proofs.
|
||||
* [#4141](https://github.com/leanprover/lean4/pull/4141) and [#4184](https://github.com/leanprover/lean4/pull/4184) fix bugs.
|
||||
* [#4264](https://github.com/leanprover/lean4/pull/4264) improves `omega` error message if no facts found in local context.
|
||||
* [#4358](https://github.com/leanprover/lean4/pull/4358) improves expression matching in `omega` by using `match_expr`.
|
||||
* `simp` tactic
|
||||
* [#4176](https://github.com/leanprover/lean4/pull/4176) makes names of erased lemmas clickable.
|
||||
* [#4208](https://github.com/leanprover/lean4/pull/4208) adds a pretty printer for discrimination tree keys.
|
||||
* [#4202](https://github.com/leanprover/lean4/pull/4202) adds `Simp.Config.index` configuration option,
|
||||
which controls whether to use the full discrimination tree when selecting candidate simp lemmas.
|
||||
When `index := false`, only the head function is taken into account, like in Lean 3.
|
||||
This feature can help users diagnose tricky simp failures or issues in code from libraries
|
||||
developed using Lean 3 and then ported to Lean 4.
|
||||
|
||||
In the following example, it will report that `foo` is a problematic theorem.
|
||||
```lean
|
||||
opaque f : Nat → Nat → Nat
|
||||
|
||||
@[simp] theorem foo : f x (x, y).2 = y := by sorry
|
||||
|
||||
example : f a b ≤ b := by
|
||||
set_option diagnostics true in
|
||||
simp (config := { index := false })
|
||||
/-
|
||||
[simp] theorems with bad keys
|
||||
foo, key: f _ (@Prod.mk ℕ ℕ _ _).2
|
||||
-/
|
||||
```
|
||||
With the information above, users can annotate theorems such as `foo` using `no_index` for problematic subterms. Example:
|
||||
```lean
|
||||
opaque f : Nat → Nat → Nat
|
||||
|
||||
@[simp] theorem foo : f x (no_index (x, y).2) = y := by sorry
|
||||
|
||||
example : f a b ≤ b := by
|
||||
simp -- `foo` is still applied with `index := true`
|
||||
```
|
||||
* [#4274](https://github.com/leanprover/lean4/pull/4274) prevents internal `match` equational theorems from appearing in simp trace.
|
||||
* [#4177](https://github.com/leanprover/lean4/pull/4177) and [#4359](https://github.com/leanprover/lean4/pull/4359) make `simp` continue even if a simp lemma does not elaborate, if the tactic state is in recovery mode.
|
||||
* [#4341](https://github.com/leanprover/lean4/pull/4341) fixes panic when applying `@[simp]` to malformed theorem syntax.
|
||||
* [#4345](https://github.com/leanprover/lean4/pull/4345) fixes `simp` so that it does not use the forward version of a user-specified backward theorem.
|
||||
* [#4352](https://github.com/leanprover/lean4/pull/4352) adds missing `dsimp` simplifications for fixed parameters of generated congruence theorems.
|
||||
* [#4362](https://github.com/leanprover/lean4/pull/4362) improves trace messages for `simp` so that constants are hoverable.
|
||||
* **Elaboration**
|
||||
* [#4046](https://github.com/leanprover/lean4/pull/4046) makes subst notation (`he ▸ h`) try rewriting in both directions even when there is no expected type available.
|
||||
* [#3328](https://github.com/leanprover/lean4/pull/3328) adds support for identifiers in autoparams (for example, `rfl` in `(h : x = y := by exact rfl)`).
|
||||
* [#4096](https://github.com/leanprover/lean4/pull/4096) changes how the type in `let` and `have` is elaborated, requiring that any tactics in the type be evaluated before proceeding, improving performance.
|
||||
* [#4215](https://github.com/leanprover/lean4/pull/4215) ensures the expression tree elaborator commits to the computed "max type" for the entire arithmetic expression.
|
||||
* [#4267](https://github.com/leanprover/lean4/pull/4267) cases signature elaboration errors to show even if there are parse errors in the body.
|
||||
* [#4368](https://github.com/leanprover/lean4/pull/4368) improves error messages when numeric literals fail to synthesize an `OfNat` instance,
|
||||
including special messages warning when the expected type of the numeral can be a proposition.
|
||||
* **Metaprogramming**
|
||||
* [#4167](https://github.com/leanprover/lean4/pull/4167) adds `Lean.MVarId.revertAll` to revert all free variables.
|
||||
* [#4169](https://github.com/leanprover/lean4/pull/4169) adds `Lean.MVarId.ensureNoMVar` to ensure the goal's target contains no expression metavariables.
|
||||
* [#4180](https://github.com/leanprover/lean4/pull/4180) adds `cleanupAnnotations` parameter to `forallTelescope` methods.
|
||||
* [#4307](https://github.com/leanprover/lean4/pull/4307) adds support for parser aliases in syntax quotations.
|
||||
* Work toward implementing `grind` tactic
|
||||
* [0a515e](https://github.com/leanprover/lean4/commit/0a515e2ec939519dafb4b99daa81d6bf3c411404)
|
||||
and [#4164](https://github.com/leanprover/lean4/pull/4164)
|
||||
add `grind_norm` and `grind_norm_proc` attributes and `@[grind_norm]` theorems.
|
||||
* [#4170](https://github.com/leanprover/lean4/pull/4170), [#4221](https://github.com/leanprover/lean4/pull/4221),
|
||||
and [#4249](https://github.com/leanprover/lean4/pull/4249) create `grind` preprocessor and core module.
|
||||
* [#4235](https://github.com/leanprover/lean4/pull/4235) and [d6709e](https://github.com/leanprover/lean4/commit/d6709eb1576c5d40fc80462637dc041f970e4d9f)
|
||||
add special `cases` tactic to `grind` along with `@[grind_cases]` attribute to mark types that this `cases` tactic should automatically apply to.
|
||||
* [#4243](https://github.com/leanprover/lean4/pull/4243) adds special `injection?` tactic to `grind`.
|
||||
* **Other fixes or improvements**
|
||||
* [#4065](https://github.com/leanprover/lean4/pull/4065) fixes a bug in the `Nat.reduceLeDiff` simproc.
|
||||
* [#3969](https://github.com/leanprover/lean4/pull/3969) makes deprecation warnings activate even for generalized field notation ("dot notation").
|
||||
* [#4132](https://github.com/leanprover/lean4/pull/4132) fixes the `sorry` term so that it does not activate the implicit lambda feature
|
||||
* [9803c5](https://github.com/leanprover/lean4/commit/9803c5dd63dc993628287d5f998525e74af03839)
|
||||
and [47c8e3](https://github.com/leanprover/lean4/commit/47c8e340d65b01f4d9f011686e3dda0d4bb30a20)
|
||||
move `cdot` and `calc` parsers to `Lean` namespace.
|
||||
* [#4252](https://github.com/leanprover/lean4/pull/4252) fixes the `case` tactic so that it is usable in macros by having it erase macro scopes from the tag.
|
||||
* [26b671](https://github.com/leanprover/lean4/commit/26b67184222e75529e1b166db050aaebee323d2d)
|
||||
and [cc33c3](https://github.com/leanprover/lean4/commit/cc33c39cb022d8a3166b1e89677c78835ead1fc7)
|
||||
extract `haveId` syntax.
|
||||
* [#4335](https://github.com/leanprover/lean4/pull/4335) fixes bugs in partial `calc` tactic when there is mdata or metavariables.
|
||||
* [#4329](https://github.com/leanprover/lean4/pull/4329) makes `termination_by?` report unused each unused parameter as `_`.
|
||||
* **Docs:** [#4238](https://github.com/leanprover/lean4/pull/4238), [#4294](https://github.com/leanprover/lean4/pull/4294),
|
||||
[#4338](https://github.com/leanprover/lean4/pull/4338).
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
* [#4066](https://github.com/leanprover/lean4/pull/4066) fixes features like "Find References" when browsing core Lean sources.
|
||||
* [#4254](https://github.com/leanprover/lean4/pull/4254) allows embedding user widgets in structured messages.
|
||||
Companion PR is [vscode-lean4#449](https://github.com/leanprover/vscode-lean4/pull/449).
|
||||
* [#4445](https://github.com/leanprover/lean4/pull/4445) makes watchdog more resilient against badly behaving clients.
|
||||
|
||||
### Library
|
||||
* [#4059](https://github.com/leanprover/lean4/pull/4059) upstreams many `List` and `Array` operations and theorems from Batteries.
|
||||
* [#4055](https://github.com/leanprover/lean4/pull/4055) removes the unused `Inhabited` instance for `Subtype`.
|
||||
* [#3967](https://github.com/leanprover/lean4/pull/3967) adds dates in existing `@[deprecated]` attributes.
|
||||
* [#4231](https://github.com/leanprover/lean4/pull/4231) adds boilerplate `Char`, `UInt`, and `Fin` theorems.
|
||||
* [#4205](https://github.com/leanprover/lean4/pull/4205) fixes the `MonadStore` type classes to use `semiOutParam`.
|
||||
* [#4350](https://github.com/leanprover/lean4/pull/4350) renames `IsLawfulSingleton` to `LawfulSingleton`.
|
||||
* `Nat`
|
||||
* [#4094](https://github.com/leanprover/lean4/pull/4094) swaps `Nat.zero_or` and `Nat.or_zero`.
|
||||
* [#4098](https://github.com/leanprover/lean4/pull/4098) and [#4145](https://github.com/leanprover/lean4/pull/4145)
|
||||
change the definition of `Nat.mod` so that `n % (m + n)` reduces when `n` is literal without relying on well-founded recursion,
|
||||
which becomes irreducible by default in [#4061](https://github.com/leanprover/lean4/pull/4061).
|
||||
* [#4188](https://github.com/leanprover/lean4/pull/4188) redefines `Nat.testBit` to be more performant.
|
||||
* Theorems: [#4199](https://github.com/leanprover/lean4/pull/4199).
|
||||
* `Array`
|
||||
* [#4074](https://github.com/leanprover/lean4/pull/4074) improves the functional induction principle `Array.feraseIdx.induct`.
|
||||
* `List`
|
||||
* [#4172](https://github.com/leanprover/lean4/pull/4172) removes `@[simp]` from `List.length_pos`.
|
||||
* `Option`
|
||||
* [#4037](https://github.com/leanprover/lean4/pull/4037) adds theorems to simplify `Option`-valued dependent if-then-else.
|
||||
* [#4314](https://github.com/leanprover/lean4/pull/4314) removes `@[simp]` from `Option.bind_eq_some`.
|
||||
* `BitVec`
|
||||
* Theorems: [#3920](https://github.com/leanprover/lean4/pull/3920), [#4095](https://github.com/leanprover/lean4/pull/4095),
|
||||
[#4075](https://github.com/leanprover/lean4/pull/4075), [#4148](https://github.com/leanprover/lean4/pull/4148),
|
||||
[#4165](https://github.com/leanprover/lean4/pull/4165), [#4178](https://github.com/leanprover/lean4/pull/4178),
|
||||
[#4200](https://github.com/leanprover/lean4/pull/4200), [#4201](https://github.com/leanprover/lean4/pull/4201),
|
||||
[#4298](https://github.com/leanprover/lean4/pull/4298), [#4299](https://github.com/leanprover/lean4/pull/4299),
|
||||
[#4257](https://github.com/leanprover/lean4/pull/4257), [#4179](https://github.com/leanprover/lean4/pull/4179),
|
||||
[#4321](https://github.com/leanprover/lean4/pull/4321), [#4187](https://github.com/leanprover/lean4/pull/4187).
|
||||
* [#4193](https://github.com/leanprover/lean4/pull/4193) adds simprocs for reducing `x >>> i` and `x <<< i` where `i` is a bitvector literal.
|
||||
* [#4194](https://github.com/leanprover/lean4/pull/4194) adds simprocs for reducing `(x <<< i) <<< j` and `(x >>> i) >>> j` where `i` and `j` are natural number literals.
|
||||
* [#4229](https://github.com/leanprover/lean4/pull/4229) redefines `rotateLeft`/`rotateRight` to use modulo reduction of shift offset.
|
||||
* [0d3051](https://github.com/leanprover/lean4/commit/0d30517dca094a07bcb462252f718e713b93ffba) makes `<num>#<term>` bitvector literal notation global.
|
||||
* `Char`/`String`
|
||||
* [#4143](https://github.com/leanprover/lean4/pull/4143) modifies `String.substrEq` to avoid linter warnings in downstream code.
|
||||
* [#4233](https://github.com/leanprover/lean4/pull/4233) adds simprocs for `Char` and `String` inequalities.
|
||||
* [#4348](https://github.com/leanprover/lean4/pull/4348) upstreams Mathlib lemmas.
|
||||
* [#4354](https://github.com/leanprover/lean4/pull/4354) upstreams basic `String` lemmas.
|
||||
* `HashMap`
|
||||
* [#4248](https://github.com/leanprover/lean4/pull/4248) fixes implicitness of typeclass arguments in `HashMap.ofList`.
|
||||
* `IO`
|
||||
* [#4036](https://github.com/leanprover/lean4/pull/4036) adds `IO.Process.getCurrentDir` and `IO.Process.setCurrentDir` for adjusting the current process's working directory.
|
||||
* **Cleanup:** [#4077](https://github.com/leanprover/lean4/pull/4077), [#4189](https://github.com/leanprover/lean4/pull/4189),
|
||||
[#4304](https://github.com/leanprover/lean4/pull/4304).
|
||||
* **Docs:** [#4001](https://github.com/leanprover/lean4/pull/4001), [#4166](https://github.com/leanprover/lean4/pull/4166),
|
||||
[#4332](https://github.com/leanprover/lean4/pull/4332).
|
||||
|
||||
### Lean internals
|
||||
* **Defeq and WHNF algorithms**
|
||||
* [#4029](https://github.com/leanprover/lean4/pull/4029) remove unnecessary `checkpointDefEq`
|
||||
* [#4206](https://github.com/leanprover/lean4/pull/4206) fixes `isReadOnlyOrSyntheticOpaque` to respect metavariable depth.
|
||||
* [#4217](https://github.com/leanprover/lean4/pull/4217) fixes missing occurs check for delayed assignments.
|
||||
* **Definition transparency**
|
||||
* [#4052](https://github.com/leanprover/lean4/pull/4052) adds validation to application of `@[reducible]`/`@[semireducible]`/`@[irreducible]` attributes (with `local`/`scoped` modifiers as well).
|
||||
Setting `set_option allowUnsafeReductibility true` turns this validation off.
|
||||
* **Inductive types**
|
||||
* [#3591](https://github.com/leanprover/lean4/pull/3591) fixes a bug where indices could be incorrectly promoted to parameters.
|
||||
* [#3398](https://github.com/leanprover/lean4/pull/3398) fixes a bug in the injectivity theorem generator.
|
||||
* [#4342](https://github.com/leanprover/lean4/pull/4342) fixes elaboration of mutual inductives with instance parameters.
|
||||
* **Diagnostics and profiling**
|
||||
* [#3986](https://github.com/leanprover/lean4/pull/3986) adds option `trace.profiler.useHeartbeats` to switch `trace.profiler.threshold` to being in terms of heartbeats instead of milliseconds.
|
||||
* [#4082](https://github.com/leanprover/lean4/pull/4082) makes `set_option diagnostics true` report kernel diagnostic information.
|
||||
* **Typeclass resolution**
|
||||
* [#4119](https://github.com/leanprover/lean4/pull/4119) fixes multiple issues with TC caching interacting with `synthPendingDepth`, adds `maxSynthPendingDepth` option with default value `1`.
|
||||
* [#4210](https://github.com/leanprover/lean4/pull/4210) ensures local instance cache does not contain multiple copies of the same instance.
|
||||
* [#4216](https://github.com/leanprover/lean4/pull/4216) fix handling of metavariables, to avoid needing to set the option `backward.synthInstance.canonInstances` to `false`.
|
||||
* **Other fixes or improvements**
|
||||
* [#4080](https://github.com/leanprover/lean4/pull/4080) fixes propagation of state for `Lean.Elab.Command.liftCoreM` and `Lean.Elab.Command.liftTermElabM`.
|
||||
* [#3944](https://github.com/leanprover/lean4/pull/3944) makes the `Repr` deriving handler be consistent between `structure` and `inductive` for how types and proofs are erased.
|
||||
* [#4113](https://github.com/leanprover/lean4/pull/4113) propagates `maxHeartbeats` to kernel to control "(kernel) deterministic timeout" error.
|
||||
* [#4125](https://github.com/leanprover/lean4/pull/4125) reverts [#3970](https://github.com/leanprover/lean4/pull/3970) (monadic generalization of `FindExpr`).
|
||||
* [#4128](https://github.com/leanprover/lean4/pull/4128) catches stack overflow in auto-bound implicits feature.
|
||||
* [#4129](https://github.com/leanprover/lean4/pull/4129) adds `tryCatchRuntimeEx` combinator to replace `catchRuntimeEx` reader state.
|
||||
* [#4155](https://github.com/leanprover/lean4/pull/4155) simplifies the expression canonicalizer.
|
||||
* [#4151](https://github.com/leanprover/lean4/pull/4151) and [#4369](https://github.com/leanprover/lean4/pull/4369)
|
||||
add many missing trace classes.
|
||||
* [#4185](https://github.com/leanprover/lean4/pull/4185) makes congruence theorem generators clean up type annotations of argument types.
|
||||
* [#4192](https://github.com/leanprover/lean4/pull/4192) fixes restoration of infotrees when auto-bound implicit feature is activated,
|
||||
fixing a pretty printing error in hovers and strengthening the unused variable linter.
|
||||
* [dfb496](https://github.com/leanprover/lean4/commit/dfb496a27123c3864571aec72f6278e2dad1cecf) fixes `declareBuiltin` to allow it to be called multiple times per declaration.
|
||||
* Cleanup: [#4112](https://github.com/leanprover/lean4/pull/4112), [#4126](https://github.com/leanprover/lean4/pull/4126), [#4091](https://github.com/leanprover/lean4/pull/4091), [#4139](https://github.com/leanprover/lean4/pull/4139), [#4153](https://github.com/leanprover/lean4/pull/4153).
|
||||
* Tests: [030406](https://github.com/leanprover/lean4/commit/03040618b8f9b35b7b757858483e57340900cdc4), [#4133](https://github.com/leanprover/lean4/pull/4133).
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
* [#4100](https://github.com/leanprover/lean4/pull/4100) improves reset/reuse algorithm; it now runs a second pass relaxing the constraint that reused memory cells must only be for the exact same constructor.
|
||||
* [#2903](https://github.com/leanprover/lean4/pull/2903) fixes segfault in old compiler from mishandling `noConfusion` applications.
|
||||
* [#4311](https://github.com/leanprover/lean4/pull/4311) fixes bug in constant folding.
|
||||
* [#3915](https://github.com/leanprover/lean4/pull/3915) documents the runtime memory layout for inductive types.
|
||||
|
||||
### Lake
|
||||
* [#4057](https://github.com/leanprover/lean4/pull/4057) adds support for docstrings on `require` commands.
|
||||
* [#4088](https://github.com/leanprover/lean4/pull/4088) improves hovers for `family_def` and `library_data` commands.
|
||||
* [#4147](https://github.com/leanprover/lean4/pull/4147) adds default `README.md` to package templates
|
||||
* [#4261](https://github.com/leanprover/lean4/pull/4261) extends `lake test` help page, adds help page for `lake check-test`,
|
||||
adds `lake lint` and tag `@[lint_driver]`, adds support for specifying test and lint drivers from dependencies,
|
||||
adds `testDriverArgs` and `lintDriverArgs` options, adds support for library test drivers,
|
||||
makes `lake check-test` and `lake check-lint` only load the package without dependencies.
|
||||
* [#4270](https://github.com/leanprover/lean4/pull/4270) adds `lake pack` and `lake unpack` for packing and unpacking Lake build artifacts from an archive.
|
||||
* [#4083](https://github.com/leanprover/lean4/pull/4083)
|
||||
Switches the manifest format to use `major.minor.patch` semantic
|
||||
versions. Major version increments indicate breaking changes (e.g., new
|
||||
required fields and semantic changes to existing fields). Minor version
|
||||
increments (after `0.x`) indicate backwards-compatible extensions (e.g.,
|
||||
adding optional fields, removing fields). This change is backwards
|
||||
compatible. Lake will still successfully read old manifests with numeric
|
||||
versions. It will treat the numeric version `N` as semantic version
|
||||
`0.N.0`. Lake will also accept manifest versions with `-` suffixes
|
||||
(e.g., `x.y.z-foo`) and then ignore the suffix.
|
||||
* [#4273](https://github.com/leanprover/lean4/pull/4273) adds a lift from `JobM` to `FetchM` for backwards compatibility reasons.
|
||||
* [#4351](https://github.com/leanprover/lean4/pull/4351) fixes `LogIO`-to-`CliM`-lifting performance issues.
|
||||
* [#4343](https://github.com/leanprover/lean4/pull/4343) make Lake store the dependency trace for a build in
|
||||
the cached build long and then verifies that it matches the trace of the current build before replaying the log.
|
||||
* [#4402](https://github.com/leanprover/lean4/pull/4402) moves the cached log into the trace file (no more `.log.json`).
|
||||
This means logs are no longer cached on fatal errors and this ensures that an out-of-date log is not associated with an up-to-date trace.
|
||||
Separately, `.hash` file generation was changed to be more reliable as well.
|
||||
The `.hash` files are deleted as part of the build and always regenerate with `--rehash`.
|
||||
* **Other fixes or improvements**
|
||||
* [#4056](https://github.com/leanprover/lean4/pull/4056) cleans up tests
|
||||
* [#4244](https://github.com/leanprover/lean4/pull/4244) fixes `noRelease` test when Lean repo is tagged
|
||||
* [#4346](https://github.com/leanprover/lean4/pull/4346) improves `tests/serve`
|
||||
* [#4356](https://github.com/leanprover/lean4/pull/4356) adds build log path to the warning for a missing or invalid build log.
|
||||
|
||||
### DevOps
|
||||
* [#3984](https://github.com/leanprover/lean4/pull/3984) adds a script (`script/rebase-stage0.sh`) for `git rebase -i` that automatically updates each stage0.
|
||||
* [#4108](https://github.com/leanprover/lean4/pull/4108) finishes renamings from transition to Std to Batteries.
|
||||
* [#4109](https://github.com/leanprover/lean4/pull/4109) adjusts the Github bug template to mention testing using [live.lean-lang.org](https://live.lean-lang.org).
|
||||
* [#4136](https://github.com/leanprover/lean4/pull/4136) makes CI rerun only when `full-ci` label is added or removed.
|
||||
* [#4175](https://github.com/leanprover/lean4/pull/4175) and [72b345](https://github.com/leanprover/lean4/commit/72b345c621a9a06d3a5a656da2b793a5eea5f168)
|
||||
switch to using `#guard_msgs` to run tests as much as possible.
|
||||
* [#3125](https://github.com/leanprover/lean4/pull/3125) explains the Lean4 `pygments` lexer.
|
||||
* [#4247](https://github.com/leanprover/lean4/pull/4247) sets up a procedure for preparing release notes.
|
||||
* [#4032](https://github.com/leanprover/lean4/pull/4032) modernizes build instructions and workflows.
|
||||
* [#4255](https://github.com/leanprover/lean4/pull/4255) moves some expensive checks from merge queue to releases.
|
||||
* [#4265](https://github.com/leanprover/lean4/pull/4265) adds aarch64 macOS as native compilation target for CI.
|
||||
* [f05a82](https://github.com/leanprover/lean4/commit/f05a82799a01569edeb5e2594cd7d56282320f9e) restores macOS aarch64 install suffix in CI
|
||||
* [#4317](https://github.com/leanprover/lean4/pull/4317) updates build instructions for macOS.
|
||||
* [#4333](https://github.com/leanprover/lean4/pull/4333) adjusts workflow to update Batteries in manifest when creating `lean-pr-testing-NNNN` Mathlib branches.
|
||||
* [#4355](https://github.com/leanprover/lean4/pull/4355) simplifies `lean4checker` step of release checklist.
|
||||
* [#4361](https://github.com/leanprover/lean4/pull/4361) adds installing elan to `pr-release` CI step.
|
||||
|
||||
### Breaking changes
|
||||
While most changes could be considered to be a breaking change, this section makes special note of API changes.
|
||||
|
||||
* `Nat.zero_or` and `Nat.or_zero` have been swapped ([#4094](https://github.com/leanprover/lean4/pull/4094)).
|
||||
* `IsLawfulSingleton` is now `LawfulSingleton` ([#4350](https://github.com/leanprover/lean4/pull/4350)).
|
||||
* `BitVec.rotateLeft` and `BitVec.rotateRight` now take the shift modulo the bitwidth ([#4229](https://github.com/leanprover/lean4/pull/4229)).
|
||||
* These are no longer simp lemmas:
|
||||
`List.length_pos` ([#4172](https://github.com/leanprover/lean4/pull/4172)),
|
||||
`Option.bind_eq_some` ([#4314](https://github.com/leanprover/lean4/pull/4314)).
|
||||
* Types in `let` and `have` (both the expressions and tactics) may fail to elaborate due to new restrictions on what sorts of elaboration problems may be postponed ([#4096](https://github.com/leanprover/lean4/pull/4096)).
|
||||
In particular, tactics embedded in the type will no longer make use of the type of `value` in expressions such as `let x : type := value; body`.
|
||||
* Now functions defined by well-founded recursion are marked with `@[irreducible]` by default ([#4061](https://github.com/leanprover/lean4/pull/4061)).
|
||||
Existing proofs that hold by definitional equality (e.g. `rfl`) can be
|
||||
rewritten to explictly unfold the function definition (using `simp`,
|
||||
`unfold`, `rw`), or the recursive function can be temporarily made
|
||||
semireducible (using `unseal f in` before the command), or the function
|
||||
definition itself can be marked as `@[semireducible]` to get the previous
|
||||
behavior.
|
||||
* Due to [#3929](https://github.com/leanprover/lean4/pull/3929):
|
||||
* The `MessageData.ofPPFormat` constructor has been removed.
|
||||
Its functionality has been split into two:
|
||||
|
||||
- for lazy structured messages, please use `MessageData.lazy`;
|
||||
- for embedding `Format` or `FormatWithInfos`, use `MessageData.ofFormatWithInfos`.
|
||||
|
||||
An example migration can be found in [#3929](https://github.com/leanprover/lean4/pull/3929/files#diff-5910592ab7452a0e1b2616c62d22202d2291a9ebb463145f198685aed6299867L109).
|
||||
|
||||
* The `MessageData.ofFormat` constructor has been turned into a function.
|
||||
If you need to inspect `MessageData`, you can pattern-match on `MessageData.ofFormatWithInfos`.
|
||||
Release candidate, release notes will be copied from branch `releases/v4.9.0` once completed.
|
||||
|
||||
v4.8.0
|
||||
---------
|
||||
|
||||
10
doc/char.md
10
doc/char.md
@@ -1,11 +1 @@
|
||||
# Characters
|
||||
|
||||
A value of type `Char`, also known as a character, is a [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value). It is represented using an unsigned 32-bit integer and is statically guaranteed to be a valid Unicode scalar value.
|
||||
|
||||
Syntactically, character literals are enclosed in single quotes.
|
||||
```lean
|
||||
#eval 'a' -- 'a'
|
||||
#eval '∀' -- '∀'
|
||||
```
|
||||
|
||||
Characters are ordered and can be decidably compared using the relational operators `=`, `<`, `≤`, `>`, `≥`.
|
||||
|
||||
@@ -5,8 +5,7 @@ See below for the checklist for release candidates.
|
||||
|
||||
We'll use `v4.6.0` as the intended release version as a running example.
|
||||
|
||||
- One week before the planned release, ensure that (1) someone has written the release notes and (2) someone has written the first draft of the release blog post.
|
||||
If there is any material in `./releases_drafts/`, then the release notes are not done. (See the section "Writing the release notes".)
|
||||
- One week before the planned release, ensure that someone has written the first draft of the release blog post
|
||||
- `git checkout releases/v4.6.0`
|
||||
(This branch should already exist, from the release candidates.)
|
||||
- `git pull`
|
||||
@@ -14,6 +13,13 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- `set(LEAN_VERSION_MINOR 6)` (for whichever `6` is appropriate)
|
||||
- `set(LEAN_VERSION_IS_RELEASE 1)`
|
||||
- (both of these should already be in place from the release candidates)
|
||||
- It is possible that the `v4.6.0` section of `RELEASES.md` is out of sync between
|
||||
`releases/v4.6.0` and `master`. This should be reconciled:
|
||||
- Run `git diff master RELEASES.md`.
|
||||
- You should expect to see additons on `master` in the `v4.7.0-rc1` section; ignore these.
|
||||
(i.e. the new release notes for the upcoming release candidate).
|
||||
- Reconcile discrepancies in the `v4.6.0` section,
|
||||
usually via copy and paste and a commit to `releases/v4.6.0`.
|
||||
- `git tag v4.6.0`
|
||||
- `git push $REMOTE v4.6.0`, where `$REMOTE` is the upstream Lean repository (e.g., `origin`, `upstream`)
|
||||
- Now wait, while CI runs.
|
||||
@@ -24,9 +30,8 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
you may want to start on the release candidate checklist now.
|
||||
- Go to https://github.com/leanprover/lean4/releases and verify that the `v4.6.0` release appears.
|
||||
- Edit the release notes on Github to select the "Set as the latest release".
|
||||
- Follow the instructions in creating a release candidate for the "GitHub release notes" step,
|
||||
now that we have a written `RELEASES.md` section.
|
||||
Do a quick sanity check.
|
||||
- Copy and paste the Github release notes from the previous releases candidate for this version
|
||||
(e.g. `v4.6.0-rc1`), and quickly sanity check.
|
||||
- Next, we will move a curated list of downstream repos to the latest stable release.
|
||||
- For each of the repositories listed below:
|
||||
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
|
||||
@@ -89,10 +94,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- Toolchain bump PR including updated Lake manifest
|
||||
- Create and push the tag
|
||||
- Merge the tag into `stable`
|
||||
- The `v4.6.0` section of `RELEASES.md` is out of sync between
|
||||
`releases/v4.6.0` and `master`. This should be reconciled:
|
||||
- Replace the `v4.6.0` section on `master` with the `v4.6.0` section on `releases/v4.6.0`
|
||||
and commit this to `master`.
|
||||
- Merge the release announcement PR for the Lean website - it will be deployed automatically
|
||||
- Finally, make an announcement!
|
||||
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
|
||||
@@ -103,6 +104,7 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
|
||||
## Optimistic(?) time estimates:
|
||||
- Initial checks and push the tag: 30 minutes.
|
||||
- Note that if `RELEASES.md` has discrepancies this could take longer!
|
||||
- Waiting for the release: 60 minutes.
|
||||
- Fixing release notes: 10 minutes.
|
||||
- Bumping toolchains in downstream repositories, up to creating the Mathlib PR: 30 minutes.
|
||||
@@ -129,26 +131,29 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
git checkout nightly-2024-02-29
|
||||
git checkout -b releases/v4.7.0
|
||||
```
|
||||
- In `RELEASES.md` replace `Development in progress` in the `v4.7.0` section with `Release notes to be written.`
|
||||
- We will rely on automatically generated release notes for release candidates,
|
||||
and the written release notes will be used for stable versions only.
|
||||
It is essential to choose the nightly that will become the release candidate as early as possible, to avoid confusion.
|
||||
- In `RELEASES.md` remove `(development in progress)` from the `v4.7.0` section header.
|
||||
- Our current goal is to have written release notes only about major language features or breaking changes,
|
||||
and to rely on automatically generated release notes for bugfixes and minor changes.
|
||||
- Do not wait on `RELEASES.md` being perfect before creating the `release/v4.7.0` branch. It is essential to choose the nightly which will become the release candidate as early as possible, to avoid confusion.
|
||||
- If there are major changes not reflected in `RELEASES.md` already, you may need to solicit help from the authors.
|
||||
- Minor changes and bug fixes do not need to be documented in `RELEASES.md`: they will be added automatically on the Github release page.
|
||||
- Commit your changes to `RELEASES.md`, and push.
|
||||
- Remember that changes to `RELEASES.md` after you have branched `releases/v4.7.0` should also be cherry-picked back to `master`.
|
||||
- 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.
|
||||
- `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
|
||||
- Commit your changes to `src/CMakeLists.txt`, and push.
|
||||
- `git tag v4.7.0-rc1`
|
||||
- `git push origin v4.7.0-rc1`
|
||||
- Ping the FRO Zulip that release notes need to be written. The release notes do not block completing the rest of this checklist.
|
||||
- Now wait, while CI runs.
|
||||
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`, looking for the `v4.7.0-rc1` tag.
|
||||
- This step can take up to an hour.
|
||||
- (GitHub release notes) Once the release appears at https://github.com/leanprover/lean4/releases/
|
||||
- Once the release appears at https://github.com/leanprover/lean4/releases/
|
||||
- Edit the release notes on Github to select the "Set as a pre-release box".
|
||||
- If release notes have been written already, copy the section of `RELEASES.md` for this version into the Github release notes
|
||||
and use the title "Changes since v4.6.0 (from RELEASES.md)".
|
||||
- Otherwise, in the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
|
||||
This will add a list of all the commits since the last stable version.
|
||||
- Copy the section of `RELEASES.md` for this version into the Github release notes.
|
||||
- Use the title "Changes since v4.6.0 (from RELEASES.md)"
|
||||
- Then in the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
|
||||
- This will add a list of all the commits since the last stable version.
|
||||
- Delete anything already mentioned in the hand-written release notes above.
|
||||
- Delete "update stage0" commits, and anything with a completely inscrutable commit message.
|
||||
- Briefly rearrange the remaining items by category (e.g. `simp`, `lake`, `bug fixes`),
|
||||
@@ -174,9 +179,6 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
- We do this for the same list of repositories as for stable releases, see above.
|
||||
As above, there are dependencies between these, and so the process above is iterative.
|
||||
It greatly helps if you can merge the `bump/v4.7.0` PRs yourself!
|
||||
It is essential for Mathlib CI that you then create the next `bump/v4.8.0` branch
|
||||
for the next development cycle.
|
||||
Set the `lean-toolchain` file on this branch to same `nightly` you used for this release.
|
||||
- For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
|
||||
`nightly-testing-2024-02-29` with date corresponding to the nightly used for the release
|
||||
(create it if not), and then on the `nightly-testing` branch `git reset --hard master`, and force push.
|
||||
@@ -187,17 +189,8 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
||||
Please also make sure that whoever is handling social media knows the release is out.
|
||||
- Begin the next development cycle (i.e. for `v4.8.0`) on the Lean repository, by making a PR that:
|
||||
- Updates `src/CMakeLists.txt` to say `set(LEAN_VERSION_MINOR 8)`
|
||||
- Replaces the "development in progress" in the `v4.7.0` section of `RELEASES.md` with
|
||||
```
|
||||
Release candidate, release notes will be copied from `branch releases/v4.7.0` once completed.
|
||||
```
|
||||
and inserts the following section before that section:
|
||||
```
|
||||
v4.8.0
|
||||
----------
|
||||
Development in progress.
|
||||
```
|
||||
- Removes all the entries from the `./releases_drafts/` folder.
|
||||
- Removes `(in development)` from the section heading in `RELEASES.md` for `v4.7.0`,
|
||||
and creates a new `v4.8.0 (in development)` section heading.
|
||||
|
||||
## Time estimates:
|
||||
Slightly longer than the corresponding steps for a stable release.
|
||||
@@ -231,18 +224,3 @@ Please read https://leanprover-community.github.io/contribute/tags_and_branches.
|
||||
* It is always okay to merge in the following directions:
|
||||
`master` -> `bump/v4.7.0` -> `bump/nightly-2024-02-15` -> `nightly-testing`.
|
||||
Please remember to push any merges you make to intermediate steps!
|
||||
|
||||
# Writing the release notes
|
||||
|
||||
We are currently trying a system where release notes are compiled all at once from someone looking through the commit history.
|
||||
The exact steps are a work in progress.
|
||||
Here is the general idea:
|
||||
|
||||
* The work is done right on the `releases/v4.6.0` branch sometime after it is created but before the stable release is made.
|
||||
The release notes for `v4.6.0` will be copied to `master`.
|
||||
* There can be material for release notes entries in commit messages.
|
||||
* There can also be pre-written entries in `./releases_drafts`, which should be all incorporated in the release notes and then deleted from the branch.
|
||||
See `./releases_drafts/README.md` for more information.
|
||||
* The release notes should be written from a downstream expert user's point of view.
|
||||
|
||||
This section will be updated when the next release notes are written (for `v4.10.0`).
|
||||
|
||||
1
doc/examples/compiler/.gitignore
vendored
1
doc/examples/compiler/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
build
|
||||
@@ -13,7 +13,7 @@ Recall that nonnegative numerals are considered to be a `Nat` if there are no ty
|
||||
|
||||
The operator `/` for `Int` implements integer division.
|
||||
```lean
|
||||
#eval -10 / 4 -- -3
|
||||
#eval -10 / 4 -- -2
|
||||
```
|
||||
|
||||
Similar to `Nat`, the internal representation of `Int` is optimized. Small integers are
|
||||
|
||||
42
flake.nix
42
flake.nix
@@ -35,28 +35,26 @@
|
||||
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; inherit nix lean4-mode; };
|
||||
|
||||
devShellWithDist = pkgsDist: pkgs.mkShell.override {
|
||||
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
||||
} ({
|
||||
buildInputs = with pkgs; [
|
||||
cmake gmp ccache
|
||||
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
gdb
|
||||
# TODO: only add when proven to not affect the flakification
|
||||
#pkgs.python3
|
||||
tree # for CI
|
||||
];
|
||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||
hardeningDisable = [ "all" ];
|
||||
# more convenient `ctest` output
|
||||
CTEST_OUTPUT_ON_FAILURE = 1;
|
||||
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
GMP = pkgsDist.gmp.override { withStatic = true; };
|
||||
GLIBC = pkgsDist.glibc;
|
||||
GLIBC_DEV = pkgsDist.glibc.dev;
|
||||
GCC_LIB = pkgsDist.gcc.cc.lib;
|
||||
ZLIB = pkgsDist.zlib;
|
||||
GDB = pkgsDist.gdb;
|
||||
});
|
||||
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
||||
} ({
|
||||
buildInputs = with pkgs; [
|
||||
cmake gmp ccache
|
||||
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
# TODO: only add when proven to not affect the flakification
|
||||
#pkgs.python3
|
||||
];
|
||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||
hardeningDisable = [ "all" ];
|
||||
# more convenient `ctest` output
|
||||
CTEST_OUTPUT_ON_FAILURE = 1;
|
||||
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
GMP = pkgsDist.gmp.override { withStatic = true; };
|
||||
GLIBC = pkgsDist.glibc;
|
||||
GLIBC_DEV = pkgsDist.glibc.dev;
|
||||
GCC_LIB = pkgsDist.gcc.cc.lib;
|
||||
ZLIB = pkgsDist.zlib;
|
||||
GDB = pkgsDist.gdb;
|
||||
});
|
||||
in {
|
||||
packages = lean-packages // rec {
|
||||
debug = lean-packages.override { debug = true; };
|
||||
|
||||
@@ -87,8 +87,7 @@ rec {
|
||||
leanFlags = [ "-DwarningAsError=true" ];
|
||||
} // args);
|
||||
Init' = build { name = "Init"; deps = []; };
|
||||
Std' = build { name = "Std"; deps = [ Init' ]; };
|
||||
Lean' = build { name = "Lean"; deps = [ Std' ]; };
|
||||
Lean' = build { name = "Lean"; deps = [ Init' ]; };
|
||||
attachSharedLib = sharedLib: pkg: pkg // {
|
||||
inherit sharedLib;
|
||||
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
|
||||
@@ -96,8 +95,7 @@ rec {
|
||||
in (all: all // all.lean) rec {
|
||||
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
|
||||
Init = attachSharedLib leanshared Init';
|
||||
Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; };
|
||||
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; };
|
||||
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Init ]; };
|
||||
Lake = build {
|
||||
name = "Lake";
|
||||
src = src + "/src/lake";
|
||||
@@ -111,24 +109,23 @@ rec {
|
||||
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
|
||||
src = src + "/src/lake";
|
||||
};
|
||||
stdlib = [ Init Std Lean Lake ];
|
||||
stdlib = [ Init Lean Lake ];
|
||||
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
|
||||
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
|
||||
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
|
||||
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
|
||||
stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean";
|
||||
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${Lake.staticLib} -L${leancpp}/lib/lean";
|
||||
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
touch empty.c
|
||||
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared -Wl,-Bsymbolic \
|
||||
-Wl,--whole-archive -lInit ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ -lm ${stdlibLinkFlags} \
|
||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
||||
-o $out/$libName
|
||||
'';
|
||||
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||
mkdir $out
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
|
||||
${if stdenv.isDarwin
|
||||
then "-Wl,-force_load,${Init.staticLib}/libInit.a -Wl,-force_load,${Std.staticLib}/libStd.a -Wl,-force_load,${Lean.staticLib}/libLean.a -Wl,-force_load,${leancpp}/lib/lean/libleancpp.a ${leancpp}/lib/libleanrt_initial-exec.a -lc++"
|
||||
else "-Wl,--whole-archive -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++"} \
|
||||
-lm ${stdlibLinkFlags} \
|
||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared -Wl,-Bsymbolic \
|
||||
${libInit_shared}/* -Wl,--whole-archive -lLean -lleancpp -Wl,--no-whole-archive -lstdc++ -lm ${stdlibLinkFlags} \
|
||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
||||
-o $out/$libName
|
||||
'';
|
||||
@@ -154,9 +151,11 @@ rec {
|
||||
'';
|
||||
meta.mainProgram = "lean";
|
||||
};
|
||||
cacheRoots = linkFarmFromDrvs "cacheRoots" ([
|
||||
cacheRoots = linkFarmFromDrvs "cacheRoots" [
|
||||
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
|
||||
] ++ map (lib: lib.oTree) stdlib);
|
||||
# .o files are not a runtime dependency on macOS because of lack of thin archives
|
||||
Lean.oTree Lake.oTree
|
||||
];
|
||||
test = buildCMake {
|
||||
name = "lean-test-${desc}";
|
||||
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
|
||||
@@ -171,7 +170,7 @@ rec {
|
||||
ln -sf ${lean-all}/* .
|
||||
'';
|
||||
buildPhase = ''
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
|
||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_init' -j$NIX_BUILD_CORES
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
@@ -179,7 +178,7 @@ rec {
|
||||
'';
|
||||
};
|
||||
update-stage0 =
|
||||
let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) stdlib; }; in
|
||||
let cTree = symlinkJoin { name = "cs"; paths = [ Init.cTree Lean.cTree ]; }; in
|
||||
writeShellScriptBin "update-stage0" ''
|
||||
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
|
||||
'';
|
||||
|
||||
@@ -5,7 +5,7 @@ let lean-final' = lean-final; in
|
||||
lib.makeOverridable (
|
||||
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
|
||||
# Lean dependencies. Each entry should be an output of buildLeanPackage.
|
||||
deps ? [ lean.Init lean.Std lean.Lean ],
|
||||
deps ? [ lean.Lean ],
|
||||
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
|
||||
staticLibDeps ? [],
|
||||
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
|
||||
@@ -224,8 +224,7 @@ with builtins; let
|
||||
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
|
||||
|
||||
objects = mapAttrs (_: m: m.obj) mods';
|
||||
bintools = if stdenv.isDarwin then darwin.cctools else stdenv.cc.bintools.bintools;
|
||||
staticLib = runCommand "${name}-lib" { buildInputs = [ bintools ]; } ''
|
||||
staticLib = runCommand "${name}-lib" { buildInputs = [ stdenv.cc.bintools.bintools ]; } ''
|
||||
mkdir -p $out
|
||||
ar Trcs $out/lib${libName}.a ${lib.concatStringsSep " " (map (drv: "${drv}/${drv.oPath}") (attrValues objects))};
|
||||
'';
|
||||
@@ -250,7 +249,7 @@ in rec {
|
||||
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
|
||||
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
|
||||
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
|
||||
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.leanshared}/*";
|
||||
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.libInit_shared}/* ${lean-final.leanshared}/*";
|
||||
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
|
||||
mkdir -p $out/bin
|
||||
leanc ${staticLibLinkWrapper (lib.concatStringsSep " " (objPaths ++ map (d: "${d}/*.a") allStaticLibDeps))} \
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
A new linter flags situations where a local variable's name is one of
|
||||
the argumentless constructors of its type. This can arise when a user either
|
||||
doesn't open a namespace or doesn't add a dot or leading qualifier, as
|
||||
in the following:
|
||||
|
||||
````
|
||||
inductive Tree (α : Type) where
|
||||
| leaf
|
||||
| branch (left : Tree α) (val : α) (right : Tree α)
|
||||
|
||||
def depth : Tree α → Nat
|
||||
| leaf => 0
|
||||
````
|
||||
|
||||
With this linter, the `leaf` pattern is highlighted as a local
|
||||
variable whose name overlaps with the constructor `Tree.leaf`.
|
||||
|
||||
The linter can be disabled with `set_option linter.constructorNameAsVariable false`.
|
||||
|
||||
Additionally, the error message that occurs when a name in a pattern that takes arguments isn't valid now suggests similar names that would be valid. This means that the following definition:
|
||||
|
||||
```
|
||||
def length (list : List α) : Nat :=
|
||||
match list with
|
||||
| nil => 0
|
||||
| cons x xs => length xs + 1
|
||||
```
|
||||
|
||||
now results in the following warning:
|
||||
|
||||
```
|
||||
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
|
||||
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
|
||||
```
|
||||
|
||||
and error:
|
||||
|
||||
```
|
||||
invalid pattern, constructor or constant marked with '[match_pattern]' expected
|
||||
|
||||
Suggestion: 'List.cons' is similar
|
||||
```
|
||||
|
||||
|
||||
#4301
|
||||
@@ -15,19 +15,4 @@ for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
|
||||
cp $f stage0/$f
|
||||
fi
|
||||
done
|
||||
|
||||
# special handling for Lake files due to its nested directory
|
||||
# copy the README to ensure the `stage0/src/lake` directory is comitted
|
||||
for f in $(git ls-files 'src/lake/Lake/*' src/lake/Lake.lean src/lake/README.md ':!:src/lakefile.toml'); do
|
||||
if [[ $f == *.lean ]]; then
|
||||
f=${f#src/lake}
|
||||
f=${f%.lean}.c
|
||||
mkdir -p $(dirname stage0/stdlib/$f)
|
||||
cp ${CP_C_PARAMS:-} $CSRCS/$f stage0/stdlib/$f
|
||||
else
|
||||
mkdir -p $(dirname stage0/$f)
|
||||
cp $f stage0/$f
|
||||
fi
|
||||
done
|
||||
|
||||
git add stage0
|
||||
|
||||
@@ -9,7 +9,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 11)
|
||||
set(LEAN_VERSION_MINOR 10)
|
||||
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'")
|
||||
@@ -73,7 +73,6 @@ option(USE_GMP "USE_GMP" ON)
|
||||
|
||||
# development-specific options
|
||||
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
|
||||
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" OFF)
|
||||
|
||||
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
|
||||
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
|
||||
@@ -300,11 +299,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
|
||||
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
|
||||
endif()
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lStd -lLean -lleanrt")
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lStd -lLean -lnodefs.js -lleanrt")
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lnodefs.js -lleanrt")
|
||||
else()
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -lStd -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
|
||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
|
||||
endif()
|
||||
|
||||
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")
|
||||
@@ -510,15 +509,15 @@ file(RELATIVE_PATH LIB ${LEAN_SOURCE_DIR} ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
# set up libInit_shared only on Windows; see also stdlib.make.in
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
set(INIT_SHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libInit.a.export ${CMAKE_BINARY_DIR}/lib/temp/libStd.a.export ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a -Wl,--no-whole-archive -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libInit_shared.dll.a")
|
||||
set(INIT_SHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libInit.a.export ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a -Wl,--no-whole-archive -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libInit_shared.dll.a")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(LEANSHARED_LINKER_FLAGS "-Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libInit.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libStd.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLean.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
||||
set(LEANSHARED_LINKER_FLAGS "-Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libInit.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLean.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLean.a.export -lleancpp -Wl,--no-whole-archive -lInit_shared -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libleanshared.dll.a")
|
||||
else()
|
||||
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive -lInit -lStd -lLean -lleancpp -Wl,--no-whole-archive ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
||||
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive -lInit -lLean -lleancpp -Wl,--no-whole-archive ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
@@ -540,7 +539,7 @@ add_custom_target(make_stdlib ALL
|
||||
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
|
||||
# for a parallelized nested build, but CMake doesn't let us do that.
|
||||
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Std Lean
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Lean
|
||||
VERBATIM)
|
||||
|
||||
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
||||
@@ -578,7 +577,11 @@ else()
|
||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared")
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
if(${STAGE} GREATER 0 AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
if(NOT EXISTS ${LEAN_SOURCE_DIR}/lake/Lake.lean)
|
||||
message(FATAL_ERROR "src/lake does not exist. Please check out the Lake submodule using `git submodule update --init src/lake`.")
|
||||
endif()
|
||||
|
||||
add_custom_target(lake ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS leanshared
|
||||
@@ -655,9 +658,3 @@ endif()
|
||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
|
||||
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
|
||||
|
||||
if(USE_LAKE AND STAGE EQUAL 1)
|
||||
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/lakefile.toml)
|
||||
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../tests/lakefile.toml)
|
||||
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../lakefile.toml)
|
||||
endif()
|
||||
|
||||
@@ -131,7 +131,7 @@ protected def adapt {ε' α : Type u} (f : ε → ε') : ExceptT ε m α → Exc
|
||||
end ExceptT
|
||||
|
||||
@[always_inline]
|
||||
instance (m : Type u → Type v) (ε₁ : Type u) (ε₂ : Type u) [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
|
||||
instance (m : Type u → Type v) (ε₁ : Type u) (ε₂ : Type u) [Monad m] [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
|
||||
throw e := ExceptT.mk <| throwThe ε₁ e
|
||||
tryCatch x handle := ExceptT.mk <| tryCatchThe ε₁ x handle
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import Init.Meta
|
||||
|
||||
open Function
|
||||
|
||||
@[simp] theorem monadLift_self {m : Type u → Type v} (x : m α) : monadLift x = x :=
|
||||
@[simp] theorem monadLift_self [Monad m] (x : m α) : monadLift x = x :=
|
||||
rfl
|
||||
|
||||
/--
|
||||
|
||||
@@ -14,7 +14,7 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
theorem ext [Monad m] {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@@ -50,7 +50,7 @@ theorem run_bind [Monad m] (x : ExceptT ε m α)
|
||||
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α → β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
|
||||
rfl
|
||||
|
||||
protected theorem bind_pure_comp [Monad m] (f : α → β) (x : ExceptT ε m α) : x >>= pure ∘ f = f <$> x := by
|
||||
protected theorem bind_pure_comp [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α) : x >>= pure ∘ f = f <$> x := by
|
||||
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
|
||||
@@ -188,23 +188,23 @@ theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
|
||||
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
|
||||
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||
@[simp] theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
||||
|
||||
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[simp] theorem run_monadMap [MonadFunctor n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
@[simp] theorem run_monadMap [Monad m] [MonadFunctor n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ)
|
||||
: (monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||
show (f >>= fun g => g <$> x).run s = _
|
||||
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
|
||||
@[simp] theorem run_seqRight [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
|
||||
show (x >>= fun _ => y).run s = _
|
||||
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
|
||||
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
|
||||
show (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||
simp
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ instance : MonadExceptOf Unit (OptionT m) where
|
||||
throw := fun _ => OptionT.fail
|
||||
tryCatch := OptionT.tryCatch
|
||||
|
||||
instance (ε : Type u) [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
|
||||
instance (ε : Type u) [Monad m] [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
|
||||
throw e := OptionT.mk <| throwThe ε e
|
||||
tryCatch x handle := OptionT.mk <| tryCatchThe ε x handle
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ instance : MonadControl m (ReaderT ρ m) where
|
||||
restoreM x _ := x
|
||||
|
||||
@[always_inline]
|
||||
instance ReaderT.tryFinally [MonadFinally m] : MonadFinally (ReaderT ρ m) where
|
||||
instance ReaderT.tryFinally [MonadFinally m] [Monad m] : MonadFinally (ReaderT ρ m) where
|
||||
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
|
||||
|
||||
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id
|
||||
|
||||
@@ -87,7 +87,7 @@ protected def lift {α : Type u} (t : m α) : StateT σ m α :=
|
||||
instance : MonadLift m (StateT σ m) := ⟨StateT.lift⟩
|
||||
|
||||
@[always_inline]
|
||||
instance (σ m) : MonadFunctor m (StateT σ m) := ⟨fun f x s => f (x s)⟩
|
||||
instance (σ m) [Monad m] : MonadFunctor m (StateT σ m) := ⟨fun f x s => f (x s)⟩
|
||||
|
||||
@[always_inline]
|
||||
instance (ε) [MonadExceptOf ε m] : MonadExceptOf ε (StateT σ m) := {
|
||||
|
||||
@@ -14,18 +14,16 @@ def StateCpsT (σ : Type u) (m : Type u → Type v) (α : Type u) := (δ : Type
|
||||
|
||||
namespace StateCpsT
|
||||
|
||||
variable {α σ : Type u} {m : Type u → Type v}
|
||||
|
||||
@[always_inline, inline]
|
||||
def runK (x : StateCpsT σ m α) (s : σ) (k : α → σ → m β) : m β :=
|
||||
def runK {α σ : Type u} {m : Type u → Type v} (x : StateCpsT σ m α) (s : σ) (k : α → σ → m β) : m β :=
|
||||
x _ s k
|
||||
|
||||
@[always_inline, inline]
|
||||
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
||||
def run {α σ : Type u} {m : Type u → Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
||||
runK x s (fun a s => pure (a, s))
|
||||
|
||||
@[always_inline, inline]
|
||||
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
|
||||
def run' {α σ : Type u} {m : Type u → Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
|
||||
runK x s (fun a _ => pure a)
|
||||
|
||||
@[always_inline]
|
||||
@@ -50,29 +48,29 @@ protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
|
||||
instance [Monad m] : MonadLift m (StateCpsT σ m) where
|
||||
monadLift := StateCpsT.lift
|
||||
|
||||
@[simp] theorem runK_pure (a : α) (s : σ) (k : α → σ → m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
|
||||
@[simp] theorem runK_pure {m : Type u → Type v} (a : α) (s : σ) (k : α → σ → m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
|
||||
|
||||
@[simp] theorem runK_get (s : σ) (k : σ → σ → m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
|
||||
@[simp] theorem runK_get {m : Type u → Type v} (s : σ) (k : σ → σ → m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
|
||||
|
||||
@[simp] theorem runK_set (s s' : σ) (k : PUnit → σ → m β) : (set s' : StateCpsT σ m PUnit).runK s k = k ⟨⟩ s' := rfl
|
||||
@[simp] theorem runK_set {m : Type u → Type v} (s s' : σ) (k : PUnit → σ → m β) : (set s' : StateCpsT σ m PUnit).runK s k = k ⟨⟩ s' := rfl
|
||||
|
||||
@[simp] theorem runK_modify (f : σ → σ) (s : σ) (k : PUnit → σ → m β) : (modify f : StateCpsT σ m PUnit).runK s k = k ⟨⟩ (f s) := rfl
|
||||
@[simp] theorem runK_modify {m : Type u → Type v} (f : σ → σ) (s : σ) (k : PUnit → σ → m β) : (modify f : StateCpsT σ m PUnit).runK s k = k ⟨⟩ (f s) := rfl
|
||||
|
||||
@[simp] theorem runK_lift [Monad m] (x : m α) (s : σ) (k : α → σ → m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
|
||||
@[simp] theorem runK_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) (k : α → σ → m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
|
||||
|
||||
@[simp] theorem runK_monadLift [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α → σ → m β)
|
||||
@[simp] theorem runK_monadLift {σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α → σ → m β)
|
||||
: (monadLift x : StateCpsT σ m α).runK s k = (monadLift x : m α) >>= (k . s) := rfl
|
||||
|
||||
@[simp] theorem runK_bind_pure (a : α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
|
||||
@[simp] theorem runK_bind_pure {α σ : Type u} [Monad m] (a : α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
|
||||
|
||||
@[simp] theorem runK_bind_lift [Monad m] (x : m α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ)
|
||||
@[simp] theorem runK_bind_lift {α σ : Type u} [Monad m] (x : m α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ)
|
||||
: (StateCpsT.lift x >>= f).runK s k = x >>= fun a => (f a).runK s k := rfl
|
||||
|
||||
@[simp] theorem runK_bind_get (f : σ → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
|
||||
@[simp] theorem runK_bind_get {σ : Type u} [Monad m] (f : σ → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
|
||||
|
||||
@[simp] theorem runK_bind_set (f : PUnit → StateCpsT σ m β) (s s' : σ) (k : β → σ → m γ) : (set s' >>= f).runK s k = (f ⟨⟩).runK s' k := rfl
|
||||
@[simp] theorem runK_bind_set {σ : Type u} [Monad m] (f : PUnit → StateCpsT σ m β) (s s' : σ) (k : β → σ → m γ) : (set s' >>= f).runK s k = (f ⟨⟩).runK s' k := rfl
|
||||
|
||||
@[simp] theorem runK_bind_modify (f : σ → σ) (g : PUnit → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (modify f >>= g).runK s k = (g ⟨⟩).runK (f s) k := rfl
|
||||
@[simp] theorem runK_bind_modify {σ : Type u} [Monad m] (f : σ → σ) (g : PUnit → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (modify f >>= g).runK s k = (g ⟨⟩).runK (f s) k := rfl
|
||||
|
||||
@[simp] theorem run_eq [Monad m] (x : StateCpsT σ m α) (s : σ) : x.run s = x.runK s (fun a s => pure (a, s)) := rfl
|
||||
|
||||
|
||||
@@ -34,22 +34,22 @@ protected def lift (x : m α) : StateRefT' ω σ m α :=
|
||||
|
||||
instance [Monad m] : Monad (StateRefT' ω σ m) := inferInstanceAs (Monad (ReaderT _ _))
|
||||
instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
|
||||
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
|
||||
instance (σ m) [Monad m] : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
|
||||
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
|
||||
|
||||
@[inline]
|
||||
protected def get [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
|
||||
protected def get [Monad m] [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
|
||||
fun ref => ref.get
|
||||
|
||||
@[inline]
|
||||
protected def set [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
|
||||
protected def set [Monad m] [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
|
||||
fun ref => ref.set s
|
||||
|
||||
@[inline]
|
||||
protected def modifyGet [MonadLiftT (ST ω) m] (f : σ → α × σ) : StateRefT' ω σ m α :=
|
||||
protected def modifyGet [Monad m] [MonadLiftT (ST ω) m] (f : σ → α × σ) : StateRefT' ω σ m α :=
|
||||
fun ref => ref.modifyGet f
|
||||
|
||||
instance [MonadLiftT (ST ω) m] : MonadStateOf σ (StateRefT' ω σ m) where
|
||||
instance [MonadLiftT (ST ω) m] [Monad m] : MonadStateOf σ (StateRefT' ω σ m) where
|
||||
get := StateRefT'.get
|
||||
set := StateRefT'.set
|
||||
modifyGet := StateRefT'.modifyGet
|
||||
@@ -64,5 +64,5 @@ end StateRefT'
|
||||
instance (ω σ : Type) (m : Type → Type) : MonadControl m (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (MonadControl m (ReaderT _ _))
|
||||
|
||||
instance {m : Type → Type} {ω σ : Type} [MonadFinally m] : MonadFinally (StateRefT' ω σ m) :=
|
||||
instance {m : Type → Type} {ω σ : Type} [MonadFinally m] [Monad m] : MonadFinally (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (MonadFinally (ReaderT _ _))
|
||||
|
||||
@@ -642,7 +642,7 @@ instance : LawfulBEq String := inferInstance
|
||||
|
||||
/-! # Logical connectives and equality -/
|
||||
|
||||
@[inherit_doc True.intro] theorem trivial : True := ⟨⟩
|
||||
@[inherit_doc True.intro] def trivial : True := ⟨⟩
|
||||
|
||||
theorem mt {a b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a :=
|
||||
fun ha => h₂ (h₁ ha)
|
||||
@@ -1089,18 +1089,15 @@ def InvImage {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β
|
||||
fun a₁ a₂ => r (f a₁) (f a₂)
|
||||
|
||||
/--
|
||||
The transitive closure `TransGen r` of a relation `r` is the smallest relation which is
|
||||
transitive and contains `r`. `TransGen r a z` if and only if there exists a sequence
|
||||
The transitive closure `r⁺` of a relation `r` is the smallest relation which is
|
||||
transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence
|
||||
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
|
||||
-/
|
||||
inductive Relation.TransGen {α : Sort u} (r : α → α → Prop) : α → α → Prop
|
||||
/-- If `r a b` then `TransGen r a b`. This is the base case of the transitive closure. -/
|
||||
| single {a b} : r a b → TransGen r a b
|
||||
inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where
|
||||
/-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/
|
||||
| base : ∀ a b, r a b → TC r a b
|
||||
/-- The transitive closure is transitive. -/
|
||||
| tail {a b c} : TransGen r a b → r b c → TransGen r a c
|
||||
|
||||
/-- Deprecated synonym for `Relation.TransGen`. -/
|
||||
@[deprecated Relation.TransGen (since := "2024-07-16")] abbrev TC := @Relation.TransGen
|
||||
| trans : ∀ a b c, TC r a b → TC r b c → TC r a c
|
||||
|
||||
/-! # Subtype -/
|
||||
|
||||
@@ -1176,7 +1173,7 @@ def Prod.lexLt [LT α] [LT β] (s : α × β) (t : α × β) : Prop :=
|
||||
s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)
|
||||
|
||||
instance Prod.lexLtDec
|
||||
[LT α] [LT β] [DecidableEq α]
|
||||
[LT α] [LT β] [DecidableEq α] [DecidableEq β]
|
||||
[(a b : α) → Decidable (a < b)] [(a b : β) → Decidable (a < b)]
|
||||
: (s t : α × β) → Decidable (Prod.lexLt s t) :=
|
||||
fun _ _ => inferInstanceAs (Decidable (_ ∨ _))
|
||||
@@ -1194,11 +1191,6 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
|
||||
(f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂
|
||||
| (a, b) => (f a, g b)
|
||||
|
||||
@[simp] theorem Prod.map_apply (f : α → β) (g : γ → δ) (x) (y) :
|
||||
Prod.map f g (x, y) = (f x, g y) := rfl
|
||||
@[simp] theorem Prod.map_fst (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).1 = f x.1 := rfl
|
||||
@[simp] theorem Prod.map_snd (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).2 = g x.2 := rfl
|
||||
|
||||
/-! # Dependent products -/
|
||||
|
||||
theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
|
||||
@@ -1365,9 +1357,6 @@ theorem iff_false_right (ha : ¬a) : (b ↔ a) ↔ ¬b := Iff.comm.trans (iff_fa
|
||||
theorem of_iff_true (h : a ↔ True) : a := h.mpr trivial
|
||||
theorem iff_true_intro (h : a) : a ↔ True := iff_of_true h trivial
|
||||
|
||||
theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True :=
|
||||
iff_true_intro (Subsingleton.elim ..)
|
||||
|
||||
theorem not_of_iff_false : (p ↔ False) → ¬p := Iff.mp
|
||||
theorem iff_false_intro (h : ¬a) : a ↔ False := iff_of_false h id
|
||||
|
||||
@@ -1873,7 +1862,7 @@ instance : Subsingleton (Squash α) where
|
||||
/--
|
||||
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
||||
-/
|
||||
class Antisymm {α : Sort u} (r : α → α → Prop) : Prop where
|
||||
class Antisymm {α : Sort u} (r : α → α → Prop) where
|
||||
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
||||
antisymm {a b : α} : r a b → r b a → a = b
|
||||
|
||||
|
||||
@@ -35,4 +35,3 @@ import Init.Data.Queue
|
||||
import Init.Data.Channel
|
||||
import Init.Data.Cast
|
||||
import Init.Data.Sum
|
||||
import Init.Data.BEq
|
||||
|
||||
@@ -10,7 +10,5 @@ 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
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2021 Floris van Doorn. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Mem
|
||||
import Init.Data.List.Attach
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`Array {x // P x}` is the same as the input `Array α`.
|
||||
-/
|
||||
@[inline] private unsafe def attachWithImpl
|
||||
(xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs
|
||||
|
||||
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array
|
||||
with the same elements but in the type `{x // P x}`. -/
|
||||
@[implemented_by attachWithImpl] def attachWith
|
||||
(xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} :=
|
||||
⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩
|
||||
|
||||
/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array
|
||||
with the same elements but in the type `{x // x ∈ xs}`. -/
|
||||
@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id
|
||||
|
||||
end Array
|
||||
@@ -60,6 +60,8 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||
|
||||
def back [Inhabited α] (a : Array α) : α :=
|
||||
a.get! (a.size - 1)
|
||||
|
||||
@@ -479,7 +481,7 @@ def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
|
||||
Id.run <| as.allM p start stop
|
||||
|
||||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||||
as.any (· == a)
|
||||
as.any fun b => a == b
|
||||
|
||||
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||||
as.contains a
|
||||
|
||||
@@ -9,7 +9,7 @@ import Init.Data.Nat.Linear
|
||||
import Init.NotationExtra
|
||||
|
||||
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs ∧ a = b := by
|
||||
simp only [push, mk.injEq] at h
|
||||
simp [push] at h
|
||||
have ⟨h₁, h₂⟩ := List.of_concat_eq_concat h
|
||||
cases as; cases bs
|
||||
simp_all
|
||||
|
||||
@@ -14,7 +14,7 @@ import Init.TacticsExtra
|
||||
/-!
|
||||
## Bootstrapping theorems about arrays
|
||||
|
||||
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
|
||||
This file contains some theorems about `Array` and `List` needed for `Std.List.Basic`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
@@ -34,12 +34,8 @@ attribute [simp] data_toArray uset
|
||||
|
||||
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
|
||||
|
||||
theorem getElem_eq_data_getElem (a : Array α) (h : i < a.size) : a[i] = a.data[i] := by
|
||||
by_cases i < a.size <;> (try simp [*]) <;> rfl
|
||||
|
||||
@[deprecated getElem_eq_data_getElem (since := "2024-06-12")]
|
||||
theorem getElem_eq_data_get (a : Array α) (h : i < a.size) : a[i] = a.data.get ⟨i, h⟩ := by
|
||||
simp [getElem_eq_data_getElem]
|
||||
by_cases i < a.size <;> (try simp [*]) <;> rfl
|
||||
|
||||
theorem foldlM_eq_foldlM_data.aux [Monad m]
|
||||
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
||||
@@ -51,7 +47,7 @@ theorem foldlM_eq_foldlM_data.aux [Monad m]
|
||||
simp [foldlM_eq_foldlM_data.aux f arr i (j+1) H]
|
||||
rw (config := {occs := .pos [2]}) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
· rw [List.drop_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
|
||||
theorem foldlM_eq_foldlM_data [Monad m]
|
||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||
@@ -118,11 +114,11 @@ theorem foldr_push (f : α → β → β) (init : β) (arr : Array α) (a : α)
|
||||
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
|
||||
(a.push x)[i] = a[i] := by
|
||||
simp only [push, getElem_eq_data_getElem, List.concat_eq_append, List.getElem_append_left, h]
|
||||
simp only [push, getElem_eq_data_get, List.concat_eq_append, List.get_append_left, h]
|
||||
|
||||
@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
||||
simp only [push, getElem_eq_data_getElem, List.concat_eq_append]
|
||||
rw [List.getElem_append_right] <;> simp [getElem_eq_data_getElem, Nat.zero_lt_one]
|
||||
simp only [push, getElem_eq_data_get, List.concat_eq_append]
|
||||
rw [List.get_append_right] <;> simp [getElem_eq_data_get, Nat.zero_lt_one]
|
||||
|
||||
theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||
(a.push x)[i] = if h : i < a.size then a[i] else x := by
|
||||
@@ -139,9 +135,8 @@ where
|
||||
mapM.map f arr i r = (arr.data.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
||||
unfold mapM.map; split
|
||||
· rw [← List.get_drop_eq_drop _ i ‹_›]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, data_length, List.foldlM_cons, bind_assoc, pure_bind]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
simp [aux (i+1), map_eq_pure_bind]; rfl
|
||||
· rw [List.drop_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
termination_by arr.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
|
||||
@@ -220,7 +215,7 @@ theorem getElem?_len_le (a : Array α) {i : Nat} (h : a.size ≤ i) : a[i]? = no
|
||||
theorem getD_get? (a : Array α) (i : Nat) (d : α) :
|
||||
Option.getD a[i]? d = if p : i < a.size then a[i]'p else d := by
|
||||
if h : i < a.size then
|
||||
simp [setD, h, getElem?_def]
|
||||
simp [setD, h, getElem?]
|
||||
else
|
||||
have p : i ≥ a.size := Nat.le_of_not_gt h
|
||||
simp [setD, getElem?_len_le _ p, h]
|
||||
@@ -238,11 +233,11 @@ theorem get!_eq_getD [Inhabited α] (a : Array α) : a.get! n = a.getD n default
|
||||
@[simp] theorem getElem_set_eq (a : Array α) (i : Fin a.size) (v : α) {j : Nat}
|
||||
(eq : i.val = j) (p : j < (a.set i v).size) :
|
||||
(a.set i v)[j]'p = v := by
|
||||
simp [set, getElem_eq_data_getElem, ←eq]
|
||||
simp [set, getElem_eq_data_get, ←eq]
|
||||
|
||||
@[simp] theorem getElem_set_ne (a : Array α) (i : Fin a.size) (v : α) {j : Nat} (pj : j < (a.set i v).size)
|
||||
(h : i.val ≠ j) : (a.set i v)[j]'pj = a[j]'(size_set a i v ▸ pj) := by
|
||||
simp only [set, getElem_eq_data_getElem, List.getElem_set_ne h]
|
||||
simp only [set, getElem_eq_data_get, List.get_set_ne _ h]
|
||||
|
||||
theorem getElem_set (a : Array α) (i : Fin a.size) (v : α) (j : Nat)
|
||||
(h : j < (a.set i v).size) :
|
||||
@@ -326,7 +321,7 @@ termination_by n - i
|
||||
@[simp] theorem mkArray_data (n : Nat) (v : α) : (mkArray n v).data = List.replicate n v := rfl
|
||||
|
||||
@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) :
|
||||
(mkArray n v)[i] = v := by simp [Array.getElem_eq_data_getElem]
|
||||
(mkArray n v)[i] = v := by simp [Array.getElem_eq_data_get]
|
||||
|
||||
/-- # mem -/
|
||||
|
||||
@@ -337,7 +332,7 @@ theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||
/-- # get lemmas -/
|
||||
|
||||
theorem getElem?_mem {l : Array α} {i : Fin l.size} : l[i] ∈ l := by
|
||||
erw [Array.mem_def, getElem_eq_data_getElem]
|
||||
erw [Array.mem_def, getElem_eq_data_get]
|
||||
apply List.get_mem
|
||||
|
||||
theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl
|
||||
@@ -352,7 +347,7 @@ theorem get?_len_le (a : Array α) (i : Nat) (h : a.size ≤ i) : a[i]? = none :
|
||||
simp [getElem?_neg, h]
|
||||
|
||||
theorem getElem_mem_data (a : Array α) (h : i < a.size) : a[i] ∈ a.data := by
|
||||
simp only [getElem_eq_data_getElem, List.getElem_mem]
|
||||
simp only [getElem_eq_data_get, List.get_mem]
|
||||
|
||||
theorem getElem?_eq_data_get? (a : Array α) (i : Nat) : a[i]? = a.data.get? i := by
|
||||
by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm]; rfl
|
||||
@@ -383,24 +378,24 @@ theorem get?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x el
|
||||
| Or.inl g =>
|
||||
have h1 : i < a.size + 1 := by omega
|
||||
have h2 : i ≠ a.size := by omega
|
||||
simp [getElem?_def, size_push, g, h1, h2, get_push_lt]
|
||||
simp [getElem?, size_push, g, h1, h2, get_push_lt]
|
||||
| Or.inr (Or.inl heq) =>
|
||||
simp [heq, getElem?_pos, get_push_eq]
|
||||
| Or.inr (Or.inr g) =>
|
||||
simp only [getElem?_def, size_push]
|
||||
simp only [getElem?, size_push]
|
||||
have h1 : ¬ (i < a.size) := by omega
|
||||
have h2 : ¬ (i < a.size + 1) := by omega
|
||||
have h3 : i ≠ a.size := by omega
|
||||
simp [h1, h2, h3]
|
||||
|
||||
@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by
|
||||
simp only [getElem?_def, Nat.lt_irrefl, dite_false]
|
||||
simp only [getElem?, Nat.lt_irrefl, dite_false]
|
||||
|
||||
@[simp] theorem data_set (a : Array α) (i v) : (a.set i v).data = a.data.set i.1 v := rfl
|
||||
|
||||
theorem get_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||
(a.set i v)[i.1] = v := by
|
||||
simp only [set, getElem_eq_data_getElem, List.getElem_set_eq]
|
||||
simp only [set, getElem_eq_data_get, List.get_set_eq]
|
||||
|
||||
theorem get?_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||
(a.set i v)[i.1]? = v := by simp [getElem?_pos, i.2]
|
||||
@@ -419,7 +414,7 @@ theorem get_set (a : Array α) (i : Fin a.size) (j : Nat) (hj : j < a.size) (v :
|
||||
|
||||
@[simp] theorem get_set_ne (a : Array α) (i : Fin a.size) {j : Nat} (v : α) (hj : j < a.size)
|
||||
(h : i.1 ≠ j) : (a.set i v)[j]'(by simp [*]) = a[j] := by
|
||||
simp only [set, getElem_eq_data_getElem, List.getElem_set_ne h]
|
||||
simp only [set, getElem_eq_data_get, List.get_set_ne _ h]
|
||||
|
||||
theorem getElem_setD (a : Array α) (i : Nat) (v : α) (h : i < (setD a i v).size) :
|
||||
(setD a i v)[i] = v := by
|
||||
@@ -457,7 +452,7 @@ theorem swapAt!_def (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
||||
|
||||
@[simp] theorem getElem_pop (a : Array α) (i : Nat) (hi : i < a.pop.size) :
|
||||
a.pop[i] = a[i]'(Nat.lt_of_lt_of_le (a.size_pop ▸ hi) (Nat.sub_le _ _)) :=
|
||||
List.getElem_dropLast ..
|
||||
List.get_dropLast ..
|
||||
|
||||
theorem eq_empty_of_size_eq_zero {as : Array α} (h : as.size = 0) : as = #[] := by
|
||||
apply ext
|
||||
@@ -505,7 +500,6 @@ theorem size_eq_length_data (as : Array α) : as.size = as.data.length := rfl
|
||||
simp only [mkEmpty_eq, size_push] at *
|
||||
omega
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem reverse_data (a : Array α) : a.reverse.data = a.data.reverse := by
|
||||
let rec go (as : Array α) (i j hj)
|
||||
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
|
||||
@@ -523,10 +517,10 @@ set_option linter.deprecated false in
|
||||
simp only [H, getElem_eq_data_get, ← List.get?_eq_get, Nat.le_of_lt h₁, getElem?_eq_data_get?]
|
||||
split <;> rename_i h₂
|
||||
· simp only [← h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
|
||||
exact (List.get?_reverse' (j+1) i (Eq.trans (by simp_arith) h)).symm
|
||||
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
|
||||
split <;> rename_i h₃
|
||||
· simp only [← h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
|
||||
exact (List.get?_reverse' i (j+1) (Eq.trans (by simp_arith) h)).symm
|
||||
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
|
||||
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
|
||||
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
|
||||
· rw [H]; split <;> rename_i h₂
|
||||
@@ -539,7 +533,7 @@ set_option linter.deprecated false in
|
||||
split
|
||||
· match a with | ⟨[]⟩ | ⟨[_]⟩ => rfl
|
||||
· have := Nat.sub_add_cancel (Nat.le_of_not_le ‹_›)
|
||||
refine List.ext_get? <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
|
||||
refine List.ext <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
|
||||
split
|
||||
· rfl
|
||||
· rename_i h
|
||||
@@ -750,7 +744,7 @@ theorem mem_of_mem_filter {a : α} {l} (h : a ∈ filter p l) : a ∈ l :=
|
||||
exact this #[]
|
||||
induction l
|
||||
· simp_all [Id.run]
|
||||
· simp_all [Id.run, List.filterMap_cons]
|
||||
· simp_all [Id.run]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem mem_filterMap (f : α → Option β) (l : Array α) {b : β} :
|
||||
@@ -775,17 +769,17 @@ theorem size_append (as bs : Array α) : (as ++ bs).size = as.size + bs.size :=
|
||||
|
||||
theorem get_append_left {as bs : Array α} {h : i < (as ++ bs).size} (hlt : i < as.size) :
|
||||
(as ++ bs)[i] = as[i] := by
|
||||
simp only [getElem_eq_data_getElem]
|
||||
simp only [getElem_eq_data_get]
|
||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||
conv => rhs; rw [← List.getElem_append_left (bs := bs.data) (h' := h')]
|
||||
conv => rhs; rw [← List.get_append_left (bs:=bs.data) (h':=h')]
|
||||
apply List.get_of_eq; rw [append_data]
|
||||
|
||||
theorem get_append_right {as bs : Array α} {h : i < (as ++ bs).size} (hle : as.size ≤ i)
|
||||
(hlt : i - as.size < bs.size := Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) :
|
||||
(as ++ bs)[i] = bs[i - as.size] := by
|
||||
simp only [getElem_eq_data_getElem]
|
||||
simp only [getElem_eq_data_get]
|
||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||
conv => rhs; rw [← List.getElem_append_right (h' := h') (h := Nat.not_lt_of_ge hle)]
|
||||
conv => rhs; rw [← List.get_append_right (h':=h') (h:=Nat.not_lt_of_ge hle)]
|
||||
apply List.get_of_eq; rw [append_data]
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
@@ -993,13 +987,13 @@ theorem all_eq_true (p : α → Bool) (as : Array α) : all as p ↔ ∀ i : Fin
|
||||
simp [all_iff_forall, Fin.isLt]
|
||||
|
||||
theorem all_def {p : α → Bool} (as : Array α) : as.all p = as.data.all p := by
|
||||
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_getElem]
|
||||
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_get]
|
||||
constructor
|
||||
· rintro w x ⟨r, h, rfl⟩
|
||||
rw [← getElem_eq_data_getElem]
|
||||
exact w ⟨r, h⟩
|
||||
· rintro w x ⟨r, rfl⟩
|
||||
rw [← getElem_eq_data_get]
|
||||
apply w
|
||||
· intro w i
|
||||
exact w as[i] ⟨i, i.2, (getElem_eq_data_getElem as i.2).symm⟩
|
||||
exact w as[i] ⟨i, (getElem_eq_data_get as i.2).symm⟩
|
||||
|
||||
theorem all_eq_true_iff_forall_mem {l : Array α} : l.all p ↔ ∀ x, x ∈ l → p x := by
|
||||
simp only [all_def, List.all_eq_true, mem_def]
|
||||
|
||||
@@ -23,7 +23,7 @@ theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a <
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
|
||||
|
||||
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
||||
@[simp] theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
||||
cases as with | _ as =>
|
||||
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ def get (s : Subarray α) (i : Fin s.size) : α :=
|
||||
instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||
|
||||
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
||||
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.TakeDrop
|
||||
|
||||
namespace Array
|
||||
|
||||
theorem exists_of_uset (self : Array α) (i d h) :
|
||||
∃ l₁ l₂, self.data = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||
(self.uset i d h).data = l₁ ++ d :: l₂ := by
|
||||
simpa [Array.getElem_eq_data_getElem] using List.exists_of_set _
|
||||
|
||||
end Array
|
||||
@@ -1,60 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Markus Himmel
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Bool
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
/-- `PartialEquivBEq α` says that the `BEq` implementation is a
|
||||
partial equivalence relation, that is:
|
||||
* it is symmetric: `a == b → b == a`
|
||||
* it is transitive: `a == b → b == c → a == c`.
|
||||
-/
|
||||
class PartialEquivBEq (α) [BEq α] : Prop where
|
||||
/-- Symmetry for `BEq`. If `a == b` then `b == a`. -/
|
||||
symm : (a : α) == b → b == a
|
||||
/-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/
|
||||
trans : (a : α) == b → b == c → a == c
|
||||
|
||||
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
|
||||
class ReflBEq (α) [BEq α] : Prop where
|
||||
/-- Reflexivity for `BEq`. -/
|
||||
refl : (a : α) == a
|
||||
|
||||
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
|
||||
class EquivBEq (α) [BEq α] extends PartialEquivBEq α, ReflBEq α : Prop
|
||||
|
||||
@[simp]
|
||||
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=
|
||||
ReflBEq.refl
|
||||
|
||||
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b → a == b
|
||||
| rfl => BEq.refl
|
||||
|
||||
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||
PartialEquivBEq.symm
|
||||
|
||||
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
||||
|
||||
theorem BEq.symm_false [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = false → (b == a) = false :=
|
||||
BEq.comm (α := α) ▸ id
|
||||
|
||||
theorem BEq.trans [BEq α] [PartialEquivBEq α] {a b c : α} : a == b → b == c → a == c :=
|
||||
PartialEquivBEq.trans
|
||||
|
||||
theorem BEq.neq_of_neq_of_beq [BEq α] [PartialEquivBEq α] {a b c : α} :
|
||||
(a == b) = false → b == c → (a == c) = false :=
|
||||
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₁ (BEq.trans h₃ (BEq.symm h₂))
|
||||
|
||||
theorem BEq.neq_of_beq_of_neq [BEq α] [PartialEquivBEq α] {a b c : α} :
|
||||
a == b → (b == c) = false → (a == c) = false :=
|
||||
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₂ (BEq.trans (BEq.symm h₁) h₃)
|
||||
|
||||
instance (priority := low) [BEq α] [LawfulBEq α] : EquivBEq α where
|
||||
refl := LawfulBEq.rfl
|
||||
symm h := (beq_iff_eq _ _).2 <| Eq.symm <| (beq_iff_eq _ _).1 h
|
||||
trans hab hbc := (beq_iff_eq _ _).2 <| ((beq_iff_eq _ _).1 hab).trans <| (beq_iff_eq _ _).1 hbc
|
||||
@@ -198,7 +198,7 @@ instance : Add (BitVec n) := ⟨BitVec.add⟩
|
||||
Subtraction for bit vectors. This can be interpreted as either signed or unsigned subtraction
|
||||
modulo `2^n`.
|
||||
-/
|
||||
protected def sub (x y : BitVec n) : BitVec n := .ofNat n ((2^n - y.toNat) + x.toNat)
|
||||
protected def sub (x y : BitVec n) : BitVec n := .ofNat n (x.toNat + (2^n - y.toNat))
|
||||
instance : Sub (BitVec n) := ⟨BitVec.sub⟩
|
||||
|
||||
/--
|
||||
@@ -614,13 +614,6 @@ theorem ofBool_append (msb : Bool) (lsbs : BitVec w) :
|
||||
ofBool msb ++ lsbs = (cons msb lsbs).cast (Nat.add_comm ..) :=
|
||||
rfl
|
||||
|
||||
/--
|
||||
`twoPow w i` is the bitvector `2^i` if `i < w`, and `0` otherwise.
|
||||
That is, 2 to the power `i`.
|
||||
For the bitwise point of view, it has the `i`th bit as `1` and all other bits as `0`.
|
||||
-/
|
||||
def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
|
||||
|
||||
end bitwise
|
||||
|
||||
section normalization_eqs
|
||||
|
||||
@@ -159,21 +159,6 @@ theorem add_eq_adc (w : Nat) (x y : BitVec w) : x + y = (adc x y false).snd := b
|
||||
theorem allOnes_sub_eq_not (x : BitVec w) : allOnes w - x = ~~~x := by
|
||||
rw [← add_not_self x, BitVec.add_comm, add_sub_cancel]
|
||||
|
||||
/-- Addition of bitvectors is the same as bitwise or, if bitwise and is zero. -/
|
||||
theorem add_eq_or_of_and_eq_zero {w : Nat} (x y : BitVec w)
|
||||
(h : x &&& y = 0#w) : x + y = x ||| y := by
|
||||
rw [add_eq_adc, adc, iunfoldr_replace (fun _ => false) (x ||| y)]
|
||||
· rfl
|
||||
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false, getLsb_or,
|
||||
Prod.mk.injEq, and_eq_false_imp]
|
||||
intros i
|
||||
replace h : (x &&& y).getLsb i = (0#w).getLsb i := by rw [h]
|
||||
simp only [getLsb_and, getLsb_zero, and_eq_false_imp] at h
|
||||
constructor
|
||||
· intros hx
|
||||
simp_all [hx]
|
||||
· by_cases hx : x.getLsb i <;> simp_all [hx]
|
||||
|
||||
/-! ### Negation -/
|
||||
|
||||
theorem bit_not_testBit (x : BitVec w) (i : Fin w) :
|
||||
@@ -250,80 +235,4 @@ theorem sle_eq_carry (x y : BitVec w) :
|
||||
x.sle y = !((x.msb == y.msb).xor (carry w y (~~~x) true)) := by
|
||||
rw [sle_eq_not_slt, slt_eq_not_carry, beq_comm]
|
||||
|
||||
/-! ### mul recurrence for bitblasting -/
|
||||
|
||||
/--
|
||||
A recurrence that describes multiplication as repeated addition.
|
||||
Is useful for bitblasting multiplication.
|
||||
-/
|
||||
def mulRec (l r : BitVec w) (s : Nat) : BitVec w :=
|
||||
let cur := if r.getLsb s then (l <<< s) else 0
|
||||
match s with
|
||||
| 0 => cur
|
||||
| s + 1 => mulRec l r s + cur
|
||||
|
||||
theorem mulRec_zero_eq (l r : BitVec w) :
|
||||
mulRec l r 0 = if r.getLsb 0 then l else 0 := by
|
||||
simp [mulRec]
|
||||
|
||||
theorem mulRec_succ_eq (l r : BitVec w) (s : Nat) :
|
||||
mulRec l r (s + 1) = mulRec l r s + if r.getLsb (s + 1) then (l <<< (s + 1)) else 0 := rfl
|
||||
|
||||
/--
|
||||
Recurrence lemma: truncating to `i+1` bits and then zero extending to `w`
|
||||
equals truncating upto `i` bits `[0..i-1]`, and then adding the `i`th bit of `x`.
|
||||
-/
|
||||
theorem zeroExtend_truncate_succ_eq_zeroExtend_truncate_add_twoPow (x : BitVec w) (i : Nat) :
|
||||
zeroExtend w (x.truncate (i + 1)) =
|
||||
zeroExtend w (x.truncate i) + (x &&& twoPow w i) := by
|
||||
rw [add_eq_or_of_and_eq_zero]
|
||||
· ext k
|
||||
simp only [getLsb_zeroExtend, Fin.is_lt, decide_True, Bool.true_and, getLsb_or, getLsb_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
· simp only [getLsb_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
|
||||
by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
· have hik'' : ¬ (k < i) := by omega
|
||||
simp [hik', hik'']
|
||||
· ext k
|
||||
simp
|
||||
omega
|
||||
|
||||
/--
|
||||
Recurrence lemma: multiplying `l` with the first `s` bits of `r` is the
|
||||
same as truncating `r` to `s` bits, then zero extending to the original length,
|
||||
and performing the multplication. -/
|
||||
theorem mulRec_eq_mul_signExtend_truncate (l r : BitVec w) (s : Nat) :
|
||||
mulRec l r s = l * ((r.truncate (s + 1)).zeroExtend w) := by
|
||||
induction s
|
||||
case zero =>
|
||||
simp only [mulRec_zero_eq, ofNat_eq_ofNat, Nat.reduceAdd]
|
||||
by_cases r.getLsb 0
|
||||
case pos hr =>
|
||||
simp only [hr, ↓reduceIte, truncate, zeroExtend_one_eq_ofBool_getLsb_zero,
|
||||
hr, ofBool_true, ofNat_eq_ofNat]
|
||||
rw [zeroExtend_ofNat_one_eq_ofNat_one_of_lt (by omega)]
|
||||
simp
|
||||
case neg hr =>
|
||||
simp [hr, zeroExtend_one_eq_ofBool_getLsb_zero]
|
||||
case succ s' hs =>
|
||||
rw [mulRec_succ_eq, hs]
|
||||
have heq :
|
||||
(if r.getLsb (s' + 1) = true then l <<< (s' + 1) else 0) =
|
||||
(l * (r &&& (BitVec.twoPow w (s' + 1)))) := by
|
||||
simp only [ofNat_eq_ofNat, and_twoPow_eq]
|
||||
by_cases hr : r.getLsb (s' + 1) <;> simp [hr]
|
||||
rw [heq, ← BitVec.mul_add, ← zeroExtend_truncate_succ_eq_zeroExtend_truncate_add_twoPow]
|
||||
|
||||
theorem getLsb_mul (x y : BitVec w) (i : Nat) :
|
||||
(x * y).getLsb i = (mulRec x y w).getLsb i := by
|
||||
simp only [mulRec_eq_mul_signExtend_truncate]
|
||||
rw [truncate, ← truncate_eq_zeroExtend, ← truncate_eq_zeroExtend,
|
||||
truncate_truncate_of_le]
|
||||
· simp
|
||||
· omega
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -110,8 +110,8 @@ theorem eq_of_getMsb_eq {x y : BitVec w}
|
||||
theorem of_length_zero {x : BitVec 0} : x = 0#0 := by ext; simp
|
||||
|
||||
@[simp] theorem toNat_zero_length (x : BitVec 0) : x.toNat = 0 := by simp [of_length_zero]
|
||||
theorem getLsb_zero_length (x : BitVec 0) : x.getLsb i = false := by simp
|
||||
theorem getMsb_zero_length (x : BitVec 0) : x.getMsb i = false := by simp
|
||||
@[simp] theorem getLsb_zero_length (x : BitVec 0) : x.getLsb i = false := by simp [of_length_zero]
|
||||
@[simp] theorem getMsb_zero_length (x : BitVec 0) : x.getMsb i = false := by simp [of_length_zero]
|
||||
@[simp] theorem msb_zero_length (x : BitVec 0) : x.msb = false := by simp [BitVec.msb, of_length_zero]
|
||||
|
||||
theorem eq_of_toFin_eq : ∀ {x y : BitVec w}, x.toFin = y.toFin → x = y
|
||||
@@ -163,13 +163,6 @@ theorem toNat_zero (n : Nat) : (0#n).toNat = 0 := by trivial
|
||||
private theorem lt_two_pow_of_le {x m n : Nat} (lt : x < 2 ^ m) (le : m ≤ n) : x < 2 ^ n :=
|
||||
Nat.lt_of_lt_of_le lt (Nat.pow_le_pow_of_le_right (by trivial : 0 < 2) le)
|
||||
|
||||
@[simp]
|
||||
theorem getLsb_ofBool (b : Bool) (i : Nat) : (BitVec.ofBool b).getLsb i = ((i = 0) && b) := by
|
||||
rcases b with rfl | rfl
|
||||
· simp [ofBool]
|
||||
· simp only [ofBool, ofNat_eq_ofNat, cond_true, getLsb_ofNat, Bool.and_true]
|
||||
by_cases hi : i = 0 <;> simp [hi] <;> omega
|
||||
|
||||
/-! ### msb -/
|
||||
|
||||
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsb]
|
||||
@@ -191,7 +184,8 @@ theorem msb_eq_getLsb_last (x : BitVec w) :
|
||||
· simp only [h]
|
||||
rw [Nat.div_eq_sub_div (Nat.two_pow_pos w) h, Nat.div_eq_of_lt]
|
||||
· decide
|
||||
· omega
|
||||
· have : BitVec.toNat x < 2^w + 2^w := by simpa [Nat.pow_succ, Nat.mul_two] using x.isLt
|
||||
omega
|
||||
|
||||
@[bv_toNat] theorem getLsb_succ_last (x : BitVec (w + 1)) :
|
||||
x.getLsb w = decide (2 ^ w ≤ x.toNat) := getLsb_last x
|
||||
@@ -293,9 +287,6 @@ theorem toInt_ofNat {n : Nat} (x : Nat) :
|
||||
|
||||
/-! ### zeroExtend and truncate -/
|
||||
|
||||
theorem truncate_eq_zeroExtend {v : Nat} {x : BitVec w} :
|
||||
truncate v x = zeroExtend v x := rfl
|
||||
|
||||
@[simp, bv_toNat] theorem toNat_zeroExtend' {m n : Nat} (p : m ≤ n) (x : BitVec m) :
|
||||
(zeroExtend' p x).toNat = x.toNat := by
|
||||
unfold zeroExtend'
|
||||
@@ -329,7 +320,7 @@ theorem zeroExtend'_eq {x : BitVec w} (h : w ≤ v) : x.zeroExtend' h = x.zeroEx
|
||||
apply eq_of_toNat_eq
|
||||
simp [toNat_zeroExtend]
|
||||
|
||||
theorem truncate_eq (x : BitVec n) : truncate n x = x := zeroExtend_eq x
|
||||
@[simp] theorem truncate_eq (x : BitVec n) : truncate n x = x := zeroExtend_eq x
|
||||
|
||||
@[simp] theorem ofNat_toNat (m : Nat) (x : BitVec n) : BitVec.ofNat m x.toNat = truncate m x := by
|
||||
apply eq_of_toNat_eq
|
||||
@@ -340,7 +331,10 @@ theorem toNat_eq_nat (x : BitVec w) (y : Nat)
|
||||
: (x.toNat = y) ↔ (y < 2^w ∧ (x = BitVec.ofNat w y)) := by
|
||||
apply Iff.intro
|
||||
· intro eq
|
||||
simp [←eq, x.isLt]
|
||||
simp at eq
|
||||
have lt := x.isLt
|
||||
simp [eq] at lt
|
||||
simp [←eq, lt, x.isLt]
|
||||
· intro eq
|
||||
simp [Nat.mod_eq_of_lt, eq]
|
||||
|
||||
@@ -383,7 +377,7 @@ theorem nat_eq_toNat (x : BitVec w) (y : Nat)
|
||||
all_goals (first | apply getLsb_ge | apply Eq.symm; apply getLsb_ge)
|
||||
<;> omega
|
||||
|
||||
theorem getLsb_truncate (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
@[simp] theorem getLsb_truncate (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
getLsb (truncate m x) i = (decide (i < m) && getLsb x i) :=
|
||||
getLsb_zeroExtend m x i
|
||||
|
||||
@@ -402,12 +396,6 @@ theorem msb_truncate (x : BitVec w) : (x.truncate (k + 1)).msb = x.getLsb k := b
|
||||
(x.truncate l).truncate k = x.truncate k :=
|
||||
zeroExtend_zeroExtend_of_le x h
|
||||
|
||||
/--Truncating by the bitwidth has no effect. -/
|
||||
@[simp]
|
||||
theorem truncate_eq_self {x : BitVec w} : x.truncate w = x := by
|
||||
ext i
|
||||
simp [getLsb_zeroExtend]
|
||||
|
||||
@[simp] theorem truncate_cast {h : w = v} : (cast h x).truncate k = x.truncate k := by
|
||||
apply eq_of_getLsb_eq
|
||||
simp
|
||||
@@ -420,22 +408,6 @@ theorem msb_zeroExtend (x : BitVec w) : (x.zeroExtend v).msb = (decide (0 < v) &
|
||||
theorem msb_zeroExtend' (x : BitVec w) (h : w ≤ v) : (x.zeroExtend' h).msb = (decide (0 < v) && x.getLsb (v - 1)) := by
|
||||
rw [zeroExtend'_eq, msb_zeroExtend]
|
||||
|
||||
/-- zero extending a bitvector to width 1 equals the boolean of the lsb. -/
|
||||
theorem zeroExtend_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||
x.zeroExtend 1 = BitVec.ofBool (x.getLsb 0) := by
|
||||
ext i
|
||||
simp [getLsb_zeroExtend, Fin.fin_one_eq_zero i]
|
||||
|
||||
/-- Zero extending `1#v` to `1#w` equals `1#w` when `v > 0`. -/
|
||||
theorem zeroExtend_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
(BitVec.ofNat v 1).zeroExtend w = BitVec.ofNat w 1 := by
|
||||
ext ⟨i, hilt⟩
|
||||
simp only [getLsb_zeroExtend, hilt, decide_True, getLsb_ofNat, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||
intros hi₁
|
||||
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
||||
omega
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp]
|
||||
@@ -608,7 +580,7 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
ext
|
||||
simp_all [lt_of_getLsb]
|
||||
|
||||
@[simp] theorem xor_cast {x y : BitVec w} (h : w = w') : cast h x ^^^ cast h y = cast h (x ^^^ y) := by
|
||||
@[simp] theorem xor_cast {x y : BitVec w} (h : w = w') : cast h x &&& cast h y = cast h (x &&& y) := by
|
||||
ext
|
||||
simp_all [lt_of_getLsb]
|
||||
|
||||
@@ -621,11 +593,6 @@ theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
@[simp] theorem toFin_shiftLeft {n : Nat} (x : BitVec w) :
|
||||
BitVec.toFin (x <<< n) = Fin.ofNat' (x.toNat <<< n) (Nat.two_pow_pos w) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem shiftLeft_zero_eq (x : BitVec w) : x <<< 0 = x := by
|
||||
apply eq_of_toNat_eq
|
||||
simp
|
||||
|
||||
@[simp] theorem getLsb_shiftLeft (x : BitVec m) (n) :
|
||||
getLsb (x <<< n) i = (decide (i < m) && !decide (i < n) && getLsb x (i - n)) := by
|
||||
rw [← testBit_toNat, getLsb]
|
||||
@@ -1078,18 +1045,10 @@ theorem ofInt_add {n} (x y : Int) : BitVec.ofInt n (x + y) =
|
||||
|
||||
/-! ### sub/neg -/
|
||||
|
||||
theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toNat) := by rfl
|
||||
|
||||
@[simp] theorem toNat_sub {n} (x y : BitVec n) :
|
||||
(x - y).toNat = (((2^n - y.toNat) + x.toNat) % 2^n) := rfl
|
||||
|
||||
-- We prefer this lemma to `toNat_sub` for the `bv_toNat` simp set.
|
||||
-- For reasons we don't yet understand, unfolding via `toNat_sub` sometimes
|
||||
-- results in `omega` generating proof terms that are very slow in the kernel.
|
||||
@[bv_toNat] theorem toNat_sub' {n} (x y : BitVec n) :
|
||||
(x - y).toNat = ((x.toNat + (2^n - y.toNat)) % 2^n) := by
|
||||
rw [toNat_sub, Nat.add_comm]
|
||||
theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n (x.toNat + (2^n - y.toNat)) := by rfl
|
||||
|
||||
@[simp, bv_toNat] theorem toNat_sub {n} (x y : BitVec n) :
|
||||
(x - y).toNat = ((x.toNat + (2^n - y.toNat)) % 2^n) := rfl
|
||||
@[simp] theorem toFin_sub (x y : BitVec n) : (x - y).toFin = toFin x - toFin y := rfl
|
||||
|
||||
@[simp] theorem ofFin_sub (x : Fin (2^n)) (y : BitVec n) : .ofFin x - y = .ofFin (x - y.toFin) :=
|
||||
@@ -1098,7 +1057,7 @@ theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toN
|
||||
rfl
|
||||
-- Remark: we don't use `[simp]` here because simproc` subsumes it for literals.
|
||||
-- If `x` and `n` are not literals, applying this theorem eagerly may not be a good idea.
|
||||
theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y = .ofNat n ((2^n - y % 2^n) + x) := by
|
||||
theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y = .ofNat n (x + (2^n - y % 2^n)) := by
|
||||
apply eq_of_toNat_eq ; simp [BitVec.ofNat]
|
||||
|
||||
@[simp] protected theorem sub_zero (x : BitVec n) : x - 0#n = x := by apply eq_of_toNat_eq ; simp
|
||||
@@ -1106,7 +1065,7 @@ theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y =
|
||||
@[simp] protected theorem sub_self (x : BitVec n) : x - x = 0#n := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_sub]
|
||||
rw [Nat.add_comm, Nat.add_sub_of_le]
|
||||
rw [Nat.add_sub_of_le]
|
||||
· simp
|
||||
· exact Nat.le_of_lt x.isLt
|
||||
|
||||
@@ -1120,15 +1079,14 @@ theorem ofNat_sub_ofNat {n} (x y : Nat) : BitVec.ofNat n x - BitVec.ofNat n y =
|
||||
theorem sub_toAdd {n} (x y : BitVec n) : x - y = x + - y := by
|
||||
apply eq_of_toNat_eq
|
||||
simp
|
||||
rw [Nat.add_comm]
|
||||
|
||||
@[simp] theorem neg_zero (n:Nat) : -BitVec.ofNat n 0 = BitVec.ofNat n 0 := by apply eq_of_toNat_eq ; simp
|
||||
|
||||
theorem add_sub_cancel (x y : BitVec w) : x + y - y = x := by
|
||||
apply eq_of_toNat_eq
|
||||
have y_toNat_le := Nat.le_of_lt y.isLt
|
||||
rw [toNat_sub, toNat_add, Nat.add_comm, Nat.mod_add_mod, Nat.add_assoc, ← Nat.add_sub_assoc y_toNat_le,
|
||||
Nat.add_sub_cancel_left, Nat.add_mod_right, toNat_mod_cancel]
|
||||
rw [toNat_sub, toNat_add, Nat.mod_add_mod, Nat.add_assoc, ← Nat.add_sub_assoc y_toNat_le,
|
||||
Nat.add_sub_cancel_left, Nat.add_mod_right, toNat_mod_cancel]
|
||||
|
||||
theorem sub_add_cancel (x y : BitVec w) : x - y + y = x := by
|
||||
rw [sub_toAdd, BitVec.add_assoc, BitVec.add_comm _ y,
|
||||
@@ -1181,18 +1139,6 @@ instance : Std.Associative (fun (x y : BitVec w) => x * y) := ⟨BitVec.mul_asso
|
||||
instance : Std.LawfulCommIdentity (fun (x y : BitVec w) => x * y) (1#w) where
|
||||
right_id := BitVec.mul_one
|
||||
|
||||
@[simp]
|
||||
theorem BitVec.mul_zero {x : BitVec w} : x * 0#w = 0#w := by
|
||||
apply eq_of_toNat_eq
|
||||
simp [toNat_mul]
|
||||
|
||||
theorem BitVec.mul_add {x y z : BitVec w} :
|
||||
x * (y + z) = x * y + x * z := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_mul, toNat_add, Nat.add_mod_mod, Nat.mod_add_mod]
|
||||
rw [Nat.mul_mod, Nat.mod_mod (y.toNat + z.toNat),
|
||||
← Nat.mul_mod, Nat.mul_add]
|
||||
|
||||
@[simp, bv_toNat] theorem toInt_mul (x y : BitVec w) :
|
||||
(x * y).toInt = (x.toInt * y.toInt).bmod (2^w) := by
|
||||
simp [toInt_eq_toNat_bmod]
|
||||
@@ -1293,7 +1239,11 @@ x.rotateLeft 2 = (<6 5 | 4 3 2 1 0>).rotateLeft 2 = <3 2 1 0 | 6 5>
|
||||
theorem getLsb_rotateLeftAux_of_le {x : BitVec w} {r : Nat} {i : Nat} (hi : i < r) :
|
||||
(x.rotateLeftAux r).getLsb i = x.getLsb (w - r + i) := by
|
||||
rw [rotateLeftAux, getLsb_or, getLsb_ushiftRight]
|
||||
simp; omega
|
||||
suffices (x <<< r).getLsb i = false by
|
||||
simp; omega
|
||||
simp only [getLsb_shiftLeft, Bool.and_eq_false_imp, Bool.and_eq_true, decide_eq_true_eq,
|
||||
Bool.not_eq_true', decide_eq_false_iff_not, Nat.not_lt, and_imp]
|
||||
omega
|
||||
|
||||
/--
|
||||
Accessing bits in `x.rotateLeft r` the range `[r, w)` is equal to
|
||||
@@ -1424,84 +1374,4 @@ theorem getLsb_rotateRight {x : BitVec w} {r i : Nat} :
|
||||
· simp
|
||||
· rw [← rotateRight_mod_eq_rotateRight, getLsb_rotateRight_of_le (Nat.mod_lt _ (by omega))]
|
||||
|
||||
/- ## twoPow -/
|
||||
|
||||
@[simp, bv_toNat]
|
||||
theorem toNat_twoPow (w : Nat) (i : Nat) : (twoPow w i).toNat = 2^i % 2^w := by
|
||||
rcases w with rfl | w
|
||||
· simp [Nat.mod_one]
|
||||
· simp only [twoPow, toNat_shiftLeft, toNat_ofNat]
|
||||
have h1 : 1 < 2 ^ (w + 1) := Nat.one_lt_two_pow (by omega)
|
||||
rw [Nat.mod_eq_of_lt h1, Nat.shiftLeft_eq, Nat.one_mul]
|
||||
|
||||
@[simp]
|
||||
theorem getLsb_twoPow (i j : Nat) : (twoPow w i).getLsb j = ((i < w) && (i = j)) := by
|
||||
rcases w with rfl | w
|
||||
· simp
|
||||
· simp only [twoPow, getLsb_shiftLeft, getLsb_ofNat]
|
||||
by_cases hj : j < i
|
||||
· simp only [hj, decide_True, Bool.not_true, Bool.and_false, Bool.false_and, Bool.false_eq,
|
||||
Bool.and_eq_false_imp, decide_eq_true_eq, decide_eq_false_iff_not]
|
||||
omega
|
||||
· by_cases hi : Nat.testBit 1 (j - i)
|
||||
· obtain hi' := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi
|
||||
have hij : j = i := by omega
|
||||
simp_all
|
||||
· have hij : i ≠ j := by
|
||||
intro h; subst h
|
||||
simp at hi
|
||||
simp_all
|
||||
|
||||
theorem and_twoPow_eq (x : BitVec w) (i : Nat) :
|
||||
x &&& (twoPow w i) = if x.getLsb i then twoPow w i else 0#w := by
|
||||
ext j
|
||||
simp only [getLsb_and, getLsb_twoPow]
|
||||
by_cases hj : i = j <;> by_cases hx : x.getLsb i <;> simp_all
|
||||
|
||||
@[simp]
|
||||
theorem mul_twoPow_eq_shiftLeft (x : BitVec w) (i : Nat) :
|
||||
x * (twoPow w i) = x <<< i := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_mul, toNat_twoPow, toNat_shiftLeft, Nat.shiftLeft_eq]
|
||||
by_cases hi : i < w
|
||||
· have hpow : 2^i < 2^w := Nat.pow_lt_pow_of_lt (by omega) (by omega)
|
||||
rw [Nat.mod_eq_of_lt hpow]
|
||||
· have hpow : 2 ^ i % 2 ^ w = 0 := by
|
||||
rw [Nat.mod_eq_zero_of_dvd]
|
||||
apply Nat.pow_dvd_pow 2 (by omega)
|
||||
simp [Nat.mul_mod, hpow]
|
||||
|
||||
/- ### zeroExtend, truncate, and bitwise operations -/
|
||||
|
||||
/--
|
||||
When the `(i+1)`th bit of `x` is false,
|
||||
keeping the lower `(i + 1)` bits of `x` equals keeping the lower `i` bits.
|
||||
-/
|
||||
theorem zeroExtend_truncate_succ_eq_zeroExtend_truncate_of_getLsb_false
|
||||
{x : BitVec w} {i : Nat} (hx : x.getLsb i = false) :
|
||||
zeroExtend w (x.truncate (i + 1)) =
|
||||
zeroExtend w (x.truncate i) := by
|
||||
ext k
|
||||
simp only [getLsb_zeroExtend, Fin.is_lt, decide_True, Bool.true_and, getLsb_or, getLsb_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
· by_cases hik' : k < i + 1 <;> simp [hik'] <;> omega
|
||||
|
||||
/--
|
||||
When the `(i+1)`th bit of `x` is true,
|
||||
keeping the lower `(i + 1)` bits of `x` equalsk eeping the lower `i` bits
|
||||
and then performing bitwise-or with `twoPow i = (1 << i)`,
|
||||
-/
|
||||
theorem zeroExtend_truncate_succ_eq_zeroExtend_truncate_or_twoPow_of_getLsb_true
|
||||
{x : BitVec w} {i : Nat} (hx : x.getLsb i = true) :
|
||||
zeroExtend w (x.truncate (i + 1)) =
|
||||
zeroExtend w (x.truncate i) ||| (twoPow w i) := by
|
||||
ext k
|
||||
simp only [getLsb_zeroExtend, Fin.is_lt, decide_True, Bool.true_and, getLsb_or, getLsb_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
· by_cases hik' : k < i + 1 <;> simp [hik, hik'] <;> omega
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -52,8 +52,8 @@ theorem eq_iff_iff {a b : Bool} : a = b ↔ (a ↔ b) := by cases b <;> simp
|
||||
|
||||
@[simp] theorem decide_eq_true {b : Bool} [Decidable (b = true)] : decide (b = true) = b := by cases b <;> simp
|
||||
@[simp] theorem decide_eq_false {b : Bool} [Decidable (b = false)] : decide (b = false) = !b := by cases b <;> simp
|
||||
theorem decide_true_eq {b : Bool} [Decidable (true = b)] : decide (true = b) = b := by cases b <;> simp
|
||||
theorem decide_false_eq {b : Bool} [Decidable (false = b)] : decide (false = b) = !b := by cases b <;> simp
|
||||
@[simp] theorem decide_true_eq {b : Bool} [Decidable (true = b)] : decide (true = b) = b := by cases b <;> simp
|
||||
@[simp] theorem decide_false_eq {b : Bool} [Decidable (false = b)] : decide (false = b) = !b := by cases b <;> simp
|
||||
|
||||
/-! ### and -/
|
||||
|
||||
@@ -163,7 +163,7 @@ Consider the term: `¬((b && c) = true)`:
|
||||
-/
|
||||
@[simp] theorem and_eq_false_imp : ∀ (x y : Bool), (x && y) = false ↔ (x = true → y = false) := by decide
|
||||
|
||||
theorem or_eq_true_iff : ∀ (x y : Bool), (x || y) = true ↔ x = true ∨ y = true := by simp
|
||||
@[simp] theorem or_eq_true_iff : ∀ (x y : Bool), (x || y) = true ↔ x = true ∨ y = true := by decide
|
||||
|
||||
@[simp] theorem or_eq_false_iff : ∀ (x y : Bool), (x || y) = false ↔ x = false ∧ y = false := by decide
|
||||
|
||||
@@ -187,9 +187,11 @@ in false_eq and true_eq.
|
||||
|
||||
@[simp] theorem true_beq : ∀b, (true == b) = b := by decide
|
||||
@[simp] theorem false_beq : ∀b, (false == b) = !b := by decide
|
||||
@[simp] theorem beq_true : ∀b, (b == true) = b := by decide
|
||||
instance : Std.LawfulIdentity (· == ·) true where
|
||||
left_id := true_beq
|
||||
right_id := beq_true
|
||||
@[simp] theorem beq_false : ∀b, (b == false) = !b := by decide
|
||||
|
||||
@[simp] theorem true_bne : ∀(b : Bool), (true != b) = !b := by decide
|
||||
@[simp] theorem false_bne : ∀(b : Bool), (false != b) = b := by decide
|
||||
@@ -351,7 +353,7 @@ theorem and_or_inj_left_iff :
|
||||
/-! ## toNat -/
|
||||
|
||||
/-- convert a `Bool` to a `Nat`, `false -> 0`, `true -> 1` -/
|
||||
def toNat (b : Bool) : Nat := cond b 1 0
|
||||
def toNat (b:Bool) : Nat := cond b 1 0
|
||||
|
||||
@[simp] theorem toNat_false : false.toNat = 0 := rfl
|
||||
|
||||
@@ -494,16 +496,6 @@ protected theorem cond_false {α : Type u} {a b : α} : cond false a b = b := co
|
||||
@[simp] theorem cond_true_same : ∀(c b : Bool), cond c c b = (c || b) := by decide
|
||||
@[simp] theorem cond_false_same : ∀(c b : Bool), cond c b c = (c && b) := by decide
|
||||
|
||||
theorem cond_pos {b : Bool} {a a' : α} (h : b = true) : (bif b then a else a') = a := by
|
||||
rw [h, cond_true]
|
||||
|
||||
theorem cond_neg {b : Bool} {a a' : α} (h : b = false) : (bif b then a else a') = a' := by
|
||||
rw [h, cond_false]
|
||||
|
||||
theorem apply_cond (f : α → β) {b : Bool} {a a' : α} :
|
||||
f (bif b then a else a') = bif b then f a else f a' := by
|
||||
cases b <;> simp
|
||||
|
||||
/-# decidability -/
|
||||
|
||||
protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = true) = b := decide_eq_true
|
||||
|
||||
@@ -52,9 +52,13 @@ def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
|
||||
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||
|
||||
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||
|
||||
@[extern "lean_byte_array_set"]
|
||||
def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
||||
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
||||
@@ -92,24 +96,20 @@ protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
|
||||
instance : Append ByteArray := ⟨ByteArray.append⟩
|
||||
|
||||
def toList (bs : ByteArray) : List UInt8 :=
|
||||
partial def toList (bs : ByteArray) : List UInt8 :=
|
||||
let rec loop (i : Nat) (r : List UInt8) :=
|
||||
if i < bs.size then
|
||||
loop (i+1) (bs.get! i :: r)
|
||||
else
|
||||
r.reverse
|
||||
termination_by bs.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
loop 0 []
|
||||
|
||||
@[inline] def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
||||
@[inline] partial def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
||||
let rec @[specialize] loop (i : Nat) :=
|
||||
if i < a.size then
|
||||
if p (a.get! i) then some i else loop (i+1)
|
||||
else
|
||||
none
|
||||
termination_by a.size - i
|
||||
decreasing_by decreasing_trivial_pre_omega
|
||||
loop start
|
||||
|
||||
/--
|
||||
|
||||
@@ -22,18 +22,13 @@ protected theorem le_total (a b : Char) : a ≤ b ∨ b ≤ a := UInt32.le_total
|
||||
protected theorem lt_asymm {a b : Char} (h : a < b) : ¬ b < a := UInt32.lt_asymm h
|
||||
protected theorem ne_of_lt {a b : Char} (h : a < b) : a ≠ b := Char.ne_of_val_ne (UInt32.ne_of_lt h)
|
||||
|
||||
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
have := c.utf8Size_pos
|
||||
have := c.utf8Size_le_four
|
||||
omega
|
||||
theorem utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
simp only [utf8Size]
|
||||
repeat (split; decide)
|
||||
decide
|
||||
|
||||
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@[ext] protected theorem ext : {a b : Char} → a.val = b.val → a = b
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl => rfl
|
||||
|
||||
end Char
|
||||
|
||||
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size
|
||||
|
||||
@@ -66,24 +66,7 @@ protected def mul : Fin n → Fin n → Fin n
|
||||
|
||||
/-- Subtraction modulo `n` -/
|
||||
protected def sub : Fin n → Fin n → Fin n
|
||||
/-
|
||||
The definition of `Fin.sub` has been updated to improve performance.
|
||||
The right-hand-side of the following `match` was originally
|
||||
```
|
||||
⟨(a + (n - b)) % n, mlt h⟩
|
||||
```
|
||||
This caused significant performance issues when testing definitional equality,
|
||||
such as `x =?= x - 1` where `x : Fin n` and `n` is a big number,
|
||||
as Lean spent a long time reducing
|
||||
```
|
||||
((n - 1) + x.val) % n
|
||||
```
|
||||
For example, this was an issue for `Fin 2^64` (i.e., `UInt64`).
|
||||
This change improves performance by leveraging the fact that `Nat.add` is defined
|
||||
using recursion on the second argument.
|
||||
See issue #4413.
|
||||
-/
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, mlt h⟩
|
||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
|
||||
|
||||
/-!
|
||||
Remark: land/lor can be defined without using (% n), but
|
||||
@@ -210,7 +193,4 @@ theorem val_add_one_le_of_lt {n : Nat} {a b : Fin n} (h : a < b) : (a : Nat) + 1
|
||||
|
||||
theorem val_add_one_le_of_gt {n : Nat} {a b : Fin n} (h : a > b) : (b : Nat) + 1 ≤ (a : Nat) := h
|
||||
|
||||
theorem exists_iff {p : Fin n → Prop} : (Exists fun i => p i) ↔ Exists fun i => Exists fun h => p ⟨i, h⟩ :=
|
||||
⟨fun ⟨⟨i, hi⟩, hpi⟩ => ⟨i, hi, hpi⟩, fun ⟨i, hi, hpi⟩ => ⟨⟨i, hi⟩, hpi⟩⟩
|
||||
|
||||
end Fin
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Bitwise
|
||||
import Init.Data.Fin.Basic
|
||||
|
||||
namespace Fin
|
||||
|
||||
@[simp] theorem and_val (a b : Fin n) : (a &&& b).val = a.val &&& b.val :=
|
||||
Nat.mod_eq_of_lt (Nat.lt_of_le_of_lt Nat.and_le_left a.isLt)
|
||||
|
||||
end Fin
|
||||
@@ -24,7 +24,7 @@ theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk ((a + (n - b)) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||
|
||||
theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.size_pos
|
||||
|
||||
@@ -37,20 +37,25 @@ theorem pos_iff_nonempty {n : Nat} : 0 < n ↔ Nonempty (Fin n) :=
|
||||
|
||||
@[simp] protected theorem eta (a : Fin n) (h : a < n) : (⟨a, h⟩ : Fin n) = a := rfl
|
||||
|
||||
@[ext] protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
||||
@[ext] theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
||||
|
||||
theorem ext_iff {a b : Fin n} : a = b ↔ a.1 = b.1 := val_inj.symm
|
||||
|
||||
theorem val_ne_iff {a b : Fin n} : a.1 ≠ b.1 ↔ a ≠ b := not_congr val_inj
|
||||
|
||||
theorem exists_iff {p : Fin n → Prop} : (∃ i, p i) ↔ ∃ i h, p ⟨i, h⟩ :=
|
||||
⟨fun ⟨⟨i, hi⟩, hpi⟩ => ⟨i, hi, hpi⟩, fun ⟨i, hi, hpi⟩ => ⟨⟨i, hi⟩, hpi⟩⟩
|
||||
|
||||
theorem forall_iff {p : Fin n → Prop} : (∀ i, p i) ↔ ∀ i h, p ⟨i, h⟩ :=
|
||||
⟨fun h i hi => h ⟨i, hi⟩, fun h ⟨i, hi⟩ => h i hi⟩
|
||||
|
||||
protected theorem mk.inj_iff {n a b : Nat} {ha : a < n} {hb : b < n} :
|
||||
(⟨a, ha⟩ : Fin n) = ⟨b, hb⟩ ↔ a = b := Fin.ext_iff
|
||||
(⟨a, ha⟩ : Fin n) = ⟨b, hb⟩ ↔ a = b := ext_iff
|
||||
|
||||
theorem val_mk {m n : Nat} (h : m < n) : (⟨m, h⟩ : Fin n).val = m := rfl
|
||||
|
||||
theorem eq_mk_iff_val_eq {a : Fin n} {k : Nat} {hk : k < n} :
|
||||
a = ⟨k, hk⟩ ↔ (a : Nat) = k := Fin.ext_iff
|
||||
a = ⟨k, hk⟩ ↔ (a : Nat) = k := ext_iff
|
||||
|
||||
theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@@ -143,7 +148,7 @@ theorem eq_succ_of_ne_zero {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) : ∃ j :
|
||||
|
||||
@[simp] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := ext <| by
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem rev_le_rev {i j : Fin n} : rev i ≤ rev j ↔ j ≤ i := by
|
||||
@@ -169,12 +174,12 @@ theorem le_last (i : Fin (n + 1)) : i ≤ last n := Nat.le_of_lt_succ i.is_lt
|
||||
theorem last_pos : (0 : Fin (n + 2)) < last (n + 1) := Nat.succ_pos _
|
||||
|
||||
theorem eq_last_of_not_lt {i : Fin (n + 1)} (h : ¬(i : Nat) < n) : i = last n :=
|
||||
Fin.ext <| Nat.le_antisymm (le_last i) (Nat.not_lt.1 h)
|
||||
ext <| Nat.le_antisymm (le_last i) (Nat.not_lt.1 h)
|
||||
|
||||
theorem val_lt_last {i : Fin (n + 1)} : i ≠ last n → (i : Nat) < n :=
|
||||
Decidable.not_imp_comm.1 eq_last_of_not_lt
|
||||
|
||||
@[simp] theorem rev_last (n : Nat) : rev (last n) = 0 := Fin.ext <| by simp
|
||||
@[simp] theorem rev_last (n : Nat) : rev (last n) = 0 := ext <| by simp
|
||||
|
||||
@[simp] theorem rev_zero (n : Nat) : rev 0 = last n := by
|
||||
rw [← rev_rev (last _), rev_last]
|
||||
@@ -242,11 +247,11 @@ theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt one_pos
|
||||
@[simp] theorem succ_lt_succ_iff {a b : Fin n} : a.succ < b.succ ↔ a < b := Nat.succ_lt_succ_iff
|
||||
|
||||
@[simp] theorem succ_inj {a b : Fin n} : a.succ = b.succ ↔ a = b := by
|
||||
refine ⟨fun h => Fin.ext ?_, congrArg _⟩
|
||||
refine ⟨fun h => ext ?_, congrArg _⟩
|
||||
apply Nat.le_antisymm <;> exact succ_le_succ_iff.1 (h ▸ Nat.le_refl _)
|
||||
|
||||
theorem succ_ne_zero {n} : ∀ k : Fin n, Fin.succ k ≠ 0
|
||||
| ⟨k, _⟩, heq => Nat.succ_ne_zero k <| congrArg Fin.val heq
|
||||
| ⟨k, _⟩, heq => Nat.succ_ne_zero k <| ext_iff.1 heq
|
||||
|
||||
@[simp] theorem succ_zero_eq_one : Fin.succ (0 : Fin (n + 1)) = 1 := rfl
|
||||
|
||||
@@ -265,7 +270,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
||||
rw [← succ_zero_eq_one, succ_lt_succ_iff]; exact succ_pos a
|
||||
|
||||
@[simp] theorem add_one_lt_iff {n : Nat} {k : Fin (n + 2)} : k + 1 < k ↔ k = last _ := by
|
||||
simp only [lt_def, val_add, val_last, Fin.ext_iff]
|
||||
simp only [lt_def, val_add, val_last, ext_iff]
|
||||
let ⟨k, hk⟩ := k
|
||||
match Nat.eq_or_lt_of_le (Nat.le_of_lt_succ hk) with
|
||||
| .inl h => cases h; simp [Nat.succ_pos]
|
||||
@@ -283,7 +288,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
||||
split <;> simp [*, (Nat.succ_ne_zero _).symm, Nat.ne_of_gt (Nat.lt_succ_self _)]
|
||||
|
||||
@[simp] theorem last_le_iff {n : Nat} {k : Fin (n + 1)} : last n ≤ k ↔ k = last n := by
|
||||
rw [Fin.ext_iff, Nat.le_antisymm_iff, le_def, and_iff_right (by apply le_last)]
|
||||
rw [ext_iff, Nat.le_antisymm_iff, le_def, and_iff_right (by apply le_last)]
|
||||
|
||||
@[simp] theorem lt_add_one_iff {n : Nat} {k : Fin (n + 1)} : k < k + 1 ↔ k < last n := by
|
||||
rw [← Decidable.not_iff_not]; simp
|
||||
@@ -304,10 +309,10 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
@[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n ≤ m) :
|
||||
castLE h ⟨i, hn⟩ = ⟨i, Nat.lt_of_lt_of_le hn h⟩ := rfl
|
||||
|
||||
@[simp] theorem castLE_zero {n m : Nat} (h : n.succ ≤ m.succ) : castLE h 0 = 0 := by simp [Fin.ext_iff]
|
||||
@[simp] theorem castLE_zero {n m : Nat} (h : n.succ ≤ m.succ) : castLE h 0 = 0 := by simp [ext_iff]
|
||||
|
||||
@[simp] theorem castLE_succ {m n : Nat} (h : m + 1 ≤ n + 1) (i : Fin m) :
|
||||
castLE h i.succ = (castLE (Nat.succ_le_succ_iff.mp h) i).succ := by simp [Fin.ext_iff]
|
||||
castLE h i.succ = (castLE (Nat.succ_le_succ_iff.mp h) i).succ := by simp [ext_iff]
|
||||
|
||||
@[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (i : Fin k) :
|
||||
Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i :=
|
||||
@@ -320,7 +325,7 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
|
||||
|
||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
|
||||
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||
ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||
|
||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||
|
||||
@@ -346,7 +351,7 @@ theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m :=
|
||||
|
||||
/-- For rewriting in the reverse direction, see `Fin.cast_castAdd_left`. -/
|
||||
theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
|
||||
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := ext rfl
|
||||
|
||||
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
|
||||
@@ -376,7 +381,7 @@ theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
|
||||
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
||||
|
||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ := by
|
||||
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
|
||||
simpa [lt_def, le_def] using Nat.succ_le_succ_iff.symm
|
||||
|
||||
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
Fin.castSucc i < j ↔ i.succ ≤ j := .rfl
|
||||
@@ -395,7 +400,7 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
|
||||
Fin.castSucc a < Fin.castSucc b ↔ a < b := .rfl
|
||||
|
||||
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [Fin.ext_iff]
|
||||
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [ext_iff]
|
||||
|
||||
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
||||
|
||||
@@ -407,7 +412,7 @@ theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
|
||||
simpa [lt_def] using h
|
||||
|
||||
@[simp] theorem castSucc_eq_zero_iff (a : Fin (n + 1)) : castSucc a = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||
@[simp] theorem castSucc_eq_zero_iff (a : Fin (n + 1)) : castSucc a = 0 ↔ a = 0 := by simp [ext_iff]
|
||||
|
||||
theorem castSucc_ne_zero_iff (a : Fin (n + 1)) : castSucc a ≠ 0 ↔ a ≠ 0 :=
|
||||
not_congr <| castSucc_eq_zero_iff a
|
||||
@@ -419,7 +424,7 @@ theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
||||
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
|
||||
cases n
|
||||
· exact a.elim0
|
||||
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||
· simp [ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||
|
||||
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
|
||||
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||
@@ -452,7 +457,7 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
|
||||
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||
cast h (addNat i m') = addNat i m :=
|
||||
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||
ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||
|
||||
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||
|
||||
@@ -472,7 +477,7 @@ theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
|
||||
|
||||
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
|
||||
cast h (natAdd m' i) = natAdd m i :=
|
||||
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||
ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||
|
||||
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
|
||||
@@ -482,27 +487,27 @@ theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||
|
||||
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
|
||||
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
|
||||
Fin.ext <| (Nat.add_assoc ..).symm
|
||||
ext <| (Nat.add_assoc ..).symm
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
||||
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
|
||||
Fin.ext <| Nat.zero_add _
|
||||
ext <| Nat.zero_add _
|
||||
|
||||
@[simp]
|
||||
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
||||
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := ext <| Nat.add_comm ..
|
||||
|
||||
@[simp]
|
||||
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
||||
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := ext <| Nat.add_comm ..
|
||||
|
||||
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
||||
|
||||
theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSucc (natAdd n i) :=
|
||||
rfl
|
||||
|
||||
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := Fin.ext <| by
|
||||
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := ext <| by
|
||||
rw [val_rev, coe_castAdd, coe_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
|
||||
|
||||
theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) := by
|
||||
@@ -532,7 +537,7 @@ theorem pred_eq_iff_eq_succ {n : Nat} (i : Fin (n + 1)) (hi : i ≠ 0) (j : Fin
|
||||
theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
|
||||
Fin.pred ⟨i + 1, Nat.add_lt_add_right h 1⟩ (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
|
||||
⟨i, h⟩ := by
|
||||
simp only [Fin.ext_iff, coe_pred, Nat.add_sub_cancel]
|
||||
simp only [ext_iff, coe_pred, Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
|
||||
Fin.pred ⟨i + 1, h₁⟩ h₂ = ⟨i, Nat.lt_of_succ_lt_succ h₁⟩ := pred_mk_succ i _
|
||||
@@ -552,14 +557,14 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
||||
∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
|
||||
| ⟨0, _⟩, _, ha, _ => by simp only [mk_zero, ne_eq, not_true] at ha
|
||||
| ⟨i + 1, _⟩, ⟨0, _⟩, _, hb => by simp only [mk_zero, ne_eq, not_true] at hb
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [Fin.ext_iff, Nat.succ.injEq]
|
||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [ext_iff, Nat.succ.injEq]
|
||||
|
||||
@[simp] theorem pred_one {n : Nat} :
|
||||
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
|
||||
|
||||
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
|
||||
rw [Fin.ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
||||
rw [ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
||||
exact Nat.add_lt_add_right h 1
|
||||
|
||||
@[simp] theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
||||
@@ -571,10 +576,10 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||
pred (castSucc i.succ) (Fin.ne_of_gt (castSucc_pos i.succ_pos)) = castSucc i := rfl
|
||||
|
||||
@[simp] theorem addNat_subNat {i : Fin (n + m)} (h : m ≤ i) : addNat (subNat m i h) m = i :=
|
||||
Fin.ext <| Nat.sub_add_cancel h
|
||||
ext <| Nat.sub_add_cancel h
|
||||
|
||||
@[simp] theorem subNat_addNat (i : Fin n) (m : Nat) (h : m ≤ addNat i m := le_coe_addNat m i) :
|
||||
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
|
||||
subNat m (addNat i m) h = i := ext <| Nat.add_sub_cancel i m
|
||||
|
||||
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
|
||||
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [← cast_addNat]; rfl
|
||||
@@ -757,16 +762,16 @@ theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right
|
||||
|
||||
/-! ### sub -/
|
||||
|
||||
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n := by
|
||||
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = (a + (n - b)) % n := by
|
||||
cases a; cases b; rfl
|
||||
|
||||
@[simp] theorem ofNat'_sub (x : Nat) (lt : 0 < n) (y : Fin n) :
|
||||
Fin.ofNat' x lt - y = Fin.ofNat' ((n - y.val) + x) lt := by
|
||||
Fin.ofNat' x lt - y = Fin.ofNat' (x + (n - y.val)) lt := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.sub_def]
|
||||
|
||||
@[simp] theorem sub_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
|
||||
x - Fin.ofNat' y lt = Fin.ofNat' ((n - y % n) + x.val) lt := by
|
||||
x - Fin.ofNat' y lt = Fin.ofNat' (x.val + (n - y % n)) lt := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat', Fin.sub_def]
|
||||
|
||||
@@ -777,20 +782,17 @@ private theorem _root_.Nat.mod_eq_sub_of_lt_two_mul {x n} (h₁ : n ≤ x) (h₂
|
||||
theorem coe_sub_iff_le {a b : Fin n} : (↑(a - b) : Nat) = a - b ↔ b ≤ a := by
|
||||
rw [sub_def, le_def]
|
||||
dsimp only
|
||||
if h : n ≤ (n - b) + a then
|
||||
if h : n ≤ a + (n - b) then
|
||||
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
||||
all_goals omega
|
||||
else
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
all_goals omega
|
||||
|
||||
theorem sub_val_of_le {a b : Fin n} : b ≤ a → (a - b).val = a.val - b.val :=
|
||||
coe_sub_iff_le.2
|
||||
|
||||
theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b := by
|
||||
rw [sub_def, lt_def]
|
||||
dsimp only
|
||||
if h : n ≤ (n - b) + a then
|
||||
if h : n ≤ a + (n - b) then
|
||||
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
||||
all_goals omega
|
||||
else
|
||||
@@ -808,10 +810,10 @@ theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
|
||||
protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k := by
|
||||
match n with
|
||||
| 0 => exact Subsingleton.elim (α := Fin 1) ..
|
||||
| n+1 => simp [Fin.ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
||||
| n+1 => simp [ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
||||
|
||||
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
|
||||
Fin.ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
||||
ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
||||
instance : Std.Commutative (α := Fin n) (· * ·) := ⟨Fin.mul_comm⟩
|
||||
|
||||
protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
|
||||
@@ -827,9 +829,9 @@ instance : Std.LawfulIdentity (α := Fin (n + 1)) (· * ·) 1 where
|
||||
left_id := Fin.one_mul
|
||||
right_id := Fin.mul_one
|
||||
|
||||
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [Fin.ext_iff, mul_def]
|
||||
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [ext_iff, mul_def]
|
||||
|
||||
protected theorem zero_mul (k : Fin (n + 1)) : (0 : Fin (n + 1)) * k = 0 := by
|
||||
simp [Fin.ext_iff, mul_def]
|
||||
simp [ext_iff, mul_def]
|
||||
|
||||
end Fin
|
||||
|
||||
@@ -101,13 +101,13 @@ Returns an undefined value if `x` is not finite.
|
||||
instance : ToString Float where
|
||||
toString := Float.toString
|
||||
|
||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
||||
|
||||
instance : Repr Float where
|
||||
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
|
||||
reprPrec n _ := Float.toString n
|
||||
|
||||
instance : ReprAtom Float := ⟨⟩
|
||||
|
||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
||||
|
||||
@[extern "sin"] opaque Float.sin : Float → Float
|
||||
@[extern "cos"] opaque Float.cos : Float → Float
|
||||
@[extern "tan"] opaque Float.tan : Float → Float
|
||||
|
||||
@@ -58,9 +58,13 @@ def get? (ds : FloatArray) (i : Nat) : Option Float :=
|
||||
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||
|
||||
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
getElem xs i h := xs.uget i h
|
||||
|
||||
instance : LawfulGetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||
|
||||
@[extern "lean_float_array_uset"]
|
||||
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
||||
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
||||
|
||||
@@ -62,16 +62,3 @@ instance (P : Prop) : Hashable P where
|
||||
/-- An opaque (low-level) hash operation used to implement hashing for pointers. -/
|
||||
@[always_inline, inline] def hash64 (u : UInt64) : UInt64 :=
|
||||
mixHash u 11
|
||||
|
||||
/-- `LawfulHashable α` says that the `BEq α` and `Hashable α` instances on `α` are compatible, i.e.,
|
||||
that `a == b` implies `hash a = hash b`. This is automatic if the `BEq` instance is lawful.
|
||||
-/
|
||||
class LawfulHashable (α : Type u) [BEq α] [Hashable α] where
|
||||
/-- If `a == b`, then `hash a = hash b`. -/
|
||||
hash_eq (a b : α) : a == b → hash a = hash b
|
||||
|
||||
theorem hash_eq [BEq α] [Hashable α] [LawfulHashable α] {a b : α} : a == b → hash a = hash b :=
|
||||
LawfulHashable.hash_eq a b
|
||||
|
||||
instance (priority := low) [BEq α] [Hashable α] [LawfulBEq α] : LawfulHashable α where
|
||||
hash_eq _ _ h := eq_of_beq h ▸ rfl
|
||||
|
||||
@@ -636,7 +636,7 @@ theorem sub_ediv_of_dvd (a : Int) {b c : Int}
|
||||
have := Int.mul_ediv_cancel 1 H; rwa [Int.one_mul] at this
|
||||
|
||||
@[simp]
|
||||
theorem emod_sub_cancel (x y : Int): (x - y)%y = x%y := by
|
||||
theorem Int.emod_sub_cancel (x y : Int): (x - y)%y = x%y := by
|
||||
by_cases h : y = 0
|
||||
· simp [h]
|
||||
· simp only [Int.emod_def, Int.sub_ediv_of_dvd, Int.dvd_refl, Int.ediv_self h, Int.mul_sub]
|
||||
|
||||
@@ -127,14 +127,9 @@ protected theorem lt_iff_le_not_le {a b : Int} : a < b ↔ a ≤ b ∧ ¬b ≤ a
|
||||
· exact Int.le_antisymm h h'
|
||||
· subst h'; apply Int.le_refl
|
||||
|
||||
protected theorem lt_of_not_ge {a b : Int} (h : ¬a ≤ b) : b < a :=
|
||||
Int.lt_iff_le_not_le.mpr ⟨(Int.le_total ..).resolve_right h, h⟩
|
||||
|
||||
protected theorem not_le_of_gt {a b : Int} (h : b < a) : ¬a ≤ b :=
|
||||
(Int.lt_iff_le_not_le.mp h).right
|
||||
|
||||
protected theorem not_le {a b : Int} : ¬a ≤ b ↔ b < a :=
|
||||
Iff.intro Int.lt_of_not_ge Int.not_le_of_gt
|
||||
⟨fun h => Int.lt_iff_le_not_le.2 ⟨(Int.le_total ..).resolve_right h, h⟩,
|
||||
fun h => (Int.lt_iff_le_not_le.1 h).2⟩
|
||||
|
||||
protected theorem not_lt {a b : Int} : ¬a < b ↔ b ≤ a :=
|
||||
by rw [← Int.not_le, Decidable.not_not]
|
||||
@@ -514,6 +509,9 @@ theorem mem_toNat' : ∀ (a : Int) (n : Nat), toNat' a = some n ↔ a = n
|
||||
|
||||
/-! ## Order properties of the integers -/
|
||||
|
||||
protected theorem lt_of_not_ge {a b : Int} : ¬a ≤ b → b < a := Int.not_le.mp
|
||||
protected theorem not_le_of_gt {a b : Int} : b < a → ¬a ≤ b := Int.not_le.mpr
|
||||
|
||||
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
||||
|
||||
@[simp] theorem negSucc_not_pos (n : Nat) : 0 < -[n+1] ↔ False := by
|
||||
@@ -588,10 +586,7 @@ theorem add_one_le_iff {a b : Int} : a + 1 ≤ b ↔ a < b := .rfl
|
||||
theorem lt_add_one_iff {a b : Int} : a < b + 1 ↔ a ≤ b := Int.add_le_add_iff_right _
|
||||
|
||||
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
|
||||
lt_add_one_iff.mpr (ofNat_zero_le _)
|
||||
|
||||
theorem not_ofNat_neg (n : Nat) : ¬((n : Int) < 0) :=
|
||||
Int.not_lt.mpr (ofNat_zero_le ..)
|
||||
lt_add_one_iff.2 (ofNat_zero_le _)
|
||||
|
||||
theorem le_add_one {a b : Int} (h : a ≤ b) : a ≤ b + 1 :=
|
||||
Int.le_of_lt (Int.lt_add_one_iff.2 h)
|
||||
@@ -806,12 +801,6 @@ protected theorem lt_add_of_neg_lt_sub_right {a b c : Int} (h : -b < a - c) : c
|
||||
protected theorem neg_lt_sub_right_of_lt_add {a b c : Int} (h : c < a + b) : -b < a - c :=
|
||||
Int.lt_sub_left_of_add_lt (Int.sub_right_lt_of_lt_add h)
|
||||
|
||||
protected theorem add_lt_iff (a b c : Int) : a + b < c ↔ a < -b + c := by
|
||||
rw [← Int.add_lt_add_iff_left (-b), Int.add_comm (-b), Int.add_neg_cancel_right]
|
||||
|
||||
protected theorem sub_lt_iff (a b c : Int) : a - b < c ↔ a < c + b :=
|
||||
Iff.intro Int.lt_add_of_sub_right_lt Int.sub_right_lt_of_lt_add
|
||||
|
||||
protected theorem sub_lt_of_sub_lt {a b c : Int} (h : a - b < c) : a - c < b :=
|
||||
Int.sub_left_lt_of_lt_add (Int.lt_add_of_sub_right_lt h)
|
||||
|
||||
|
||||
@@ -8,7 +8,5 @@ import Init.Data.List.Basic
|
||||
import Init.Data.List.BasicAux
|
||||
import Init.Data.List.Control
|
||||
import Init.Data.List.Lemmas
|
||||
import Init.Data.List.Attach
|
||||
import Init.Data.List.Impl
|
||||
import Init.Data.List.TakeDrop
|
||||
import Init.Data.List.Notation
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2023 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Lemmas
|
||||
|
||||
namespace List
|
||||
|
||||
/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`. -/
|
||||
@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
| [], _ => []
|
||||
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`List {x // P x}` is the same as the input `List α`.
|
||||
(Someday, the compiler might do this optimization automatically, but until then...)
|
||||
-/
|
||||
@[inline] private unsafe def attachWithImpl
|
||||
(l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l
|
||||
|
||||
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list
|
||||
with the same elements but in the type `{x // P x}`. -/
|
||||
@[implemented_by attachWithImpl] def attachWith
|
||||
(l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H
|
||||
|
||||
/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list
|
||||
with the same elements but in the type `{x // x ∈ l}`. -/
|
||||
@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id
|
||||
|
||||
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||
@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) :
|
||||
List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h'
|
||||
|
||||
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
|
||||
funext α β p f L h'
|
||||
let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x),
|
||||
pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL')
|
||||
| nil, hL' => rfl
|
||||
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
|
||||
exact go L h'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Linear
|
||||
import Init.Ext
|
||||
|
||||
universe u
|
||||
|
||||
@@ -12,10 +13,6 @@ namespace List
|
||||
/-! The following functions can't be defined at `Init.Data.List.Basic`, because they depend on `Init.Util`,
|
||||
and `Init.Util` depends on `Init.Data.List.Basic`. -/
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
/-! ### get! -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
@@ -27,26 +24,33 @@ def get! [Inhabited α] : (as : List α) → (i : Nat) → α
|
||||
| _::as, n+1 => get! as n
|
||||
| _, _ => panic! "invalid index"
|
||||
|
||||
theorem get!_nil [Inhabited α] (n : Nat) : [].get! n = (default : α) := rfl
|
||||
theorem get!_cons_succ [Inhabited α] (l : List α) (a : α) (n : Nat) :
|
||||
(a::l).get! (n+1) = get! l n := rfl
|
||||
theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
/-! ### getLast! -/
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
|
||||
Also see `get`, `getD` and `get!`.
|
||||
-/
|
||||
def get? : (as : List α) → (i : Nat) → Option α
|
||||
| a::_, 0 => some a
|
||||
| _::as, n+1 => get? as n
|
||||
| _, _ => none
|
||||
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `getLast` and `getLastD` for safer alternatives.
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
|
||||
See also `get?` and `get!`.
|
||||
-/
|
||||
def getLast! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::as => getLast (a::as) (fun h => List.noConfusion h)
|
||||
def getD (as : List α) (i : Nat) (fallback : α) : α :=
|
||||
(as.get? i).getD fallback
|
||||
|
||||
/-! ## Head and tail -/
|
||||
|
||||
/-! ### head! -/
|
||||
@[ext] theorem ext : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n) → l₁ = l₂
|
||||
| [], [], _ => rfl
|
||||
| a :: l₁, [], h => nomatch h 0
|
||||
| [], a' :: l₂, h => nomatch h 0
|
||||
| a :: l₁, a' :: l₂, h => by
|
||||
have h0 : some a = some a' := h 0
|
||||
injection h0 with aa; simp only [aa, ext fun n => h (n+1)]
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
@@ -58,7 +62,31 @@ def head! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::_ => a
|
||||
|
||||
/-! ### tail! -/
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `headD` and `head!`.
|
||||
-/
|
||||
def head? : List α → Option α
|
||||
| [] => none
|
||||
| a::_ => some a
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `head?` and `head!`.
|
||||
-/
|
||||
def headD : (as : List α) → (fallback : α) → α
|
||||
| [], fallback => fallback
|
||||
| a::_, _ => a
|
||||
|
||||
/--
|
||||
Returns the first element of a non-empty list.
|
||||
-/
|
||||
def head : (as : List α) → as ≠ [] → α
|
||||
| a::_, _ => a
|
||||
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
@@ -70,92 +98,100 @@ def tail! : List α → List α
|
||||
| [] => panic! "empty list"
|
||||
| _::as => as
|
||||
|
||||
@[simp] theorem tail!_cons : @tail! α (a::l) = l := rfl
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
|
||||
/-! ### partitionM -/
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `tailD` and `tail!`.
|
||||
-/
|
||||
def tail? : List α → Option (List α)
|
||||
| [] => none
|
||||
| _::as => some as
|
||||
|
||||
/--
|
||||
Monadic generalization of `List.partition`.
|
||||
Drops the first element of the list.
|
||||
|
||||
This uses `Array.toList` and which isn't imported by `Init.Data.List.Basic` or `Init.Data.List.Control`.
|
||||
```
|
||||
def posOrNeg (x : Int) : Except String Bool :=
|
||||
if x > 0 then pure true
|
||||
else if x < 0 then pure false
|
||||
else throw "Zero is not positive or negative"
|
||||
|
||||
partitionM posOrNeg [-1, 2, 3] = Except.ok ([2, 3], [-1])
|
||||
partitionM posOrNeg [0, 2, 3] = Except.error "Zero is not positive or negative"
|
||||
```
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `head?` and `head!`.
|
||||
-/
|
||||
@[inline] def partitionM [Monad m] (p : α → m Bool) (l : List α) : m (List α × List α) :=
|
||||
go l #[] #[]
|
||||
where
|
||||
/-- Auxiliary for `partitionM`:
|
||||
`partitionM.go p l acc₁ acc₂` returns `(acc₁.toList ++ left, acc₂.toList ++ right)`
|
||||
if `partitionM p l` returns `(left, right)`. -/
|
||||
@[specialize] go : List α → Array α → Array α → m (List α × List α)
|
||||
| [], acc₁, acc₂ => pure (acc₁.toList, acc₂.toList)
|
||||
| x :: xs, acc₁, acc₂ => do
|
||||
if ← p x then
|
||||
go xs (acc₁.push x) acc₂
|
||||
else
|
||||
go xs acc₁ (acc₂.push x)
|
||||
|
||||
/-! ### partitionMap -/
|
||||
def tailD (list fallback : List α) : List α :=
|
||||
match list with
|
||||
| [] => fallback
|
||||
| _ :: tl => tl
|
||||
|
||||
/--
|
||||
Given a function `f : α → β ⊕ γ`, `partitionMap f l` maps the list by `f`
|
||||
whilst partitioning the result into a pair of lists, `List β × List γ`,
|
||||
partitioning the `.inl _` into the left list, and the `.inr _` into the right List.
|
||||
```
|
||||
partitionMap (id : Nat ⊕ Nat → Nat ⊕ Nat) [inl 0, inr 1, inl 2] = ([0, 2], [1])
|
||||
```
|
||||
Returns the last element of a non-empty list.
|
||||
-/
|
||||
@[inline] def partitionMap (f : α → β ⊕ γ) (l : List α) : List β × List γ := go l #[] #[] where
|
||||
/-- Auxiliary for `partitionMap`:
|
||||
`partitionMap.go f l acc₁ acc₂ = (acc₁.toList ++ left, acc₂.toList ++ right)`
|
||||
if `partitionMap f l = (left, right)`. -/
|
||||
@[specialize] go : List α → Array β → Array γ → List β × List γ
|
||||
| [], acc₁, acc₂ => (acc₁.toList, acc₂.toList)
|
||||
| x :: xs, acc₁, acc₂ =>
|
||||
match f x with
|
||||
| .inl a => go xs (acc₁.push a) acc₂
|
||||
| .inr b => go xs acc₁ (acc₂.push b)
|
||||
|
||||
/-! ### mapMono
|
||||
|
||||
This is a performance optimization for `List.mapM` that avoids allocating a new list when the result of each `f a` is a pointer equal value `a`.
|
||||
|
||||
For verification purposes, `List.mapMono = List.map`.
|
||||
-/
|
||||
|
||||
@[specialize] private unsafe def mapMonoMImp [Monad m] (as : List α) (f : α → m α) : m (List α) := do
|
||||
match as with
|
||||
| [] => return as
|
||||
| b :: bs =>
|
||||
let b' ← f b
|
||||
let bs' ← mapMonoMImp bs f
|
||||
if ptrEq b' b && ptrEq bs' bs then
|
||||
return as
|
||||
else
|
||||
return b' :: bs'
|
||||
def getLast : ∀ (as : List α), as ≠ [] → α
|
||||
| [], h => absurd rfl h
|
||||
| [a], _ => a
|
||||
| _::b::as, _ => getLast (b::as) (fun h => List.noConfusion h)
|
||||
|
||||
/--
|
||||
Monomorphic `List.mapM`. The internal implementation uses pointer equality, and does not allocate a new list
|
||||
if the result of each `f a` is a pointer equal value `a`.
|
||||
Returns the last element in the list.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `getLast` and `getLastD` for safer alternatives.
|
||||
-/
|
||||
@[implemented_by mapMonoMImp] def mapMonoM [Monad m] (as : List α) (f : α → m α) : m (List α) :=
|
||||
match as with
|
||||
| [] => return []
|
||||
| a :: as => return (← f a) :: (← mapMonoM as f)
|
||||
def getLast! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::as => getLast (a::as) (fun h => List.noConfusion h)
|
||||
|
||||
def mapMono (as : List α) (f : α → α) : List α :=
|
||||
Id.run <| as.mapMonoM f
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
|
||||
/-! ## Additional lemmas required for bootstrapping `Array`. -/
|
||||
If the list is empty, this function returns `none`.
|
||||
Also see `getLastD` and `getLast!`.
|
||||
-/
|
||||
def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
|
||||
theorem getElem_append_left (as bs : List α) (h : i < as.length) {h'} : (as ++ bs)[i] = as[i] := by
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
|
||||
If the list is empty, this function returns `fallback`.
|
||||
Also see `getLast?` and `getLast!`.
|
||||
-/
|
||||
def getLastD : (as : List α) → (fallback : α) → α
|
||||
| [], a₀ => a₀
|
||||
| a::as, _ => getLast (a::as) (fun h => List.noConfusion h)
|
||||
|
||||
/--
|
||||
`O(n)`. Rotates the elements of `xs` to the left such that the element at
|
||||
`xs[i]` rotates to `xs[(i - n) % l.length]`.
|
||||
* `rotateLeft [1, 2, 3, 4, 5] 3 = [4, 5, 1, 2, 3]`
|
||||
* `rotateLeft [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
|
||||
* `rotateLeft [1, 2, 3, 4, 5] = [2, 3, 4, 5, 1]`
|
||||
-/
|
||||
def rotateLeft (xs : List α) (n : Nat := 1) : List α :=
|
||||
let len := xs.length
|
||||
if len ≤ 1 then
|
||||
xs
|
||||
else
|
||||
let n := n % len
|
||||
let b := xs.take n
|
||||
let e := xs.drop n
|
||||
e ++ b
|
||||
|
||||
/--
|
||||
`O(n)`. Rotates the elements of `xs` to the right such that the element at
|
||||
`xs[i]` rotates to `xs[(i + n) % l.length]`.
|
||||
* `rotateRight [1, 2, 3, 4, 5] 3 = [3, 4, 5, 1, 2]`
|
||||
* `rotateRight [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
|
||||
* `rotateRight [1, 2, 3, 4, 5] = [5, 1, 2, 3, 4]`
|
||||
-/
|
||||
def rotateRight (xs : List α) (n : Nat := 1) : List α :=
|
||||
let len := xs.length
|
||||
if len ≤ 1 then
|
||||
xs
|
||||
else
|
||||
let n := len - n % len
|
||||
let b := xs.take n
|
||||
let e := xs.drop n
|
||||
e ++ b
|
||||
|
||||
theorem get_append_left (as bs : List α) (h : i < as.length) {h'} : (as ++ bs).get ⟨i, h'⟩ = as.get ⟨i, h⟩ := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
@@ -163,7 +199,7 @@ theorem getElem_append_left (as bs : List α) (h : i < as.length) {h'} : (as ++
|
||||
| zero => rfl
|
||||
| succ i => apply ih
|
||||
|
||||
theorem getElem_append_right (as bs : List α) (h : ¬ i < as.length) {h' h''} : (as ++ bs)[i]'h' = bs[i - as.length]'h'' := by
|
||||
theorem get_append_right (as bs : List α) (h : ¬ i < as.length) {h' h''} : (as ++ bs).get ⟨i, h'⟩ = bs.get ⟨i - as.length, h''⟩ := by
|
||||
induction as generalizing i with
|
||||
| nil => trivial
|
||||
| cons a as ih =>
|
||||
@@ -249,4 +285,74 @@ theorem le_antisymm [LT α] [s : Antisymm (¬ · < · : α → α → Prop)] {as
|
||||
instance [LT α] [Antisymm (¬ · < · : α → α → Prop)] : Antisymm (· ≤ · : List α → List α → Prop) where
|
||||
antisymm h₁ h₂ := le_antisymm h₁ h₂
|
||||
|
||||
@[specialize] private unsafe def mapMonoMImp [Monad m] (as : List α) (f : α → m α) : m (List α) := do
|
||||
match as with
|
||||
| [] => return as
|
||||
| b :: bs =>
|
||||
let b' ← f b
|
||||
let bs' ← mapMonoMImp bs f
|
||||
if ptrEq b' b && ptrEq bs' bs then
|
||||
return as
|
||||
else
|
||||
return b' :: bs'
|
||||
|
||||
/--
|
||||
Monomorphic `List.mapM`. The internal implementation uses pointer equality, and does not allocate a new list
|
||||
if the result of each `f a` is a pointer equal value `a`.
|
||||
-/
|
||||
@[implemented_by mapMonoMImp] def mapMonoM [Monad m] (as : List α) (f : α → m α) : m (List α) :=
|
||||
match as with
|
||||
| [] => return []
|
||||
| a :: as => return (← f a) :: (← mapMonoM as f)
|
||||
|
||||
def mapMono (as : List α) (f : α → α) : List α :=
|
||||
Id.run <| as.mapMonoM f
|
||||
|
||||
/--
|
||||
Monadic generalization of `List.partition`.
|
||||
|
||||
This uses `Array.toList` and which isn't imported by `Init.Data.List.Basic`.
|
||||
```
|
||||
def posOrNeg (x : Int) : Except String Bool :=
|
||||
if x > 0 then pure true
|
||||
else if x < 0 then pure false
|
||||
else throw "Zero is not positive or negative"
|
||||
|
||||
partitionM posOrNeg [-1, 2, 3] = Except.ok ([2, 3], [-1])
|
||||
partitionM posOrNeg [0, 2, 3] = Except.error "Zero is not positive or negative"
|
||||
```
|
||||
-/
|
||||
@[inline] def partitionM [Monad m] (p : α → m Bool) (l : List α) : m (List α × List α) :=
|
||||
go l #[] #[]
|
||||
where
|
||||
/-- Auxiliary for `partitionM`:
|
||||
`partitionM.go p l acc₁ acc₂` returns `(acc₁.toList ++ left, acc₂.toList ++ right)`
|
||||
if `partitionM p l` returns `(left, right)`. -/
|
||||
@[specialize] go : List α → Array α → Array α → m (List α × List α)
|
||||
| [], acc₁, acc₂ => pure (acc₁.toList, acc₂.toList)
|
||||
| x :: xs, acc₁, acc₂ => do
|
||||
if ← p x then
|
||||
go xs (acc₁.push x) acc₂
|
||||
else
|
||||
go xs acc₁ (acc₂.push x)
|
||||
|
||||
/--
|
||||
Given a function `f : α → β ⊕ γ`, `partitionMap f l` maps the list by `f`
|
||||
whilst partitioning the result it into a pair of lists, `List β × List γ`,
|
||||
partitioning the `.inl _` into the left list, and the `.inr _` into the right List.
|
||||
```
|
||||
partitionMap (id : Nat ⊕ Nat → Nat ⊕ Nat) [inl 0, inr 1, inl 2] = ([0, 2], [1])
|
||||
```
|
||||
-/
|
||||
@[inline] def partitionMap (f : α → β ⊕ γ) (l : List α) : List β × List γ := go l #[] #[] where
|
||||
/-- Auxiliary for `partitionMap`:
|
||||
`partitionMap.go f l acc₁ acc₂ = (acc₁.toList ++ left, acc₂.toList ++ right)`
|
||||
if `partitionMap f l = (left, right)`. -/
|
||||
@[specialize] go : List α → Array β → Array γ → List β × List γ
|
||||
| [], acc₁, acc₂ => (acc₁.toList, acc₂.toList)
|
||||
| x :: xs, acc₁, acc₂ =>
|
||||
match f x with
|
||||
| .inl a => go xs (acc₁.push a) acc₂
|
||||
| .inr b => go xs acc₁ (acc₂.push b)
|
||||
|
||||
end List
|
||||
|
||||
@@ -151,11 +151,6 @@ protected def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w
|
||||
let s' ← f s a
|
||||
List.foldlM f s' as
|
||||
|
||||
@[simp] theorem foldlM_nil [Monad m] (f : β → α → m β) (b) : [].foldlM f b = pure b := rfl
|
||||
@[simp] theorem foldlM_cons [Monad m] (f : β → α → m β) (b) (a) (l : List α) :
|
||||
(a :: l).foldlM f b = f b a >>= l.foldlM f := by
|
||||
simp [List.foldlM]
|
||||
|
||||
/--
|
||||
Folds a monadic function over a list from right to left:
|
||||
```
|
||||
@@ -170,8 +165,6 @@ foldrM f x₀ [a, b, c] = do
|
||||
def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} (f : α → s → m s) (init : s) (l : List α) : m s :=
|
||||
l.reverse.foldlM (fun s a => f a s) init
|
||||
|
||||
@[simp] theorem foldrM_nil [Monad m] (f : α → β → m β) (b) : [].foldrM f b = pure b := rfl
|
||||
|
||||
/--
|
||||
Maps `f` over the list and collects the results with `<|>`.
|
||||
```
|
||||
|
||||
@@ -16,44 +16,7 @@ so these are in a separate file to minimize imports.
|
||||
|
||||
namespace List
|
||||
|
||||
/-! ## Basic `List` operations.
|
||||
|
||||
The following operations are already tail-recursive, and do not need `@[csimp]` replacements:
|
||||
`get`, `foldl`, `beq`, `isEqv`, `reverse`, `elem` (and hence `contains`), `drop`, `dropWhile`,
|
||||
`partition`, `isPrefixOf`, `isPrefixOf?`, `find?`, `findSome?`, `lookup`, `any` (and hence `or`),
|
||||
`all` (and hence `and`) , `range`, `eraseDups`, `eraseReps`, `span`, `groupBy`.
|
||||
|
||||
The following operations are still missing `@[csimp]` replacements:
|
||||
`concat`, `zipWithAll`.
|
||||
|
||||
The following operations are not recursive to begin with
|
||||
(or are defined in terms of recursive primitives):
|
||||
`isEmpty`, `isSuffixOf`, `isSuffixOf?`, `rotateLeft`, `rotateRight`, `insert`, `zip`, `enum`,
|
||||
`minimum?`, `maximum?`, and `removeAll`.
|
||||
|
||||
The following operations are given `@[csimp]` replacements below:
|
||||
`length`, `set`, `map`, `filter`, `filterMap`, `foldr`, `append`, `bind`, `join`, `replicate`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `erase`, `eraseIdx`, `zipWith`, `unzip`, `iota`,
|
||||
`enumFrom`, `intersperse`, and `intercalate`.
|
||||
|
||||
-/
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
theorem length_add_eq_lengthTRAux (as : List α) (n : Nat) : as.length + n = as.lengthTRAux n := by
|
||||
induction as generalizing n with
|
||||
| nil => simp [length, lengthTRAux]
|
||||
| cons a as ih =>
|
||||
simp [length, lengthTRAux, ← ih, Nat.succ_add]
|
||||
rfl
|
||||
|
||||
@[csimp] theorem length_eq_lengthTR : @List.length = @List.lengthTR := by
|
||||
apply funext; intro α; apply funext; intro as
|
||||
simp [lengthTR, ← length_add_eq_lengthTRAux]
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
/-- Tail recursive version of `List.set`. -/
|
||||
/-- Tail recursive version of `erase`. -/
|
||||
@[inline] def setTR (l : List α) (n : Nat) (a : α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `setTR`: `setTR.go l a xs n acc = acc.toList ++ set xs a`,
|
||||
unless `n ≥ l.length` in which case it returns `l` -/
|
||||
@@ -68,214 +31,10 @@ theorem length_add_eq_lengthTRAux (as : List α) (n : Nat) : as.length + n = as.
|
||||
setTR.go l a xs n acc = acc.data ++ xs.set n a
|
||||
| [], _ => fun h => by simp [setTR.go, set, h]
|
||||
| x::xs, 0 => by simp [setTR.go, set]
|
||||
| x::xs, n+1 => fun h => by simp only [setTR.go, set]; rw [go _ xs] <;> simp [h]
|
||||
| x::xs, n+1 => fun h => by simp [setTR.go, set]; rw [go _ xs]; {simp}; simp [h]
|
||||
exact (go #[] _ _ rfl).symm
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
/-- Tail-recursive version of `List.map`. -/
|
||||
@[inline] def mapTR (f : α → β) (as : List α) : List β :=
|
||||
loop as []
|
||||
where
|
||||
@[specialize] loop : List α → List β → List β
|
||||
| [], bs => bs.reverse
|
||||
| a::as, bs => loop as (f a :: bs)
|
||||
|
||||
theorem mapTR_loop_eq (f : α → β) (as : List α) (bs : List β) :
|
||||
mapTR.loop f as bs = bs.reverse ++ map f as := by
|
||||
induction as generalizing bs with
|
||||
| nil => simp [mapTR.loop, map]
|
||||
| cons a as ih =>
|
||||
simp only [mapTR.loop, map]
|
||||
rw [ih (f a :: bs), reverse_cons, append_assoc]
|
||||
rfl
|
||||
|
||||
@[csimp] theorem map_eq_mapTR : @map = @mapTR :=
|
||||
funext fun α => funext fun β => funext fun f => funext fun as => by
|
||||
simp [mapTR, mapTR_loop_eq]
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
/-- Tail-recursive version of `List.filter`. -/
|
||||
@[inline] def filterTR (p : α → Bool) (as : List α) : List α :=
|
||||
loop as []
|
||||
where
|
||||
@[specialize] loop : List α → List α → List α
|
||||
| [], rs => rs.reverse
|
||||
| a::as, rs => match p a with
|
||||
| true => loop as (a::rs)
|
||||
| false => loop as rs
|
||||
|
||||
theorem filterTR_loop_eq (p : α → Bool) (as bs : List α) :
|
||||
filterTR.loop p as bs = bs.reverse ++ filter p as := by
|
||||
induction as generalizing bs with
|
||||
| nil => simp [filterTR.loop, filter]
|
||||
| cons a as ih =>
|
||||
simp only [filterTR.loop, filter]
|
||||
split <;> simp_all
|
||||
|
||||
@[csimp] theorem filter_eq_filterTR : @filter = @filterTR := by
|
||||
apply funext; intro α; apply funext; intro p; apply funext; intro as
|
||||
simp [filterTR, filterTR_loop_eq]
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
/-- Tail recursive version of `filterMap`. -/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
/-- Auxiliary for `filterMap`: `filterMap.go f l = acc.toList ++ filterMap f l` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| a::as, acc => match f a with
|
||||
| none => go as acc
|
||||
| some b => go as (acc.push b)
|
||||
|
||||
@[csimp] theorem filterMap_eq_filterMapTR : @List.filterMap = @filterMapTR := by
|
||||
funext α β f l
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.data ++ as.filterMap f
|
||||
| [], acc => by simp [filterMapTR.go, filterMap]
|
||||
| a::as, acc => by
|
||||
simp only [filterMapTR.go, go as, Array.push_data, append_assoc, singleton_append, filterMap]
|
||||
split <;> simp [*]
|
||||
exact (go l #[]).symm
|
||||
|
||||
/-! ### foldr -/
|
||||
|
||||
/-- Tail recursive version of `List.foldr`. -/
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_data, -Array.size_toArray]
|
||||
|
||||
/-! ### bind -/
|
||||
|
||||
/-- Tail recursive version of `List.bind`. -/
|
||||
@[inline] def bindTR (as : List α) (f : α → List β) : List β := go as #[] where
|
||||
/-- Auxiliary for `bind`: `bind.go f as = acc.toList ++ bind f as` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| x::xs, acc => go xs (acc ++ f x)
|
||||
|
||||
@[csimp] theorem bind_eq_bindTR : @List.bind = @bindTR := by
|
||||
funext α β as f
|
||||
let rec go : ∀ as acc, bindTR.go f as acc = acc.data ++ as.bind f
|
||||
| [], acc => by simp [bindTR.go, bind]
|
||||
| x::xs, acc => by simp [bindTR.go, bind, go xs]
|
||||
exact (go as #[]).symm
|
||||
|
||||
/-! ### join -/
|
||||
|
||||
/-- Tail recursive version of `List.join`. -/
|
||||
@[inline] def joinTR (l : List (List α)) : List α := bindTR l id
|
||||
|
||||
@[csimp] theorem join_eq_joinTR : @join = @joinTR := by
|
||||
funext α l; rw [← List.bind_id, List.bind_eq_bindTR]; rfl
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
/-- Tail-recursive version of `List.replicate`. -/
|
||||
def replicateTR {α : Type u} (n : Nat) (a : α) : List α :=
|
||||
let rec loop : Nat → List α → List α
|
||||
| 0, as => as
|
||||
| n+1, as => loop n (a::as)
|
||||
loop n []
|
||||
|
||||
theorem replicateTR_loop_replicate_eq (a : α) (m n : Nat) :
|
||||
replicateTR.loop a n (replicate m a) = replicate (n + m) a := by
|
||||
induction n generalizing m with simp [replicateTR.loop]
|
||||
| succ n ih => simp [Nat.succ_add]; exact ih (m+1)
|
||||
|
||||
theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++ acc
|
||||
| 0 => rfl
|
||||
| n+1 => by rw [← replicateTR_loop_replicate_eq _ 1 n, replicate, replicate,
|
||||
replicateTR.loop, replicateTR_loop_eq n, replicateTR_loop_eq n, append_assoc]; rfl
|
||||
|
||||
@[csimp] theorem replicate_eq_replicateTR : @List.replicate = @List.replicateTR := by
|
||||
apply funext; intro α; apply funext; intro n; apply funext; intro a
|
||||
exact (replicateTR_loop_replicate_eq _ 0 n).symm
|
||||
|
||||
/-! ## Sublists -/
|
||||
|
||||
/-! ### take -/
|
||||
|
||||
/-- Tail recursive version of `List.take`. -/
|
||||
@[inline] def takeTR (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `take`: `take.go l xs n acc = acc.toList ++ take n xs`,
|
||||
unless `n ≥ xs.length` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Nat → Array α → List α
|
||||
| [], _, _ => l
|
||||
| _::_, 0, acc => acc.toList
|
||||
| a::as, n+1, acc => go as n (acc.push a)
|
||||
|
||||
@[csimp] theorem take_eq_takeTR : @take = @takeTR := by
|
||||
funext α n l; simp [takeTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → takeTR.go l xs n acc = acc.data ++ xs.take n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc
|
||||
| nil => cases n <;> simp [take, takeTR.go]
|
||||
| cons x xs IH =>
|
||||
cases n with simp only [take, takeTR.go]
|
||||
| zero => simp
|
||||
| succ n => intro h; rw [IH] <;> simp_all
|
||||
|
||||
/-! ### takeWhile -/
|
||||
|
||||
/-- Tail recursive version of `List.takeWhile`. -/
|
||||
@[inline] def takeWhileTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `takeWhile`: `takeWhile.go p l xs acc = acc.toList ++ takeWhile p xs`,
|
||||
unless no element satisfying `p` is found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif p a then go as (acc.push a) else acc.toList
|
||||
|
||||
@[csimp] theorem takeWhile_eq_takeWhileTR : @takeWhile = @takeWhileTR := by
|
||||
funext α p l; simp [takeWhileTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
takeWhileTR.go p l xs acc = acc.data ++ xs.takeWhile p from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [takeWhile, takeWhileTR.go]
|
||||
| cons x xs IH =>
|
||||
simp only [takeWhileTR.go, Array.toList_eq, takeWhile]
|
||||
split
|
||||
· intro h; rw [IH] <;> simp_all
|
||||
· simp [*]
|
||||
|
||||
/-! ### dropLast -/
|
||||
|
||||
/-- Tail recursive version of `dropLast`. -/
|
||||
@[inline] def dropLastTR (l : List α) : List α := l.toArray.pop.toList
|
||||
|
||||
@[csimp] theorem dropLast_eq_dropLastTR : @dropLast = @dropLastTR := by
|
||||
funext α l; simp [dropLastTR]
|
||||
|
||||
/-! ## Manipulating elements -/
|
||||
|
||||
/-! ### replace -/
|
||||
|
||||
/-- Tail recursive version of `List.replace`. -/
|
||||
@[inline] def replaceTR [BEq α] (l : List α) (b c : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `replace`: `replace.go l b c xs acc = acc.toList ++ replace xs b c`,
|
||||
unless `b` is not found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif b == a then acc.toListAppend (c::as) else go as (acc.push a)
|
||||
|
||||
@[csimp] theorem replace_eq_replaceTR : @List.replace = @replaceTR := by
|
||||
funext α _ l b c; simp [replaceTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
replaceTR.go l b c xs acc = acc.data ++ xs.replace b c from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [replace, replaceTR.go]
|
||||
| cons x xs IH =>
|
||||
simp only [replaceTR.go, Array.toListAppend_eq, replace]
|
||||
split
|
||||
· simp [*]
|
||||
· intro h; rw [IH] <;> simp_all
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/-- Tail recursive version of `List.erase`. -/
|
||||
/-- Tail recursive version of `erase`. -/
|
||||
@[inline] def eraseTR [BEq α] (l : List α) (a : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `eraseTR`: `eraseTR.go l a xs acc = acc.toList ++ erase xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
@@ -290,32 +49,11 @@ theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++
|
||||
intro xs; induction xs with intro acc h
|
||||
| nil => simp [List.erase, eraseTR.go, h]
|
||||
| cons x xs IH =>
|
||||
simp only [eraseTR.go, Array.toListAppend_eq, List.erase]
|
||||
cases x == a
|
||||
· rw [IH] <;> simp_all
|
||||
· simp
|
||||
simp [List.erase, eraseTR.go]
|
||||
cases x == a <;> simp
|
||||
· rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail-recursive version of `eraseP`. -/
|
||||
@[inline] def erasePTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `erasePTR`: `erasePTR.go p l xs acc = acc.toList ++ eraseP p xs`,
|
||||
unless `xs` does not contain any elements satisfying `p`, where it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a :: l, acc => bif p a then acc.toListAppend l else go l (acc.push a)
|
||||
|
||||
@[csimp] theorem eraseP_eq_erasePTR : @eraseP = @erasePTR := by
|
||||
funext α p l; simp [erasePTR]
|
||||
let rec go (acc) : ∀ xs, l = acc.data ++ xs →
|
||||
erasePTR.go p l xs acc = acc.data ++ xs.eraseP p
|
||||
| [] => fun h => by simp [erasePTR.go, eraseP, h]
|
||||
| x::xs => by
|
||||
simp [erasePTR.go, eraseP]; cases p x <;> simp
|
||||
· intro h; rw [go _ xs]; {simp}; simp [h]
|
||||
exact (go #[] _ rfl).symm
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
/-- Tail recursive version of `List.eraseIdx`. -/
|
||||
/-- Tail recursive version of `eraseIdx`. -/
|
||||
@[inline] def eraseIdxTR (l : List α) (n : Nat) : List α := go l n #[] where
|
||||
/-- Auxiliary for `eraseIdxTR`: `eraseIdxTR.go l n xs acc = acc.toList ++ eraseIdx xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
@@ -334,14 +72,109 @@ theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++
|
||||
match n with
|
||||
| 0 => simp [eraseIdx, eraseIdxTR.go]
|
||||
| n+1 =>
|
||||
simp only [eraseIdxTR.go, eraseIdx]
|
||||
simp [eraseIdx, eraseIdxTR.go]
|
||||
rw [IH]; simp; simp; exact h
|
||||
|
||||
/-! ## Zippers -/
|
||||
/-- Tail recursive version of `bind`. -/
|
||||
@[inline] def bindTR (as : List α) (f : α → List β) : List β := go as #[] where
|
||||
/-- Auxiliary for `bind`: `bind.go f as = acc.toList ++ bind f as` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| x::xs, acc => go xs (acc ++ f x)
|
||||
|
||||
/-! ### zipWith -/
|
||||
@[csimp] theorem bind_eq_bindTR : @List.bind = @bindTR := by
|
||||
funext α β as f
|
||||
let rec go : ∀ as acc, bindTR.go f as acc = acc.data ++ as.bind f
|
||||
| [], acc => by simp [bindTR.go, bind]
|
||||
| x::xs, acc => by simp [bindTR.go, bind, go xs]
|
||||
exact (go as #[]).symm
|
||||
|
||||
/-- Tail recursive version of `List.zipWith`. -/
|
||||
/-- Tail recursive version of `join`. -/
|
||||
@[inline] def joinTR (l : List (List α)) : List α := bindTR l id
|
||||
|
||||
@[csimp] theorem join_eq_joinTR : @join = @joinTR := by
|
||||
funext α l; rw [← List.bind_id, List.bind_eq_bindTR]; rfl
|
||||
|
||||
/-- Tail recursive version of `filterMap`. -/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
/-- Auxiliary for `filterMap`: `filterMap.go f l = acc.toList ++ filterMap f l` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| a::as, acc => match f a with
|
||||
| none => go as acc
|
||||
| some b => go as (acc.push b)
|
||||
|
||||
@[csimp] theorem filterMap_eq_filterMapTR : @List.filterMap = @filterMapTR := by
|
||||
funext α β f l
|
||||
let rec go : ∀ as acc, filterMapTR.go f as acc = acc.data ++ as.filterMap f
|
||||
| [], acc => by simp [filterMapTR.go, filterMap]
|
||||
| a::as, acc => by simp [filterMapTR.go, filterMap, go as]; split <;> simp [*]
|
||||
exact (go l #[]).symm
|
||||
|
||||
/-- Tail recursive version of `replace`. -/
|
||||
@[inline] def replaceTR [BEq α] (l : List α) (b c : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `replace`: `replace.go l b c xs acc = acc.toList ++ replace xs b c`,
|
||||
unless `b` is not found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif a == b then acc.toListAppend (c::as) else go as (acc.push a)
|
||||
|
||||
@[csimp] theorem replace_eq_replaceTR : @List.replace = @replaceTR := by
|
||||
funext α _ l b c; simp [replaceTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
replaceTR.go l b c xs acc = acc.data ++ xs.replace b c from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [replace, replaceTR.go]
|
||||
| cons x xs IH =>
|
||||
simp [replace, replaceTR.go]; split <;> simp [*]
|
||||
· intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `take`. -/
|
||||
@[inline] def takeTR (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `take`: `take.go l xs n acc = acc.toList ++ take n xs`,
|
||||
unless `n ≥ xs.length` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Nat → Array α → List α
|
||||
| [], _, _ => l
|
||||
| _::_, 0, acc => acc.toList
|
||||
| a::as, n+1, acc => go as n (acc.push a)
|
||||
|
||||
@[csimp] theorem take_eq_takeTR : @take = @takeTR := by
|
||||
funext α n l; simp [takeTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs → takeTR.go l xs n acc = acc.data ++ xs.take n from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs generalizing n with intro acc
|
||||
| nil => cases n <;> simp [take, takeTR.go]
|
||||
| cons x xs IH =>
|
||||
cases n with simp [take, takeTR.go]
|
||||
| succ n => intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `takeWhile`. -/
|
||||
@[inline] def takeWhileTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `takeWhile`: `takeWhile.go p l xs acc = acc.toList ++ takeWhile p xs`,
|
||||
unless no element satisfying `p` is found in `xs` in which case it returns `l`. -/
|
||||
@[specialize] go : List α → Array α → List α
|
||||
| [], _ => l
|
||||
| a::as, acc => bif p a then go as (acc.push a) else acc.toList
|
||||
|
||||
@[csimp] theorem takeWhile_eq_takeWhileTR : @takeWhile = @takeWhileTR := by
|
||||
funext α p l; simp [takeWhileTR]
|
||||
suffices ∀ xs acc, l = acc.data ++ xs →
|
||||
takeWhileTR.go p l xs acc = acc.data ++ xs.takeWhile p from
|
||||
(this l #[] (by simp)).symm
|
||||
intro xs; induction xs with intro acc
|
||||
| nil => simp [takeWhile, takeWhileTR.go]
|
||||
| cons x xs IH =>
|
||||
simp [takeWhile, takeWhileTR.go]; split <;> simp [*]
|
||||
· intro h; rw [IH]; simp; simp; exact h
|
||||
|
||||
/-- Tail recursive version of `foldr`. -/
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
funext α β f init l; simp [foldrTR, Array.foldr_eq_foldr_data, -Array.size_toArray]
|
||||
|
||||
/-- Tail recursive version of `zipWith`. -/
|
||||
@[inline] def zipWithTR (f : α → β → γ) (as : List α) (bs : List β) : List γ := go as bs #[] where
|
||||
/-- Auxiliary for `zipWith`: `zipWith.go f as bs acc = acc.toList ++ zipWith f as bs` -/
|
||||
go : List α → List β → Array γ → List γ
|
||||
@@ -355,37 +188,14 @@ theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++
|
||||
| a::as, b::bs, acc => by simp [zipWithTR.go, zipWith, go as bs]
|
||||
exact (go as bs #[]).symm
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
/-- Tail recursive version of `List.unzip`. -/
|
||||
/-- Tail recursive version of `unzip`. -/
|
||||
def unzipTR (l : List (α × β)) : List α × List β :=
|
||||
l.foldr (fun (a, b) (al, bl) => (a::al, b::bl)) ([], [])
|
||||
|
||||
@[csimp] theorem unzip_eq_unzipTR : @unzip = @unzipTR := by
|
||||
funext α β l; simp [unzipTR]; induction l <;> simp [*]
|
||||
|
||||
/-! ## Ranges and enumeration -/
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
/-- Tail-recursive version of `List.iota`. -/
|
||||
def iotaTR (n : Nat) : List Nat :=
|
||||
let rec go : Nat → List Nat → List Nat
|
||||
| 0, r => r.reverse
|
||||
| m@(n+1), r => go n (m::r)
|
||||
go n []
|
||||
|
||||
@[csimp]
|
||||
theorem iota_eq_iotaTR : @iota = @iotaTR :=
|
||||
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by
|
||||
induction n generalizing r with
|
||||
| zero => simp [iota, iotaTR.go]
|
||||
| succ n ih => simp [iota, iotaTR.go, ih, append_assoc]
|
||||
funext fun n => by simp [iotaTR, aux]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/-- Tail recursive version of `List.enumFrom`. -/
|
||||
/-- Tail recursive version of `enumFrom`. -/
|
||||
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
let arr := l.toArray
|
||||
(arr.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + arr.size, [])).2
|
||||
@@ -401,11 +211,18 @@ def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
rw [Array.foldr_eq_foldr_data]
|
||||
simp [go]
|
||||
|
||||
/-! ## Other list operations -/
|
||||
theorem replicateTR_loop_eq : ∀ n, replicateTR.loop a n acc = replicate n a ++ acc
|
||||
| 0 => rfl
|
||||
| n+1 => by rw [← replicateTR_loop_replicate_eq _ 1 n, replicate, replicate,
|
||||
replicateTR.loop, replicateTR_loop_eq n, replicateTR_loop_eq n, append_assoc]; rfl
|
||||
|
||||
/-! ### intersperse -/
|
||||
/-- Tail recursive version of `dropLast`. -/
|
||||
@[inline] def dropLastTR (l : List α) : List α := l.toArray.pop.toList
|
||||
|
||||
/-- Tail recursive version of `List.intersperse`. -/
|
||||
@[csimp] theorem dropLast_eq_dropLastTR : @dropLast = @dropLastTR := by
|
||||
funext α l; simp [dropLastTR]
|
||||
|
||||
/-- Tail recursive version of `intersperse`. -/
|
||||
def intersperseTR (sep : α) : List α → List α
|
||||
| [] => []
|
||||
| [x] => [x]
|
||||
@@ -417,9 +234,7 @@ def intersperseTR (sep : α) : List α → List α
|
||||
| [] | [_] => rfl
|
||||
| x::y::xs => simp [intersperse]; induction xs generalizing y <;> simp [*]
|
||||
|
||||
/-! ### intercalate -/
|
||||
|
||||
/-- Tail recursive version of `List.intercalate`. -/
|
||||
/-- Tail recursive version of `intercalate`. -/
|
||||
def intercalateTR (sep : List α) : List (List α) → List α
|
||||
| [] => []
|
||||
| [x] => x
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,53 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Nat.Div
|
||||
|
||||
/-!
|
||||
# Notation for `List` literals.
|
||||
-/
|
||||
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
open Decidable List
|
||||
|
||||
/--
|
||||
The syntax `[a, b, c]` is shorthand for `a :: b :: c :: []`, or
|
||||
`List.cons a (List.cons b (List.cons c List.nil))`. It allows conveniently constructing
|
||||
list literals.
|
||||
|
||||
For lists of length at least 64, an alternative desugaring strategy is used
|
||||
which uses let bindings as intermediates as in
|
||||
`let left := [d, e, f]; a :: b :: c :: left` to avoid creating very deep expressions.
|
||||
Note that this changes the order of evaluation, although it should not be observable
|
||||
unless you use side effecting operations like `dbg_trace`.
|
||||
-/
|
||||
syntax "[" withoutPosition(term,*,?) "]" : term
|
||||
|
||||
/--
|
||||
Auxiliary syntax for implementing `[$elem,*]` list literal syntax.
|
||||
The syntax `%[a,b,c|tail]` constructs a value equivalent to `a::b::c::tail`.
|
||||
It uses binary partitioning to construct a tree of intermediate let bindings as in
|
||||
`let left := [d, e, f]; a :: b :: c :: left` to avoid creating very deep expressions.
|
||||
-/
|
||||
syntax "%[" withoutPosition(term,*,? " | " term) "]" : term
|
||||
|
||||
namespace Lean
|
||||
|
||||
macro_rules
|
||||
| `([ $elems,* ]) => do
|
||||
-- NOTE: we do not have `TSepArray.getElems` yet at this point
|
||||
let rec expandListLit (i : Nat) (skip : Bool) (result : TSyntax `term) : MacroM Syntax := do
|
||||
match i, skip with
|
||||
| 0, _ => pure result
|
||||
| i+1, true => expandListLit i false result
|
||||
| i+1, false => expandListLit i true (← ``(List.cons $(⟨elems.elemsAndSeps.get! i⟩) $result))
|
||||
let size := elems.elemsAndSeps.size
|
||||
if size < 64 then
|
||||
expandListLit size (size % 2 == 0) (← ``(List.nil))
|
||||
else
|
||||
`(%[ $elems,* | List.nil ])
|
||||
|
||||
end Lean
|
||||
@@ -8,10 +8,10 @@ import Init.Data.List.Lemmas
|
||||
import Init.Data.Nat.Lemmas
|
||||
|
||||
/-!
|
||||
# Further lemmas about `List.take`, `List.drop`, `List.zip` and `List.zipWith`.
|
||||
# Lemmas about `List.take`, `List.drop`, `List.zip` and `List.zipWith`.
|
||||
|
||||
These are in a separate file from most of the list lemmas
|
||||
as they required importing more lemmas about natural numbers, and use `omega`.
|
||||
as they required importing more lemmas about natural numbers.
|
||||
-/
|
||||
|
||||
namespace List
|
||||
@@ -20,6 +20,8 @@ open Nat
|
||||
|
||||
/-! ### take -/
|
||||
|
||||
abbrev take_succ_cons := @take_cons_succ
|
||||
|
||||
@[simp] theorem length_take : ∀ (i : Nat) (l : List α), length (take i l) = min i (length l)
|
||||
| 0, l => by simp [Nat.zero_min]
|
||||
| succ n, [] => by simp [Nat.min_zero]
|
||||
@@ -32,6 +34,17 @@ theorem length_take_le' (n) (l : List α) : length (take n l) ≤ l.length :=
|
||||
|
||||
theorem length_take_of_le (h : n ≤ length l) : length (take n l) = n := by simp [Nat.min_eq_left h]
|
||||
|
||||
theorem take_all_of_le {n} {l : List α} (h : length l ≤ n) : take n l = l :=
|
||||
take_length_le h
|
||||
|
||||
@[simp]
|
||||
theorem take_left : ∀ l₁ l₂ : List α, take (length l₁) (l₁ ++ l₂) = l₁
|
||||
| [], _ => rfl
|
||||
| a :: l₁, l₂ => congrArg (cons a) (take_left l₁ l₂)
|
||||
|
||||
theorem take_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : take n (l₁ ++ l₂) = l₁ := by
|
||||
rw [← h]; apply take_left
|
||||
|
||||
theorem take_take : ∀ (n m) (l : List α), take n (take m l) = take (min n m) l
|
||||
| n, 0, l => by rw [Nat.min_zero, take_zero, take_nil]
|
||||
| 0, m, l => by rw [Nat.zero_min, take_zero, take_zero]
|
||||
@@ -39,15 +52,16 @@ theorem take_take : ∀ (n m) (l : List α), take n (take m l) = take (min n m)
|
||||
| succ n, succ m, a :: l => by
|
||||
simp only [take, succ_min_succ, take_take n m l]
|
||||
|
||||
@[simp] theorem take_replicate (a : α) : ∀ n m : Nat, take n (replicate m a) = replicate (min n m) a
|
||||
theorem take_replicate (a : α) : ∀ n m : Nat, take n (replicate m a) = replicate (min n m) a
|
||||
| n, 0 => by simp [Nat.min_zero]
|
||||
| 0, m => by simp [Nat.zero_min]
|
||||
| succ n, succ m => by simp [replicate_succ, succ_min_succ, take_replicate]
|
||||
| succ n, succ m => by simp [succ_min_succ, take_replicate]
|
||||
|
||||
@[simp] theorem drop_replicate (a : α) : ∀ n m : Nat, drop n (replicate m a) = replicate (m - n) a
|
||||
| n, 0 => by simp
|
||||
| 0, m => by simp
|
||||
| succ n, succ m => by simp [replicate_succ, succ_sub_succ, drop_replicate]
|
||||
theorem map_take (f : α → β) :
|
||||
∀ (L : List α) (i : Nat), (L.take i).map f = (L.map f).take i
|
||||
| [], i => by simp
|
||||
| _, 0 => by simp
|
||||
| h :: t, n + 1 => by dsimp; rw [map_take f t n]
|
||||
|
||||
/-- Taking the first `n` elements in `l₁ ++ l₂` is the same as appending the first `n` elements
|
||||
of `l₁` to the first `n - l₁.length` elements of `l₂`. -/
|
||||
@@ -74,88 +88,55 @@ theorem take_append {l₁ l₂ : List α} (i : Nat) :
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the big list to the small list. -/
|
||||
theorem getElem_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||||
L[i] = (L.take j)[i]'(length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩) :=
|
||||
getElem_of_eq (take_append_drop j L).symm _ ▸ getElem_append ..
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the small list to the big list. -/
|
||||
theorem getElem_take' (L : List α) {j i : Nat} {h : i < (L.take j).length} :
|
||||
(L.take j)[i] =
|
||||
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
|
||||
rw [length_take, Nat.lt_min] at h; rw [getElem_take L _ h.1]
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the big list to the small list. -/
|
||||
@[deprecated getElem_take (since := "2024-06-12")]
|
||||
theorem get_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||||
get L ⟨i, hi⟩ = get (L.take j) ⟨i, length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩⟩ := by
|
||||
simp [getElem_take _ hi hj]
|
||||
get L ⟨i, hi⟩ = get (L.take j) ⟨i, length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩⟩ :=
|
||||
get_of_eq (take_append_drop j L).symm _ ▸ get_append ..
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the small list to the big list. -/
|
||||
@[deprecated getElem_take (since := "2024-06-12")]
|
||||
theorem get_take' (L : List α) {j i} :
|
||||
get (L.take j) i =
|
||||
get L ⟨i.1, Nat.lt_of_lt_of_le i.2 (length_take_le' _ _)⟩ := by
|
||||
simp [getElem_take']
|
||||
let ⟨i, hi⟩ := i; rw [length_take, Nat.lt_min] at hi; rw [get_take L _ hi.1]
|
||||
|
||||
theorem getElem?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||||
(l.take n)[m]? = none :=
|
||||
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
|
||||
theorem get?_take {l : List α} {n m : Nat} (h : m < n) : (l.take n).get? m = l.get? m := by
|
||||
induction n generalizing l m with
|
||||
| zero =>
|
||||
exact absurd h (Nat.not_lt_of_le m.zero_le)
|
||||
| succ _ hn =>
|
||||
cases l with
|
||||
| nil => simp only [take_nil]
|
||||
| cons hd tl =>
|
||||
cases m
|
||||
· simp only [get?, take]
|
||||
· simpa only using hn (Nat.lt_of_succ_lt_succ h)
|
||||
|
||||
@[deprecated getElem?_take_eq_none (since := "2024-06-12")]
|
||||
theorem get?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||||
(l.take n).get? m = none := by
|
||||
simp [getElem?_take_eq_none h]
|
||||
(l.take n).get? m = none :=
|
||||
get?_eq_none.mpr <| Nat.le_trans (length_take_le _ _) h
|
||||
|
||||
theorem getElem?_take_eq_if {l : List α} {n m : Nat} :
|
||||
(l.take n)[m]? = if m < n then l[m]? else none := by
|
||||
split
|
||||
· next h => exact getElem?_take h
|
||||
· next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
|
||||
|
||||
@[deprecated getElem?_take_eq_if (since := "2024-06-12")]
|
||||
theorem get?_take_eq_if {l : List α} {n m : Nat} :
|
||||
(l.take n).get? m = if m < n then l.get? m else none := by
|
||||
simp [getElem?_take_eq_if]
|
||||
|
||||
theorem head?_take {l : List α} {n : Nat} :
|
||||
(l.take n).head? = if n = 0 then none else l.head? := by
|
||||
simp [head?_eq_getElem?, getElem?_take_eq_if]
|
||||
split
|
||||
· rw [if_neg (by omega)]
|
||||
· rw [if_pos (by omega)]
|
||||
· next h => exact get?_take h
|
||||
· next h => exact get?_take_eq_none (Nat.le_of_not_lt h)
|
||||
|
||||
theorem head_take {l : List α} {n : Nat} (h : l.take n ≠ []) :
|
||||
(l.take n).head h = l.head (by simp_all) := by
|
||||
apply Option.some_inj.1
|
||||
rw [← head?_eq_head, ← head?_eq_head, head?_take, if_neg]
|
||||
simp_all
|
||||
@[simp]
|
||||
theorem nth_take_of_succ {l : List α} {n : Nat} : (l.take (n + 1)).get? n = l.get? n :=
|
||||
get?_take (Nat.lt_succ_self n)
|
||||
|
||||
theorem getLast?_take {l : List α} : (l.take n).getLast? = if n = 0 then none else l[n - 1]?.or l.getLast? := by
|
||||
rw [getLast?_eq_getElem?, getElem?_take_eq_if, length_take]
|
||||
split
|
||||
· rw [if_neg (by omega)]
|
||||
rw [Nat.min_def]
|
||||
split
|
||||
· rw [getElem?_eq_getElem (by omega)]
|
||||
simp
|
||||
· rw [← getLast?_eq_getElem?, getElem?_eq_none (by omega)]
|
||||
simp
|
||||
· rw [if_pos]
|
||||
omega
|
||||
theorem take_succ {l : List α} {n : Nat} : l.take (n + 1) = l.take n ++ (l.get? n).toList := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
simp only [Option.toList, get?, take_nil, append_nil]
|
||||
| cons hd tl hl =>
|
||||
cases n
|
||||
· simp only [Option.toList, get?, eq_self_iff_true, take, nil_append]
|
||||
· simp only [hl, cons_append, get?, eq_self_iff_true, take]
|
||||
|
||||
theorem getLast_take {l : List α} (h : l.take n ≠ []) :
|
||||
(l.take n).getLast h = l[n - 1]?.getD (l.getLast (by simp_all)) := by
|
||||
rw [getLast_eq_getElem, getElem_take']
|
||||
simp [length_take, Nat.min_def]
|
||||
simp at h
|
||||
split
|
||||
· rw [getElem?_eq_getElem (by omega)]
|
||||
simp
|
||||
· rw [getElem?_eq_none (by omega), getLast_eq_getElem]
|
||||
simp
|
||||
@[simp]
|
||||
theorem take_eq_nil_iff {l : List α} {k : Nat} : l.take k = [] ↔ l = [] ∨ k = 0 := by
|
||||
cases l <;> cases k <;> simp [Nat.succ_ne_zero]
|
||||
|
||||
@[simp]
|
||||
theorem take_eq_take :
|
||||
@@ -177,6 +158,20 @@ theorem take_add (l : List α) (m n : Nat) : l.take (m + n) = l.take m ++ (l.dro
|
||||
· apply length_take_le
|
||||
· apply Nat.le_add_right
|
||||
|
||||
theorem take_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.take i = []
|
||||
| _, _, rfl => take_nil
|
||||
|
||||
theorem ne_nil_of_take_ne_nil {as : List α} {i : Nat} (h: as.take i ≠ []) : as ≠ [] :=
|
||||
mt take_eq_nil_of_eq_nil h
|
||||
|
||||
theorem dropLast_eq_take (l : List α) : l.dropLast = l.take l.length.pred := by
|
||||
cases l with
|
||||
| nil => simp [dropLast]
|
||||
| cons x l =>
|
||||
induction l generalizing x with
|
||||
| nil => simp [dropLast]
|
||||
| cons hd tl hl => simp [dropLast, hl]
|
||||
|
||||
theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||||
(l.take n).dropLast = l.take n.pred := by
|
||||
simp only [dropLast_eq_take, length_take, Nat.le_of_lt h, take_take, pred_le, Nat.min_eq_left]
|
||||
@@ -193,6 +188,19 @@ theorem map_eq_append_split {f : α → β} {l : List α} {s₁ s₂ : List β}
|
||||
|
||||
/-! ### drop -/
|
||||
|
||||
@[simp]
|
||||
theorem drop_eq_nil_iff_le {l : List α} {k : Nat} : l.drop k = [] ↔ l.length ≤ k := by
|
||||
refine' ⟨fun h => _, drop_eq_nil_of_le⟩
|
||||
induction k generalizing l with
|
||||
| zero =>
|
||||
simp only [drop] at h
|
||||
simp [h]
|
||||
| succ k hk =>
|
||||
cases l
|
||||
· simp
|
||||
· simp only [drop] at h
|
||||
simpa [Nat.succ_le_succ_iff] using hk h
|
||||
|
||||
theorem drop_length_cons {l : List α} (h : l ≠ []) (a : α) :
|
||||
(a :: l).drop l.length = [l.getLast h] := by
|
||||
induction l generalizing a with
|
||||
@@ -229,6 +237,15 @@ theorem drop_append {l₁ l₂ : List α} (i : Nat) : drop (l₁.length + i) (l
|
||||
rw [drop_append_eq_append_drop, drop_eq_nil_of_le] <;>
|
||||
simp [Nat.add_sub_cancel_left, Nat.le_add_right]
|
||||
|
||||
theorem drop_sizeOf_le [SizeOf α] (l : List α) (n : Nat) : sizeOf (l.drop n) ≤ sizeOf l := by
|
||||
induction l generalizing n with
|
||||
| nil => rw [drop_nil]; apply Nat.le_refl
|
||||
| cons _ _ lih =>
|
||||
induction n with
|
||||
| zero => apply Nat.le_refl
|
||||
| succ n =>
|
||||
exact Trans.trans (lih _) (Nat.le_add_left _ _)
|
||||
|
||||
theorem lt_length_drop (L : List α) {i j : Nat} (h : i + j < L.length) : j < (L.drop i).length := by
|
||||
have A : i < L.length := Nat.lt_of_le_of_lt (Nat.le.intro rfl) h
|
||||
rw [(take_append_drop i L).symm] at h
|
||||
@@ -237,40 +254,24 @@ theorem lt_length_drop (L : List α) {i j : Nat} (h : i + j < L.length) : j < (L
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
|
||||
theorem getElem_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
L[i + j] = (L.drop i)[j]'(lt_length_drop L h) := by
|
||||
theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
get L ⟨i + j, h⟩ = get (L.drop i) ⟨j, lt_length_drop L h⟩ := by
|
||||
have : i ≤ L.length := Nat.le_trans (Nat.le_add_right _ _) (Nat.le_of_lt h)
|
||||
rw [getElem_of_eq (take_append_drop i L).symm h, getElem_append_right'] <;>
|
||||
rw [get_of_eq (take_append_drop i L).symm ⟨i + j, h⟩, get_append_right'] <;>
|
||||
simp [Nat.min_eq_left this, Nat.add_sub_cancel_left, Nat.le_add_right]
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
|
||||
@[deprecated getElem_drop (since := "2024-06-12")]
|
||||
theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
get L ⟨i + j, h⟩ = get (L.drop i) ⟨j, lt_length_drop L h⟩ := by
|
||||
simp [getElem_drop]
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||||
theorem getElem_drop' (L : List α) {i : Nat} {j : Nat} {h : j < (L.drop i).length} :
|
||||
(L.drop i)[j] = L[i + j]'(by
|
||||
rw [Nat.add_comm]
|
||||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ h)) := by
|
||||
rw [getElem_drop]
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||||
@[deprecated getElem_drop' (since := "2024-06-12")]
|
||||
theorem get_drop' (L : List α) {i j} :
|
||||
get (L.drop i) j = get L ⟨i + j, by
|
||||
rw [Nat.add_comm]
|
||||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ j.2)⟩ := by
|
||||
simp [getElem_drop']
|
||||
rw [get_drop]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? := by
|
||||
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
|
||||
ext
|
||||
simp only [getElem?_eq_some, getElem_drop', Option.mem_def]
|
||||
simp only [get?_eq_some, get_drop', Option.mem_def]
|
||||
constructor <;> intro ⟨h, ha⟩
|
||||
· exact ⟨_, ha⟩
|
||||
· refine ⟨?_, ha⟩
|
||||
@@ -278,70 +279,19 @@ theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? :=
|
||||
rw [Nat.add_comm] at h
|
||||
apply Nat.lt_sub_of_add_lt h
|
||||
|
||||
@[deprecated getElem?_drop (since := "2024-06-12")]
|
||||
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
|
||||
simp
|
||||
@[simp] theorem drop_drop (n : Nat) : ∀ (m) (l : List α), drop n (drop m l) = drop (n + m) l
|
||||
| m, [] => by simp
|
||||
| 0, l => by simp
|
||||
| m + 1, a :: l =>
|
||||
calc
|
||||
drop n (drop (m + 1) (a :: l)) = drop n (drop m l) := rfl
|
||||
_ = drop (n + m) l := drop_drop n m l
|
||||
_ = drop (n + (m + 1)) (a :: l) := rfl
|
||||
|
||||
theorem head?_drop (l : List α) (n : Nat) :
|
||||
(l.drop n).head? = l[n]? := by
|
||||
rw [head?_eq_getElem?, getElem?_drop, Nat.add_zero]
|
||||
|
||||
theorem head_drop {l : List α} {n : Nat} (h : l.drop n ≠ []) :
|
||||
(l.drop n).head h = l[n]'(by simp_all) := by
|
||||
have w : n < l.length := length_lt_of_drop_ne_nil h
|
||||
simpa [head?_eq_head, getElem?_eq_getElem, h, w] using head?_drop l n
|
||||
|
||||
theorem getLast?_drop {l : List α} : (l.drop n).getLast? = if l.length ≤ n then none else l.getLast? := by
|
||||
rw [getLast?_eq_getElem?, getElem?_drop]
|
||||
rw [length_drop]
|
||||
split
|
||||
· rw [getElem?_eq_none (by omega)]
|
||||
· rw [getLast?_eq_getElem?]
|
||||
congr
|
||||
omega
|
||||
|
||||
theorem getLast_drop {l : List α} (h : l.drop n ≠ []) :
|
||||
(l.drop n).getLast h = l.getLast (ne_nil_of_length_pos (by simp at h; omega)) := by
|
||||
simp only [ne_eq, drop_eq_nil_iff_le] at h
|
||||
apply Option.some_inj.1
|
||||
simp only [← getLast?_eq_getLast, getLast?_drop, ite_eq_right_iff]
|
||||
omega
|
||||
|
||||
theorem set_eq_take_append_cons_drop {l : List α} {n : Nat} {a : α} :
|
||||
l.set n a = if n < l.length then l.take n ++ a :: l.drop (n + 1) else l := by
|
||||
split <;> rename_i h
|
||||
· ext1 m
|
||||
by_cases h' : m < n
|
||||
· rw [getElem?_append (by simp [length_take]; omega), getElem?_set_ne (by omega),
|
||||
getElem?_take h']
|
||||
· by_cases h'' : m = n
|
||||
· subst h''
|
||||
rw [getElem?_set_eq (by simp; omega), getElem?_append_right, length_take,
|
||||
Nat.min_eq_left (by omega), Nat.sub_self, getElem?_cons_zero]
|
||||
rw [length_take]
|
||||
exact Nat.min_le_left m l.length
|
||||
· have h''' : n < m := by omega
|
||||
rw [getElem?_set_ne (by omega), getElem?_append_right, length_take,
|
||||
Nat.min_eq_left (by omega)]
|
||||
· obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_lt h'''
|
||||
have p : n + k + 1 - n = k + 1 := by omega
|
||||
rw [p]
|
||||
rw [getElem?_cons_succ, getElem?_drop]
|
||||
congr 1
|
||||
omega
|
||||
· rw [length_take]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by omega)
|
||||
· rw [set_eq_of_length_le]
|
||||
omega
|
||||
|
||||
theorem exists_of_set {n : Nat} {a' : α} {l : List α} (h : n < l.length) :
|
||||
∃ l₁ l₂, l = l₁ ++ l[n] :: l₂ ∧ l₁.length = n ∧ l.set n a' = l₁ ++ a' :: l₂ := by
|
||||
refine ⟨l.take n, l.drop (n + 1), ⟨by simp, ⟨length_take_of_le (Nat.le_of_lt h), ?_⟩⟩⟩
|
||||
simp [set_eq_take_append_cons_drop, h]
|
||||
|
||||
theorem drop_set_of_lt (a : α) {n m : Nat} (l : List α)
|
||||
(hnm : n < m) : drop m (l.set n a) = l.drop m :=
|
||||
ext_getElem? fun k => by simpa only [getElem?_drop] using getElem?_set_ne (by omega)
|
||||
theorem take_drop : ∀ (m n : Nat) (l : List α), take n (drop m l) = drop m (take (m + n) l)
|
||||
| 0, _, _ => by simp
|
||||
| _, _, [] => by simp
|
||||
| _+1, _, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop ..
|
||||
|
||||
theorem drop_take : ∀ (m n : Nat) (l : List α), drop n (take m l) = take (m - n) (drop n l)
|
||||
| 0, _, _ => by simp
|
||||
@@ -352,7 +302,15 @@ theorem drop_take : ∀ (m n : Nat) (l : List α), drop n (take m l) = take (m -
|
||||
congr 1
|
||||
omega
|
||||
|
||||
theorem take_reverse {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
||||
theorem map_drop (f : α → β) :
|
||||
∀ (L : List α) (i : Nat), (L.drop i).map f = (L.map f).drop i
|
||||
| [], i => by simp
|
||||
| L, 0 => by simp
|
||||
| h :: t, n + 1 => by
|
||||
dsimp
|
||||
rw [map_drop f t]
|
||||
|
||||
theorem reverse_take {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
||||
xs.reverse.take n = (xs.drop (xs.length - n)).reverse := by
|
||||
induction xs generalizing n <;>
|
||||
simp only [reverse_cons, drop, reverse_nil, Nat.zero_sub, length, take_nil]
|
||||
@@ -372,33 +330,19 @@ theorem take_reverse {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
||||
rw [length_append, length_reverse]
|
||||
rfl
|
||||
|
||||
@[deprecated (since := "2024-06-15")] abbrev reverse_take := @take_reverse
|
||||
@[simp]
|
||||
theorem get_cons_drop : ∀ (l : List α) i, get l i :: drop (i + 1) l = drop i l
|
||||
| _::_, ⟨0, _⟩ => rfl
|
||||
| _::_, ⟨i+1, _⟩ => get_cons_drop _ ⟨i, _⟩
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
theorem drop_eq_get_cons {n} {l : List α} (h) : drop n l = get l ⟨n, h⟩ :: drop (n + 1) l :=
|
||||
(get_cons_drop _ ⟨n, h⟩).symm
|
||||
|
||||
@[simp] theorem rotateLeft_replicate (n) (a : α) : rotateLeft (replicate m a) n = replicate m a := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
suffices 1 < m → m - (n + 1) % m + min ((n + 1) % m) m = m by
|
||||
simpa [rotateLeft]
|
||||
intro h
|
||||
rw [Nat.min_eq_left (Nat.le_of_lt (Nat.mod_lt _ (by omega)))]
|
||||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||||
omega
|
||||
theorem drop_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.drop i = []
|
||||
| _, _, rfl => drop_nil
|
||||
|
||||
/-! ### rotateRight -/
|
||||
|
||||
@[simp] theorem rotateRight_replicate (n) (a : α) : rotateRight (replicate m a) n = replicate m a := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
suffices 1 < m → m - (m - (n + 1) % m) + min (m - (n + 1) % m) m = m by
|
||||
simpa [rotateRight]
|
||||
intro h
|
||||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||||
rw [Nat.min_eq_left (by omega)]
|
||||
omega
|
||||
theorem ne_nil_of_drop_ne_nil {as : List α} {i : Nat} (h: as.drop i ≠ []) : as ≠ [] :=
|
||||
mt drop_eq_nil_of_eq_nil h
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
@@ -407,98 +351,10 @@ theorem take_reverse {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;>
|
||||
simp_all [succ_min_succ, Nat.zero_min, Nat.min_zero]
|
||||
|
||||
theorem zipWith_eq_zipWith_take_min : ∀ (l₁ : List α) (l₂ : List β),
|
||||
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||||
| [], _ => by simp
|
||||
| _, [] => by simp
|
||||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zipWith_eq_zipWith_take_min l₁ l₂]
|
||||
|
||||
@[simp] theorem zipWith_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zipWith f (replicate m a) (replicate n b) = replicate (min m n) (f a b) := by
|
||||
rw [zipWith_eq_zipWith_take_min]
|
||||
simp
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
@[simp] theorem length_zip (l₁ : List α) (l₂ : List β) :
|
||||
length (zip l₁ l₂) = min (length l₁) (length l₂) := by
|
||||
simp [zip]
|
||||
|
||||
theorem zip_eq_zip_take_min : ∀ (l₁ : List α) (l₂ : List β),
|
||||
zip l₁ l₂ = zip (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||||
| [], _ => by simp
|
||||
| _, [] => by simp
|
||||
| a :: l₁, b :: l₂ => by simp [succ_min_succ, zip_eq_zip_take_min l₁ l₂]
|
||||
|
||||
@[simp] theorem zip_replicate {a : α} {b : β} {m n : Nat} :
|
||||
zip (replicate m a) (replicate n b) = replicate (min m n) (a, b) := by
|
||||
rw [zip_eq_zip_take_min]
|
||||
simp
|
||||
|
||||
/-! ### minimum? -/
|
||||
|
||||
-- A specialization of `minimum?_eq_some_iff` to Nat.
|
||||
theorem minimum?_eq_some_iff' {xs : List Nat} :
|
||||
xs.minimum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, a ≤ b) :=
|
||||
minimum?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(min_eq_or := fun _ _ => by omega)
|
||||
(le_min_iff := fun _ _ _ => by omega)
|
||||
|
||||
-- This could be generalized,
|
||||
-- but will first require further work on order typeclasses in the core repository.
|
||||
theorem minimum?_cons' {a : Nat} {l : List Nat} :
|
||||
(a :: l).minimum? = some (match l.minimum? with
|
||||
| none => a
|
||||
| some m => min a m) := by
|
||||
rw [minimum?_eq_some_iff']
|
||||
split <;> rename_i h m
|
||||
· simp_all
|
||||
· rw [minimum?_eq_some_iff'] at m
|
||||
obtain ⟨m, le⟩ := m
|
||||
rw [Nat.min_def]
|
||||
constructor
|
||||
· split
|
||||
· exact mem_cons_self a l
|
||||
· exact mem_cons_of_mem a m
|
||||
· intro b m
|
||||
cases List.mem_cons.1 m with
|
||||
| inl => split <;> omega
|
||||
| inr h =>
|
||||
specialize le b h
|
||||
split <;> omega
|
||||
|
||||
/-! ### maximum? -/
|
||||
|
||||
-- A specialization of `maximum?_eq_some_iff` to Nat.
|
||||
theorem maximum?_eq_some_iff' {xs : List Nat} :
|
||||
xs.maximum? = some a ↔ (a ∈ xs ∧ ∀ b ∈ xs, b ≤ a) :=
|
||||
maximum?_eq_some_iff
|
||||
(le_refl := Nat.le_refl)
|
||||
(max_eq_or := fun _ _ => by omega)
|
||||
(max_le_iff := fun _ _ _ => by omega)
|
||||
|
||||
-- This could be generalized,
|
||||
-- but will first require further work on order typeclasses in the core repository.
|
||||
theorem maximum?_cons' {a : Nat} {l : List Nat} :
|
||||
(a :: l).maximum? = some (match l.maximum? with
|
||||
| none => a
|
||||
| some m => max a m) := by
|
||||
rw [maximum?_eq_some_iff']
|
||||
split <;> rename_i h m
|
||||
· simp_all
|
||||
· rw [maximum?_eq_some_iff'] at m
|
||||
obtain ⟨m, le⟩ := m
|
||||
rw [Nat.max_def]
|
||||
constructor
|
||||
· split
|
||||
· exact mem_cons_of_mem a m
|
||||
· exact mem_cons_self a l
|
||||
· intro b m
|
||||
cases List.mem_cons.1 m with
|
||||
| inl => split <;> omega
|
||||
| inr h =>
|
||||
specialize le b h
|
||||
split <;> omega
|
||||
|
||||
end List
|
||||
|
||||
@@ -100,7 +100,6 @@ def blt (a b : Nat) : Bool :=
|
||||
ble a.succ b
|
||||
|
||||
attribute [simp] Nat.zero_le
|
||||
attribute [simp] Nat.not_lt_zero
|
||||
|
||||
/-! # Helper "packing" theorems -/
|
||||
|
||||
@@ -125,8 +124,13 @@ instance : LawfulBEq Nat where
|
||||
eq_of_beq h := Nat.eq_of_beq_eq_true h
|
||||
rfl := by simp [BEq.beq]
|
||||
|
||||
theorem beq_eq_true_eq (a b : Nat) : ((a == b) = true) = (a = b) := by simp
|
||||
theorem not_beq_eq_true_eq (a b : Nat) : ((!(a == b)) = true) = ¬(a = b) := by simp
|
||||
@[simp] theorem beq_eq_true_eq (a b : Nat) : ((a == b) = true) = (a = b) := propext <| Iff.intro eq_of_beq (fun h => by subst h; apply LawfulBEq.rfl)
|
||||
@[simp] theorem not_beq_eq_true_eq (a b : Nat) : ((!(a == b)) = true) = ¬(a = b) :=
|
||||
propext <| Iff.intro
|
||||
(fun h₁ h₂ => by subst h₂; rw [LawfulBEq.rfl] at h₁; contradiction)
|
||||
(fun h =>
|
||||
have : ¬ ((a == b) = true) := fun h' => absurd (eq_of_beq h') h
|
||||
by simp [this])
|
||||
|
||||
/-! # Nat.add theorems -/
|
||||
|
||||
@@ -196,9 +200,6 @@ protected theorem eq_zero_of_add_eq_zero_left (h : n + m = 0) : m = 0 :=
|
||||
theorem mul_succ (n m : Nat) : n * succ m = n * m + n :=
|
||||
rfl
|
||||
|
||||
theorem mul_add_one (n m : Nat) : n * (m + 1) = n * m + n :=
|
||||
rfl
|
||||
|
||||
@[simp] protected theorem zero_mul : ∀ (n : Nat), 0 * n = 0
|
||||
| 0 => rfl
|
||||
| succ n => mul_succ 0 n ▸ (Nat.zero_mul n).symm ▸ rfl
|
||||
@@ -208,8 +209,6 @@ theorem succ_mul (n m : Nat) : (succ n) * m = (n * m) + m := by
|
||||
| zero => rfl
|
||||
| succ m ih => rw [mul_succ, add_succ, ih, mul_succ, add_succ, Nat.add_right_comm]
|
||||
|
||||
theorem add_one_mul (n m : Nat) : (n + 1) * m = (n * m) + m := succ_mul n m
|
||||
|
||||
protected theorem mul_comm : ∀ (n m : Nat), n * m = m * n
|
||||
| n, 0 => (Nat.zero_mul n).symm ▸ (Nat.mul_zero n).symm ▸ rfl
|
||||
| n, succ m => (mul_succ n m).symm ▸ (succ_mul m n).symm ▸ (Nat.mul_comm n m).symm ▸ rfl
|
||||
@@ -257,24 +256,14 @@ theorem succ_lt_succ {n m : Nat} : n < m → succ n < succ m := succ_le_succ
|
||||
|
||||
theorem lt_succ_of_le {n m : Nat} : n ≤ m → n < succ m := succ_le_succ
|
||||
|
||||
theorem le_of_lt_add_one {n m : Nat} : n < m + 1 → n ≤ m := le_of_succ_le_succ
|
||||
|
||||
theorem lt_add_one_of_le {n m : Nat} : n ≤ m → n < m + 1 := succ_le_succ
|
||||
|
||||
@[simp] protected theorem sub_zero (n : Nat) : n - 0 = n := rfl
|
||||
|
||||
theorem not_add_one_le_zero (n : Nat) : ¬ n + 1 ≤ 0 := nofun
|
||||
|
||||
theorem not_add_one_le_self : (n : Nat) → ¬ n + 1 ≤ n := Nat.not_succ_le_self
|
||||
|
||||
theorem add_one_pos (n : Nat) : 0 < n + 1 := Nat.zero_lt_succ n
|
||||
|
||||
theorem succ_sub_succ_eq_sub (n m : Nat) : succ n - succ m = n - m := by
|
||||
induction m with
|
||||
| zero => exact rfl
|
||||
| succ m ih => apply congrArg pred ih
|
||||
|
||||
theorem pred_le : ∀ (n : Nat), pred n ≤ n
|
||||
@[simp] theorem pred_le : ∀ (n : Nat), pred n ≤ n
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
@@ -282,9 +271,7 @@ theorem pred_lt : ∀ {n : Nat}, n ≠ 0 → pred n < n
|
||||
| zero, h => absurd rfl h
|
||||
| succ _, _ => lt_succ_of_le (Nat.le_refl _)
|
||||
|
||||
theorem sub_one_lt : ∀ {n : Nat}, n ≠ 0 → n - 1 < n := pred_lt
|
||||
|
||||
@[simp] theorem sub_le (n m : Nat) : n - m ≤ n := by
|
||||
theorem sub_le (n m : Nat) : n - m ≤ n := by
|
||||
induction m with
|
||||
| zero => exact Nat.le_refl (n - 0)
|
||||
| succ m ih => apply Nat.le_trans (pred_le (n - m)) ih
|
||||
@@ -351,9 +338,7 @@ protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_po
|
||||
|
||||
theorem lt.base (n : Nat) : n < succ n := Nat.le_refl (succ n)
|
||||
|
||||
theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
|
||||
|
||||
@[simp] protected theorem lt_add_one (n : Nat) : n < n + 1 := lt.base n
|
||||
@[simp] theorem lt_succ_self (n : Nat) : n < succ n := lt.base n
|
||||
|
||||
protected theorem le_total (m n : Nat) : m ≤ n ∨ n ≤ m :=
|
||||
match Nat.lt_or_ge m n with
|
||||
@@ -385,9 +370,6 @@ theorem le_or_eq_of_le_succ {m n : Nat} (h : m ≤ succ n) : m ≤ n ∨ m = suc
|
||||
have : succ m ≤ succ n := succ_le_of_lt this
|
||||
Or.inl (le_of_succ_le_succ this))
|
||||
|
||||
theorem le_or_eq_of_le_add_one {m n : Nat} (h : m ≤ n + 1) : m ≤ n ∨ m = n + 1 :=
|
||||
le_or_eq_of_le_succ h
|
||||
|
||||
theorem le_add_right : ∀ (n k : Nat), n ≤ n + k
|
||||
| n, 0 => Nat.le_refl n
|
||||
| n, k+1 => le_succ_of_le (le_add_right n k)
|
||||
@@ -395,25 +377,12 @@ theorem le_add_right : ∀ (n k : Nat), n ≤ n + k
|
||||
theorem le_add_left (n m : Nat): n ≤ m + n :=
|
||||
Nat.add_comm n m ▸ le_add_right n m
|
||||
|
||||
theorem le_of_add_right_le {n m k : Nat} (h : n + k ≤ m) : n ≤ m :=
|
||||
Nat.le_trans (le_add_right n k) h
|
||||
|
||||
theorem le_add_right_of_le {n m k : Nat} (h : n ≤ m) : n ≤ m + k :=
|
||||
Nat.le_trans h (le_add_right m k)
|
||||
|
||||
theorem lt_of_add_one_le {n m : Nat} (h : n + 1 ≤ m) : n < m := h
|
||||
|
||||
theorem add_one_le_of_lt {n m : Nat} (h : n < m) : n + 1 ≤ m := h
|
||||
|
||||
protected theorem lt_add_left (c : Nat) (h : a < b) : a < c + b :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
|
||||
|
||||
protected theorem lt_add_right (c : Nat) (h : a < b) : a < b + c :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
|
||||
|
||||
theorem lt_of_add_right_lt {n m k : Nat} (h : n + k < m) : n < m :=
|
||||
Nat.lt_of_le_of_lt (Nat.le_add_right ..) h
|
||||
|
||||
theorem le.dest : ∀ {n m : Nat}, n ≤ m → Exists (fun k => n + k = m)
|
||||
| zero, zero, _ => ⟨0, rfl⟩
|
||||
| zero, succ n, _ => ⟨succ n, Nat.add_comm 0 (succ n) ▸ rfl⟩
|
||||
@@ -568,14 +537,9 @@ protected theorem le_iff_lt_or_eq {n m : Nat} : n ≤ m ↔ n < m ∨ n = m :=
|
||||
|
||||
protected theorem lt_succ_iff : m < succ n ↔ m ≤ n := ⟨le_of_lt_succ, lt_succ_of_le⟩
|
||||
|
||||
protected theorem lt_add_one_iff : m < n + 1 ↔ m ≤ n := ⟨le_of_lt_succ, lt_succ_of_le⟩
|
||||
|
||||
protected theorem lt_succ_iff_lt_or_eq : m < succ n ↔ m < n ∨ m = n :=
|
||||
Nat.lt_succ_iff.trans Nat.le_iff_lt_or_eq
|
||||
|
||||
protected theorem lt_add_one_iff_lt_or_eq : m < n + 1 ↔ m < n ∨ m = n :=
|
||||
Nat.lt_add_one_iff.trans Nat.le_iff_lt_or_eq
|
||||
|
||||
protected theorem eq_of_lt_succ_of_not_lt (hmn : m < n + 1) (h : ¬ m < n) : m = n :=
|
||||
(Nat.lt_succ_iff_lt_or_eq.1 hmn).resolve_left h
|
||||
|
||||
@@ -607,18 +571,12 @@ attribute [simp] zero_lt_succ
|
||||
|
||||
theorem succ_ne_self (n) : succ n ≠ n := Nat.ne_of_gt (lt_succ_self n)
|
||||
|
||||
theorem add_one_ne_self (n) : n + 1 ≠ n := Nat.ne_of_gt (lt_succ_self n)
|
||||
|
||||
theorem succ_le : succ n ≤ m ↔ n < m := .rfl
|
||||
|
||||
theorem add_one_le_iff : n + 1 ≤ m ↔ n < m := .rfl
|
||||
|
||||
theorem lt_succ : m < succ n ↔ m ≤ n := ⟨le_of_lt_succ, lt_succ_of_le⟩
|
||||
|
||||
theorem lt_succ_of_lt (h : a < b) : a < succ b := le_succ_of_le h
|
||||
|
||||
theorem lt_add_one_of_lt (h : a < b) : a < b + 1 := le_succ_of_le h
|
||||
|
||||
theorem succ_pred_eq_of_ne_zero : ∀ {n}, n ≠ 0 → succ (pred n) = n
|
||||
| _+1, _ => rfl
|
||||
|
||||
@@ -632,25 +590,12 @@ theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := ⟨le_of_succ_le_suc
|
||||
|
||||
theorem succ_lt_succ_iff : succ a < succ b ↔ a < b := ⟨lt_of_succ_lt_succ, succ_lt_succ⟩
|
||||
|
||||
theorem add_one_inj : a + 1 = b + 1 ↔ a = b := succ_inj'
|
||||
|
||||
theorem ne_add_one (n : Nat) : n ≠ n + 1 := fun h => by cases h
|
||||
|
||||
theorem add_one_ne (n : Nat) : n + 1 ≠ n := fun h => by cases h
|
||||
|
||||
theorem add_one_le_add_one_iff : a + 1 ≤ b + 1 ↔ a ≤ b := succ_le_succ_iff
|
||||
|
||||
theorem add_one_lt_add_one_iff : a + 1 < b + 1 ↔ a < b := succ_lt_succ_iff
|
||||
|
||||
theorem pred_inj : ∀ {a b}, 0 < a → 0 < b → pred a = pred b → a = b
|
||||
| _+1, _+1, _, _ => congrArg _
|
||||
|
||||
theorem pred_ne_self : ∀ {a}, a ≠ 0 → pred a ≠ a
|
||||
| _+1, _ => (succ_ne_self _).symm
|
||||
|
||||
theorem sub_one_ne_self : ∀ {a}, a ≠ 0 → a - 1 ≠ a
|
||||
| _+1, _ => (succ_ne_self _).symm
|
||||
|
||||
theorem pred_lt_self : ∀ {a}, 0 < a → pred a < a
|
||||
| _+1, _ => lt_succ_self _
|
||||
|
||||
@@ -683,17 +628,9 @@ theorem le_sub_one_of_lt : a < b → a ≤ b - 1 := Nat.le_pred_of_lt
|
||||
|
||||
theorem lt_of_le_pred (h : 0 < m) : n ≤ pred m → n < m := (le_pred_iff_lt h).1
|
||||
|
||||
theorem lt_of_le_sub_one (h : 0 < m) : n ≤ m - 1 → n < m := (le_pred_iff_lt h).1
|
||||
|
||||
protected theorem le_sub_one_iff_lt (h : 0 < m) : n ≤ m - 1 ↔ n < m :=
|
||||
⟨Nat.lt_of_le_sub_one h, Nat.le_sub_one_of_lt⟩
|
||||
|
||||
theorem exists_eq_succ_of_ne_zero : ∀ {n}, n ≠ 0 → Exists fun k => n = succ k
|
||||
| _+1, _ => ⟨_, rfl⟩
|
||||
|
||||
theorem exists_eq_add_one_of_ne_zero : ∀ {n}, n ≠ 0 → Exists fun k => n = k + 1
|
||||
| _+1, _ => ⟨_, rfl⟩
|
||||
|
||||
/-! # Basic theorems for comparing numerals -/
|
||||
|
||||
theorem ctor_eq_zero : Nat.zero = 0 :=
|
||||
@@ -705,7 +642,8 @@ protected theorem one_ne_zero : 1 ≠ (0 : Nat) :=
|
||||
protected theorem zero_ne_one : 0 ≠ (1 : Nat) :=
|
||||
fun h => Nat.noConfusion h
|
||||
|
||||
theorem succ_ne_zero (n : Nat) : succ n ≠ 0 := by simp
|
||||
@[simp] theorem succ_ne_zero (n : Nat) : succ n ≠ 0 :=
|
||||
fun h => Nat.noConfusion h
|
||||
|
||||
/-! # mul + order -/
|
||||
|
||||
@@ -748,9 +686,6 @@ theorem eq_of_mul_eq_mul_right {n m k : Nat} (hm : 0 < m) (h : n * m = k * m) :
|
||||
protected theorem pow_succ (n m : Nat) : n^(succ m) = n^m * n :=
|
||||
rfl
|
||||
|
||||
protected theorem pow_add_one (n m : Nat) : n^(m + 1) = n^m * n :=
|
||||
rfl
|
||||
|
||||
protected theorem pow_zero (n : Nat) : n^0 = 1 := rfl
|
||||
|
||||
theorem pow_le_pow_of_le_left {n m : Nat} (h : n ≤ m) : ∀ (i : Nat), n^i ≤ m^i
|
||||
@@ -802,46 +737,25 @@ theorem not_eq_zero_of_lt (h : b < a) : a ≠ 0 := by
|
||||
exact absurd h (Nat.not_lt_zero _)
|
||||
apply Nat.noConfusion
|
||||
|
||||
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
|
||||
theorem pred_lt' {n m : Nat} (h : m < n) : pred n < n :=
|
||||
pred_lt (not_eq_zero_of_lt h)
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
|
||||
|
||||
theorem sub_one_lt_of_lt {n m : Nat} (h : m < n) : n - 1 < n :=
|
||||
sub_one_lt (not_eq_zero_of_lt h)
|
||||
|
||||
/-! # pred theorems -/
|
||||
|
||||
protected theorem pred_zero : pred 0 = 0 := rfl
|
||||
protected theorem pred_succ (n : Nat) : pred n.succ = n := rfl
|
||||
|
||||
@[simp] protected theorem zero_sub_one : 0 - 1 = 0 := rfl
|
||||
@[simp] protected theorem add_one_sub_one (n : Nat) : n + 1 - 1 = n := rfl
|
||||
|
||||
theorem sub_one_eq_self (n : Nat) : n - 1 = n ↔ n = 0 := by cases n <;> simp [ne_add_one]
|
||||
theorem eq_self_sub_one (n : Nat) : n = n - 1 ↔ n = 0 := by cases n <;> simp [add_one_ne]
|
||||
@[simp] protected theorem pred_zero : pred 0 = 0 := rfl
|
||||
@[simp] protected theorem pred_succ (n : Nat) : pred n.succ = n := rfl
|
||||
|
||||
theorem succ_pred {a : Nat} (h : a ≠ 0) : a.pred.succ = a := by
|
||||
induction a with
|
||||
| zero => contradiction
|
||||
| succ => rfl
|
||||
|
||||
theorem sub_one_add_one {a : Nat} (h : a ≠ 0) : a - 1 + 1 = a := by
|
||||
induction a with
|
||||
| zero => contradiction
|
||||
| succ => rfl
|
||||
|
||||
theorem succ_pred_eq_of_pos : ∀ {n}, 0 < n → succ (pred n) = n
|
||||
| _+1, _ => rfl
|
||||
|
||||
theorem sub_one_add_one_eq_of_pos : ∀ {n}, 0 < n → (n - 1) + 1 = n
|
||||
| _+1, _ => rfl
|
||||
|
||||
theorem eq_zero_or_eq_sub_one_add_one : ∀ {n}, n = 0 ∨ n = n - 1 + 1
|
||||
| 0 => Or.inl rfl
|
||||
| _+1 => Or.inr rfl
|
||||
|
||||
@[simp] theorem pred_eq_sub_one : pred n = n - 1 := rfl
|
||||
|
||||
/-! # sub theorems -/
|
||||
@@ -892,9 +806,6 @@ theorem add_sub_of_le {a b : Nat} (h : a ≤ b) : a + (b - a) = b := by
|
||||
have : a ≤ b := Nat.le_of_succ_le h
|
||||
rw [sub_succ, Nat.succ_add, ← Nat.add_succ, Nat.succ_pred hne, ih this]
|
||||
|
||||
theorem sub_one_cancel : ∀ {a b : Nat}, 0 < a → 0 < b → a - 1 = b - 1 → a = b
|
||||
| _+1, _+1, _, _ => congrArg _
|
||||
|
||||
@[simp] protected theorem sub_add_cancel {n m : Nat} (h : m ≤ n) : n - m + m = n := by
|
||||
rw [Nat.add_comm, Nat.add_sub_of_le h]
|
||||
|
||||
@@ -946,17 +857,6 @@ protected theorem sub_lt_sub_left : ∀ {k m n : Nat}, k < m → k < n → m - n
|
||||
| zero => rfl
|
||||
| succ n ih => simp only [ih, Nat.sub_succ]; decide
|
||||
|
||||
protected theorem sub_lt_sub_right : ∀ {a b c : Nat}, c ≤ a → a < b → a - c < b - c
|
||||
| 0, _, _, hle, h => by
|
||||
rw [Nat.eq_zero_of_le_zero hle, Nat.sub_zero, Nat.sub_zero]
|
||||
exact h
|
||||
| _, _, 0, _, h => by
|
||||
rw [Nat.sub_zero, Nat.sub_zero]
|
||||
exact h
|
||||
| _+1, _+1, _+1, hle, h => by
|
||||
rw [Nat.add_sub_add_right, Nat.add_sub_add_right]
|
||||
exact Nat.sub_lt_sub_right (le_of_succ_le_succ hle) (lt_of_succ_lt_succ h)
|
||||
|
||||
protected theorem sub_self_add (n m : Nat) : n - (n + m) = 0 := by
|
||||
show (n + 0) - (n + m) = 0
|
||||
rw [Nat.add_sub_add_left, Nat.zero_sub]
|
||||
@@ -1035,9 +935,6 @@ protected theorem sub_le_sub_right {n m : Nat} (h : n ≤ m) : ∀ k, n - k ≤
|
||||
| 0 => h
|
||||
| z+1 => pred_le_pred (Nat.sub_le_sub_right h z)
|
||||
|
||||
protected theorem sub_le_add_right_sub (a i j : Nat) : a - i ≤ a + j - i :=
|
||||
Nat.sub_le_sub_right (Nat.le_add_right ..) ..
|
||||
|
||||
protected theorem lt_of_sub_ne_zero (h : n - m ≠ 0) : m < n :=
|
||||
Nat.not_le.1 (mt Nat.sub_eq_zero_of_le h)
|
||||
|
||||
@@ -1050,9 +947,6 @@ protected theorem lt_of_sub_pos (h : 0 < n - m) : m < n :=
|
||||
protected theorem lt_of_sub_eq_succ (h : m - n = succ l) : n < m :=
|
||||
Nat.lt_of_sub_pos (h ▸ Nat.zero_lt_succ _)
|
||||
|
||||
protected theorem lt_of_sub_eq_sub_one (h : m - n = l + 1) : n < m :=
|
||||
Nat.lt_of_sub_pos (h ▸ Nat.zero_lt_succ _)
|
||||
|
||||
protected theorem sub_lt_left_of_lt_add {n k m : Nat} (H : n ≤ k) (h : k < n + m) : k - n < m := by
|
||||
have := Nat.sub_le_sub_right (succ_le_of_lt h) n
|
||||
rwa [Nat.add_sub_cancel_left, Nat.succ_sub H] at this
|
||||
@@ -1080,35 +974,21 @@ protected theorem sub_eq_iff_eq_add {c : Nat} (h : b ≤ a) : a - b = c ↔ a =
|
||||
protected theorem sub_eq_iff_eq_add' {c : Nat} (h : b ≤ a) : a - b = c ↔ a = b + c := by
|
||||
rw [Nat.add_comm, Nat.sub_eq_iff_eq_add h]
|
||||
|
||||
/-! ## Mul sub distrib -/
|
||||
|
||||
theorem pred_mul (n m : Nat) : pred n * m = n * m - m := by
|
||||
theorem mul_pred_left (n m : Nat) : pred n * m = n * m - m := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n => rw [Nat.pred_succ, succ_mul, Nat.add_sub_cancel]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
|
||||
/-! ## Mul sub distrib -/
|
||||
|
||||
protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
rw [Nat.add_sub_cancel, add_one_mul, Nat.add_sub_cancel]
|
||||
theorem mul_pred_right (n m : Nat) : n * pred m = n * m - n := by
|
||||
rw [Nat.mul_comm, mul_pred_left, Nat.mul_comm]
|
||||
|
||||
theorem mul_pred (n m : Nat) : n * pred m = n * m - n := by
|
||||
rw [Nat.mul_comm, pred_mul, Nat.mul_comm]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
|
||||
|
||||
theorem mul_sub_one (n m : Nat) : n * (m - 1) = n * m - n := by
|
||||
rw [Nat.mul_comm, Nat.sub_one_mul , Nat.mul_comm]
|
||||
|
||||
protected theorem mul_sub_right_distrib (n m k : Nat) : (n - m) * k = n * k - m * k := by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => rw [Nat.sub_succ, Nat.pred_mul, ih, succ_mul, Nat.sub_sub]; done
|
||||
| succ m ih => rw [Nat.sub_succ, Nat.mul_pred_left, ih, succ_mul, Nat.sub_sub]; done
|
||||
|
||||
protected theorem mul_sub_left_distrib (n m k : Nat) : n * (m - k) = n * m - n * k := by
|
||||
rw [Nat.mul_comm, Nat.mul_sub_right_distrib, Nat.mul_comm m n, Nat.mul_comm n k]
|
||||
|
||||
@@ -86,11 +86,7 @@ noncomputable def div2Induction {motive : Nat → Sort u}
|
||||
@[simp] theorem testBit_zero (x : Nat) : testBit x 0 = decide (x % 2 = 1) := by
|
||||
cases mod_two_eq_zero_or_one x with | _ p => simp [testBit, p]
|
||||
|
||||
theorem testBit_succ (x i : Nat) : testBit x (succ i) = testBit (x/2) i := by
|
||||
unfold testBit
|
||||
simp [shiftRight_succ_inside]
|
||||
|
||||
@[simp] theorem testBit_add_one (x i : Nat) : testBit x (i + 1) = testBit (x/2) i := by
|
||||
@[simp] theorem testBit_succ (x i : Nat) : testBit x (succ i) = testBit (x/2) i := by
|
||||
unfold testBit
|
||||
simp [shiftRight_succ_inside]
|
||||
|
||||
@@ -310,11 +306,6 @@ theorem testBit_bool_to_nat (b : Bool) (i : Nat) :
|
||||
←Nat.div_div_eq_div_mul _ 2, one_div_two,
|
||||
Nat.mod_eq_of_lt]
|
||||
|
||||
/-- `testBit 1 i` is true iff the index `i` equals 0. -/
|
||||
theorem testBit_one_eq_true_iff_self_eq_zero {i : Nat} :
|
||||
Nat.testBit 1 i = true ↔ i = 0 := by
|
||||
cases i <;> simp
|
||||
|
||||
/-! ### bitwise -/
|
||||
|
||||
theorem testBit_bitwise
|
||||
@@ -504,27 +495,3 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
|
||||
|
||||
@[simp] theorem testBit_shiftRight (x : Nat) : testBit (x >>> i) j = testBit x (i+j) := by
|
||||
simp [testBit, ←shiftRight_add]
|
||||
|
||||
/-! ### le -/
|
||||
|
||||
theorem le_of_testBit {n m : Nat} (h : ∀ i, n.testBit i = true → m.testBit i = true) : n ≤ m := by
|
||||
induction n using div2Induction generalizing m
|
||||
next n ih =>
|
||||
have : n / 2 ≤ m / 2 := by
|
||||
rcases n with (_|n)
|
||||
· simp
|
||||
· exact ih (Nat.succ_pos _) fun i => by simpa using h (i + 1)
|
||||
rw [← div_add_mod n 2, ← div_add_mod m 2]
|
||||
cases hn : n.testBit 0
|
||||
· have hn2 : n % 2 = 0 := by simp at hn; omega
|
||||
rw [hn2]
|
||||
omega
|
||||
· have hn2 : n % 2 = 1 := by simpa using hn
|
||||
have hm2 : m % 2 = 1 := by simpa using h _ hn
|
||||
omega
|
||||
|
||||
theorem and_le_left {n m : Nat} : n &&& m ≤ n :=
|
||||
le_of_testBit (by simpa using fun i x _ => x)
|
||||
|
||||
theorem and_le_right {n m : Nat} : n &&& m ≤ m :=
|
||||
le_of_testBit (by simp)
|
||||
|
||||
@@ -251,10 +251,10 @@ theorem div_mul_le_self : ∀ (m n : Nat), m / n * n ≤ m
|
||||
theorem div_lt_iff_lt_mul (Hk : 0 < k) : x / k < y ↔ x < y * k := by
|
||||
rw [← Nat.not_le, ← Nat.not_le]; exact not_congr (le_div_iff_mul_le Hk)
|
||||
|
||||
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = (x / z) + 1 := by
|
||||
@[simp] theorem add_div_right (x : Nat) {z : Nat} (H : 0 < z) : (x + z) / z = succ (x / z) := by
|
||||
rw [div_eq_sub_div H (Nat.le_add_left _ _), Nat.add_sub_cancel]
|
||||
|
||||
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = (x / z) + 1 := by
|
||||
@[simp] theorem add_div_left (x : Nat) {z : Nat} (H : 0 < z) : (z + x) / z = succ (x / z) := by
|
||||
rw [Nat.add_comm, add_div_right x H]
|
||||
|
||||
theorem add_mul_div_left (x z : Nat) {y : Nat} (H : 0 < y) : (x + y * z) / y = x / y + z := by
|
||||
@@ -285,7 +285,7 @@ theorem add_mul_div_right (x y : Nat) {z : Nat} (H : 0 < z) : (x + y * z) / z =
|
||||
@[simp] theorem mul_mod_left (m n : Nat) : (m * n) % n = 0 := by
|
||||
rw [Nat.mul_comm, mul_mod_right]
|
||||
|
||||
protected theorem div_eq_of_lt_le (lo : k * n ≤ m) (hi : m < (k + 1) * n) : m / n = k :=
|
||||
protected theorem div_eq_of_lt_le (lo : k * n ≤ m) (hi : m < succ k * n) : m / n = k :=
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun hn => by
|
||||
rw [hn, Nat.mul_zero] at hi lo; exact absurd lo (Nat.not_le_of_gt hi)
|
||||
Nat.le_antisymm
|
||||
@@ -307,7 +307,7 @@ theorem sub_mul_div (x n p : Nat) (h₁ : n*p ≤ x) : (x - n*p) / n = x / n - p
|
||||
rw [sub_succ, ← IH h₂, div_eq_sub_div h₀ h₃]
|
||||
simp [Nat.pred_succ, mul_succ, Nat.sub_sub]
|
||||
|
||||
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - (x + 1)) / n = p - ((x / n) + 1) := by
|
||||
theorem mul_sub_div (x n p : Nat) (h₁ : x < n*p) : (n * p - succ x) / n = p - succ (x / n) := by
|
||||
have npos : 0 < n := (eq_zero_or_pos _).resolve_left fun n0 => by
|
||||
rw [n0, Nat.zero_mul] at h₁; exact not_lt_zero _ h₁
|
||||
apply Nat.div_eq_of_lt_le
|
||||
|
||||
@@ -43,9 +43,6 @@ def gcd (m n : @& Nat) : Nat :=
|
||||
theorem gcd_succ (x y : Nat) : gcd (succ x) y = gcd (y % succ x) (succ x) := by
|
||||
rw [gcd]; rfl
|
||||
|
||||
theorem gcd_add_one (x y : Nat) : gcd (x + 1) y = gcd (y % (x + 1)) (x + 1) := by
|
||||
rw [gcd]; rfl
|
||||
|
||||
@[simp] theorem gcd_one_left (n : Nat) : gcd 1 n = 1 := by
|
||||
rw [gcd_succ, mod_one]
|
||||
rfl
|
||||
|
||||
@@ -101,10 +101,6 @@ protected theorem one_sub : ∀ n, 1 - n = if n = 0 then 1 else 0
|
||||
theorem succ_sub_sub_succ (n m k) : succ n - m - succ k = n - m - k := by
|
||||
rw [Nat.sub_sub, Nat.sub_sub, add_succ, succ_sub_succ]
|
||||
|
||||
theorem add_sub_sub_add_right (n m k l : Nat) :
|
||||
(n + l) - m - (k + l) = n - m - k := by
|
||||
rw [Nat.sub_sub, Nat.sub_sub, ←Nat.add_assoc, Nat.add_sub_add_right]
|
||||
|
||||
protected theorem sub_right_comm (m n k : Nat) : m - n - k = m - k - n := by
|
||||
rw [Nat.sub_sub, Nat.sub_sub, Nat.add_comm]
|
||||
|
||||
@@ -115,6 +111,8 @@ protected theorem add_sub_cancel_right (n m : Nat) : (n + m) - m = n := Nat.add_
|
||||
|
||||
theorem succ_sub_one (n) : succ n - 1 = n := rfl
|
||||
|
||||
protected theorem add_one_sub_one (n : Nat) : (n + 1) - 1 = n := rfl
|
||||
|
||||
protected theorem one_add_sub_one (n : Nat) : (1 + n) - 1 = n := Nat.add_sub_cancel_left 1 _
|
||||
|
||||
protected theorem sub_sub_self {n m : Nat} (h : m ≤ n) : n - (n - m) = m :=
|
||||
@@ -178,12 +176,10 @@ protected theorem sub_add_lt_sub (h₁ : m + k ≤ n) (h₂ : 0 < k) : n - (m +
|
||||
rw [← Nat.sub_sub]; exact Nat.sub_lt_of_pos_le h₂ (Nat.le_sub_of_add_le' h₁)
|
||||
|
||||
theorem sub_one_lt_of_le (h₀ : 0 < a) (h₁ : a ≤ b) : a - 1 < b :=
|
||||
Nat.lt_of_lt_of_le (Nat.pred_lt_of_lt h₀) h₁
|
||||
Nat.lt_of_lt_of_le (Nat.pred_lt' h₀) h₁
|
||||
|
||||
theorem sub_lt_succ (a b) : a - b < succ a := lt_succ_of_le (sub_le a b)
|
||||
|
||||
theorem sub_lt_add_one (a b) : a - b < a + 1 := lt_add_one_of_le (sub_le a b)
|
||||
|
||||
theorem sub_one_sub_lt (h : i < n) : n - 1 - i < n := by
|
||||
rw [Nat.sub_right_comm]; exact Nat.sub_one_lt_of_le (Nat.sub_pos_of_lt h) (Nat.sub_le ..)
|
||||
|
||||
@@ -210,19 +206,13 @@ instance : Std.IdempotentOp (α := Nat) min := ⟨Nat.min_self⟩
|
||||
|
||||
@[simp] protected theorem min_zero (a) : min a 0 = 0 := Nat.min_eq_right (Nat.zero_le _)
|
||||
|
||||
@[simp] protected theorem min_assoc : ∀ (a b c : Nat), min (min a b) c = min a (min b c)
|
||||
protected theorem min_assoc : ∀ (a b c : Nat), min (min a b) c = min a (min b c)
|
||||
| 0, _, _ => by rw [Nat.zero_min, Nat.zero_min, Nat.zero_min]
|
||||
| _, 0, _ => by rw [Nat.zero_min, Nat.min_zero, Nat.zero_min]
|
||||
| _, _, 0 => by rw [Nat.min_zero, Nat.min_zero, Nat.min_zero]
|
||||
| _+1, _+1, _+1 => by simp only [Nat.succ_min_succ]; exact congrArg succ <| Nat.min_assoc ..
|
||||
instance : Std.Associative (α := Nat) min := ⟨Nat.min_assoc⟩
|
||||
|
||||
@[simp] protected theorem min_self_assoc {m n : Nat} : min m (min m n) = min m n := by
|
||||
rw [← Nat.min_assoc, Nat.min_self]
|
||||
|
||||
@[simp] protected theorem min_self_assoc' {m n : Nat} : min n (min m n) = min n m := by
|
||||
rw [Nat.min_comm m n, ← Nat.min_assoc, Nat.min_self]
|
||||
|
||||
protected theorem sub_sub_eq_min : ∀ (a b : Nat), a - (a - b) = min a b
|
||||
| 0, _ => by rw [Nat.zero_sub, Nat.zero_min]
|
||||
| _, 0 => by rw [Nat.sub_zero, Nat.sub_self, Nat.min_zero]
|
||||
@@ -489,9 +479,6 @@ protected theorem mul_lt_mul_of_lt_of_lt {a b c d : Nat} (hac : a < c) (hbd : b
|
||||
theorem succ_mul_succ (a b) : succ a * succ b = a * b + a + b + 1 := by
|
||||
rw [succ_mul, mul_succ]; rfl
|
||||
|
||||
theorem add_one_mul_add_one (a b : Nat) : (a + 1) * (b + 1) = a * b + a + b + 1 := by
|
||||
rw [add_one_mul, mul_add_one]; rfl
|
||||
|
||||
theorem mul_le_add_right (m k n : Nat) : k * m ≤ m + n ↔ (k-1) * m ≤ n := by
|
||||
match k with
|
||||
| 0 =>
|
||||
@@ -575,9 +562,6 @@ theorem add_mod (a b n : Nat) : (a + b) % n = ((a % n) + (b % n)) % n := by
|
||||
theorem pow_succ' {m n : Nat} : m ^ n.succ = m * m ^ n := by
|
||||
rw [Nat.pow_succ, Nat.mul_comm]
|
||||
|
||||
theorem pow_add_one' {m n : Nat} : m ^ (n + 1) = m * m ^ n := by
|
||||
rw [Nat.pow_add_one, Nat.mul_comm]
|
||||
|
||||
@[simp] theorem pow_eq {m n : Nat} : m.pow n = m ^ n := rfl
|
||||
|
||||
theorem one_shiftLeft (n : Nat) : 1 <<< n = 2 ^ n := by rw [shiftLeft_eq, Nat.one_mul]
|
||||
|
||||
@@ -583,6 +583,8 @@ theorem PolyCnstr.denote_mul (ctx : Context) (k : Nat) (c : PolyCnstr) : (c.mul
|
||||
have : k ≠ 0 → k + 1 ≠ 1 := by intro h; match k with | 0 => contradiction | k+1 => simp [Nat.succ.injEq]
|
||||
have : ¬ (k == 0) → (k + 1 == 1) = false := fun h => beq_false_of_ne (this (ne_of_beq_false (Bool.of_not_eq_true h)))
|
||||
have : ¬ ((k + 1 == 0) = true) := fun h => absurd (eq_of_beq h) (Nat.succ_ne_zero k)
|
||||
have : (1 == (0 : Nat)) = false := rfl
|
||||
have : (1 == (1 : Nat)) = true := rfl
|
||||
by_cases he : eq = true <;> simp [he, PolyCnstr.mul, PolyCnstr.denote, Poly.denote_le, Poly.denote_eq]
|
||||
<;> by_cases hk : k == 0 <;> (try simp [eq_of_beq hk]) <;> simp [*] <;> apply Iff.intro <;> intro h
|
||||
· exact Nat.eq_of_mul_eq_mul_left (Nat.zero_lt_succ _) h
|
||||
|
||||
@@ -19,7 +19,6 @@ def getM [Alternative m] : Option α → m α
|
||||
| some a => pure a
|
||||
|
||||
@[deprecated getM (since := "2024-04-17")]
|
||||
-- `[Monad m]` is not needed here.
|
||||
def toMonad [Monad m] [Alternative m] : Option α → m α := getM
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@@ -27,7 +26,7 @@ def toMonad [Monad m] [Alternative m] : Option α → m α := getM
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[deprecated isSome (since := "2024-04-17"), inline] def toBool : Option α → Bool := isSome
|
||||
@[deprecated isSome, inline] def toBool : Option α → Bool := isSome
|
||||
|
||||
/-- Returns `true` on `none` and `false` on `some x`. -/
|
||||
@[inline] def isNone : Option α → Bool
|
||||
@@ -81,9 +80,7 @@ theorem map_id : (Option.map id : Option α → Option α) = id :=
|
||||
| none => false
|
||||
|
||||
/--
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
|
||||
`some a`, otherwise evaluates and returns the second argument. See also `or` for a version that is
|
||||
strict in the second argument.
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`.
|
||||
-/
|
||||
@[always_inline, macro_inline] protected def orElse : Option α → (Unit → Option α) → Option α
|
||||
| some a, _ => some a
|
||||
@@ -92,12 +89,6 @@ strict in the second argument.
|
||||
instance : OrElse (Option α) where
|
||||
orElse := Option.orElse
|
||||
|
||||
/-- If the first argument is `some a`, returns `some a`, otherwise returns the second argument.
|
||||
This is similar to `<|>`/`orElse`, but it is strict in the second argument. -/
|
||||
@[always_inline, macro_inline] def or : Option α → Option α → Option α
|
||||
| some a, _ => some a
|
||||
| none, b => b
|
||||
|
||||
@[inline] protected def lt (r : α → α → Prop) : Option α → Option α → Prop
|
||||
| none, some _ => True
|
||||
| some x, some y => r x y
|
||||
@@ -128,7 +119,7 @@ def merge (fn : α → α → α) : Option α → Option α → Option α
|
||||
|
||||
|
||||
/-- An elimination principle for `Option`. It is a nondependent version of `Option.recOn`. -/
|
||||
@[inline] protected def elim : Option α → β → (α → β) → β
|
||||
@[simp, inline] protected def elim : Option α → β → (α → β) → β
|
||||
| some x, _, f => f x
|
||||
| none, y, _ => y
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ instance : Membership α (Option α) := ⟨fun a b => b = some a⟩
|
||||
instance [DecidableEq α] (j : α) (o : Option α) : Decidable (j ∈ o) :=
|
||||
inferInstanceAs <| Decidable (o = some j)
|
||||
|
||||
@[simp] theorem isNone_iff_eq_none {o : Option α} : o.isNone ↔ o = none :=
|
||||
theorem isNone_iff_eq_none {o : Option α} : o.isNone ↔ o = none :=
|
||||
⟨Option.eq_none_of_isNone, fun e => e.symm ▸ rfl⟩
|
||||
|
||||
theorem some_inj {a b : α} : some a = some b ↔ a = b := by simp; rfl
|
||||
|
||||
@@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Option.BasicAux
|
||||
import Init.Data.Option.Instances
|
||||
import Init.Classical
|
||||
import Init.Ext
|
||||
@@ -42,21 +41,6 @@ theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.get
|
||||
theorem getD_eq_iff {o : Option α} {a b} : o.getD a = b ↔ (o = some b ∨ o = none ∧ a = b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem get!_none [Inhabited α] : (none : Option α).get! = default := rfl
|
||||
|
||||
@[simp] theorem get!_some [Inhabited α] {a : α} : (some a).get! = a := rfl
|
||||
|
||||
theorem get_eq_get! [Inhabited α] : (o : Option α) → {h : o.isSome} → o.get h = o.get!
|
||||
| some _, _ => rfl
|
||||
|
||||
theorem get_eq_getD {fallback : α} : (o : Option α) → {h : o.isSome} → o.get h = o.getD fallback
|
||||
| some _, _ => rfl
|
||||
|
||||
theorem some_get! [Inhabited α] : (o : Option α) → o.isSome → some (o.get!) = o
|
||||
| some _, _ => rfl
|
||||
|
||||
theorem get!_eq_getD_default [Inhabited α] (o : Option α) : o.get! = o.getD default := rfl
|
||||
|
||||
theorem mem_unique {o : Option α} {a b : α} (ha : a ∈ o) (hb : b ∈ o) : a = b :=
|
||||
some.inj <| ha ▸ hb
|
||||
|
||||
@@ -82,7 +66,7 @@ theorem isSome_iff_exists : isSome x ↔ ∃ a, x = some a := by cases x <;> sim
|
||||
cases a <;> simp
|
||||
|
||||
theorem eq_some_iff_get_eq : o = some a ↔ ∃ h : o.isSome, o.get h = a := by
|
||||
cases o <;> simp
|
||||
cases o <;> simp; nofun
|
||||
|
||||
theorem eq_some_of_isSome : ∀ {o : Option α} (h : o.isSome), o = some (o.get h)
|
||||
| some _, _ => rfl
|
||||
@@ -161,12 +145,6 @@ theorem map_eq_some : f <$> x = some b ↔ ∃ a, x = some a ∧ f a = b := map_
|
||||
@[simp] theorem map_eq_none' : x.map f = none ↔ x = none := by
|
||||
cases x <;> simp only [map_none', map_some', eq_self_iff_true]
|
||||
|
||||
theorem isSome_map {x : Option α} : (f <$> x).isSome = x.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
@[simp] theorem isSome_map' {x : Option α} : (x.map f).isSome = x.isSome := by
|
||||
cases x <;> simp
|
||||
|
||||
theorem map_eq_none : f <$> x = none ↔ x = none := map_eq_none'
|
||||
|
||||
theorem map_eq_bind {x : Option α} : x.map f = x.bind (some ∘ f) := by
|
||||
@@ -190,9 +168,6 @@ theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘
|
||||
|
||||
theorem mem_map_of_mem (g : α → β) (h : a ∈ x) : g a ∈ Option.map g x := h.symm ▸ map_some' ..
|
||||
|
||||
@[simp] theorem filter_none (p : α → Bool) : none.filter p = none := rfl
|
||||
theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
|
||||
|
||||
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α → β} :
|
||||
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
|
||||
|
||||
@@ -233,9 +208,9 @@ theorem liftOrGet_eq_or_eq {f : α → α → α} (h : ∀ a b, f a b = a ∨ f
|
||||
@[simp] theorem liftOrGet_some_some {f} {a b : α} :
|
||||
liftOrGet f (some a) (some b) = f a b := rfl
|
||||
|
||||
@[simp] theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
theorem elim_none (x : β) (f : α → β) : none.elim x f = x := rfl
|
||||
|
||||
@[simp] theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
theorem elim_some (x : β) (f : α → β) (a : α) : (some a).elim x f = f a := rfl
|
||||
|
||||
@[simp] theorem getD_map (f : α → β) (x : α) (o : Option α) :
|
||||
(o.map f).getD (f x) = f (getD o x) := by cases o <;> rfl
|
||||
@@ -261,46 +236,3 @@ end
|
||||
@[simp] theorem toList_some (a : α) : (a : Option α).toList = [a] := rfl
|
||||
|
||||
@[simp] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
|
||||
|
||||
@[simp] theorem or_some : (some a).or o = some a := rfl
|
||||
@[simp] theorem none_or : none.or o = o := rfl
|
||||
|
||||
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem isSome_or : (or o o').isSome = (o.isSome || o'.isSome) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp] theorem or_eq_none : or o o' = none ↔ o = none ∧ o' = none := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem or_eq_some : or o o' = some a ↔ o = some a ∨ (o = none ∧ o' = some a) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
|
||||
cases o₁ <;> cases o₂ <;> rfl
|
||||
instance : Std.Associative (or (α := α)) := ⟨@or_assoc _⟩
|
||||
|
||||
@[simp]
|
||||
theorem or_none : or o none = o := by
|
||||
cases o <;> rfl
|
||||
instance : Std.LawfulIdentity (or (α := α)) none where
|
||||
left_id := @none_or _
|
||||
right_id := @or_none _
|
||||
|
||||
@[simp]
|
||||
theorem or_self : or o o = o := by
|
||||
cases o <;> rfl
|
||||
instance : Std.IdempotentOp (or (α := α)) := ⟨@or_self _⟩
|
||||
|
||||
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem map_or : f <$> or o o' = (f <$> o).or (f <$> o') := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem map_or' : (or o o').map f = (o.map f).or (o'.map f) := by
|
||||
cases o <;> rfl
|
||||
|
||||
@@ -230,7 +230,7 @@ protected def Int.repr : Int → String
|
||||
| negSucc m => "-" ++ Nat.repr (succ m)
|
||||
|
||||
instance : Repr Int where
|
||||
reprPrec i prec := if i < 0 then Repr.addAppParen i.repr prec else i.repr
|
||||
reprPrec i _ := i.repr
|
||||
|
||||
def hexDigitRepr (n : Nat) : String :=
|
||||
String.singleton <| Nat.digitChar n
|
||||
|
||||
@@ -305,20 +305,15 @@ def next' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Pos :=
|
||||
let c := get s p
|
||||
p + c
|
||||
|
||||
theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
repeat first | apply iteInduction (motive := (0 < ·)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size ≤ 4 := by
|
||||
repeat first | apply iteInduction (motive := (· ≤ 4)) <;> intros | decide
|
||||
|
||||
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
|
||||
theorem one_le_csize (c : Char) : 1 ≤ csize c := by
|
||||
repeat first | apply iteInduction (motive := (1 ≤ UInt32.toNat ·)) <;> intros | decide
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
|
||||
@[simp] theorem pos_add_char (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + c.utf8Size := rfl
|
||||
@[simp] theorem pos_add_char (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl
|
||||
|
||||
theorem lt_next (s : String) (i : Pos) : i.1 < (s.next i).1 :=
|
||||
Nat.add_lt_add_left (Char.utf8Size_pos _) _
|
||||
Nat.add_lt_add_left (one_le_csize _) _
|
||||
|
||||
theorem utf8PrevAux_lt_of_pos : ∀ (cs : List Char) (i p : Pos), p ≠ 0 →
|
||||
(utf8PrevAux cs i p).1 < p.1
|
||||
@@ -328,7 +323,7 @@ theorem utf8PrevAux_lt_of_pos : ∀ (cs : List Char) (i p : Pos), p ≠ 0 →
|
||||
| c::cs, i, p, h => by
|
||||
simp [utf8PrevAux]
|
||||
apply iteInduction (motive := (Pos.byteIdx · < _)) <;> intro h'
|
||||
next => exact h' ▸ Nat.add_lt_add_left (Char.utf8Size_pos _) _
|
||||
next => exact h' ▸ Nat.add_lt_add_left (one_le_csize _) _
|
||||
next => exact utf8PrevAux_lt_of_pos _ _ _ h
|
||||
|
||||
theorem prev_lt_of_pos (s : String) (i : Pos) (h : i ≠ 0) : (s.prev i).1 < i.1 := by
|
||||
@@ -481,7 +476,7 @@ decreasing_by
|
||||
focus
|
||||
rename_i i₀ j₀ _ eq h'
|
||||
rw [show (s.next i₀ - sep.next j₀).1 = (i₀ - j₀).1 by
|
||||
show (_ + Char.utf8Size _) - (_ + Char.utf8Size _) = _
|
||||
show (_ + csize _) - (_ + csize _) = _
|
||||
rw [(beq_iff_eq ..).1 eq, Nat.add_sub_add_right]; rfl]
|
||||
right; exact Nat.sub_lt_sub_left
|
||||
(Nat.lt_of_le_of_lt (Nat.le_add_right ..) (Nat.gt_of_not_le (mt decide_eq_true h')))
|
||||
@@ -729,18 +724,18 @@ theorem set_next_add (s : String) (i : Pos) (c : Char) (b₁ b₂)
|
||||
simp [next, get, set, endPos, utf8ByteSize] at h ⊢
|
||||
rw [Nat.add_comm i.1, Nat.add_assoc] at h ⊢
|
||||
let rec foo : ∀ cs a b₁ b₂,
|
||||
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize.go cs + b₂ →
|
||||
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
|
||||
csize (utf8GetAux cs a i) + b₁ = utf8ByteSize.go cs + b₂ →
|
||||
csize (utf8GetAux (utf8SetAux c cs a i) a i) + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
|
||||
| [], _, _, _, h => h
|
||||
| c'::cs, a, b₁, b₂, h => by
|
||||
unfold utf8SetAux
|
||||
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize.go p + b₂) <;>
|
||||
apply iteInduction (motive := fun p => csize (utf8GetAux p a i) + b₁ = utf8ByteSize.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize.go] at h ⊢
|
||||
next =>
|
||||
rw [Nat.add_assoc, Nat.add_left_comm] at h ⊢; rw [Nat.add_left_cancel h]
|
||||
next =>
|
||||
rw [Nat.add_assoc] at h ⊢
|
||||
refine foo cs (a + c') b₁ (c'.utf8Size + b₂) h
|
||||
refine foo cs (a + c') b₁ (csize c' + b₂) h
|
||||
exact foo s.1 0 _ _ h
|
||||
|
||||
theorem mapAux_lemma (s : String) (i : Pos) (c : Char) (h : ¬s.atEnd i) :
|
||||
@@ -793,7 +788,7 @@ where
|
||||
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)
|
||||
have := Nat.sub_lt_sub_left _h (Nat.add_lt_add_left (one_le_csize c₁) off1.1)
|
||||
decreasing_tactic
|
||||
|
||||
/-- Return true iff `p` is a prefix of `s` -/
|
||||
@@ -1141,14 +1136,14 @@ theorem add_eq (p₁ p₂ : Pos) : p₁ + p₂ = ⟨p₁.byteIdx + p₂.byteIdx
|
||||
|
||||
theorem sub_eq (p₁ p₂ : Pos) : p₁ - p₂ = ⟨p₁.byteIdx - p₂.byteIdx⟩ := rfl
|
||||
|
||||
@[simp] theorem addChar_byteIdx (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + c.utf8Size := rfl
|
||||
@[simp] theorem addChar_byteIdx (p : Pos) (c : Char) : (p + c).byteIdx = p.byteIdx + csize c := rfl
|
||||
|
||||
theorem addChar_eq (p : Pos) (c : Char) : p + c = ⟨p.byteIdx + c.utf8Size⟩ := rfl
|
||||
theorem addChar_eq (p : Pos) (c : Char) : p + c = ⟨p.byteIdx + csize c⟩ := rfl
|
||||
|
||||
theorem zero_addChar_byteIdx (c : Char) : ((0 : Pos) + c).byteIdx = c.utf8Size := by
|
||||
theorem zero_addChar_byteIdx (c : Char) : ((0 : Pos) + c).byteIdx = csize c := by
|
||||
simp only [addChar_byteIdx, byteIdx_zero, Nat.zero_add]
|
||||
|
||||
theorem zero_addChar_eq (c : Char) : (0 : Pos) + c = ⟨c.utf8Size⟩ := by rw [← zero_addChar_byteIdx]
|
||||
theorem zero_addChar_eq (c : Char) : (0 : Pos) + c = ⟨csize c⟩ := by rw [← zero_addChar_byteIdx]
|
||||
|
||||
theorem addChar_right_comm (p : Pos) (c₁ c₂ : Char) : p + c₁ + c₂ = p + c₂ + c₁ := by
|
||||
apply ext
|
||||
|
||||
@@ -63,23 +63,23 @@ where
|
||||
loop (i : Nat) : Option Unit := do
|
||||
if i < a.size then
|
||||
let c ← utf8DecodeChar? a i
|
||||
loop (i + c.utf8Size)
|
||||
loop (i + csize c)
|
||||
else pure ()
|
||||
termination_by a.size - i
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right c.utf8Size_pos)
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right (one_le_csize c))
|
||||
|
||||
/-- Converts a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`. -/
|
||||
@[extern "lean_string_from_utf8_unchecked"]
|
||||
@[extern "lean_string_from_utf8"]
|
||||
def fromUTF8 (a : @& ByteArray) (h : validateUTF8 a) : String :=
|
||||
loop 0 ""
|
||||
where
|
||||
loop (i : Nat) (acc : String) : String :=
|
||||
if i < a.size then
|
||||
let c := (utf8DecodeChar? a i).getD default
|
||||
loop (i + c.utf8Size) (acc.push c)
|
||||
loop (i + csize c) (acc.push c)
|
||||
else acc
|
||||
termination_by a.size - i
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right c.utf8Size_pos)
|
||||
decreasing_by exact Nat.sub_lt_sub_left ‹_› (Nat.lt_add_of_pos_right (one_le_csize c))
|
||||
|
||||
/-- Converts a [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoded `ByteArray` string to `String`,
|
||||
or returns `none` if `a` is not properly UTF-8 encoded. -/
|
||||
@@ -108,8 +108,8 @@ def utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
|
||||
simp [Char.utf8Size, utf8EncodeChar]
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = csize c := by
|
||||
simp [csize, utf8EncodeChar, Char.utf8Size]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
@@ -7,4 +7,3 @@ prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.UInt.Log2
|
||||
import Init.Data.UInt.Lemmas
|
||||
import Init.Data.UInt.Bitwise
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Lean FRO, LLC. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.UInt.Basic
|
||||
import Init.Data.Fin.Bitwise
|
||||
|
||||
set_option hygiene false in
|
||||
macro "declare_bitwise_uint_theorems" typeName:ident : command =>
|
||||
`(
|
||||
namespace $typeName
|
||||
|
||||
@[simp] protected theorem and_toNat (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := Fin.and_val ..
|
||||
|
||||
end $typeName
|
||||
)
|
||||
|
||||
declare_bitwise_uint_theorems UInt8
|
||||
declare_bitwise_uint_theorems UInt16
|
||||
declare_bitwise_uint_theorems UInt32
|
||||
declare_bitwise_uint_theorems UInt64
|
||||
declare_bitwise_uint_theorems USize
|
||||
@@ -26,8 +26,6 @@ theorem add_def (a b : $typeName) : a + b = ⟨a.val + b.val⟩ := rfl
|
||||
| ⟨_, _⟩ => rfl
|
||||
theorem val_eq_of_lt {a : Nat} : a < size → ((ofNat a).val : Nat) = a :=
|
||||
Nat.mod_eq_of_lt
|
||||
theorem toNat_ofNat_of_lt {n : Nat} (h : n < size) : (ofNat n).toNat = n := by
|
||||
rw [toNat, val_eq_of_lt h]
|
||||
|
||||
theorem le_def {a b : $typeName} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
|
||||
theorem lt_def {a b : $typeName} : a < b ↔ a.1 < b.1 := .rfl
|
||||
@@ -50,7 +48,6 @@ protected theorem ne_of_lt {a b : $typeName} (h : a < b) : a ≠ b := ne_of_val_
|
||||
@[simp] protected theorem zero_toNat : (0 : $typeName).toNat = 0 := Nat.zero_mod _
|
||||
@[simp] protected theorem mod_toNat (a b : $typeName) : (a % b).toNat = a.toNat % b.toNat := Fin.mod_val ..
|
||||
@[simp] protected theorem div_toNat (a b : $typeName) : (a / b).toNat = a.toNat / b.toNat := Fin.div_val ..
|
||||
@[simp] protected theorem sub_toNat_of_le (a b : $typeName) : b ≤ a → (a - b).toNat = a.toNat - b.toNat := Fin.sub_val_of_le
|
||||
@[simp] protected theorem modn_toNat (a : $typeName) (b : Nat) : (a.modn b).toNat = a.toNat % b := Fin.modn_val ..
|
||||
protected theorem modn_lt {m : Nat} : ∀ (u : $typeName), m > 0 → toNat (u % m) < m
|
||||
| ⟨u⟩, h => Fin.modn_lt u h
|
||||
@@ -58,8 +55,6 @@ open $typeName (modn_lt) in
|
||||
protected theorem mod_lt (a b : $typeName) (h : 0 < b) : a % b < b := modn_lt _ (by simp [lt_def] at h; exact h)
|
||||
protected theorem toNat.inj : ∀ {a b : $typeName}, a.toNat = b.toNat → a = b
|
||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
||||
protected theorem toNat_lt_size (a : $typeName) : a.toNat < size := a.1.2
|
||||
@[simp] protected theorem ofNat_one : ofNat 1 = 1 := rfl
|
||||
|
||||
end $typeName
|
||||
)
|
||||
|
||||
@@ -10,39 +10,58 @@ import Init.RCases
|
||||
|
||||
namespace Lean
|
||||
namespace Parser.Attr
|
||||
/-- Registers an extensionality theorem.
|
||||
|
||||
/--
|
||||
The flag `(iff := false)` prevents `ext` from generating an `ext_iff` lemma.
|
||||
-/
|
||||
syntax extIff := atomic("(" &"iff" " := " &"false" ")")
|
||||
* When `@[ext]` is applied to a structure, it generates `.ext` and `.ext_iff` theorems and registers
|
||||
them for the `ext` tactic.
|
||||
|
||||
/--
|
||||
The flag `(flat := false)` causes `ext` to not flatten parents' fields when generating an `ext` lemma.
|
||||
-/
|
||||
syntax extFlat := atomic("(" &"flat" " := " &"false" ")")
|
||||
* When `@[ext]` is applied to a theorem, the theorem is registered for the `ext` tactic.
|
||||
|
||||
/--
|
||||
Registers an extensionality theorem.
|
||||
|
||||
* When `@[ext]` is applied to a theorem, the theorem is registered for the `ext` tactic, and it generates an "`ext_iff`" theorem.
|
||||
The name of the theorem is from adding the suffix `_iff` to the theorem name.
|
||||
|
||||
* When `@[ext]` is applied to a structure, it generates an `.ext` theorem and applies the `@[ext]` attribute to it.
|
||||
The result is an `.ext` and an `.ext_iff` theorem with the `.ext` theorem registered for the `ext` tactic.
|
||||
|
||||
* An optional natural number argument, e.g. `@[ext 9000]`, specifies a priority for the `ext` lemma.
|
||||
Higher-priority lemmas are chosen first, and the default is `1000`.
|
||||
|
||||
* The flag `@[ext (iff := false)]` disables generating an `ext_iff` theorem.
|
||||
* An optional natural number argument, e.g. `@[ext 9000]`, specifies a priority for the lemma. Higher-priority lemmas are chosen first, and the default is `1000`.
|
||||
|
||||
* The flag `@[ext (flat := false)]` causes generated structure extensionality theorems to show inherited fields based on their representation,
|
||||
rather than flattening the parents' fields into the lemma's equality hypotheses.
|
||||
-/
|
||||
syntax (name := ext) "ext" (ppSpace extIff)? (ppSpace extFlat)? (ppSpace prio)? : attr
|
||||
structures in the generated extensionality theorems. -/
|
||||
syntax (name := ext) "ext" (" (" &"flat" " := " term ")")? (ppSpace prio)? : attr
|
||||
end Parser.Attr
|
||||
|
||||
-- TODO: rename this namespace?
|
||||
-- Remark: `ext` has scoped syntax, Mathlib may depend on the actual namespace name.
|
||||
namespace Elab.Tactic.Ext
|
||||
/--
|
||||
Creates the type of the extensionality theorem for the given structure,
|
||||
elaborating to `x.1 = y.1 → x.2 = y.2 → x = y`, for example.
|
||||
-/
|
||||
scoped syntax (name := extType) "ext_type% " term:max ppSpace ident : term
|
||||
|
||||
/--
|
||||
Creates the type of the iff-variant of the extensionality theorem for the given structure,
|
||||
elaborating to `x = y ↔ x.1 = y.1 ∧ x.2 = y.2`, for example.
|
||||
-/
|
||||
scoped syntax (name := extIffType) "ext_iff_type% " term:max ppSpace ident : term
|
||||
|
||||
/--
|
||||
`declare_ext_theorems_for A` declares the extensionality theorems for the structure `A`.
|
||||
|
||||
These theorems state that two expressions with the structure type are equal if their fields are equal.
|
||||
-/
|
||||
syntax (name := declareExtTheoremFor) "declare_ext_theorems_for " ("(" &"flat" " := " term ") ")? ident (ppSpace prio)? : command
|
||||
|
||||
macro_rules | `(declare_ext_theorems_for $[(flat := $f)]? $struct:ident $(prio)?) => do
|
||||
let flat := f.getD (mkIdent `true)
|
||||
let names ← Macro.resolveGlobalName struct.getId.eraseMacroScopes
|
||||
let name ← match names.filter (·.2.isEmpty) with
|
||||
| [] => Macro.throwError s!"unknown constant {struct.getId}"
|
||||
| [(name, _)] => pure name
|
||||
| _ => Macro.throwError s!"ambiguous name {struct.getId}"
|
||||
let extName := mkIdentFrom struct (canonical := true) <| name.mkStr "ext"
|
||||
let extIffName := mkIdentFrom struct (canonical := true) <| name.mkStr "ext_iff"
|
||||
`(@[ext $(prio)?] protected theorem $extName:ident : ext_type% $flat $struct:ident :=
|
||||
fun {..} {..} => by intros; subst_eqs; rfl
|
||||
protected theorem $extIffName:ident : ext_iff_type% $flat $struct:ident :=
|
||||
fun {..} {..} =>
|
||||
⟨fun h => by cases h; and_intros <;> rfl,
|
||||
fun _ => by (repeat cases ‹_ ∧ _›); subst_eqs; rfl⟩)
|
||||
|
||||
/--
|
||||
Applies extensionality lemmas that are registered with the `@[ext]` attribute.
|
||||
@@ -77,8 +96,19 @@ macro "ext1" xs:(colGt ppSpace rintroPat)* : tactic =>
|
||||
end Elab.Tactic.Ext
|
||||
end Lean
|
||||
|
||||
attribute [ext] Prod PProd Sigma PSigma
|
||||
attribute [ext] funext propext Subtype.eq
|
||||
|
||||
@[ext] theorem Prod.ext : {x y : Prod α β} → x.fst = y.fst → x.snd = y.snd → x = y
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl, rfl => rfl
|
||||
|
||||
@[ext] theorem PProd.ext : {x y : PProd α β} → x.fst = y.fst → x.snd = y.snd → x = y
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl, rfl => rfl
|
||||
|
||||
@[ext] theorem Sigma.ext : {x y : Sigma β} → x.fst = y.fst → HEq x.snd y.snd → x = y
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl, .rfl => rfl
|
||||
|
||||
@[ext] theorem PSigma.ext : {x y : PSigma β} → x.fst = y.fst → HEq x.snd y.snd → x = y
|
||||
| ⟨_,_⟩, ⟨_,_⟩, rfl, .rfl => rfl
|
||||
|
||||
@[ext] protected theorem PUnit.ext (x y : PUnit) : x = y := rfl
|
||||
protected theorem Unit.ext (x y : Unit) : x = y := rfl
|
||||
|
||||
@@ -7,57 +7,22 @@ prelude
|
||||
import Init.Util
|
||||
|
||||
@[never_extract]
|
||||
def outOfBounds [Inhabited α] : α :=
|
||||
private def outOfBounds [Inhabited α] : α :=
|
||||
panic! "index out of bounds"
|
||||
|
||||
theorem outOfBounds_eq_default [Inhabited α] : (outOfBounds : α) = default := rfl
|
||||
|
||||
/--
|
||||
The classes `GetElem` and `GetElem?` implement lookup notation,
|
||||
specifically `xs[i]`, `xs[i]?`, `xs[i]!`, and `xs[i]'p`.
|
||||
|
||||
Both classes are indexed by types `coll`, `idx`, and `elem` which are
|
||||
the collection, the index, and the element types.
|
||||
A single collection may support lookups with multiple index
|
||||
types. The relation `valid` determines when the index is guaranteed to be
|
||||
valid; lookups of valid indices are guaranteed not to fail.
|
||||
|
||||
For example, an instance for arrays looks like
|
||||
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`. In other words, given an
|
||||
array `xs` and a natural number `i`, `xs[i]` will return an `α` when `valid xs i`
|
||||
holds, which is true when `i` is less than the size of the array. `Array`
|
||||
additionally supports indexing with `USize` instead of `Nat`.
|
||||
In either case, because the bounds are checked at compile time,
|
||||
no runtime check is required.
|
||||
|
||||
The class `GetElem coll idx elem valid` implements the `xs[i]` notation.
|
||||
Given `xs[i]` with `xs : coll` and `i : idx`, Lean looks for an instance of
|
||||
`GetElem coll idx elem valid` and uses this to infer the type of the return
|
||||
value `elem` and side condition `valid` required to ensure `xs[i]` yields
|
||||
a valid value of type `elem`. The tactic `get_elem_tactic` is
|
||||
invoked to prove validity automatically. The `xs[i]'p` notation uses the
|
||||
proof `p` to satisfy the validity condition.
|
||||
If the proof `p` is long, it is often easier to place the
|
||||
proof in the context using `have`, because `get_elem_tactic` tries
|
||||
`assumption`.
|
||||
`GetElem coll idx elem valid` and uses this to infer the type of return
|
||||
value `elem` and side conditions `valid` required to ensure `xs[i]` yields
|
||||
a valid value of type `elem`.
|
||||
|
||||
For example, the instance for arrays looks like
|
||||
`GetElem (Array α) Nat α (fun xs i => i < xs.size)`.
|
||||
|
||||
The proof side-condition `valid xs i` is automatically dispatched by the
|
||||
`get_elem_tactic` tactic; this tactic can be extended by adding more clauses to
|
||||
`get_elem_tactic_trivial` using `macro_rules`.
|
||||
|
||||
`xs[i]?` and `xs[i]!` do not impose a proof obligation; the former returns
|
||||
an `Option elem`, with `none` signalling that the value isn't present, and
|
||||
the latter returns `elem` but panics if the value isn't there, returning
|
||||
`default : elem` based on the `Inhabited elem` instance.
|
||||
These are provided by the `GetElem?` class, for which there is a default instance
|
||||
generated from a `GetElem` class as long as `valid xs i` is always decidable.
|
||||
|
||||
Important instances include:
|
||||
* `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
|
||||
indexing with no runtime bounds check and a proof side goal `i < arr.size`.
|
||||
* `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
|
||||
side goal `i < l.length`.
|
||||
|
||||
`get_elem_tactic` tactic, which can be extended by adding more clauses to
|
||||
`get_elem_tactic_trivial`.
|
||||
-/
|
||||
class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
(valid : outParam (coll → idx → Prop)) where
|
||||
@@ -65,10 +30,33 @@ class GetElem (coll : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
The syntax `arr[i]` gets the `i`'th element of the collection `arr`. If there
|
||||
are proof side conditions to the application, they will be automatically
|
||||
inferred by the `get_elem_tactic` tactic.
|
||||
|
||||
The actual behavior of this class is type-dependent, but here are some
|
||||
important implementations:
|
||||
* `arr[i] : α` where `arr : Array α` and `i : Nat` or `i : USize`: does array
|
||||
indexing with no bounds check and a proof side goal `i < arr.size`.
|
||||
* `l[i] : α` where `l : List α` and `i : Nat`: index into a list, with proof
|
||||
side goal `i < l.length`.
|
||||
* `stx[i] : Syntax` where `stx : Syntax` and `i : Nat`: get a syntax argument,
|
||||
no side goal (returns `.missing` out of range)
|
||||
|
||||
There are other variations on this syntax:
|
||||
* `arr[i]!` is syntax for `getElem! arr i` which should panic and return
|
||||
`default : α` if the index is not valid.
|
||||
* `arr[i]?` is syntax for `getElem?` which should return `none` if the index
|
||||
is not valid.
|
||||
* `arr[i]'h` is syntax for `getElem arr i h` with `h` an explicit proof the
|
||||
index is valid.
|
||||
-/
|
||||
getElem (xs : coll) (i : idx) (h : valid xs i) : elem
|
||||
|
||||
export GetElem (getElem)
|
||||
getElem? (xs : coll) (i : idx) [Decidable (valid xs i)] : Option elem :=
|
||||
if h : _ then some (getElem xs i h) else none
|
||||
|
||||
getElem! [Inhabited elem] (xs : coll) (i : idx) [Decidable (valid xs i)] : elem :=
|
||||
match getElem? xs i with | some e => e | none => outOfBounds
|
||||
|
||||
export GetElem (getElem getElem! getElem?)
|
||||
|
||||
@[inherit_doc getElem]
|
||||
syntax:max term noWs "[" withoutPosition(term) "]" : term
|
||||
@@ -78,30 +66,6 @@ macro_rules | `($x[$i]) => `(getElem $x $i (by get_elem_tactic))
|
||||
syntax term noWs "[" withoutPosition(term) "]'" term:max : term
|
||||
macro_rules | `($x[$i]'$h) => `(getElem $x $i $h)
|
||||
|
||||
/-- Helper function for implementation of `GetElem?.getElem?`. -/
|
||||
abbrev decidableGetElem? [GetElem coll idx elem valid] (xs : coll) (i : idx) [Decidable (valid xs i)] :
|
||||
Option elem :=
|
||||
if h : valid xs i then some xs[i] else none
|
||||
|
||||
@[inherit_doc GetElem]
|
||||
class GetElem? (coll : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
(valid : outParam (coll → idx → Prop)) extends GetElem coll idx elem valid where
|
||||
/--
|
||||
The syntax `arr[i]?` gets the `i`'th element of the collection `arr`,
|
||||
if it is present (and wraps it in `some`), and otherwise returns `none`.
|
||||
-/
|
||||
getElem? : coll → idx → Option elem
|
||||
|
||||
/--
|
||||
The syntax `arr[i]!` gets the `i`'th element of the collection `arr`,
|
||||
if it is present, and otherwise panics at runtime and returns the `default` term
|
||||
from `Inhabited elem`.
|
||||
-/
|
||||
getElem! [Inhabited elem] (xs : coll) (i : idx) : elem :=
|
||||
match getElem? xs i with | some e => e | none => outOfBounds
|
||||
|
||||
export GetElem? (getElem? getElem!)
|
||||
|
||||
/--
|
||||
The syntax `arr[i]?` gets the `i`'th element of the collection `arr` or
|
||||
returns `none` if `i` is out of bounds.
|
||||
@@ -114,51 +78,32 @@ panics `i` is out of bounds.
|
||||
-/
|
||||
macro:max x:term noWs "[" i:term "]" noWs "!" : term => `(getElem! $x $i)
|
||||
|
||||
instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
|
||||
GetElem? coll idx elem valid where
|
||||
getElem? xs i := decidableGetElem? xs i
|
||||
|
||||
theorem getElem_congr_coll [GetElem coll idx elem valid] {c d : coll} {i : idx} {h : valid c i}
|
||||
(h' : c = d) : c[i] = d[i]'(h' ▸ h) := by
|
||||
cases h'; rfl
|
||||
|
||||
theorem getElem_congr [GetElem coll idx elem valid] {c : coll} {i j : idx} {h : valid c i}
|
||||
(h' : i = j) : c[i] = c[j]'(h' ▸ h) := by
|
||||
cases h'; rfl
|
||||
|
||||
class LawfulGetElem (cont : Type u) (idx : Type v) (elem : outParam (Type w))
|
||||
(dom : outParam (cont → idx → Prop)) [ge : GetElem? cont idx elem dom] : Prop where
|
||||
(dom : outParam (cont → idx → Prop)) [ge : GetElem cont idx elem dom] : Prop where
|
||||
|
||||
getElem?_def (c : cont) (i : idx) [Decidable (dom c i)] :
|
||||
c[i]? = if h : dom c i then some (c[i]'h) else none := by
|
||||
intros
|
||||
try simp only [getElem?] <;> congr
|
||||
getElem!_def [Inhabited elem] (c : cont) (i : idx) :
|
||||
c[i]! = match c[i]? with | some e => e | none => default := by
|
||||
intros
|
||||
simp only [getElem!, getElem?, outOfBounds_eq_default]
|
||||
c[i]? = if h : dom c i then some (c[i]'h) else none := by intros; eq_refl
|
||||
getElem!_def [Inhabited elem] (c : cont) (i : idx) [Decidable (dom c i)] :
|
||||
c[i]! = match c[i]? with | some e => e | none => default := by intros; eq_refl
|
||||
|
||||
export LawfulGetElem (getElem?_def getElem!_def)
|
||||
|
||||
instance (priority := low) [GetElem coll idx elem valid] [∀ xs i, Decidable (valid xs i)] :
|
||||
LawfulGetElem coll idx elem valid where
|
||||
|
||||
theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
theorem getElem?_pos [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] : c[i]? = some (c[i]'h) := by
|
||||
rw [getElem?_def]
|
||||
exact dif_pos h
|
||||
|
||||
theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
theorem getElem?_neg [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
(c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]? = none := by
|
||||
rw [getElem?_def]
|
||||
exact dif_neg h
|
||||
|
||||
theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
theorem getElem!_pos [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) [Decidable (dom c i)] :
|
||||
c[i]! = c[i]'h := by
|
||||
simp only [getElem!_def, getElem?_def, h]
|
||||
|
||||
theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
theorem getElem!_neg [GetElem cont idx elem dom] [LawfulGetElem cont idx elem dom]
|
||||
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) [Decidable (dom c i)] : c[i]! = default := by
|
||||
simp only [getElem!_def, getElem?_def, h]
|
||||
|
||||
@@ -166,22 +111,23 @@ namespace Fin
|
||||
|
||||
instance instGetElemFinVal [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
getElem xs i h := getElem xs i.1 h
|
||||
|
||||
instance instGetElem?FinVal [GetElem? cont Nat elem dom] : GetElem? cont (Fin n) elem fun xs i => dom xs i where
|
||||
getElem? xs i := getElem? xs i.val
|
||||
getElem! xs i := getElem! xs i.val
|
||||
|
||||
instance [GetElem? cont Nat elem dom] [h : LawfulGetElem cont Nat elem dom] :
|
||||
instance [GetElem cont Nat elem dom] [h : LawfulGetElem cont Nat elem dom] :
|
||||
LawfulGetElem cont (Fin n) elem fun xs i => dom xs i where
|
||||
getElem?_def _c _i _d := h.getElem?_def ..
|
||||
getElem!_def _c _i := h.getElem!_def ..
|
||||
|
||||
@[simp] theorem getElem_fin [GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n) (h : Dom a i) :
|
||||
getElem?_def _c _i _d := h.getElem?_def ..
|
||||
getElem!_def _c _i _d := h.getElem!_def ..
|
||||
|
||||
@[simp] theorem getElem_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n) (h : Dom a i) :
|
||||
a[i] = a[i.1] := rfl
|
||||
|
||||
@[simp] theorem getElem?_fin [h : GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n) : a[i]? = a[i.1]? := by rfl
|
||||
@[simp] theorem getElem?_fin [h : GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
|
||||
[Decidable (Dom a i)] : a[i]? = a[i.1]? := by rfl
|
||||
|
||||
@[simp] theorem getElem!_fin [GetElem? Cont Nat Elem Dom] (a : Cont) (i : Fin n) [Inhabited Elem] : a[i]! = a[i.1]! := rfl
|
||||
@[simp] theorem getElem!_fin [GetElem Cont Nat Elem Dom] (a : Cont) (i : Fin n)
|
||||
[Decidable (Dom a i)] [Inhabited Elem] : a[i]! = a[i.1]! := rfl
|
||||
|
||||
macro_rules
|
||||
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)
|
||||
@@ -193,16 +139,14 @@ namespace List
|
||||
instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
getElem as i h := as.get ⟨i, h⟩
|
||||
|
||||
@[simp] theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
instance : LawfulGetElem (List α) Nat α fun as i => i < as.length where
|
||||
|
||||
@[simp] theorem cons_getElem_zero (a : α) (as : List α) (h : 0 < (a :: as).length) : getElem (a :: as) 0 h = a := by
|
||||
rfl
|
||||
|
||||
@[deprecated (since := "2024-06-12")] abbrev cons_getElem_zero := @getElem_cons_zero
|
||||
|
||||
@[simp] theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
@[simp] theorem cons_getElem_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) := by
|
||||
rfl
|
||||
|
||||
@[deprecated (since := "2024-06-12")] abbrev cons_getElem_succ := @getElem_cons_succ
|
||||
|
||||
theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
@@ -215,6 +159,8 @@ namespace Array
|
||||
instance : GetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
getElem xs i h := xs.get ⟨i, h⟩
|
||||
|
||||
instance : LawfulGetElem (Array α) Nat α fun xs i => i < xs.size where
|
||||
|
||||
end Array
|
||||
|
||||
namespace Lean.Syntax
|
||||
@@ -222,4 +168,6 @@ namespace Lean.Syntax
|
||||
instance : GetElem Syntax Nat Syntax fun _ _ => True where
|
||||
getElem stx i _ := stx.getArg i
|
||||
|
||||
instance : LawfulGetElem Syntax Nat Syntax fun _ _ => True where
|
||||
|
||||
end Lean.Syntax
|
||||
|
||||
@@ -1278,46 +1278,12 @@ def Occurrences.isAll : Occurrences → Bool
|
||||
| all => true
|
||||
| _ => false
|
||||
|
||||
/--
|
||||
Controls which new mvars are turned in to goals by the `apply` tactic.
|
||||
- `nonDependentFirst` mvars that don't depend on other goals appear first in the goal list.
|
||||
- `nonDependentOnly` only mvars that don't depend on other goals are added to goal list.
|
||||
- `all` all unassigned mvars are added to the goal list.
|
||||
-/
|
||||
-- TODO: Consider renaming to `Apply.NewGoals`
|
||||
inductive ApplyNewGoals where
|
||||
| nonDependentFirst | nonDependentOnly | all
|
||||
|
||||
/-- Configures the behaviour of the `apply` tactic. -/
|
||||
-- TODO: Consider renaming to `Apply.Config`
|
||||
structure ApplyConfig where
|
||||
newGoals := ApplyNewGoals.nonDependentFirst
|
||||
/--
|
||||
If `synthAssignedInstances` is `true`, then `apply` will synthesize instance implicit arguments
|
||||
even if they have assigned by `isDefEq`, and then check whether the synthesized value matches the
|
||||
one inferred. The `congr` tactic sets this flag to false.
|
||||
-/
|
||||
synthAssignedInstances := true
|
||||
/--
|
||||
If `allowSynthFailures` is `true`, then `apply` will return instance implicit arguments
|
||||
for which typeclass search failed as new goals.
|
||||
-/
|
||||
allowSynthFailures := false
|
||||
/--
|
||||
If `approx := true`, then we turn on `isDefEq` approximations. That is, we use
|
||||
the `approxDefEq` combinator.
|
||||
-/
|
||||
approx : Bool := true
|
||||
|
||||
namespace Rewrite
|
||||
|
||||
abbrev NewGoals := ApplyNewGoals
|
||||
|
||||
structure Config where
|
||||
transparency : TransparencyMode := .reducible
|
||||
transparency : TransparencyMode := TransparencyMode.reducible
|
||||
offsetCnstrs : Bool := true
|
||||
occs : Occurrences := .all
|
||||
newGoals : NewGoals := .nonDependentFirst
|
||||
occs : Occurrences := Occurrences.all
|
||||
|
||||
end Rewrite
|
||||
|
||||
|
||||
@@ -42,67 +42,23 @@ inductive EtaStructMode where
|
||||
|
||||
namespace DSimp
|
||||
|
||||
/--
|
||||
The configuration for `dsimp`.
|
||||
Passed to `dsimp` using, for example, the `dsimp (config := {zeta := false})` syntax.
|
||||
|
||||
Implementation note: this structure is only used for processing the `(config := ...)` syntax, and it is not used internally.
|
||||
It is immediately converted to `Lean.Meta.Simp.Config` by `Lean.Elab.Tactic.elabSimpConfig`.
|
||||
-/
|
||||
structure Config where
|
||||
/--
|
||||
When `true` (default: `true`), performs zeta reduction of let expressions.
|
||||
That is, `let x := v; e[x]` reduces to `e[v]`.
|
||||
See also `zetaDelta`.
|
||||
-/
|
||||
/-- `let x := v; e[x]` reduces to `e[v]`. -/
|
||||
zeta : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), performs beta reduction of applications of `fun` expressions.
|
||||
That is, `(fun x => e[x]) v` reduces to `e[v]`.
|
||||
-/
|
||||
beta : Bool := true
|
||||
/--
|
||||
TODO (currently unimplemented). When `true` (default: `true`), performs eta reduction for `fun` expressions.
|
||||
That is, `(fun x => f x)` reduces to `f`.
|
||||
-/
|
||||
eta : Bool := true
|
||||
/--
|
||||
Configures how to determine definitional equality between two structure instances.
|
||||
See documentation for `Lean.Meta.EtaStructMode`.
|
||||
-/
|
||||
etaStruct : EtaStructMode := .all
|
||||
/--
|
||||
When `true` (default: `true`), reduces `match` expressions applied to constructors.
|
||||
-/
|
||||
iota : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), reduces projections of structure constructors.
|
||||
-/
|
||||
proj : Bool := true
|
||||
/--
|
||||
When `true` (default: `false`), rewrites a proposition `p` to `True` or `False` by inferring
|
||||
a `Decidable p` instance and reducing it.
|
||||
-/
|
||||
decide : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), unfolds definitions.
|
||||
This can be enabled using the `simp!` syntax.
|
||||
-/
|
||||
autoUnfold : Bool := false
|
||||
/--
|
||||
If `failIfUnchanged` is `true` (default: `true`), then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress.
|
||||
-/
|
||||
/-- If `failIfUnchanged := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will fail if they do not make progress. -/
|
||||
failIfUnchanged : Bool := true
|
||||
/--
|
||||
If `unfoldPartialApp` is `true` (default: `false`), then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will unfold even partial applications of `f` when we request `f` to be unfolded.
|
||||
-/
|
||||
/-- If `unfoldPartialApp := true`, then calls to `simp`, `dsimp`, or `simp_all`
|
||||
will unfold even partial applications of `f` when we request `f` to be unfolded. -/
|
||||
unfoldPartialApp : Bool := false
|
||||
/--
|
||||
When `true` (default: `false`), local definitions are unfolded.
|
||||
That is, given a local context containing entry `x : t := e`, the free variable `x` reduces to `e`.
|
||||
-/
|
||||
/-- Given a local context containing entry `x : t := e`, free variable `x` reduces to `e`. -/
|
||||
zetaDelta : Bool := false
|
||||
deriving Inhabited, BEq
|
||||
|
||||
@@ -116,7 +72,7 @@ def defaultMaxSteps := 100000
|
||||
The configuration for `simp`.
|
||||
Passed to `simp` using, for example, the `simp (config := {contextual := true})` syntax.
|
||||
|
||||
See also `Lean.Meta.Simp.neutralConfig` and `Lean.Meta.DSimp.Config`.
|
||||
See also `Lean.Meta.Simp.neutralConfig`.
|
||||
-/
|
||||
structure Config where
|
||||
/--
|
||||
@@ -218,14 +174,6 @@ structure Config where
|
||||
to find candidate `simp` theorems. It approximates Lean 3 `simp` behavior.
|
||||
-/
|
||||
index : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), `simp` will **not** create a proof for a rewriting rule associated
|
||||
with an `rfl`-theorem.
|
||||
Rewriting rules are provided by users by annotating theorems with the attribute `@[simp]`.
|
||||
If the proof of the theorem is just `rfl` (reflexivity), and `implicitDefEqProofs := true`, `simp`
|
||||
will **not** create a proof term which is an application of the annotated theorem.
|
||||
-/
|
||||
implicitDefEqProofs : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
-- Configuration object for `simp_all`
|
||||
|
||||
@@ -267,7 +267,6 @@ syntax (name := rawNatLit) "nat_lit " num : term
|
||||
|
||||
@[inherit_doc] infixr:90 " ∘ " => Function.comp
|
||||
@[inherit_doc] infixr:35 " × " => Prod
|
||||
@[inherit_doc] infixr:35 " ×' " => PProd
|
||||
|
||||
@[inherit_doc] infix:50 " ∣ " => Dvd.dvd
|
||||
@[inherit_doc] infixl:55 " ||| " => HOr.hOr
|
||||
@@ -559,22 +558,6 @@ syntax (name := runMeta) "run_meta " doSeq : command
|
||||
set_option linter.missingDocs false in
|
||||
syntax guardMsgsFilterSeverity := &"info" <|> &"warning" <|> &"error" <|> &"all"
|
||||
|
||||
/--
|
||||
`#reduce <expression>` reduces the expression `<expression>` to its normal form. This
|
||||
involves applying reduction rules until no further reduction is possible.
|
||||
|
||||
By default, proofs and types within the expression are not reduced. Use modifiers
|
||||
`(proofs := true)` and `(types := true)` to reduce them.
|
||||
Recall that propositions are types in Lean.
|
||||
|
||||
**Warning:** This can be a computationally expensive operation,
|
||||
especially for complex expressions.
|
||||
|
||||
Consider using `#eval <expression>` for simple evaluation/execution
|
||||
of expressions.
|
||||
-/
|
||||
syntax (name := reduceCmd) "#reduce " (atomic("(" &"proofs" " := " &"true" ")"))? (atomic("(" &"types" " := " &"true" ")"))? term : command
|
||||
|
||||
/--
|
||||
A message filter specification for `#guard_msgs`.
|
||||
- `info`, `warning`, `error`: capture messages with the given severity level.
|
||||
@@ -704,28 +687,6 @@ syntax (name := checkSimp) "#check_simp " term "~>" term : command
|
||||
-/
|
||||
syntax (name := checkSimpFailure) "#check_simp " term "!~>" : command
|
||||
|
||||
/--
|
||||
`#discr_tree_key t` prints the discrimination tree keys for a term `t` (or, if it is a single identifier, the type of that constant).
|
||||
It uses the default configuration for generating keys.
|
||||
|
||||
For example,
|
||||
```
|
||||
#discr_tree_key (∀ {a n : Nat}, bar a (OfNat.ofNat n))
|
||||
-- bar _ (@OfNat.ofNat Nat _ _)
|
||||
|
||||
#discr_tree_simp_key Nat.add_assoc
|
||||
-- @HAdd.hAdd Nat Nat Nat _ (@HAdd.hAdd Nat Nat Nat _ _ _) _
|
||||
```
|
||||
|
||||
`#discr_tree_simp_key` is similar to `#discr_tree_key`, but treats the underlying type
|
||||
as one of a simp lemma, i.e. transforms it into an equality and produces the key of the
|
||||
left-hand side.
|
||||
-/
|
||||
syntax (name := discrTreeKeyCmd) "#discr_tree_key " term : command
|
||||
|
||||
@[inherit_doc discrTreeKeyCmd]
|
||||
syntax (name := discrTreeSimpKeyCmd) "#discr_tree_simp_key" term : command
|
||||
|
||||
/--
|
||||
The `seal foo` command ensures that the definition of `foo` is sealed, meaning it is marked as `[irreducible]`.
|
||||
This command is particularly useful in contexts where you want to prevent the reduction of `foo` in proofs.
|
||||
|
||||
@@ -187,7 +187,7 @@ theorem ofNat_val_add {x y : Fin n} :
|
||||
(((x + y : Fin n)) : Int) = ((x : Int) + (y : Int)) % n := rfl
|
||||
|
||||
theorem ofNat_val_sub {x y : Fin n} :
|
||||
(((x - y : Fin n)) : Int) = (((n - y : Nat) + (x : Int) : Int)) % n := rfl
|
||||
(((x - y : Fin n)) : Int) = ((x : Int) + ((n - y : Nat) : Int)) % n := rfl
|
||||
|
||||
theorem ofNat_val_mul {x y : Fin n} :
|
||||
(((x * y : Fin n)) : Int) = ((x : Int) * (y : Int)) % n := rfl
|
||||
|
||||
@@ -28,8 +28,8 @@ def get (xs : IntList) (i : Nat) : Int := (xs.get? i).getD 0
|
||||
@[simp] theorem get_cons_succ : get (x :: xs) (i+1) = get xs i := rfl
|
||||
|
||||
theorem get_map {xs : IntList} (h : f 0 = 0) : get (xs.map f) i = f (xs.get i) := by
|
||||
simp only [get, List.get?_eq_getElem?, List.getElem?_map]
|
||||
cases xs[i]? <;> simp_all
|
||||
simp only [get, List.get?_map]
|
||||
cases xs.get? i <;> simp_all
|
||||
|
||||
theorem get_of_length_le {xs : IntList} (h : xs.length ≤ i) : xs.get i = 0 := by
|
||||
rw [get, List.get?_eq_none.mpr h]
|
||||
@@ -66,8 +66,8 @@ theorem add_def (xs ys : IntList) :
|
||||
rfl
|
||||
|
||||
@[simp] theorem add_get (xs ys : IntList) (i : Nat) : (xs + ys).get i = xs.get i + ys.get i := by
|
||||
simp only [get, add_def, List.get?_eq_getElem?, List.getElem?_zipWithAll]
|
||||
cases xs[i]? <;> cases ys[i]? <;> simp
|
||||
simp only [add_def, get, List.zipWithAll_get?, List.get?_eq_none]
|
||||
cases xs.get? i <;> cases ys.get? i <;> simp
|
||||
|
||||
@[simp] theorem add_nil (xs : IntList) : xs + [] = xs := by simp [add_def]
|
||||
@[simp] theorem nil_add (xs : IntList) : [] + xs = xs := by simp [add_def]
|
||||
@@ -83,8 +83,8 @@ theorem mul_def (xs ys : IntList) : xs * ys = List.zipWith (· * ·) xs ys :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem mul_get (xs ys : IntList) (i : Nat) : (xs * ys).get i = xs.get i * ys.get i := by
|
||||
simp only [get, mul_def, List.get?_eq_getElem?, List.getElem?_zipWith]
|
||||
cases xs[i]? <;> cases ys[i]? <;> simp
|
||||
simp only [mul_def, get, List.zipWith_get?]
|
||||
cases xs.get? i <;> cases ys.get? i <;> simp
|
||||
|
||||
@[simp] theorem mul_nil_left : ([] : IntList) * ys = [] := rfl
|
||||
@[simp] theorem mul_nil_right : xs * ([] : IntList) = [] := List.zipWith_nil_right
|
||||
@@ -98,8 +98,8 @@ instance : Neg IntList := ⟨neg⟩
|
||||
theorem neg_def (xs : IntList) : - xs = xs.map fun x => -x := rfl
|
||||
|
||||
@[simp] theorem neg_get (xs : IntList) (i : Nat) : (- xs).get i = - xs.get i := by
|
||||
simp only [get, neg_def, List.get?_eq_getElem?, List.getElem?_map]
|
||||
cases xs[i]? <;> simp
|
||||
simp only [neg_def, get, List.get?_map]
|
||||
cases xs.get? i <;> simp
|
||||
|
||||
@[simp] theorem neg_nil : (- ([] : IntList)) = [] := rfl
|
||||
@[simp] theorem neg_cons : (- (x::xs : IntList)) = -x :: -xs := rfl
|
||||
@@ -124,8 +124,8 @@ instance : HMul Int IntList IntList where
|
||||
theorem smul_def (xs : IntList) (i : Int) : i * xs = xs.map fun x => i * x := rfl
|
||||
|
||||
@[simp] theorem smul_get (xs : IntList) (a : Int) (i : Nat) : (a * xs).get i = a * xs.get i := by
|
||||
simp only [get, smul_def, List.get?_eq_getElem?, List.getElem?_map]
|
||||
cases xs[i]? <;> simp
|
||||
simp only [smul_def, get, List.get?_map]
|
||||
cases xs.get? i <;> simp
|
||||
|
||||
@[simp] theorem smul_nil {i : Int} : i * ([] : IntList) = [] := rfl
|
||||
@[simp] theorem smul_cons {i : Int} : i * (x::xs : IntList) = i * x :: i * xs := rfl
|
||||
@@ -173,7 +173,7 @@ theorem mul_neg_left (xs ys : IntList) : (-xs) * ys = -(xs * ys) := by
|
||||
attribute [local simp] add_def neg_def sub_def in
|
||||
theorem sub_eq_add_neg (xs ys : IntList) : xs - ys = xs + (-ys) := by
|
||||
induction xs generalizing ys with
|
||||
| nil => simp
|
||||
| nil => simp; rfl
|
||||
| cons x xs ih =>
|
||||
cases ys with
|
||||
| nil => simp
|
||||
|
||||
@@ -38,10 +38,6 @@ theorem ext {a b : LinearCombo} (w₁ : a.const = b.const) (w₂ : a.coeffs = b.
|
||||
subst w₁; subst w₂
|
||||
congr
|
||||
|
||||
/-- Check if a linear combination is an atom, i.e. the constant term is zero and there is exactly one nonzero coefficient, which is one. -/
|
||||
def isAtom (a : LinearCombo) : Bool :=
|
||||
a.const == 0 && (a.coeffs.filter (· == 1)).length == 1 && a.coeffs.all fun c => c == 0 || c == 1
|
||||
|
||||
/--
|
||||
Evaluate a linear combination `⟨r, [c_1, …, c_k]⟩` at values `[v_1, …, v_k]` to obtain
|
||||
`r + (c_1 * x_1 + (c_2 * x_2 + ... (c_k * x_k + 0))))`.
|
||||
|
||||
@@ -488,9 +488,9 @@ attribute [unbox] Prod
|
||||
|
||||
/--
|
||||
Similar to `Prod`, but `α` and `β` can be propositions.
|
||||
You can use `α ×' β` as notation for `PProd α β`.
|
||||
We use this type internally to automatically generate the `brecOn` recursor.
|
||||
-/
|
||||
@[pp_using_anonymous_constructor]
|
||||
structure PProd (α : Sort u) (β : Sort v) where
|
||||
/-- The first projection out of a pair. if `p : PProd α β` then `p.1 : α`. -/
|
||||
fst : α
|
||||
@@ -740,7 +740,7 @@ prove `p` given any element `x : α`, then `p` holds. Note that it is essential
|
||||
that `p` is a `Prop` here; the version with `p` being a `Sort u` is equivalent
|
||||
to `Classical.choice`.
|
||||
-/
|
||||
protected theorem Nonempty.elim {α : Sort u} {p : Prop} (h₁ : Nonempty α) (h₂ : α → p) : p :=
|
||||
protected def Nonempty.elim {α : Sort u} {p : Prop} (h₁ : Nonempty α) (h₂ : α → p) : p :=
|
||||
match h₁ with
|
||||
| intro a => h₂ a
|
||||
|
||||
@@ -914,9 +914,6 @@ is `Bool` valued instead of `Prop` valued, and it also does not have any
|
||||
axioms like being reflexive or agreeing with `=`. It is mainly intended for
|
||||
programming applications. See `LawfulBEq` for a version that requires that
|
||||
`==` and `=` coincide.
|
||||
|
||||
Typically we prefer to put the "more variable" term on the left,
|
||||
and the "more constant" term on the right.
|
||||
-/
|
||||
class BEq (α : Type u) where
|
||||
/-- Boolean equality, notated as `a == b`. -/
|
||||
@@ -1071,15 +1068,11 @@ This type is special-cased by both the kernel and the compiler:
|
||||
library (usually [GMP](https://gmplib.org/)).
|
||||
-/
|
||||
inductive Nat where
|
||||
/-- `Nat.zero`, is the smallest natural number. This is one of the two
|
||||
constructors of `Nat`. Using `Nat.zero` should usually be avoided in favor of
|
||||
`0 : Nat` or simply `0`, in order to remain compatible with the simp normal
|
||||
form defined by `Nat.zero_eq`. -/
|
||||
/-- `Nat.zero`, normally written `0 : Nat`, is the smallest natural number.
|
||||
This is one of the two constructors of `Nat`. -/
|
||||
| zero : Nat
|
||||
/-- The successor function on natural numbers, `succ n = n + 1`.
|
||||
This is one of the two constructors of `Nat`. Using `succ n` should usually
|
||||
be avoided in favor of `n + 1`, in order to remain compatible with the simp
|
||||
normal form defined by `Nat.succ_eq_add_one`. -/
|
||||
This is one of the two constructors of `Nat`. -/
|
||||
| succ (n : Nat) : Nat
|
||||
|
||||
instance : Inhabited Nat where
|
||||
@@ -2203,11 +2196,15 @@ instance : DecidableEq Char :=
|
||||
| isFalse h => isFalse (Char.ne_of_val_ne h)
|
||||
|
||||
/-- Returns the number of bytes required to encode this `Char` in UTF-8. -/
|
||||
def Char.utf8Size (c : Char) : Nat :=
|
||||
def Char.utf8Size (c : Char) : UInt32 :=
|
||||
let v := c.val
|
||||
ite (LE.le v (UInt32.ofNatCore 0x7F (by decide))) 1
|
||||
(ite (LE.le v (UInt32.ofNatCore 0x7FF (by decide))) 2
|
||||
(ite (LE.le v (UInt32.ofNatCore 0xFFFF (by decide))) 3 4))
|
||||
ite (LE.le v (UInt32.ofNatCore 0x7F (by decide)))
|
||||
(UInt32.ofNatCore 1 (by decide))
|
||||
(ite (LE.le v (UInt32.ofNatCore 0x7FF (by decide)))
|
||||
(UInt32.ofNatCore 2 (by decide))
|
||||
(ite (LE.le v (UInt32.ofNatCore 0xFFFF (by decide)))
|
||||
(UInt32.ofNatCore 3 (by decide))
|
||||
(UInt32.ofNatCore 4 (by decide))))
|
||||
|
||||
/--
|
||||
`Option α` is the type of values which are either `some a` for some `a : α`,
|
||||
@@ -2306,6 +2303,24 @@ protected def List.hasDecEq {α : Type u} [DecidableEq α] : (a b : List α) →
|
||||
|
||||
instance {α : Type u} [DecidableEq α] : DecidableEq (List α) := List.hasDecEq
|
||||
|
||||
/--
|
||||
Folds a function over a list from the left:
|
||||
`foldl f z [a, b, c] = f (f (f z a) b) c`
|
||||
-/
|
||||
@[specialize]
|
||||
def List.foldl {α : Type u} {β : Type v} (f : α → β → α) : (init : α) → List β → α
|
||||
| a, nil => a
|
||||
| a, cons b l => foldl f (f a b) l
|
||||
|
||||
/--
|
||||
`l.set n a` sets the value of list `l` at (zero-based) index `n` to `a`:
|
||||
`[a, b, c, d].set 1 b' = [a, b', c, d]`
|
||||
-/
|
||||
def List.set : List α → Nat → α → List α
|
||||
| cons _ as, 0, b => cons b as
|
||||
| cons a as, Nat.succ n, b => cons a (set as n b)
|
||||
| nil, _, _ => nil
|
||||
|
||||
/--
|
||||
The length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`.
|
||||
|
||||
@@ -2329,6 +2344,14 @@ without running out of stack space.
|
||||
def List.lengthTR (as : List α) : Nat :=
|
||||
lengthTRAux as 0
|
||||
|
||||
@[simp] theorem List.length_cons {α} (a : α) (as : List α) : Eq (cons a as).length as.length.succ :=
|
||||
rfl
|
||||
|
||||
/-- `l.concat a` appends `a` at the *end* of `l`, that is, `l ++ [a]`. -/
|
||||
def List.concat {α : Type u} : List α → α → List α
|
||||
| nil, b => cons b nil
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
||||
/--
|
||||
`as.get i` returns the `i`'th element of the list `as`.
|
||||
This version of the function uses `i : Fin as.length` to ensure that it will
|
||||
@@ -2338,29 +2361,6 @@ def List.get {α : Type u} : (as : List α) → Fin as.length → α
|
||||
| cons a _, ⟨0, _⟩ => a
|
||||
| cons _ as, ⟨Nat.succ i, h⟩ => get as ⟨i, Nat.le_of_succ_le_succ h⟩
|
||||
|
||||
/--
|
||||
`l.set n a` sets the value of list `l` at (zero-based) index `n` to `a`:
|
||||
`[a, b, c, d].set 1 b' = [a, b', c, d]`
|
||||
-/
|
||||
def List.set : List α → Nat → α → List α
|
||||
| cons _ as, 0, b => cons b as
|
||||
| cons a as, Nat.succ n, b => cons a (set as n b)
|
||||
| nil, _, _ => nil
|
||||
|
||||
/--
|
||||
Folds a function over a list from the left:
|
||||
`foldl f z [a, b, c] = f (f (f z a) b) c`
|
||||
-/
|
||||
@[specialize]
|
||||
def List.foldl {α : Type u} {β : Type v} (f : α → β → α) : (init : α) → List β → α
|
||||
| a, nil => a
|
||||
| a, cons b l => foldl f (f a b) l
|
||||
|
||||
/-- `l.concat a` appends `a` at the *end* of `l`, that is, `l ++ [a]`. -/
|
||||
def List.concat {α : Type u} : List α → α → List α
|
||||
| nil, b => cons b nil
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
||||
/--
|
||||
`String` is the type of (UTF-8 encoded) strings.
|
||||
|
||||
@@ -2433,6 +2433,10 @@ instance : Inhabited Substring where
|
||||
@[inline] def Substring.bsize : Substring → Nat
|
||||
| ⟨_, b, e⟩ => e.byteIdx.sub b.byteIdx
|
||||
|
||||
/-- Returns the number of bytes required to encode this `Char` in UTF-8. -/
|
||||
def String.csize (c : Char) : Nat :=
|
||||
c.utf8Size.toNat
|
||||
|
||||
/--
|
||||
The UTF-8 byte length of this string.
|
||||
This is overridden by the compiler to be cached and O(1).
|
||||
@@ -2443,7 +2447,7 @@ def String.utf8ByteSize : (@& String) → Nat
|
||||
where
|
||||
go : List Char → Nat
|
||||
| .nil => 0
|
||||
| .cons c cs => hAdd (go cs) c.utf8Size
|
||||
| .cons c cs => hAdd (go cs) (csize c)
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
hAdd p₁ p₂ := { byteIdx := hAdd p₁.byteIdx p₂.byteIdx }
|
||||
@@ -2452,7 +2456,7 @@ instance : HSub String.Pos String.Pos String.Pos where
|
||||
hSub p₁ p₂ := { byteIdx := HSub.hSub p₁.byteIdx p₂.byteIdx }
|
||||
|
||||
instance : HAdd String.Pos Char String.Pos where
|
||||
hAdd p c := { byteIdx := hAdd p.byteIdx c.utf8Size }
|
||||
hAdd p c := { byteIdx := hAdd p.byteIdx (String.csize c) }
|
||||
|
||||
instance : HAdd String.Pos String String.Pos where
|
||||
hAdd p s := { byteIdx := hAdd p.byteIdx s.utf8ByteSize }
|
||||
@@ -2973,7 +2977,7 @@ def MonadExcept.ofExcept [Monad m] [MonadExcept ε m] : Except ε α → m α
|
||||
|
||||
export MonadExcept (throw tryCatch ofExcept)
|
||||
|
||||
instance (ε : Type u) (m : Type v → Type w) [MonadExceptOf ε m] : MonadExcept ε m where
|
||||
instance (ε : outParam (Type u)) (m : Type v → Type w) [MonadExceptOf ε m] : MonadExcept ε m where
|
||||
throw := throwThe ε
|
||||
tryCatch := tryCatchThe ε
|
||||
|
||||
@@ -3147,7 +3151,7 @@ instance (ρ : Type u) (m : Type u → Type v) [MonadWithReaderOf ρ m] : MonadW
|
||||
instance {ρ : Type u} {m : Type u → Type v} {n : Type u → Type v} [MonadFunctor m n] [MonadWithReaderOf ρ m] : MonadWithReaderOf ρ n where
|
||||
withReader f := monadMap (m := m) (withTheReader ρ f)
|
||||
|
||||
instance {ρ : Type u} {m : Type u → Type v} : MonadWithReaderOf ρ (ReaderT ρ m) where
|
||||
instance {ρ : Type u} {m : Type u → Type v} [Monad m] : MonadWithReaderOf ρ (ReaderT ρ m) where
|
||||
withReader f x := fun ctx => x (f ctx)
|
||||
|
||||
/--
|
||||
@@ -3172,8 +3176,8 @@ class MonadStateOf (σ : semiOutParam (Type u)) (m : Type u → Type v) where
|
||||
export MonadStateOf (set)
|
||||
|
||||
/--
|
||||
Like `get`, but with `σ` explicit. This is useful if a monad supports
|
||||
`MonadStateOf` for multiple different types `σ`.
|
||||
Like `withReader`, but with `ρ` explicit. This is useful if a monad supports
|
||||
`MonadWithReaderOf` for multiple different types `ρ`.
|
||||
-/
|
||||
abbrev getThe (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] : m σ :=
|
||||
MonadStateOf.get
|
||||
@@ -3230,7 +3234,7 @@ def modify {σ : Type u} {m : Type u → Type v} [MonadState σ m] (f : σ →
|
||||
of the state. It is equivalent to `get <* modify f` but may be more efficient.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def getModify {σ : Type u} {m : Type u → Type v} [MonadState σ m] (f : σ → σ) : m σ :=
|
||||
def getModify {σ : Type u} {m : Type u → Type v} [MonadState σ m] [Monad m] (f : σ → σ) : m σ :=
|
||||
modifyGet fun s => (s, f s)
|
||||
|
||||
-- NOTE: The Ordering of the following two instances determines that the top-most `StateT` Monad layer
|
||||
|
||||
@@ -253,9 +253,6 @@ end forall_congr
|
||||
|
||||
@[simp] theorem not_exists : (¬∃ x, p x) ↔ ∀ x, ¬p x := exists_imp
|
||||
|
||||
theorem forall_not_of_not_exists (h : ¬∃ x, p x) : ∀ x, ¬p x := not_exists.mp h
|
||||
theorem not_exists_of_forall_not (h : ∀ x, ¬p x) : ¬∃ x, p x := not_exists.mpr h
|
||||
|
||||
theorem forall_and : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) :=
|
||||
⟨fun h => ⟨fun x => (h x).1, fun x => (h x).2⟩, fun ⟨h₁, h₂⟩ x => ⟨h₁ x, h₂ x⟩⟩
|
||||
|
||||
@@ -295,8 +292,6 @@ theorem not_forall_of_exists_not {p : α → Prop} : (∃ x, ¬p x) → ¬∀ x,
|
||||
|
||||
@[simp] theorem exists_eq_left' : (∃ a, a' = a ∧ p a) ↔ p a' := by simp [@eq_comm _ a']
|
||||
|
||||
@[simp] theorem exists_eq_right' : (∃ a, p a ∧ a' = a) ↔ p a' := by simp [@eq_comm _ a']
|
||||
|
||||
@[simp] theorem forall_eq_or_imp : (∀ a, a = a' ∨ q a → p a) ↔ p a' ∧ ∀ a, q a → p a := by
|
||||
simp only [or_imp, forall_and, forall_eq]
|
||||
|
||||
@@ -309,11 +304,6 @@ theorem not_forall_of_exists_not {p : α → Prop} : (∃ x, ¬p x) → ¬∀ x,
|
||||
@[simp] theorem exists_eq_right_right' : (∃ (a : α), p a ∧ q a ∧ a' = a) ↔ p a' ∧ q a' := by
|
||||
simp [@eq_comm _ a']
|
||||
|
||||
@[simp] theorem exists_or_eq_left (y : α) (p : α → Prop) : ∃ x : α, x = y ∨ p x := ⟨y, .inl rfl⟩
|
||||
@[simp] theorem exists_or_eq_right (y : α) (p : α → Prop) : ∃ x : α, p x ∨ x = y := ⟨y, .inr rfl⟩
|
||||
@[simp] theorem exists_or_eq_left' (y : α) (p : α → Prop) : ∃ x : α, y = x ∨ p x := ⟨y, .inl rfl⟩
|
||||
@[simp] theorem exists_or_eq_right' (y : α) (p : α → Prop) : ∃ x : α, p x ∨ y = x := ⟨y, .inr rfl⟩
|
||||
|
||||
@[simp] theorem exists_prop : (∃ _h : a, b) ↔ a ∧ b :=
|
||||
⟨fun ⟨hp, hq⟩ => ⟨hp, hq⟩, fun ⟨hp, hq⟩ => ⟨hp, hq⟩⟩
|
||||
|
||||
@@ -378,6 +368,9 @@ else isTrue fun h2 => absurd h2 h
|
||||
|
||||
theorem decide_eq_true_iff (p : Prop) [Decidable p] : (decide p = true) ↔ p := by simp
|
||||
|
||||
@[simp] theorem decide_eq_false_iff_not (p : Prop) {_ : Decidable p} : (decide p = false) ↔ ¬p :=
|
||||
⟨of_decide_eq_false, decide_eq_false⟩
|
||||
|
||||
@[simp] theorem decide_eq_decide {p q : Prop} {_ : Decidable p} {_ : Decidable q} :
|
||||
decide p = decide q ↔ (p ↔ q) :=
|
||||
⟨fun h => by rw [← decide_eq_true_iff p, h, decide_eq_true_iff], fun h => by simp [h]⟩
|
||||
|
||||
@@ -102,11 +102,3 @@ instance ShareCommonT.monadShareCommon [Monad m] : MonadShareCommon (ShareCommon
|
||||
|
||||
@[inline] def ShareCommonT.run [Monad m] (x : ShareCommonT σ m α) : m α := x.run' default
|
||||
@[inline] def ShareCommonM.run (x : ShareCommonM σ α) : α := ShareCommonT.run x
|
||||
|
||||
/--
|
||||
A more restrictive but efficient max sharing primitive.
|
||||
|
||||
Remark: it optimizes the number of RC operations, and the strategy for caching results.
|
||||
-/
|
||||
@[extern "lean_sharecommon_quick"]
|
||||
def ShareCommon.shareCommon' (a : α) : α := a
|
||||
|
||||
@@ -129,7 +129,6 @@ instance : Std.LawfulIdentity Or False where
|
||||
@[simp] theorem iff_false (p : Prop) : (p ↔ False) = ¬p := propext ⟨(·.1), (⟨·, False.elim⟩)⟩
|
||||
@[simp] theorem false_iff (p : Prop) : (False ↔ p) = ¬p := propext ⟨(·.2), (⟨False.elim, ·⟩)⟩
|
||||
@[simp] theorem false_implies (p : Prop) : (False → p) = True := eq_true False.elim
|
||||
@[simp] theorem forall_false (p : False → Prop) : (∀ h : False, p h) = True := eq_true (False.elim ·)
|
||||
@[simp] theorem implies_true (α : Sort u) : (α → True) = True := eq_true fun _ => trivial
|
||||
@[simp] theorem true_implies (p : Prop) : (True → p) = p := propext ⟨(· trivial), (fun _ => ·)⟩
|
||||
@[simp] theorem not_false_eq_true : (¬ False) = True := eq_true False.elim
|
||||
@@ -229,22 +228,25 @@ instance : Std.Associative (· || ·) := ⟨Bool.or_assoc⟩
|
||||
@[simp] theorem Bool.not_not (b : Bool) : (!!b) = b := by cases b <;> rfl
|
||||
@[simp] theorem Bool.not_true : (!true) = false := by decide
|
||||
@[simp] theorem Bool.not_false : (!false) = true := by decide
|
||||
@[simp] theorem beq_true (b : Bool) : (b == true) = b := by cases b <;> rfl
|
||||
@[simp] theorem beq_false (b : Bool) : (b == false) = !b := by cases b <;> rfl
|
||||
@[simp] theorem Bool.not_beq_true (b : Bool) : (!(b == true)) = (b == false) := by cases b <;> rfl
|
||||
@[simp] theorem Bool.not_beq_false (b : Bool) : (!(b == false)) = (b == true) := by cases b <;> rfl
|
||||
@[simp] theorem Bool.not_eq_true' (b : Bool) : ((!b) = true) = (b = false) := by cases b <;> simp
|
||||
@[simp] theorem Bool.not_eq_false' (b : Bool) : ((!b) = false) = (b = true) := by cases b <;> simp
|
||||
|
||||
@[simp] theorem Bool.beq_to_eq (a b : Bool) :
|
||||
(a == b) = (a = b) := by cases a <;> cases b <;> decide
|
||||
@[simp] theorem Bool.not_beq_to_not_eq (a b : Bool) :
|
||||
(!(a == b)) = ¬(a = b) := by cases a <;> cases b <;> decide
|
||||
|
||||
@[simp] theorem Bool.not_eq_true (b : Bool) : (¬(b = true)) = (b = false) := by cases b <;> decide
|
||||
@[simp] theorem Bool.not_eq_false (b : Bool) : (¬(b = false)) = (b = true) := by cases b <;> decide
|
||||
|
||||
@[simp] theorem decide_eq_true_eq [Decidable p] : (decide p = true) = p :=
|
||||
propext <| Iff.intro of_decide_eq_true decide_eq_true
|
||||
@[simp] theorem decide_eq_false_iff_not {_ : Decidable p} : (decide p = false) ↔ ¬p :=
|
||||
⟨of_decide_eq_false, decide_eq_false⟩
|
||||
|
||||
@[simp] theorem decide_not [g : Decidable p] [h : Decidable (Not p)] : decide (Not p) = !(decide p) := by
|
||||
cases g <;> (rename_i gp; simp [gp]; rfl)
|
||||
@[simp] theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by simp
|
||||
@[simp] theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by
|
||||
cases h <;> (rename_i hp; simp [decide, hp])
|
||||
|
||||
@[simp] theorem heq_eq_eq (a b : α) : HEq a b = (a = b) := propext <| Iff.intro eq_of_heq heq_of_eq
|
||||
|
||||
@@ -252,10 +254,10 @@ instance : Std.Associative (· || ·) := ⟨Bool.or_assoc⟩
|
||||
@[simp] theorem cond_false (a b : α) : cond false a b = b := rfl
|
||||
|
||||
@[simp] theorem beq_self_eq_true [BEq α] [LawfulBEq α] (a : α) : (a == a) = true := LawfulBEq.rfl
|
||||
theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp
|
||||
@[simp] theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp [BEq.beq]
|
||||
|
||||
@[simp] theorem bne_self_eq_false [BEq α] [LawfulBEq α] (a : α) : (a != a) = false := by simp [bne]
|
||||
theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp
|
||||
@[simp] theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp [bne]
|
||||
|
||||
@[simp] theorem decide_False : decide False = false := rfl
|
||||
@[simp] theorem decide_True : decide True = true := rfl
|
||||
@@ -281,10 +283,7 @@ These will both normalize to `a = b` with the first via `bne_eq_false_iff_eq`.
|
||||
rw [bne, ← beq_iff_eq a b]
|
||||
cases a == b <;> decide
|
||||
|
||||
theorem Bool.beq_to_eq (a b : Bool) : (a == b) = (a = b) := by simp
|
||||
theorem Bool.not_beq_to_not_eq (a b : Bool) : (!(a == b)) = ¬(a = b) := by simp
|
||||
|
||||
/- # Nat -/
|
||||
/-# Nat -/
|
||||
|
||||
@[simp] theorem Nat.le_zero_eq (a : Nat) : (a ≤ 0) = (a = 0) :=
|
||||
propext ⟨fun h => Nat.le_antisymm h (Nat.zero_le ..), fun h => by rw [h]; decide⟩
|
||||
|
||||
@@ -712,17 +712,8 @@ structure Child (cfg : StdioConfig) where
|
||||
|
||||
@[extern "lean_io_process_spawn"] opaque spawn (args : SpawnArgs) : IO (Child args.toStdioConfig)
|
||||
|
||||
/--
|
||||
Block until the child process has exited and return its exit code.
|
||||
-/
|
||||
@[extern "lean_io_process_child_wait"] opaque Child.wait {cfg : @& StdioConfig} : @& Child cfg → IO UInt32
|
||||
|
||||
/--
|
||||
Check whether the child has exited yet. If it hasn't return none, otherwise its exit code.
|
||||
-/
|
||||
@[extern "lean_io_process_child_try_wait"] opaque Child.tryWait {cfg : @& StdioConfig} : @& Child cfg →
|
||||
IO (Option UInt32)
|
||||
|
||||
/-- Terminates the child process using the SIGTERM signal or a platform analogue.
|
||||
If the process was started using `SpawnArgs.setsid`, terminates the entire process group instead. -/
|
||||
@[extern "lean_io_process_child_kill"] opaque Child.kill {cfg : @& StdioConfig} : @& Child cfg → IO Unit
|
||||
@@ -823,10 +814,6 @@ def set (tk : CancelToken) : BaseIO Unit :=
|
||||
def isSet (tk : CancelToken) : BaseIO Bool :=
|
||||
tk.ref.get
|
||||
|
||||
-- separate definition as otherwise no unboxed version is generated
|
||||
@[export lean_io_cancel_token_is_set]
|
||||
private def isSetExport := @isSet
|
||||
|
||||
end CancelToken
|
||||
|
||||
namespace FS
|
||||
|
||||
@@ -267,9 +267,7 @@ syntax (name := case') "case' " sepBy1(caseArg, " | ") " => " tacticSeq : tactic
|
||||
`next x₁ ... xₙ => tac` additionally renames the `n` most recent hypotheses with
|
||||
inaccessible names to the given names.
|
||||
-/
|
||||
macro "next " args:binderIdent* arrowTk:" => " tac:tacticSeq : tactic =>
|
||||
-- Limit ref variability for incrementality; see Note [Incremental Macros]
|
||||
withRef arrowTk `(tactic| case _ $args* =>%$arrowTk $tac)
|
||||
macro "next " args:binderIdent* " => " tac:tacticSeq : tactic => `(tactic| case _ $args* => $tac)
|
||||
|
||||
/-- `all_goals tac` runs `tac` on each goal, concatenating the resulting goals, if any. -/
|
||||
syntax (name := allGoals) "all_goals " tacticSeq : tactic
|
||||
@@ -373,8 +371,7 @@ reflexivity theorems (e.g., `Iff.rfl`).
|
||||
macro "rfl" : tactic => `(tactic| case' _ => fail "The rfl tactic failed. Possible reasons:
|
||||
- The goal is not a reflexive relation (neither `=` nor a relation with a @[refl] lemma).
|
||||
- The arguments of the relation are not equal.
|
||||
Try using the reflexivity lemma for your relation explicitly, e.g. `exact Eq.refl _` or
|
||||
`exact HEq.rfl` etc.")
|
||||
Try using the reflexivitiy lemma for your relation explicitly, e.g. `exact Eq.rfl`.")
|
||||
|
||||
macro_rules | `(tactic| rfl) => `(tactic| eq_refl)
|
||||
macro_rules | `(tactic| rfl) => `(tactic| exact HEq.rfl)
|
||||
@@ -1462,7 +1459,6 @@ have been simplified by using the modifier `↓`. Here is an example
|
||||
```
|
||||
|
||||
When multiple simp theorems are applicable, the simplifier uses the one with highest priority.
|
||||
The equational theorems of function are applied at very low priority (100 and below).
|
||||
If there are several with the same priority, it is uses the "most recent one". Example:
|
||||
```lean
|
||||
@[simp high] theorem cond_true (a b : α) : cond true a b = a := rfl
|
||||
|
||||
@@ -31,19 +31,15 @@ private def expandIfThenElse
|
||||
pure (hole, #[case])
|
||||
let (posHole, posCase) ← mkCase thenTk pos `(?pos)
|
||||
let (negHole, negCase) ← mkCase elseTk neg `(?neg)
|
||||
`(tactic| ((open Classical in refine%$ifTk $(← mkIf posHole negHole)); $[$(posCase ++ negCase)]*))
|
||||
`(tactic| (open Classical in refine%$ifTk $(← mkIf posHole negHole); $[$(posCase ++ negCase)]*))
|
||||
|
||||
macro_rules
|
||||
| `(tactic| if%$tk $h : $c then%$ttk $pos else%$etk $neg) =>
|
||||
-- Limit ref variability for incrementality; see Note [Incremental Macros]
|
||||
withRef tk do
|
||||
expandIfThenElse tk ttk etk pos neg fun pos neg => `(if $h : $c then $pos else $neg)
|
||||
expandIfThenElse tk ttk etk pos neg fun pos neg => `(if $h : $c then $pos else $neg)
|
||||
|
||||
macro_rules
|
||||
| `(tactic| if%$tk $c then%$ttk $pos else%$etk $neg) =>
|
||||
-- Limit ref variability for incrementality; see Note [Incremental Macros]
|
||||
withRef tk do
|
||||
expandIfThenElse tk ttk etk pos neg fun pos neg => `(if h : $c then $pos else $neg)
|
||||
expandIfThenElse tk ttk etk pos neg fun pos neg => `(if h : $c then $pos else $neg)
|
||||
|
||||
/--
|
||||
`iterate n tac` runs `tac` exactly `n` times.
|
||||
|
||||
@@ -45,13 +45,6 @@ def dbgSleep {α : Type u} (ms : UInt32) (f : Unit → α) : α := f ()
|
||||
@[extern "lean_ptr_addr"]
|
||||
unsafe opaque ptrAddrUnsafe {α : Type u} (a : @& α) : USize
|
||||
|
||||
/--
|
||||
Returns `true` if `a` is an exclusive object.
|
||||
We say an object is exclusive if it is single-threaded and its reference counter is 1.
|
||||
-/
|
||||
@[extern "lean_is_exclusive_obj"]
|
||||
unsafe opaque isExclusiveUnsafe {α : Type u} (a : @& α) : Bool
|
||||
|
||||
set_option linter.unusedVariables.funArgs false in
|
||||
@[inline] unsafe def withPtrAddrUnsafe {α : Type u} {β : Type v} (a : α) (k : USize → β) (h : ∀ u₁ u₂, k u₁ = k u₂) : β :=
|
||||
k (ptrAddrUnsafe a)
|
||||
|
||||
@@ -37,7 +37,7 @@ noncomputable abbrev Acc.ndrecOn.{u1, u2} {α : Sort u2} {r : α → α → Prop
|
||||
namespace Acc
|
||||
variable {α : Sort u} {r : α → α → Prop}
|
||||
|
||||
theorem inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
|
||||
def inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
|
||||
h₁.recOn (fun _ ac₁ _ h₂ => ac₁ y h₂) h₂
|
||||
|
||||
end Acc
|
||||
@@ -58,7 +58,7 @@ class WellFoundedRelation (α : Sort u) where
|
||||
wf : WellFounded rel
|
||||
|
||||
namespace WellFounded
|
||||
theorem apply {α : Sort u} {r : α → α → Prop} (wf : WellFounded r) (a : α) : Acc r a :=
|
||||
def apply {α : Sort u} {r : α → α → Prop} (wf : WellFounded r) (a : α) : Acc r a :=
|
||||
wf.rec (fun p => p) a
|
||||
|
||||
section
|
||||
@@ -78,7 +78,7 @@ noncomputable def fixF (x : α) (a : Acc r x) : C x := by
|
||||
induction a with
|
||||
| intro x₁ _ ih => exact F x₁ ih
|
||||
|
||||
theorem fixFEq (x : α) (acx : Acc r x) : fixF F x acx = F x (fun (y : α) (p : r y x) => fixF F y (Acc.inv acx p)) := by
|
||||
def fixFEq (x : α) (acx : Acc r x) : fixF F x acx = F x (fun (y : α) (p : r y x) => fixF F y (Acc.inv acx p)) := by
|
||||
induction acx with
|
||||
| intro x r _ => exact rfl
|
||||
|
||||
@@ -112,14 +112,14 @@ def emptyWf {α : Sort u} : WellFoundedRelation α where
|
||||
namespace Subrelation
|
||||
variable {α : Sort u} {r q : α → α → Prop}
|
||||
|
||||
theorem accessible {a : α} (h₁ : Subrelation q r) (ac : Acc r a) : Acc q a := by
|
||||
def accessible {a : α} (h₁ : Subrelation q r) (ac : Acc r a) : Acc q a := by
|
||||
induction ac with
|
||||
| intro x _ ih =>
|
||||
apply Acc.intro
|
||||
intro y h
|
||||
exact ih y (h₁ h)
|
||||
|
||||
theorem wf (h₁ : Subrelation q r) (h₂ : WellFounded r) : WellFounded q :=
|
||||
def wf (h₁ : Subrelation q r) (h₂ : WellFounded r) : WellFounded q :=
|
||||
⟨fun a => accessible @h₁ (apply h₂ a)⟩
|
||||
end Subrelation
|
||||
|
||||
@@ -136,10 +136,10 @@ private def accAux (f : α → β) {b : β} (ac : Acc r b) : (x : α) → f x =
|
||||
subst x
|
||||
apply ih (f y) lt y rfl
|
||||
|
||||
theorem accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
|
||||
def accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
|
||||
accAux f ac a rfl
|
||||
|
||||
theorem wf (f : α → β) (h : WellFounded r) : WellFounded (InvImage r f) :=
|
||||
def wf (f : α → β) (h : WellFounded r) : WellFounded (InvImage r f) :=
|
||||
⟨fun a => accessible f (apply h (f a))⟩
|
||||
end InvImage
|
||||
|
||||
@@ -148,26 +148,22 @@ end InvImage
|
||||
wf := InvImage.wf f h.wf
|
||||
|
||||
-- The transitive closure of a well-founded relation is well-founded
|
||||
open Relation
|
||||
namespace TC
|
||||
variable {α : Sort u} {r : α → α → Prop}
|
||||
|
||||
theorem Acc.transGen (h : Acc r a) : Acc (TransGen r) a := by
|
||||
induction h with
|
||||
| intro x _ H =>
|
||||
refine Acc.intro x fun y hy ↦ ?_
|
||||
cases hy with
|
||||
| single hyx =>
|
||||
exact H y hyx
|
||||
| tail hyz hzx =>
|
||||
exact (H _ hzx).inv hyz
|
||||
def accessible {z : α} (ac : Acc r z) : Acc (TC r) z := by
|
||||
induction ac with
|
||||
| intro x acx ih =>
|
||||
apply Acc.intro x
|
||||
intro y rel
|
||||
induction rel with
|
||||
| base a b rab => exact ih a rab
|
||||
| trans a b c rab _ _ ih₂ => apply Acc.inv (ih₂ acx ih) rab
|
||||
|
||||
theorem acc_transGen_iff : Acc (TransGen r) a ↔ Acc r a :=
|
||||
⟨Subrelation.accessible TransGen.single, Acc.transGen⟩
|
||||
def wf (h : WellFounded r) : WellFounded (TC r) :=
|
||||
⟨fun a => accessible (apply h a)⟩
|
||||
end TC
|
||||
|
||||
theorem WellFounded.transGen (h : WellFounded r) : WellFounded (TransGen r) :=
|
||||
⟨fun a ↦ (h.apply a).transGen⟩
|
||||
|
||||
@[deprecated Acc.transGen (since := "2024-07-16")] abbrev TC.accessible := @Acc.transGen
|
||||
@[deprecated WellFounded.transGen (since := "2024-07-16")] abbrev TC.wf := @WellFounded.transGen
|
||||
namespace Nat
|
||||
|
||||
-- less-than is well-founded
|
||||
@@ -255,7 +251,7 @@ instance [αeqDec : DecidableEq α] {r : α → α → Prop} [rDec : DecidableRe
|
||||
apply isFalse; intro contra; cases contra <;> contradiction
|
||||
|
||||
-- TODO: generalize
|
||||
theorem right' {a₁ : Nat} {b₁ : β} (h₁ : a₁ ≤ a₂) (h₂ : rb b₁ b₂) : Prod.Lex Nat.lt rb (a₁, b₁) (a₂, b₂) :=
|
||||
def right' {a₁ : Nat} {b₁ : β} (h₁ : a₁ ≤ a₂) (h₂ : rb b₁ b₂) : Prod.Lex Nat.lt rb (a₁, b₁) (a₂, b₂) :=
|
||||
match Nat.eq_or_lt_of_le h₁ with
|
||||
| Or.inl h => h ▸ Prod.Lex.right a₁ h₂
|
||||
| Or.inr h => Prod.Lex.left b₁ _ h
|
||||
@@ -272,7 +268,7 @@ section
|
||||
variable {α : Type u} {β : Type v}
|
||||
variable {ra : α → α → Prop} {rb : β → β → Prop}
|
||||
|
||||
theorem lexAccessible {a : α} (aca : Acc ra a) (acb : (b : β) → Acc rb b) (b : β) : Acc (Prod.Lex ra rb) (a, b) := by
|
||||
def lexAccessible {a : α} (aca : Acc ra a) (acb : (b : β) → Acc rb b) (b : β) : Acc (Prod.Lex ra rb) (a, b) := by
|
||||
induction aca generalizing b with
|
||||
| intro xa _ iha =>
|
||||
induction (acb b) with
|
||||
@@ -292,7 +288,7 @@ instance [ha : WellFoundedRelation α] [hb : WellFoundedRelation β] : WellFound
|
||||
lex ha hb
|
||||
|
||||
-- relational product is a Subrelation of the Lex
|
||||
theorem RProdSubLex (a : α × β) (b : α × β) (h : RProd ra rb a b) : Prod.Lex ra rb a b := by
|
||||
def RProdSubLex (a : α × β) (b : α × β) (h : RProd ra rb a b) : Prod.Lex ra rb a b := by
|
||||
cases h with
|
||||
| intro h₁ h₂ => exact Prod.Lex.left _ _ h₁
|
||||
|
||||
@@ -324,7 +320,7 @@ section
|
||||
variable {α : Sort u} {β : α → Sort v}
|
||||
variable {r : α → α → Prop} {s : ∀ (a : α), β a → β a → Prop}
|
||||
|
||||
theorem lexAccessible {a} (aca : Acc r a) (acb : (a : α) → WellFounded (s a)) (b : β a) : Acc (Lex r s) ⟨a, b⟩ := by
|
||||
def lexAccessible {a} (aca : Acc r a) (acb : (a : α) → WellFounded (s a)) (b : β a) : Acc (Lex r s) ⟨a, b⟩ := by
|
||||
induction aca with
|
||||
| intro xa _ iha =>
|
||||
induction (WellFounded.apply (acb xa) b) with
|
||||
@@ -351,7 +347,7 @@ variable {α : Sort u} {β : Sort v}
|
||||
def lexNdep (r : α → α → Prop) (s : β → β → Prop) :=
|
||||
Lex r (fun _ => s)
|
||||
|
||||
theorem lexNdepWf {r : α → α → Prop} {s : β → β → Prop} (ha : WellFounded r) (hb : WellFounded s) : WellFounded (lexNdep r s) :=
|
||||
def lexNdepWf {r : α → α → Prop} {s : β → β → Prop} (ha : WellFounded r) (hb : WellFounded s) : WellFounded (lexNdep r s) :=
|
||||
WellFounded.intro fun ⟨a, b⟩ => lexAccessible (WellFounded.apply ha a) (fun _ => hb) b
|
||||
end
|
||||
|
||||
@@ -369,7 +365,7 @@ open WellFounded
|
||||
variable {α : Sort u} {β : Sort v}
|
||||
variable {r : α → α → Prop} {s : β → β → Prop}
|
||||
|
||||
theorem revLexAccessible {b} (acb : Acc s b) (aca : (a : α) → Acc r a): (a : α) → Acc (RevLex r s) ⟨a, b⟩ := by
|
||||
def revLexAccessible {b} (acb : Acc s b) (aca : (a : α) → Acc r a): (a : α) → Acc (RevLex r s) ⟨a, b⟩ := by
|
||||
induction acb with
|
||||
| intro xb _ ihb =>
|
||||
intro a
|
||||
@@ -381,7 +377,7 @@ theorem revLexAccessible {b} (acb : Acc s b) (aca : (a : α) → Acc r a): (a :
|
||||
| left => apply iha; assumption
|
||||
| right => apply ihb; assumption
|
||||
|
||||
theorem revLex (ha : WellFounded r) (hb : WellFounded s) : WellFounded (RevLex r s) :=
|
||||
def revLex (ha : WellFounded r) (hb : WellFounded s) : WellFounded (RevLex r s) :=
|
||||
WellFounded.intro fun ⟨a, b⟩ => revLexAccessible (apply hb b) (WellFounded.apply ha) a
|
||||
end
|
||||
|
||||
@@ -393,7 +389,7 @@ def skipLeft (α : Type u) {β : Type v} (hb : WellFoundedRelation β) : WellFou
|
||||
rel := SkipLeft α hb.rel
|
||||
wf := revLex emptyWf.wf hb.wf
|
||||
|
||||
theorem mkSkipLeft {α : Type u} {β : Type v} {b₁ b₂ : β} {s : β → β → Prop} (a₁ a₂ : α) (h : s b₁ b₂) : SkipLeft α s ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ :=
|
||||
def mkSkipLeft {α : Type u} {β : Type v} {b₁ b₂ : β} {s : β → β → Prop} (a₁ a₂ : α) (h : s b₁ b₂) : SkipLeft α s ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ :=
|
||||
RevLex.right _ _ h
|
||||
end
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ before `omega` is available.
|
||||
-/
|
||||
syntax "decreasing_trivial_pre_omega" : tactic
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.sub_succ_lt_self; assumption) -- a - (i+1) < a - i if i < a
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt_of_lt; assumption) -- i-1 < i if j < i
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt'; assumption) -- i-1 < i if j < i
|
||||
macro_rules | `(tactic| decreasing_trivial_pre_omega) => `(tactic| apply Nat.pred_lt; assumption) -- i-1 < i if i ≠ 0
|
||||
|
||||
|
||||
|
||||
@@ -8,22 +8,11 @@ import Lean.CoreM
|
||||
|
||||
namespace Lean
|
||||
|
||||
register_builtin_option debug.skipKernelTC : Bool := {
|
||||
defValue := false
|
||||
group := "debug"
|
||||
descr := "skip kernel type checker. WARNING: setting this option to true may compromise soundness because your proofs will not be checked by the Lean kernel"
|
||||
}
|
||||
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration) : Except KernelException Environment :=
|
||||
addDeclCore env (Core.getMaxHeartbeats opts).toUSize decl
|
||||
|
||||
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except KernelException Environment :=
|
||||
if debug.skipKernelTC.get opts then
|
||||
addDeclWithoutChecking env decl
|
||||
else
|
||||
addDeclCore env (Core.getMaxHeartbeats opts).toUSize decl cancelTk?
|
||||
|
||||
def Environment.addAndCompile (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except KernelException Environment := do
|
||||
let env ← addDecl env opts decl cancelTk?
|
||||
def Environment.addAndCompile (env : Environment) (opts : Options) (decl : Declaration) : Except KernelException Environment := do
|
||||
let env ← addDecl env opts decl
|
||||
compileDecl env opts decl
|
||||
|
||||
def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
@@ -31,7 +20,7 @@ def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
withTraceNode `Kernel (fun _ => return m!"typechecking declaration") do
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
logWarning "declaration uses 'sorry'"
|
||||
match (← getEnv).addDecl (← getOptions) decl (← read).cancelTk? with
|
||||
match (← getEnv).addDecl (← getOptions) decl with
|
||||
| .ok env => setEnv env
|
||||
| .error ex => throwKernelException ex
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ structure AttributeImpl extends AttributeImplCore where
|
||||
erase (decl : Name) : AttrM Unit := throwError "attribute cannot be erased"
|
||||
deriving Inhabited
|
||||
|
||||
builtin_initialize attributeMapRef : IO.Ref (HashMap Name AttributeImpl) ← IO.mkRef {}
|
||||
builtin_initialize attributeMapRef : IO.Ref (PersistentHashMap Name AttributeImpl) ← IO.mkRef {}
|
||||
|
||||
/-- Low level attribute registration function. -/
|
||||
def registerBuiltinAttribute (attr : AttributeImpl) : IO Unit := do
|
||||
@@ -185,7 +185,7 @@ structure ParametricAttributeImpl (α : Type) extends AttributeImplCore where
|
||||
afterSet : Name → α → AttrM Unit := fun _ _ _ => pure ()
|
||||
afterImport : Array (Array (Name × α)) → ImportM Unit := fun _ => pure ()
|
||||
|
||||
def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (ParametricAttribute α) := do
|
||||
def registerParametricAttribute [Inhabited α] (impl : ParametricAttributeImpl α) : IO (ParametricAttribute α) := do
|
||||
let ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α) ← registerPersistentEnvExtension {
|
||||
name := impl.ref
|
||||
mkInitial := pure {}
|
||||
@@ -239,7 +239,7 @@ structure EnumAttributes (α : Type) where
|
||||
ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α)
|
||||
deriving Inhabited
|
||||
|
||||
def registerEnumAttributes (attrDescrs : List (Name × String × α))
|
||||
def registerEnumAttributes [Inhabited α] (attrDescrs : List (Name × String × α))
|
||||
(validate : Name → α → AttrM Unit := fun _ _ => pure ())
|
||||
(applicationTime := AttributeApplicationTime.afterTypeChecking)
|
||||
(ref : Name := by exact decl_name%) : IO (EnumAttributes α) := do
|
||||
@@ -317,7 +317,7 @@ inductive AttributeExtensionOLeanEntry where
|
||||
|
||||
structure AttributeExtensionState where
|
||||
newEntries : List AttributeExtensionOLeanEntry := []
|
||||
map : HashMap Name AttributeImpl
|
||||
map : PersistentHashMap Name AttributeImpl
|
||||
deriving Inhabited
|
||||
|
||||
abbrev AttributeExtension := PersistentEnvExtension AttributeExtensionOLeanEntry (AttributeExtensionOLeanEntry × AttributeImpl) AttributeExtensionState
|
||||
@@ -348,7 +348,7 @@ private def AttributeExtension.addImported (es : Array (Array AttributeExtension
|
||||
let map ← es.foldlM
|
||||
(fun map entries =>
|
||||
entries.foldlM
|
||||
(fun (map : HashMap Name AttributeImpl) entry => do
|
||||
(fun (map : PersistentHashMap Name AttributeImpl) entry => do
|
||||
let attrImpl ← mkAttributeImplOfEntry ctx.env ctx.opts entry
|
||||
return map.insert attrImpl.name attrImpl)
|
||||
map)
|
||||
@@ -374,7 +374,7 @@ def isBuiltinAttribute (n : Name) : IO Bool := do
|
||||
|
||||
/-- Return the name of all registered attributes. -/
|
||||
def getBuiltinAttributeNames : IO (List Name) :=
|
||||
return (← attributeMapRef.get).fold (init := []) fun r n _ => n::r
|
||||
return (← attributeMapRef.get).foldl (init := []) fun r n _ => n::r
|
||||
|
||||
def getBuiltinAttributeImpl (attrName : Name) : IO AttributeImpl := do
|
||||
let m ← attributeMapRef.get
|
||||
@@ -392,7 +392,7 @@ def isAttribute (env : Environment) (attrName : Name) : Bool :=
|
||||
|
||||
def getAttributeNames (env : Environment) : List Name :=
|
||||
let m := (attributeExtension.getState env).map
|
||||
m.fold (fun r n _ => n::r) []
|
||||
m.foldl (fun r n _ => n::r) []
|
||||
|
||||
def getAttributeImpl (env : Environment) (attrName : Name) : Except String AttributeImpl :=
|
||||
let m := (attributeExtension.getState env).map
|
||||
@@ -427,7 +427,7 @@ def Attribute.erase (declName : Name) (attrName : Name) : AttrM Unit := do
|
||||
def updateEnvAttributesImpl (env : Environment) : IO Environment := do
|
||||
let map ← attributeMapRef.get
|
||||
let s := attributeExtension.getState env
|
||||
let s := map.fold (init := s) fun s attrName attrImpl =>
|
||||
let s := map.foldl (init := s) fun s attrName attrImpl =>
|
||||
if s.map.contains attrName then
|
||||
s
|
||||
else
|
||||
|
||||
@@ -13,17 +13,16 @@ def recOnSuffix := "recOn"
|
||||
def brecOnSuffix := "brecOn"
|
||||
def binductionOnSuffix := "binductionOn"
|
||||
def belowSuffix := "below"
|
||||
def ibelowSuffix := "ibelow"
|
||||
|
||||
def mkCasesOnName (indDeclName : Name) : Name := Name.mkStr indDeclName casesOnSuffix
|
||||
def mkRecOnName (indDeclName : Name) : Name := Name.mkStr indDeclName recOnSuffix
|
||||
def mkBRecOnName (indDeclName : Name) : Name := Name.mkStr indDeclName brecOnSuffix
|
||||
def mkBInductionOnName (indDeclName : Name) : Name := Name.mkStr indDeclName binductionOnSuffix
|
||||
def mkBelowName (indDeclName : Name) : Name := Name.mkStr indDeclName belowSuffix
|
||||
def mkIBelowName (indDeclName : Name) : Name := Name.mkStr indDeclName ibelowSuffix
|
||||
|
||||
builtin_initialize auxRecExt : TagDeclarationExtension ← mkTagDeclarationExtension
|
||||
|
||||
@[export lean_mark_aux_recursor]
|
||||
def markAuxRecursor (env : Environment) (declName : Name) : Environment :=
|
||||
auxRecExt.tag env declName
|
||||
|
||||
@@ -37,7 +36,7 @@ def isAuxRecursor (env : Environment) (declName : Name) : Bool :=
|
||||
|
||||
def isAuxRecursorWithSuffix (env : Environment) (declName : Name) (suffix : String) : Bool :=
|
||||
match declName with
|
||||
| .str _ s => (s == suffix || s.startsWith s!"{suffix}_") && isAuxRecursor env declName
|
||||
| .str _ s => s == suffix && isAuxRecursor env declName
|
||||
| _ => false
|
||||
|
||||
def isCasesOnRecursor (env : Environment) (declName : Name) : Bool :=
|
||||
@@ -51,6 +50,7 @@ def isBRecOnRecursor (env : Environment) (declName : Name) : Bool :=
|
||||
|
||||
builtin_initialize noConfusionExt : TagDeclarationExtension ← mkTagDeclarationExtension
|
||||
|
||||
@[export lean_mark_no_confusion]
|
||||
def markNoConfusion (env : Environment) (n : Name) : Environment :=
|
||||
noConfusionExt.tag env n
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ Authors: Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Lean.Compiler.InitAttr
|
||||
import Lean.DocString.Extension
|
||||
import Lean.DocString
|
||||
|
||||
namespace Lean
|
||||
|
||||
def declareBuiltinDocStringAndRanges (declName : Name) : AttrM Unit := do
|
||||
if let some doc ← findSimpleDocString? (← getEnv) declName (includeBuiltin := false) then
|
||||
if let some doc ← findDocString? (← getEnv) declName (includeBuiltin := false) then
|
||||
declareBuiltin (declName ++ `docString) (mkAppN (mkConst ``addBuiltinDocString) #[toExpr declName, toExpr doc])
|
||||
if let some declRanges ← findDeclarationRanges? declName then
|
||||
declareBuiltin (declName ++ `declRange) (mkAppN (mkConst ``addBuiltinDeclarationRanges) #[toExpr declName, toExpr declRanges])
|
||||
|
||||
@@ -18,13 +18,6 @@ private opaque getLeancExtraFlags : Unit → String
|
||||
def getCFlags (leanSysroot : FilePath) : Array String :=
|
||||
#["-I", (leanSysroot / "include").toString] ++ (getLeancExtraFlags ()).trim.splitOn
|
||||
|
||||
@[extern "lean_get_leanc_internal_flags"]
|
||||
private opaque getLeancInternalFlags : Unit → String
|
||||
|
||||
/-- Return C compiler flags needed to use the C compiler bundled with the Lean toolchain. -/
|
||||
def getInternalCFlags (leanSysroot : FilePath) : Array String :=
|
||||
(getLeancInternalFlags ()).trim.splitOn.toArray.map (·.replace "ROOT" leanSysroot.toString)
|
||||
|
||||
@[extern "lean_get_linker_flags"]
|
||||
private opaque getBuiltinLinkerFlags (linkStatic : Bool) : String
|
||||
|
||||
@@ -32,11 +25,4 @@ private opaque getBuiltinLinkerFlags (linkStatic : Bool) : String
|
||||
def getLinkerFlags (leanSysroot : FilePath) (linkStatic := true) : Array String :=
|
||||
#["-L", (leanSysroot / "lib" / "lean").toString] ++ (getBuiltinLinkerFlags linkStatic).trim.splitOn
|
||||
|
||||
@[extern "lean_get_internal_linker_flags"]
|
||||
private opaque getBuiltinInternalLinkerFlags : Unit → String
|
||||
|
||||
/-- Return linker flags needed to use the linker bundled with the Lean toolchain. -/
|
||||
def getInternalLinkerFlags (leanSysroot : FilePath) : Array String :=
|
||||
(getBuiltinInternalLinkerFlags ()).trim.splitOn.toArray.map (·.replace "ROOT" leanSysroot.toString)
|
||||
|
||||
end Lean.Compiler.FFI
|
||||
|
||||
@@ -94,7 +94,7 @@ def emitCInitName (n : Name) : M Unit :=
|
||||
def shouldExport (n : Name) : Bool :=
|
||||
-- HACK: exclude symbols very unlikely to be used by the interpreter or other consumers of
|
||||
-- libleanshared to avoid Windows symbol limit
|
||||
!(`Lean.Compiler.LCNF).isPrefixOf n && !(`Lean.IR).isPrefixOf n && !(`Lean.Server).isPrefixOf n
|
||||
!(`Lean.Compiler.LCNF).isPrefixOf n
|
||||
|
||||
def emitFnDeclAux (decl : Decl) (cppBaseName : String) (isExternal : Bool) : M Unit := do
|
||||
let ps := decl.params
|
||||
@@ -499,11 +499,7 @@ def emitLit (z : VarId) (t : IRType) (v : LitVal) : M Unit := do
|
||||
emitLhs z;
|
||||
match v with
|
||||
| LitVal.num v => emitNumLit t v; emitLn ";"
|
||||
| LitVal.str v =>
|
||||
emit "lean_mk_string_unchecked(";
|
||||
emit (quoteString v); emit ", ";
|
||||
emit v.utf8ByteSize; emit ", ";
|
||||
emit v.length; emitLn ");"
|
||||
| LitVal.str v => emit "lean_mk_string_from_bytes("; emit (quoteString v); emit ", "; emit v.utf8ByteSize; emitLn ");"
|
||||
|
||||
def emitVDecl (z : VarId) (t : IRType) (v : Expr) : M Unit :=
|
||||
match v with
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user