mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-23 21:34:10 +00:00
Compare commits
1 Commits
multiple_t
...
grind_modi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc58ef43ae |
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -4,9 +4,3 @@ RELEASES.md merge=union
|
||||
stage0/** binary linguist-generated
|
||||
# The following file is often manually edited, so do show it in diffs
|
||||
stage0/src/stdlib_flags.h -binary -linguist-generated
|
||||
# These files should not have line endings translated on Windows, because
|
||||
# it throws off parser tests. Later lines override earlier ones, so the
|
||||
# runner code is still treated as ordinary text.
|
||||
tests/lean/docparse/* eol=lf
|
||||
tests/lean/docparse/*.lean eol=auto
|
||||
tests/lean/docparse/*.sh eol=auto
|
||||
|
||||
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@v5
|
||||
uses: actions/checkout@v4
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
|
||||
4
.github/workflows/build-template.yml
vendored
4
.github/workflows/build-template.yml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v5
|
||||
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 }}
|
||||
@@ -229,7 +229,7 @@ jobs:
|
||||
id: test
|
||||
run: |
|
||||
ulimit -c unlimited # coredumps
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/$TARGET_STAGE -j$NPROC --output-junit test-results.xml
|
||||
if: (matrix.wasm || !matrix.cross) && (inputs.check-level >= 1 || matrix.test)
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
|
||||
2
.github/workflows/check-prelude.yml
vendored
2
.github/workflows/check-prelude.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
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 }}
|
||||
|
||||
2
.github/workflows/check-stage0.yml
vendored
2
.github/workflows/check-stage0.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
check-stage0-on-queue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
filter: blob:none
|
||||
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
# don't schedule nightlies on forks
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
- name: Set Nightly
|
||||
@@ -200,6 +200,8 @@ jobs:
|
||||
"os": "ubuntu-latest",
|
||||
"check-level": 2,
|
||||
"CMAKE_PRESET": "reldebug",
|
||||
// exclude seriously slow/stackoverflowing tests
|
||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress|3807'"
|
||||
},
|
||||
// TODO: suddenly started failing in CI
|
||||
/*{
|
||||
@@ -245,6 +247,8 @@ jobs:
|
||||
"check-level": 2,
|
||||
"shell": "msys2 {0}",
|
||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\"",
|
||||
// for reasons unknown, interactivetests are flaky on Windows
|
||||
"CTEST_OPTIONS": "--repeat until-pass:2",
|
||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/19.1.2/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
||||
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
|
||||
"binary-check": "ldd",
|
||||
@@ -363,7 +367,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
@@ -388,12 +392,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||
- uses: actions/download-artifact@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Prepare Nightly Release
|
||||
|
||||
2
.github/workflows/copyright-header.yml
vendored
2
.github/workflows/copyright-header.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
check-lean-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Verify .lean files start with a copyright header.
|
||||
run: |
|
||||
|
||||
6
.github/workflows/pr-release.yml
vendored
6
.github/workflows/pr-release.yml
vendored
@@ -395,7 +395,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@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -454,7 +454,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@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -524,7 +524,7 @@ jobs:
|
||||
# Checkout the reference manual repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: leanprover/reference-manual
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
|
||||
12
.github/workflows/update-stage0.yml
vendored
12
.github/workflows/update-stage0.yml
vendored
@@ -21,13 +21,11 @@ jobs:
|
||||
runs-on: nscloud-ubuntu-22.04-amd64-8x16
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
CCACHE_MAXSIZE: 400M
|
||||
steps:
|
||||
# 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@v5
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||
@@ -74,14 +72,10 @@ jobs:
|
||||
restore-keys: |
|
||||
Linux Lake-build-v3
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
# sync options with `Linux Lake` to ensure cache reuse
|
||||
run: |
|
||||
mkdir -p build
|
||||
cmake --preset release -B build -DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true
|
||||
run: cmake --preset release
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: |
|
||||
make -j$NPROC -C build update-stage0-commit
|
||||
run: make -j$NPROC -C build/release update-stage0-commit
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: git show --stat
|
||||
|
||||
@@ -2,19 +2,19 @@ This is the repository for **Lean 4**.
|
||||
|
||||
# About
|
||||
|
||||
- [Quickstart](https://lean-lang.org/install/)
|
||||
- [Quickstart](https://lean-lang.org/documentation/setup/)
|
||||
- [Homepage](https://lean-lang.org)
|
||||
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
|
||||
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
|
||||
- [Documentation Overview](https://lean-lang.org/learn/)
|
||||
- [Documentation Overview](https://lean-lang.org/documentation/)
|
||||
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
|
||||
- [Release notes](RELEASES.md) starting at v4.0.0-m3
|
||||
- [Examples](https://lean-lang.org/examples/)
|
||||
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
|
||||
- [External Contribution Guidelines](CONTRIBUTING.md)
|
||||
|
||||
# Installation
|
||||
|
||||
See [Install Lean](https://lean-lang.org/install/).
|
||||
See [Setting Up Lean](https://lean-lang.org/documentation/setup/).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ You should not edit the `stage0` directory except using the commands described i
|
||||
|
||||
## Development Setup
|
||||
|
||||
You can use any of the [supported editors](https://lean-lang.org/install/manual/) for editing the Lean source code.
|
||||
You can use any of the [supported editors](../setup.md) for editing the Lean source code.
|
||||
Please see below for specific instructions for VS Code.
|
||||
|
||||
### Dev setup using elan
|
||||
@@ -99,19 +99,3 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
|
||||
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
|
||||
and will report back to the Lean PR with results from Mathlib CI.
|
||||
|
||||
### Avoiding rebuilds for downstream projects
|
||||
|
||||
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
|
||||
|
||||
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
|
||||
```
|
||||
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
|
||||
```
|
||||
Alternatively, use
|
||||
```
|
||||
export LEAN_GITHASH=$(lean --githash)
|
||||
export ELAN_TOOLCHAIN=lean4
|
||||
```
|
||||
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
|
||||
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](../dev/index.md).
|
||||
|
||||
We strongly suggest that new users instead follow the [Installation Instructions](https://lean-lang.org/install/) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
We strongly suggest that new users instead follow the [Quickstart](../quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
@@ -37,15 +37,6 @@
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build-old",
|
||||
"type": "shell",
|
||||
"command": "make -C build/release -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) LAKE_EXTRA_ARGS=--old",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "build"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"type": "shell",
|
||||
|
||||
@@ -5,7 +5,6 @@ Merge a tag into a branch on a GitHub repository.
|
||||
|
||||
This script checks if a specified tag can be merged cleanly into a branch and performs
|
||||
the merge if possible. If the merge cannot be done cleanly, it prints a helpful message.
|
||||
Merge conflicts in the lean-toolchain file are automatically resolved by accepting the incoming changes.
|
||||
|
||||
Usage:
|
||||
python3 merge_remote.py <org/repo> <branch> <tag>
|
||||
@@ -59,32 +58,6 @@ def clone_repo(repo, temp_dir):
|
||||
return True
|
||||
|
||||
|
||||
def get_conflicted_files():
|
||||
"""Get list of files with merge conflicts."""
|
||||
result = run_command("git diff --name-only --diff-filter=U", check=False)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip().split('\n') if result.stdout.strip() else []
|
||||
return []
|
||||
|
||||
|
||||
def resolve_lean_toolchain_conflict(tag):
|
||||
"""Resolve lean-toolchain conflict by accepting incoming (tag) changes."""
|
||||
print("Resolving lean-toolchain conflict by accepting incoming changes...")
|
||||
# Accept theirs (incoming) version for lean-toolchain
|
||||
result = run_command(f"git checkout --theirs lean-toolchain", check=False)
|
||||
if result.returncode != 0:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
return False
|
||||
|
||||
# Add the resolved file
|
||||
add_result = run_command("git add lean-toolchain", check=False)
|
||||
if add_result.returncode != 0:
|
||||
print("Failed to stage resolved lean-toolchain")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_and_merge(repo, branch, tag, temp_dir):
|
||||
"""Check if tag can be merged into branch and perform the merge if possible."""
|
||||
# Change to the temporary directory
|
||||
@@ -125,37 +98,12 @@ def check_and_merge(repo, branch, tag, temp_dir):
|
||||
# Try merging the tag directly
|
||||
print(f"Merging {tag} into {branch}...")
|
||||
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
|
||||
|
||||
|
||||
if merge_result.returncode != 0:
|
||||
# Check which files have conflicts
|
||||
conflicted_files = get_conflicted_files()
|
||||
|
||||
if conflicted_files == ['lean-toolchain']:
|
||||
# Only lean-toolchain has conflicts, resolve it
|
||||
print("Merge conflict detected only in lean-toolchain.")
|
||||
if resolve_lean_toolchain_conflict(tag):
|
||||
# Continue the merge with the resolved conflict
|
||||
print("Continuing merge with resolved lean-toolchain...")
|
||||
continue_result = run_command(f"git commit --no-edit", check=False)
|
||||
if continue_result.returncode != 0:
|
||||
print("Failed to complete merge after resolving lean-toolchain")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
# Other files have conflicts, or unable to determine
|
||||
if conflicted_files:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print(f"Merge conflicts in: {', '.join(conflicted_files)}")
|
||||
else:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur.")
|
||||
print("Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur. Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
|
||||
print(f"Pushing changes to remote...")
|
||||
push_result = run_command(f"git push origin {branch}")
|
||||
|
||||
@@ -52,7 +52,6 @@ def sort_sections_order():
|
||||
return [
|
||||
"Language",
|
||||
"Library",
|
||||
"Tactics",
|
||||
"Compiler",
|
||||
"Pretty Printing",
|
||||
"Documentation",
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
repositories:
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: batteries
|
||||
url: https://github.com/leanprover-community/batteries
|
||||
toolchain-tag: true
|
||||
@@ -14,13 +7,6 @@ repositories:
|
||||
bump-branch: true
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: lean4checker
|
||||
url: https://github.com/leanprover/lean4checker
|
||||
toolchain-tag: true
|
||||
@@ -35,6 +21,20 @@ repositories:
|
||||
branch: master
|
||||
dependencies: []
|
||||
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
@@ -96,15 +96,6 @@ repositories:
|
||||
- import-graph
|
||||
- plausible
|
||||
|
||||
- name: cslib
|
||||
url: https://github.com/leanprover/cslib
|
||||
toolchain-tag: true
|
||||
stable-branch: true
|
||||
branch: main
|
||||
bump-branch: true
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: repl
|
||||
url: https://github.com/leanprover-community/repl
|
||||
toolchain-tag: true
|
||||
@@ -112,11 +103,3 @@ repositories:
|
||||
branch: master
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: lean-fro.org
|
||||
url: https://github.com/leanprover/lean-fro.org
|
||||
toolchain-tag: false
|
||||
stable-branch: false
|
||||
branch: master
|
||||
dependencies:
|
||||
- verso
|
||||
|
||||
@@ -377,33 +377,6 @@ def execute_release_steps(repo, version, config):
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
elif repo_name == "lean-fro.org":
|
||||
# Update lean-toolchain in examples/hero
|
||||
print(blue("Updating examples/hero/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "examples" / "hero" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated examples/hero/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
print(blue("Running `lake update`..."))
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
print(blue("Running `lake update` in examples/hero..."))
|
||||
run_command("lake update", cwd=repo_path / "examples" / "hero", stream_output=True)
|
||||
elif repo_name == "cslib":
|
||||
print(blue("Updating lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
print(blue("Updating docs/lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path / "docs")
|
||||
|
||||
# Update lean-toolchain in docs
|
||||
print(blue("Updating docs/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "docs" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated docs/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 25)
|
||||
set(LEAN_VERSION_MINOR 24)
|
||||
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'")
|
||||
|
||||
@@ -42,8 +42,5 @@ public import Init.While
|
||||
public import Init.Syntax
|
||||
public import Init.Internal
|
||||
public import Init.Try
|
||||
public meta import Init.Try -- make sure `Try.Config` can be evaluated anywhere
|
||||
public import Init.BinderNameHint
|
||||
public import Init.Task
|
||||
public import Init.MethodSpecsSimp
|
||||
public import Init.LawfulBEqTactics
|
||||
|
||||
@@ -19,8 +19,8 @@ variable {ε σ α : Type u}
|
||||
|
||||
instance [ToString ε] [ToString α] : ToString (Result ε σ α) where
|
||||
toString
|
||||
| Result.ok a _ => String.Internal.append "ok: " (toString a)
|
||||
| Result.error e _ => String.Internal.append "error: " (toString e)
|
||||
| Result.ok a _ => "ok: " ++ toString a
|
||||
| Result.error e _ => "error: " ++ toString e
|
||||
|
||||
instance [Repr ε] [Repr α] : Repr (Result ε σ α) where
|
||||
reprPrec
|
||||
|
||||
@@ -147,7 +147,7 @@ class LawfulMonad (m : Type u → Type v) [Monad m] : Prop extends LawfulApplica
|
||||
|
||||
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
|
||||
attribute [simp] pure_bind bind_assoc bind_pure_comp
|
||||
attribute [grind <=] pure_bind
|
||||
attribute [grind] pure_bind
|
||||
|
||||
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
|
||||
change x >>= (fun a => pure (id a)) = x
|
||||
|
||||
@@ -22,24 +22,23 @@ open Function
|
||||
|
||||
namespace ExceptT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
@[ext] theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α → ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
|
||||
simp [ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont]
|
||||
|
||||
@[simp, grind =] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α → ExceptT ε m β) : (throw e >>= f) = throw e := by
|
||||
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
|
||||
|
||||
@[grind =]
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
theorem run_bind [Monad m] (x : ExceptT ε m α)
|
||||
: run (x >>= f : ExceptT ε m β)
|
||||
=
|
||||
run x >>= fun
|
||||
@@ -47,10 +46,10 @@ theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
| Except.error e => pure (Except.error e) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
|
||||
simp [ExceptT.lift, pure, ExceptT.pure]
|
||||
|
||||
@[simp, grind =] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α)
|
||||
: (f <$> x).run = Except.map f <$> x.run := by
|
||||
simp [Functor.map, ExceptT.map, ←bind_pure_comp]
|
||||
apply bind_congr
|
||||
@@ -114,28 +113,28 @@ instance : LawfulFunctor (Except ε) := inferInstance
|
||||
|
||||
namespace ReaderT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
@[ext] theorem ext {x y : ReaderT ρ m α} (h : ∀ ctx, x.run ctx = y.run ctx) : x = y := by
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
|
||||
|
||||
@[simp, grind =] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
|
||||
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp] theorem run_map [Monad m] (f : α → β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <$> x).run ctx = f <$> x.run ctx := rfl
|
||||
|
||||
@[simp, grind =] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
|
||||
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
@[simp] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
|
||||
|
||||
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α → β)) (x : ReaderT ρ m α) (ctx : ρ)
|
||||
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
|
||||
@@ -176,39 +175,38 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
|
||||
|
||||
namespace StateT
|
||||
|
||||
@[ext, grind ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
@[ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp, grind =] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
|
||||
simp [bind, StateT.bind, run]
|
||||
|
||||
@[simp, grind =] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
simp [Functor.map, StateT.map, run, ←bind_pure_comp]
|
||||
|
||||
@[simp, grind =] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (⟨⟩, s') := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
@[simp] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
@[simp] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
|
||||
|
||||
@[simp, grind =] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
@[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
|
||||
|
||||
@[grind =]
|
||||
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, grind =] 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_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, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||
@[simp] theorem run_monadMap [MonadFunctorT 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
|
||||
|
||||
@@ -101,6 +101,7 @@ instance : DecidableEq Empty := fun a => a.elim
|
||||
/-- Decidable equality for PEmpty -/
|
||||
instance : DecidableEq PEmpty := fun a => a.elim
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
Delays evaluation. The delayed code is evaluated at most once.
|
||||
|
||||
@@ -616,6 +617,7 @@ class Sep (α : outParam <| Type u) (γ : Type v) where
|
||||
/-- Computes `{ a ∈ c | p a }`. -/
|
||||
sep : (α → Prop) → γ → γ
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
`Task α` is a primitive for asynchronous computation.
|
||||
It represents a computation that will resolve to a value of type `α`,
|
||||
@@ -1580,7 +1582,6 @@ instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) :=
|
||||
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% BitVec
|
||||
gen_injective_theorems% ByteArray
|
||||
gen_injective_theorems% Char
|
||||
gen_injective_theorems% DoResultBC
|
||||
gen_injective_theorems% DoResultPR
|
||||
@@ -2547,3 +2548,7 @@ class Irrefl (r : α → α → Prop) : Prop where
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
end Std
|
||||
|
||||
/-- Deprecated alias for `XorOp`. -/
|
||||
@[deprecated XorOp (since := "2025-07-30")]
|
||||
abbrev Xor := XorOp
|
||||
|
||||
@@ -121,7 +121,7 @@ theorem pmap_eq_map {p : α → Prop} {f : α → β} {xs : Array α} (H) :
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (xs : Array α) {H₁ H₂}
|
||||
(h : ∀ a ∈ xs, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
|
||||
cases xs
|
||||
simp only [List.mem_toArray] at h
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
@@ -176,6 +176,9 @@ theorem attach_map_val (xs : Array α) (f : α → β) :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
-- The argument `xs : Array α` is explicit to allow rewriting from right to left.
|
||||
theorem attach_map_subtype_val (xs : Array α) : xs.attach.map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
@@ -184,18 +187,21 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {xs : Array α} (H
|
||||
((xs.attachWith p H).map fun (i : { i // p i}) => f i) = xs.map f := by
|
||||
cases xs; simp
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} {xs : Array α} (H : ∀ a ∈ xs, p a) :
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind ←]
|
||||
@[simp, grind]
|
||||
theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem mem_attachWith {xs : Array α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ xs.attachWith q H ↔ x.1 ∈ xs := by
|
||||
cases xs
|
||||
@@ -206,13 +212,12 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
@[simp, grind =]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
@@ -340,7 +345,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
|
||||
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldl_toArray', List.mem_toArray, List.foldl_subtype]
|
||||
List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -359,7 +364,7 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
|
||||
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldr_toArray', List.mem_toArray, List.foldr_subtype]
|
||||
List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -395,6 +400,9 @@ theorem map_attach_eq_pmap {xs : Array α} {f : { x // x ∈ xs } → β} :
|
||||
cases xs
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {xs : Array α} {f : α → Option β} :
|
||||
(xs.filterMap f).attach = xs.attach.filterMap
|
||||
@@ -698,7 +706,7 @@ and simplifies these to the function directly taking the value.
|
||||
{f : { x // p x } → Array β} {g : α → Array β} (hf : ∀ x h, f ⟨x, h⟩ = g x) :
|
||||
(xs.flatMap f) = xs.unattach.flatMap g := by
|
||||
cases xs
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
simp only [List.flatMap_toArray, List.unattach_toArray,
|
||||
mk.injEq]
|
||||
rw [List.flatMap_subtype]
|
||||
simp [hf]
|
||||
|
||||
@@ -10,6 +10,8 @@ public import Init.WFTactics
|
||||
public import Init.Data.Nat.Basic
|
||||
public import Init.Data.Fin.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Repr
|
||||
public import Init.Data.ToString.Basic
|
||||
public import Init.GetElem
|
||||
public import Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
@@ -40,11 +42,11 @@ namespace Array
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp, grind =] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
|
||||
(set xs i v h).size = xs.size :=
|
||||
List.length_set ..
|
||||
|
||||
@[simp, grind =] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
@[simp, grind] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
|
||||
List.length_concat ..
|
||||
|
||||
theorem ext {xs ys : Array α}
|
||||
@@ -108,19 +110,13 @@ instance : Membership α (Array α) where
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp, grind =] theorem _root_.List.mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[deprecated List.mem_toArray (since := "2025-09-04")]
|
||||
theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l :=
|
||||
List.mem_toArray
|
||||
|
||||
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
@@ -129,10 +125,19 @@ end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[deprecated Array.toArray_toList (since := "2025-02-17")]
|
||||
abbrev toArray_toList := @Array.toArray_toList
|
||||
|
||||
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
|
||||
theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
|
||||
|
||||
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
@[deprecated toList_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.toList_toArray := @List.toList_toArray
|
||||
|
||||
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
|
||||
|
||||
@[deprecated size_toArray (since := "2025-02-17")]
|
||||
abbrev _root_.Array.size_toArray := @List.size_toArray
|
||||
|
||||
@[simp, grind =] theorem getElem_toArray {xs : List α} {i : Nat} (h : i < xs.toArray.size) :
|
||||
xs.toArray[i] = xs[i]'(by simpa using h) := rfl
|
||||
@@ -159,7 +164,7 @@ This is a low-level version of `Array.size` that directly queries the runtime sy
|
||||
representation of arrays. While this is not provable, `Array.usize` always returns the exact size of
|
||||
the array since the implementation only supports arrays of size less than `USize.size`.
|
||||
-/
|
||||
@[extern "lean_array_size", simp, expose]
|
||||
@[extern "lean_array_size", simp]
|
||||
def usize (xs : @& Array α) : USize := xs.size.toUSize
|
||||
|
||||
/--
|
||||
@@ -194,7 +199,7 @@ Examples:
|
||||
def pop (xs : Array α) : Array α where
|
||||
toList := xs.toList.dropLast
|
||||
|
||||
@[simp, grind =] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
@[simp, grind] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
|
||||
match xs with
|
||||
| ⟨[]⟩ => rfl
|
||||
| ⟨a::as⟩ => simp [pop, Nat.succ_sub_succ_eq_sub, size]
|
||||
@@ -403,6 +408,10 @@ that requires a proof the array is non-empty.
|
||||
def back? (xs : Array α) : Option α :=
|
||||
xs[xs.size - 1]?
|
||||
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
|
||||
def get? (xs : Array α) (i : Nat) : Option α :=
|
||||
if h : i < xs.size then some xs[i] else none
|
||||
|
||||
/--
|
||||
Swaps a new element with the element at the given index.
|
||||
|
||||
@@ -434,7 +443,7 @@ def swapAt! (xs : Array α) (i : Nat) (v : α) : α × Array α :=
|
||||
swapAt xs i v
|
||||
else
|
||||
have : Inhabited (α × Array α) := ⟨(v, xs)⟩
|
||||
panic! String.Internal.append (String.Internal.append "index " (toString i)) " out of bounds"
|
||||
panic! ("index " ++ toString i ++ " out of bounds")
|
||||
|
||||
/--
|
||||
Returns the first `n` elements of an array. The resulting array is produced by repeatedly calling
|
||||
@@ -1799,6 +1808,7 @@ Examples:
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
|
||||
-/
|
||||
@[grind]
|
||||
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
|
||||
if h : i < xs.size then xs.eraseIdx i h else xs
|
||||
|
||||
@@ -2159,7 +2169,7 @@ instance {α : Type u} [Repr α] : Repr (Array α) where
|
||||
reprPrec xs _ := Array.repr xs
|
||||
|
||||
instance [ToString α] : ToString (Array α) where
|
||||
toString xs := String.Internal.append "#" (toString xs.toList)
|
||||
toString xs := "#" ++ toString xs.toList
|
||||
|
||||
end Array
|
||||
|
||||
|
||||
@@ -24,6 +24,29 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
||||
|
||||
namespace Array
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]` instead.
|
||||
|
||||
Access an element from an array without needing a runtime bounds checks,
|
||||
using a `Nat` index and a proof that it is in bounds.
|
||||
|
||||
This function does not use `get_elem_tactic` to automatically find the proof that
|
||||
the index is in bounds. This is because the tactic itself needs to look up values in
|
||||
arrays.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]` instead" (since := "2025-02-17")]
|
||||
def get {α : Type u} (xs : @& Array α) (i : @& Nat) (h : LT.lt i xs.size) : α :=
|
||||
xs.toList.get ⟨i, h⟩
|
||||
|
||||
/--
|
||||
Use the indexing notation `a[i]!` instead.
|
||||
|
||||
Access an element from an array, or panic if the index is out of bounds.
|
||||
-/
|
||||
@[deprecated "Use indexing notation `as[i]!` instead" (since := "2025-02-17"), expose]
|
||||
def get! {α : Type u} [Inhabited α] (xs : @& Array α) (i : @& Nat) : α :=
|
||||
Array.getD xs i default
|
||||
|
||||
theorem foldlM_toList.aux [Monad m]
|
||||
{f : β → α → m β} {xs : Array α} {i j} (H : xs.size ≤ i + j) {b} :
|
||||
foldlM.loop f xs xs.size (Nat.le_refl _) i j b = (xs.toList.drop j).foldlM f b := by
|
||||
@@ -85,6 +108,9 @@ abbrev push_toList := @toList_push
|
||||
|
||||
@[simp, grind =] theorem toList_pop {xs : Array α} : xs.pop.toList = xs.toList.dropLast := rfl
|
||||
|
||||
@[deprecated toList_pop (since := "2025-02-17")]
|
||||
abbrev pop_toList := @Array.toList_pop
|
||||
|
||||
@[simp] theorem append_eq_append {xs ys : Array α} : xs.append ys = xs ++ ys := rfl
|
||||
|
||||
@[simp, grind =] theorem toList_append {xs ys : Array α} :
|
||||
|
||||
@@ -91,7 +91,7 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_eraseP
|
||||
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a ∈ xs.eraseP p ↔ a ∈ xs := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_eraseP_of_neg pa
|
||||
|
||||
@@ -240,7 +240,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
|
||||
rcases xs with ⟨xs⟩
|
||||
simpa using List.mem_of_mem_erase (by simpa using h)
|
||||
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a ≠ b) :
|
||||
a ∈ xs.erase b ↔ a ∈ xs :=
|
||||
erase_eq_eraseP b xs ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -271,7 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
(xs ++ ys).erase a = if a ∈ xs then xs.erase a ++ ys else xs ++ ys.erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, List.mem_toArray]
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
@@ -324,13 +324,6 @@ abbrev erase_mkArray_ne := @erase_replicate_ne
|
||||
|
||||
end erase
|
||||
|
||||
/-! ### eraseIdxIfInBounds -/
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdxIfInBounds_eq {xs : Array α} {i : Nat} :
|
||||
xs.eraseIdxIfInBounds i = if h : i < xs.size then xs.eraseIdx i else xs := by
|
||||
simp [eraseIdxIfInBounds]
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
theorem eraseIdx_eq_eraseIdxIfInBounds {xs : Array α} {i : Nat} (h : i < xs.size) :
|
||||
|
||||
@@ -27,11 +27,11 @@ open Nat
|
||||
|
||||
/-! ### findSome? -/
|
||||
|
||||
@[simp, grind =] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind =] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
@[simp, grind] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
|
||||
@[simp, grind] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
|
||||
cases xs; simp [List.findSome?_append]
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem findSome?_singleton {a : α} {f : α → Option β} : #[a].findSome? f = f a := by
|
||||
simp
|
||||
|
||||
@@ -228,12 +228,11 @@ theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ x
|
||||
simp at h
|
||||
simpa using List.mem_of_find?_eq_some h
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
cases xs
|
||||
simp [List.get_find?_mem]
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α → Bool) :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
cases xs; simp
|
||||
@@ -278,6 +277,9 @@ theorem find?_flatten_eq_none_iff {xss : Array (Array α)} {p : α → Bool} :
|
||||
xss.flatten.find? p = none ↔ ∀ ys ∈ xss, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some array in `xs` contains `a`, and no earlier element of that array satisfies `p`.
|
||||
@@ -303,6 +305,9 @@ theorem find?_flatten_eq_some_iff {xss : Array (Array α)} {p : α → Bool} {a
|
||||
⟨zs.toList, bs.toList.map Array.toList, by simpa using h⟩,
|
||||
by simpa using h₁, by simpa using h₂⟩
|
||||
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem find?_flatMap {xs : Array α} {f : α → Array β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
cases xs
|
||||
@@ -312,11 +317,17 @@ theorem find?_flatMap_eq_none_iff {xs : Array α} {f : α → Array β} {p : β
|
||||
(xs.flatMap f).find? p = none ↔ ∀ x ∈ xs, ∀ y ∈ f x, !p y := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatMap_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatMap_eq_none := @find?_flatMap_eq_none_iff
|
||||
|
||||
@[grind =]
|
||||
theorem find?_replicate :
|
||||
find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
simp [← List.toArray_replicate, List.find?_replicate]
|
||||
|
||||
@[deprecated find?_replicate (since := "2025-03-18")]
|
||||
abbrev find?_mkArray := @find?_replicate
|
||||
|
||||
@[simp] theorem find?_replicate_of_size_pos (h : 0 < n) :
|
||||
find? p (replicate n a) = if p a then some a else none := by
|
||||
simp [find?_replicate, Nat.ne_of_gt h]
|
||||
@@ -334,19 +345,34 @@ abbrev find?_mkArray_of_pos := @find?_replicate_of_pos
|
||||
@[simp] theorem find?_replicate_of_neg (h : ¬ p a) : find? p (replicate n a) = none := by
|
||||
simp [find?_replicate, h]
|
||||
|
||||
@[deprecated find?_replicate_of_neg (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_of_neg := @find?_replicate_of_neg
|
||||
|
||||
-- This isn't a `@[simp]` lemma since there is already a lemma for `l.find? p = none` for any `l`.
|
||||
theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [← List.toArray_replicate, Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_none_iff := @find?_replicate_eq_none_iff
|
||||
|
||||
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-03-18")]
|
||||
abbrev find?_mkArray_eq_some_iff := @find?_replicate_eq_some_iff
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_mkArray_eq_some := @find?_replicate_eq_some_iff
|
||||
|
||||
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α → Bool} (h) :
|
||||
((replicate n a).find? p).get h = a := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
@[deprecated get_find?_replicate (since := "2025-03-18")]
|
||||
abbrev get_find?_mkArray := @get_find?_replicate
|
||||
|
||||
@[grind =]
|
||||
theorem find?_pmap {P : α → Prop} {f : (a : α) → P a → β} {xs : Array α}
|
||||
(H : ∀ (a : α), a ∈ xs → P a) {p : β → Bool} :
|
||||
@@ -369,6 +395,7 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
@@ -701,7 +728,7 @@ theorem isNone_findFinIdx? {xs : Array α} {p : α → Bool} :
|
||||
cases xs
|
||||
simp only [List.findFinIdx?_toArray, hf, List.findFinIdx?_subtype]
|
||||
rw [findFinIdx?_congr List.unattach_toArray]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_cast]
|
||||
simp only [Option.map_map, Function.comp_def, Fin.cast_trans]
|
||||
simp [Array.size]
|
||||
|
||||
/-! ### idxOf
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,8 @@ prelude
|
||||
public import Init.Core
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
import Init.Data.Range.Polymorphic.Iterators
|
||||
import Init.Data.Range.Polymorphic.Nat
|
||||
import Init.Data.Iterators.Consumers
|
||||
|
||||
public section
|
||||
|
||||
@@ -70,8 +70,8 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.PRange.toList_eq_match rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.SupportsUpperBound.IsSatisfied, bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.PRange.toList_Rox_eq_toList_Rcx_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_Rco_succ_succ,
|
||||
simp only [Std.PRange.toList_open_eq_toList_closed_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.ClosedOpen.toList_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
|
||||
@@ -167,7 +167,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
forIn' as b f = forIn' bs b' g := by
|
||||
cases as <;> cases bs
|
||||
simp only [mk.injEq, List.mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
exact List.forIn'_congr w hb h
|
||||
|
||||
/--
|
||||
|
||||
@@ -116,7 +116,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
rw [← List.toArray_range']
|
||||
simp only [List.find?_toArray, List.mem_toArray]
|
||||
simp only [List.find?_toArray, mem_toArray]
|
||||
simp [List.find?_range'_eq_some]
|
||||
|
||||
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.GetElem
|
||||
public import Init.Data.Array.Basic
|
||||
import Init.Data.Array.GetLit
|
||||
public import Init.Data.Slice.Basic
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ set_option linter.missingDocs true
|
||||
|
||||
namespace BitVec
|
||||
|
||||
@[inline, deprecated BitVec.ofNatLT (since := "2025-02-13"), inherit_doc BitVec.ofNatLT]
|
||||
protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2 ^ n) : BitVec n :=
|
||||
BitVec.ofNatLT i p
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
@@ -202,13 +206,10 @@ Converts a bitvector into a fixed-width hexadecimal number with enough digits to
|
||||
|
||||
If `n` is `0`, then one digit is returned. Otherwise, `⌊(n + 3) / 4⌋` digits are returned.
|
||||
-/
|
||||
-- If we ever want to prove something about this, we can avoid having to use the opaque
|
||||
-- `Internal` string functions by moving this definition out to a separate file that can live
|
||||
-- downstream of `Init.Data.String.Basic`.
|
||||
protected def toHex {n : Nat} (x : BitVec n) : String :=
|
||||
let s := (Nat.toDigits 16 x.toNat).asString
|
||||
let t := (List.replicate ((n+3) / 4 - String.Internal.length s) '0').asString
|
||||
String.Internal.append t s
|
||||
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
|
||||
t ++ s
|
||||
|
||||
/-- `BitVec` representation. -/
|
||||
protected def BitVec.repr (a : BitVec n) : Std.Format :=
|
||||
@@ -870,7 +871,4 @@ def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
/-- Count the number of leading zeros. -/
|
||||
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
|
||||
/-- Count the number of trailing zeros. -/
|
||||
def ctz (x : BitVec w) : BitVec w := (x.reverse).clz
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace BitVec
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
The bitvector with value `i mod 2^n`.
|
||||
-/
|
||||
@[expose, match_pattern]
|
||||
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
||||
toFin := Fin.ofNat (2^n) i
|
||||
|
||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||
|
||||
/-- Return the bound in terms of toNat. -/
|
||||
|
||||
@@ -19,7 +19,7 @@ theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
|
||||
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
|
||||
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getLsbD x i = false := by
|
||||
let ⟨x, x_lt⟩ := x
|
||||
simp only [getLsbD_ofFin]
|
||||
apply Nat.testBit_lt_two_pow
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace BitVec
|
||||
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
|
||||
(BitVec.ofFin x)[i] = x.val.testBit i := rfl
|
||||
|
||||
@[simp, grind =] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
@[simp, grind] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w ≤ i) : getMsbD x i = false := by
|
||||
rw [getMsbD]
|
||||
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -74,6 +74,10 @@ theorem some_eq_getElem?_iff {l : BitVec w} : some a = l[n]? ↔ ∃ h : n < w,
|
||||
theorem getElem_of_getElem? {l : BitVec w} : l[n]? = some a → ∃ h : n < w, l[n] = a :=
|
||||
getElem?_eq_some_iff.mp
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated getElem?_eq_some_iff (since := "2025-02-17")]
|
||||
abbrev getElem?_eq_some := @getElem?_eq_some_iff
|
||||
|
||||
theorem getElem?_eq_none_iff {l : BitVec w} : l[n]? = none ↔ w ≤ n := by
|
||||
simp
|
||||
|
||||
@@ -118,7 +122,7 @@ theorem getElem_of_getLsbD_eq_true {x : BitVec w} {i : Nat} (h : x.getLsbD i = t
|
||||
This normalized a bitvec using `ofFin` to `ofNat`.
|
||||
-/
|
||||
theorem ofFin_eq_ofNat : @BitVec.ofFin w (Fin.mk x lt) = BitVec.ofNat w x := by
|
||||
simp only [BitVec.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
simp only [BitVec.ofNat, Fin.ofNat, lt, Nat.mod_eq_of_lt]
|
||||
|
||||
/-- Prove nonequality of bitvectors in terms of nat operations. -/
|
||||
theorem toNat_ne_iff_ne {n} {x y : BitVec n} : x.toNat ≠ y.toNat ↔ x ≠ y := by
|
||||
@@ -295,7 +299,7 @@ theorem length_pos_of_ne {x y : BitVec w} (h : x ≠ y) : 0 < w :=
|
||||
|
||||
theorem ofFin_ofNat (n : Nat) :
|
||||
ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
|
||||
simp only [OfNat.ofNat, Fin.Internal.ofNat_eq_ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
simp only [OfNat.ofNat, Fin.ofNat, BitVec.ofNat]
|
||||
|
||||
-- We use a `grind_pattern` as `@[grind]` will not use the `no_index` term.
|
||||
grind_pattern ofFin_ofNat => ofFin (OfNat.ofNat n : Fin (2^w))
|
||||
@@ -346,14 +350,25 @@ theorem ofBool_eq_iff_eq : ∀ {b b' : Bool}, BitVec.ofBool b = BitVec.ofBool b'
|
||||
@[simp] theorem ofBool_xor_ofBool : ofBool b ^^^ ofBool b' = ofBool (b ^^ b') := by
|
||||
cases b <;> cases b' <;> rfl
|
||||
|
||||
@[deprecated toNat_ofNatLT (since := "2025-02-13")]
|
||||
theorem toNat_ofNatLt (x : Nat) (p : x < 2^w) : (x#'p).toNat = x := rfl
|
||||
|
||||
@[simp, grind =] theorem getLsbD_ofNatLT {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
|
||||
getLsbD (x#'lt) i = x.testBit i := by
|
||||
simp [getLsbD, BitVec.ofNatLT]
|
||||
|
||||
@[deprecated getLsbD_ofNatLT (since := "2025-02-13")]
|
||||
theorem getLsbD_ofNatLt {n : Nat} (x : Nat) (lt : x < 2^n) (i : Nat) :
|
||||
getLsbD (x#'lt) i = x.testBit i := getLsbD_ofNatLT x lt i
|
||||
|
||||
@[simp, grind =] theorem getMsbD_ofNatLT {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := by
|
||||
simp [getMsbD, getLsbD]
|
||||
|
||||
@[deprecated getMsbD_ofNatLT (since := "2025-02-13")]
|
||||
theorem getMsbD_ofNatLt {n x i : Nat} (h : x < 2^n) :
|
||||
getMsbD (x#'h) i = (decide (i < n) && x.testBit (n - 1 - i)) := getMsbD_ofNatLT h
|
||||
|
||||
@[grind =]
|
||||
theorem ofNatLT_eq_ofNat {w : Nat} {n : Nat} (hn) : BitVec.ofNatLT n hn = BitVec.ofNat w n :=
|
||||
eq_of_toNat_eq (by simp [Nat.mod_eq_of_lt hn])
|
||||
@@ -1085,10 +1100,6 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
|
||||
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
|
||||
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
|
||||
|
||||
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w ≤ w') : (b.setWidth w').toNat = b.toNat := by
|
||||
rw [BitVec.toNat_setWidth, Nat.mod_eq_of_lt]
|
||||
exact BitVec.toNat_lt_twoPow_of_le h
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -1276,17 +1287,6 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
|
||||
ext i hi
|
||||
omega
|
||||
|
||||
theorem extractLsb'_setWidth_of_le {b : BitVec w} {start len w' : Nat} (h : start + len ≤ w') :
|
||||
(b.setWidth w').extractLsb' start len = b.extractLsb' start len := by
|
||||
ext i h_i
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem setWidth_extractLsb'_of_le {c : BitVec w} (h : len₁ ≤ len₂) :
|
||||
(c.extractLsb' start len₂).setWidth len₁ = c.extractLsb' start len₁ := by
|
||||
ext i hi
|
||||
simp [show i < len₂ by omega]
|
||||
|
||||
/-! ### allOnes -/
|
||||
|
||||
@[simp, grind =] theorem toNat_allOnes : (allOnes v).toNat = 2^v - 1 := by
|
||||
@@ -1530,12 +1530,6 @@ theorem extractLsb_and {x : BitVec w} {hi lo : Nat} :
|
||||
@[simp, grind =] theorem ofNat_and {x y : Nat} : BitVec.ofNat w (x &&& y) = BitVec.ofNat w x &&& BitVec.ofNat w y :=
|
||||
eq_of_toNat_eq (by simp [Nat.and_mod_two_pow])
|
||||
|
||||
theorem and_or_distrib_left {x y z : BitVec w} : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_left])
|
||||
|
||||
theorem and_or_distrib_right {x y z : BitVec w} : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_right])
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@[simp, grind =] theorem toNat_xor (x y : BitVec v) :
|
||||
@@ -2186,10 +2180,6 @@ theorem msb_ushiftRight {x : BitVec w} {n : Nat} :
|
||||
have := lt_of_getLsbD ha
|
||||
omega
|
||||
|
||||
theorem setWidth_ushiftRight_eq_extractLsb {b : BitVec w} : (b >>> w').setWidth w'' = b.extractLsb' w' w'' := by
|
||||
ext i hi
|
||||
simp
|
||||
|
||||
/-! ### ushiftRight reductions from BitVec to Nat -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -2980,9 +2970,10 @@ theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
|
||||
/-- Combine adjacent `extractLsb'` operations into a single `extractLsb'`. -/
|
||||
theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start₂ = start₁ + len₁) :
|
||||
((x.extractLsb' start₂ len₂) ++ (x.extractLsb' start₁ len₁)) =
|
||||
x.extractLsb' start₁ (len₂ + len₁) := by
|
||||
(x.extractLsb' start₁ (len₁ + len₂)).cast (by omega) := by
|
||||
ext i h
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, ite_eq_left_iff, Nat.not_lt]
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, getElem_cast, ite_eq_left_iff,
|
||||
Nat.not_lt]
|
||||
intro hi
|
||||
congr 1
|
||||
omega
|
||||
@@ -3094,51 +3085,6 @@ theorem extractLsb'_append_eq_of_le {v w} {xhi : BitVec v} {xlo : BitVec w}
|
||||
extractLsb' start len (xhi ++ xlo) = extractLsb' (start - w) len xhi := by
|
||||
simp [extractLsb'_append_eq_ite, show ¬ start < w by omega]
|
||||
|
||||
theorem extractLsb'_append_eq_left {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' w' w = a := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_le]
|
||||
|
||||
theorem extractLsb'_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' 0 w' = b := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_add_le]
|
||||
|
||||
theorem setWidth_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).setWidth w' = b := by
|
||||
ext i hi
|
||||
simp [getLsbD_append, hi]
|
||||
|
||||
theorem append_left_inj {s₁ s₂ : BitVec w} (t : BitVec w') : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, dif_neg] using congrArg (·[i + w']'(by omega)) h
|
||||
|
||||
theorem append_right_inj (s : BitVec w) {t₁ t₂ : BitVec w'} : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, hi] using congrArg (·[i]) h
|
||||
|
||||
theorem setWidth_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} :
|
||||
(b ++ b').setWidth w'' = (b.setWidth w'' <<< w') ||| b'.setWidth w'' := by
|
||||
ext i hi
|
||||
simp only [getElem_setWidth, getElem_or, getElem_shiftLeft]
|
||||
rw [getLsbD_append]
|
||||
split <;> simp_all
|
||||
|
||||
theorem setWidth_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} :
|
||||
(b ++ b' ++ b'').setWidth w''' = (b.setWidth w''' <<< (w' + w'')) ||| (b'.setWidth w''' <<< w'') ||| b''.setWidth w''' := by
|
||||
rw [BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem setWidth_append_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} {b''' : BitVec w'''} :
|
||||
(b ++ b' ++ b'' ++ b''').setWidth w'''' = (b.setWidth w'''' <<< (w' + w'' + w''')) ||| (b'.setWidth w'''' <<< (w'' + w''')) |||
|
||||
(b''.setWidth w'''' <<< w''') ||| b'''.setWidth w'''' := by
|
||||
simp only [BitVec.setWidth_append_eq_shiftLeft_setWidth_or, BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem and_setWidth_allOnes (w' w : Nat) (b : BitVec (w' + w)) :
|
||||
b &&& (BitVec.allOnes w).setWidth (w' + w) = 0#w' ++ b.setWidth w := by
|
||||
ext i hi
|
||||
simp only [getElem_and, getElem_setWidth, getLsbD_allOnes]
|
||||
rw [BitVec.getElem_append]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### rev -/
|
||||
|
||||
@[grind =]
|
||||
@@ -4095,9 +4041,6 @@ instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
|
||||
apply LawfulOrderLT.of_le
|
||||
simpa using fun _ _ => BitVec.lt_asymm
|
||||
|
||||
theorem length_pos_of_lt {b b' : BitVec w} (h : b < b') : 0 < w :=
|
||||
length_pos_of_ne (BitVec.ne_of_lt h)
|
||||
|
||||
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y := by
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
|
||||
apply Nat.mod_lt
|
||||
@@ -4169,14 +4112,6 @@ theorem lt_of_msb_false_of_msb_true {x y : BitVec w} (hx : x.msb = false) (hy :
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem lt_add_one {b : BitVec w} (h : b ≠ allOnes w) : b < b + 1 := by
|
||||
simp only [ne_eq, ← toNat_inj, toNat_allOnes] at h
|
||||
simp only [BitVec.lt_def, ofNat_eq_ofNat, toNat_add, toNat_ofNat, Nat.add_mod_mod]
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
· exact Nat.lt_add_one _
|
||||
· have := b.toNat_lt_twoPow_of_le (Nat.le_refl _)
|
||||
omega
|
||||
|
||||
/-! ### udiv -/
|
||||
|
||||
theorem udiv_def {x y : BitVec n} : x / y = BitVec.ofNat n (x.toNat / y.toNat) := by
|
||||
@@ -5322,7 +5257,7 @@ theorem replicate_succ' {x : BitVec w} :
|
||||
(replicate n x ++ x).cast (by rw [Nat.mul_succ]) := by
|
||||
simp [replicate_append_self]
|
||||
|
||||
theorem setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
rw [toNat_setWidth]
|
||||
simp only [toNat_setWidth, toNat_add, toNat_umod, Nat.add_mod_mod, Nat.mod_add_mod, toNat_twoPow]
|
||||
@@ -5331,14 +5266,6 @@ theorem setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitV
|
||||
· have hk : 2 ^ w < 2 ^ i := Nat.pow_lt_pow_of_lt (by decide) (Nat.lt_of_not_le h)
|
||||
rw [Nat.mod_eq_of_lt hk, Nat.mod_mod_eq_mod_mod_of_dvd (Nat.pow_dvd_pow _ (Nat.le_of_not_le h))]
|
||||
|
||||
theorem setWidth_setWidth_eq_self {a : BitVec w} {w' : Nat} (h : a < BitVec.twoPow w w') : (a.setWidth w').setWidth w = a := by
|
||||
by_cases hw : w' < w
|
||||
· simp only [toNat_eq, toNat_setWidth]
|
||||
rw [Nat.mod_mod_of_dvd' (Nat.pow_dvd_pow _ (Nat.le_of_lt hw)), Nat.mod_eq_of_lt]
|
||||
rwa [BitVec.lt_def, BitVec.toNat_twoPow_of_lt hw] at h
|
||||
· rw [BitVec.lt_def, BitVec.toNat_twoPow_of_le (by omega)] at h
|
||||
simp at h
|
||||
|
||||
/-! ### intMin -/
|
||||
|
||||
@[grind =]
|
||||
@@ -5852,25 +5779,6 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
|
||||
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
|
||||
cases n <;> cases w <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem reverse_eq_zero_iff {x : BitVec w} :
|
||||
x.reverse = 0#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro hrev
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
simp [hrev]
|
||||
· intro hzero
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, getMsbD_reverse]
|
||||
simp [hi, hzero]
|
||||
|
||||
@[simp]
|
||||
theorem reverse_reverse_eq {x : BitVec w} :
|
||||
x.reverse.reverse = x := by
|
||||
ext k hk
|
||||
rw [getElem_reverse, getMsbD_reverse, getLsbD_eq_getElem]
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
@@ -6001,12 +5909,6 @@ theorem getElem_eq_true_of_lt_of_le {x : BitVec w} (hk' : k < w) (hlt: x.toNat <
|
||||
omega
|
||||
· simp [show w ≤ k + k' by omega] at hk'
|
||||
|
||||
theorem not_lt_iff {b : BitVec w} : ~~~b < b ↔ 0 < w ∧ b.msb = true := by
|
||||
refine ⟨fun h => ?_, fun ⟨hw, hb⟩ => ?_⟩
|
||||
· have := length_pos_of_lt h
|
||||
exact ⟨this, by rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)] at h⟩
|
||||
· rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)]
|
||||
|
||||
/-! ### Count leading zeros -/
|
||||
|
||||
theorem clzAuxRec_zero (x : BitVec w) :
|
||||
@@ -6280,70 +6182,16 @@ theorem toNat_lt_two_pow_sub_clz {x : BitVec w} :
|
||||
· simp [show w + 1 ≤ i by omega]
|
||||
· simp; omega
|
||||
|
||||
theorem clz_eq_reverse_ctz {x : BitVec w} :
|
||||
x.clz = (x.reverse).ctz := by
|
||||
simp [ctz]
|
||||
|
||||
/-! ### Count trailing zeros -/
|
||||
/-! ### Deprecations -/
|
||||
|
||||
theorem ctz_eq_reverse_clz {x : BitVec w} :
|
||||
x.ctz = (x.reverse).clz := by
|
||||
simp [ctz]
|
||||
set_option linter.missingDocs false
|
||||
|
||||
@[deprecated toFin_uShiftRight (since := "2025-02-18")]
|
||||
abbrev toFin_uShiftRight := @toFin_ushiftRight
|
||||
|
||||
/-- The number of trailing zeroes is strictly less than the bitwidth iff the bitvector is nonzero. -/
|
||||
@[simp]
|
||||
theorem ctz_lt_iff_ne_zero {x : BitVec w} :
|
||||
ctz x < w ↔ x ≠ 0#w := by
|
||||
simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq]
|
||||
rw [show BitVec.ofNat w w = w by simp, ← reverse_eq_zero_iff (x := x)]
|
||||
apply clz_lt_iff_ne_zero (x := x.reverse)
|
||||
|
||||
/-- If a bitvec is different than zero the bits at indexes lower than `ctz x` are false. -/
|
||||
theorem getLsbD_false_of_lt_ctz {x : BitVec w} (hi : i < x.ctz.toNat) :
|
||||
x.getLsbD i = false := by
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have hiff := ctz_lt_iff_ne_zero (x := x)
|
||||
by_cases hzero : x = 0#w
|
||||
· simp [hzero, getLsbD_reverse]
|
||||
· simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq, hzero, not_false_eq_true,
|
||||
iff_true] at hiff
|
||||
simp only [ctz] at hi
|
||||
have hi' : i < w := by simp [BitVec.lt_def] at hiff; omega
|
||||
simp only [hi', decide_true, Bool.true_and]
|
||||
have : (x.reverse.clzAuxRec (w - 1)).toNat ≤ w := by
|
||||
rw [show ((x.reverse.clzAuxRec (w - 1)).toNat ≤ w) =
|
||||
((x.reverse.clzAuxRec (w - 1)).toNat ≤ (BitVec.ofNat w w).toNat) by simp, ← le_def]
|
||||
apply clzAuxRec_le (x := x.reverse) (n := w - 1)
|
||||
let j := (x.reverse.clzAuxRec (w - 1)).toNat - 1 - i
|
||||
rw [show w - 1 - i = w - (x.reverse.clzAuxRec (w - 1)).toNat + j by
|
||||
subst j
|
||||
rw [Nat.sub_sub (n := (x.reverse.clzAuxRec (w - 1)).toNat),
|
||||
← Nat.add_sub_assoc (by exact Nat.one_add_le_iff.mpr hi)]
|
||||
omega]
|
||||
have hfalse : ∀ (i : Nat), w - 1 < i → x.reverse.getLsbD i = false := by
|
||||
intros i hj
|
||||
simp [show w ≤ i by omega]
|
||||
exact getLsbD_false_of_clzAuxRec (x := x.reverse) (n := w - 1) hfalse (j := j)
|
||||
|
||||
/-- If a bitvec is different than zero, the bit at index `ctz x`, i.e., the first bit after the
|
||||
trailing zeros, is true. -/
|
||||
theorem getLsbD_true_ctz_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
x.getLsbD (ctz x).toNat = true := by
|
||||
simp only [ctz_eq_reverse_clz, clz]
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have := ctz_lt_iff_ne_zero (x := x)
|
||||
simp only [ctz_eq_reverse_clz, clz, natCast_eq_ofNat, lt_def, toNat_ofNat, Nat.mod_two_pow_self,
|
||||
ne_eq] at this
|
||||
simp only [this, hx, not_false_eq_true, decide_true, Bool.true_and]
|
||||
have hnotrev : ¬x.reverse = 0#w := by simp [reverse_eq_zero_iff, hx]
|
||||
apply getLsbD_true_of_eq_clzAuxRec_of_ne_zero (x := x.reverse) (n := w - 1) hnotrev
|
||||
intro i hi
|
||||
simp [show w ≤ i by omega]
|
||||
|
||||
/-- A nonzero bitvector is lower-bounded by its trailing zeroes. -/
|
||||
theorem two_pow_ctz_le_toNat_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
2 ^ (ctz x).toNat ≤ x.toNat := by
|
||||
have hclz := getLsbD_true_ctz_of_ne_zero (x := x) hx
|
||||
exact Nat.ge_two_pow_of_testBit hclz
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.NotationExtra
|
||||
|
||||
public section
|
||||
|
||||
|
||||
namespace Bool
|
||||
|
||||
/--
|
||||
|
||||
@@ -7,8 +7,5 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.ByteArray.Bootstrap
|
||||
public import Init.Data.ByteArray.Extra
|
||||
public import Init.Data.ByteArray.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -6,16 +6,25 @@ Author: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Option.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
@[expose] public section
|
||||
universe u
|
||||
|
||||
set_option genInjectivity false in
|
||||
structure ByteArray where
|
||||
data : Array UInt8
|
||||
|
||||
attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
gen_injective_theorems% ByteArray
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
deriving instance BEq for ByteArray
|
||||
@@ -25,15 +34,29 @@ attribute [ext] ByteArray
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[extern "lean_mk_empty_byte_array"]
|
||||
def emptyWithCapacity (c : @& Nat) : ByteArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
def empty : ByteArray := emptyWithCapacity 0
|
||||
|
||||
instance : Inhabited ByteArray where
|
||||
default := empty
|
||||
|
||||
instance : EmptyCollection ByteArray where
|
||||
emptyCollection := ByteArray.empty
|
||||
|
||||
@[extern "lean_byte_array_push"]
|
||||
def push : ByteArray → UInt8 → ByteArray
|
||||
| ⟨bs⟩, b => ⟨bs.push b⟩
|
||||
|
||||
@[extern "lean_byte_array_size"]
|
||||
def size : (@& ByteArray) → Nat
|
||||
| ⟨bs⟩ => bs.size
|
||||
|
||||
@[extern "lean_sarray_size", simp]
|
||||
def usize (a : @& ByteArray) : USize :=
|
||||
a.size.toUSize
|
||||
@@ -87,31 +110,11 @@ def copySlice (src : @& ByteArray) (srcOff : Nat) (dest : ByteArray) (destOff le
|
||||
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
|
||||
a.copySlice b empty 0 (e - b)
|
||||
|
||||
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
|
||||
b.copySlice 0 a a.size b.size false
|
||||
|
||||
@[simp]
|
||||
theorem size_data {a : ByteArray} :
|
||||
a.data.size = a.size := rfl
|
||||
|
||||
@[csimp]
|
||||
theorem append_eq_fastAppend : @ByteArray.append = @ByteArray.fastAppend := by
|
||||
funext a b
|
||||
ext1
|
||||
apply Array.ext'
|
||||
simp [ByteArray.fastAppend, copySlice, ← size_data, - Array.append_assoc]
|
||||
|
||||
-- Needs to come after the `csimp` lemma
|
||||
instance : Append ByteArray where
|
||||
append := ByteArray.append
|
||||
|
||||
@[simp]
|
||||
theorem append_eq {a b : ByteArray} : a.append b = a ++ b := rfl
|
||||
|
||||
@[simp]
|
||||
theorem fastAppend_eq {a b : ByteArray} : a.fastAppend b = a ++ b := by
|
||||
simp [← append_eq_fastAppend]
|
||||
instance : Append ByteArray := ⟨ByteArray.append⟩
|
||||
|
||||
def toList (bs : ByteArray) : List UInt8 :=
|
||||
let rec loop (i : Nat) (r : List UInt8) :=
|
||||
@@ -351,4 +354,37 @@ def prevn : Iterator → Nat → Iterator
|
||||
end Iterator
|
||||
end ByteArray
|
||||
|
||||
/--
|
||||
Converts a list of bytes into a `ByteArray`.
|
||||
-/
|
||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
let rec loop
|
||||
| [], r => r
|
||||
| b::bs, r => loop bs (r.push b)
|
||||
loop bs ByteArray.empty
|
||||
|
||||
instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Data.List.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem data_push {a : ByteArray} {b : UInt8} : (a.push b).data = a.data.push b := rfl
|
||||
|
||||
@[expose]
|
||||
protected def append (a b : ByteArray) : ByteArray :=
|
||||
⟨⟨a.data.toList ++ b.data.toList⟩⟩
|
||||
|
||||
@[simp]
|
||||
theorem toList_data_append' {a b : ByteArray} :
|
||||
(a.append b).data.toList = a.data.toList ++ b.data.toList := by
|
||||
have ⟨⟨a⟩⟩ := a
|
||||
have ⟨⟨b⟩⟩ := b
|
||||
rfl
|
||||
|
||||
theorem ext : {x y : ByteArray} → x.data = y.data → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
|
||||
end ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem List.toList_data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data.toList = l := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data.toList = b.data.toList ++ a by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all [toList_push]
|
||||
where
|
||||
toList_push {xs : Array UInt8} {x : UInt8} : (xs.push x).toList = xs.toList ++ [x] := by
|
||||
have ⟨xs⟩ := xs
|
||||
simp [Array.push, List.concat_eq_append]
|
||||
|
||||
theorem List.toByteArray_append' {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray.append l'.toByteArray :=
|
||||
ByteArray.ext (ext (by simp))
|
||||
where
|
||||
ext : {x y : Array UInt8} → x.toList = y.toList → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
@@ -1,34 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 7).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 0).toUInt64
|
||||
|
||||
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
|
||||
public def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
|
||||
assert! bs.size == 8
|
||||
(bs.get! 0).toUInt64 <<< 0x38 |||
|
||||
(bs.get! 1).toUInt64 <<< 0x30 |||
|
||||
(bs.get! 2).toUInt64 <<< 0x28 |||
|
||||
(bs.get! 3).toUInt64 <<< 0x20 |||
|
||||
(bs.get! 4).toUInt64 <<< 0x18 |||
|
||||
(bs.get! 5).toUInt64 <<< 0x10 |||
|
||||
(bs.get! 6).toUInt64 <<< 0x8 |||
|
||||
(bs.get! 7).toUInt64
|
||||
@@ -1,259 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
public section
|
||||
|
||||
-- At present the preferred normal form for empty byte arrays is `ByteArray.empty`
|
||||
@[simp]
|
||||
theorem emptyc_eq_empty : (∅ : ByteArray) = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem emptyWithCapacity_eq_empty : ByteArray.emptyWithCapacity 0 = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).data = a.data.extract b e := by
|
||||
simp [extract, copySlice]
|
||||
by_cases b ≤ e
|
||||
· rw [(by omega : b + (e - b) = e)]
|
||||
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
ext1
|
||||
simp [Nat.min_le_left]
|
||||
|
||||
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_append {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
|
||||
simp [List.toByteArray_append']
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_data_append {l l' : ByteArray} :
|
||||
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
|
||||
simp [← append_eq]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_append {l l' : ByteArray} :
|
||||
(l ++ l').data = l.data ++ l'.data := by
|
||||
simp [← Array.toList_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data = l.toArray := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all
|
||||
|
||||
@[simp]
|
||||
theorem List.size_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.size = l.length := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ ByteArray.size_empty⟩
|
||||
ext1
|
||||
simp [← Array.size_eq_zero_iff, h]
|
||||
|
||||
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
a[i] = a.data[i]'(by simpa [← size_data]) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_left (by simpa)]
|
||||
|
||||
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hle : a.size ≤ i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_right (by simpa)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
l.toByteArray[i]'h = l[i]'(by simp_all) := by
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
l[i]'h = l.toByteArray[i]'(by simp_all) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).size = min e a.size - b := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
rw [← size_eq_zero_iff, size_extract]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
simp only [extract_eq_empty_iff]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
|
||||
a ++ b = ByteArray.empty ↔ a = ByteArray.empty ∧ b = ByteArray.empty := by
|
||||
simp [← size_eq_zero_iff, size_append]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_eq_empty {l : List UInt8} :
|
||||
l.toByteArray = ByteArray.empty ↔ l = [] := by
|
||||
simp [← ByteArray.size_eq_zero_iff]
|
||||
|
||||
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_right_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
(hi : i ≤ j) (hk : j ≤ k) :
|
||||
a.extract i k = a.extract i j ++ a.extract j k := by
|
||||
simp
|
||||
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
|
||||
|
||||
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
simp only [ByteArray.ext_iff, ← ByteArray.size_data, ByteArray.data_append] at *
|
||||
exact Array.append_inj_left h hl
|
||||
|
||||
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract i (a ++ b).size = b := by
|
||||
subst hi
|
||||
ext1
|
||||
simp [← size_data]
|
||||
|
||||
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract 0 i = a := by
|
||||
subst hi
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
(a ++ b).extract i a.size = a.extract i a.size := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
|
||||
cases h
|
||||
rw [extract_append_size_add]
|
||||
|
||||
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
start + i < xs.size := by
|
||||
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
|
||||
apply Nat.sub_le_sub_right; apply Nat.min_le_right
|
||||
|
||||
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
|
||||
simp [getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
a.extract i j = a.extract i' j ↔ min j a.size - i = min j a.size - i' := by
|
||||
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
|
||||
|
||||
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
a.extract i (i + 1) = [a[i]].toByteArray := by
|
||||
ext
|
||||
· simp
|
||||
omega
|
||||
· rename_i j hj hj'
|
||||
obtain rfl : j = 0 := by simpa using hj'
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_one (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_two (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_three (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
|
||||
simp [ByteArray.toList, ByteArray.toList.loop]
|
||||
|
||||
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
ByteArray.copySlice src srcOff dest destOff len exact =
|
||||
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
|
||||
ext1
|
||||
simp [copySlice]
|
||||
@@ -66,6 +66,11 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
|
||||
def notLTTotal : Std.Total (¬ · < · : Char → Char → Prop) where
|
||||
total := fun x y => by simpa using Char.le_total y x
|
||||
|
||||
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
|
||||
|
||||
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
|
||||
rw [Char.ofNat, dif_pos]
|
||||
rfl
|
||||
|
||||
@@ -9,4 +9,3 @@ prelude
|
||||
public import Init.Data.Dyadic.Basic
|
||||
public import Init.Data.Dyadic.Instances
|
||||
public import Init.Data.Dyadic.Round
|
||||
public import Init.Data.Dyadic.Inv
|
||||
|
||||
@@ -75,7 +75,7 @@ theorem trailingZeros_two_mul {i : Int} (h : i ≠ 0) :
|
||||
|
||||
theorem shiftRight_trailingZeros_mod_two {i : Int} (h : i ≠ 0) :
|
||||
(i >>> i.trailingZeros) % 2 = 1 := by
|
||||
rw (occs := .pos [2]) [← Int.emod_add_mul_ediv i 2]
|
||||
rw (occs := .pos [2]) [← Int.emod_add_ediv i 2]
|
||||
rcases i.emod_two_eq with h' | h' <;> rw [h']
|
||||
· rcases Int.dvd_of_emod_eq_zero h' with ⟨a, rfl⟩
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
@@ -92,7 +92,7 @@ theorem two_pow_trailingZeros_dvd {i : Int} (h : i ≠ 0) :
|
||||
simp only [ne_eq, Int.mul_eq_zero, Int.reduceEq, false_or] at h
|
||||
rw [trailingZeros_two_mul h, Int.pow_succ']
|
||||
exact Int.mul_dvd_mul_left _ (two_pow_trailingZeros_dvd h)
|
||||
· rw (occs := .pos [1]) [← Int.emod_add_mul_ediv i 2, h', Int.add_comm, trailingZeros_two_mul_add_one]
|
||||
· rw (occs := .pos [1]) [← Int.emod_add_ediv i 2, h', Int.add_comm, trailingZeros_two_mul_add_one]
|
||||
exact Int.one_dvd _
|
||||
termination_by i.natAbs
|
||||
|
||||
@@ -415,22 +415,16 @@ theorem precision_ofIntWithPrec_le {i : Int} (h : i ≠ 0) (prec : Int) :
|
||||
| .zero => rfl
|
||||
| .ofOdd _ _ _ => rfl
|
||||
|
||||
end Dyadic
|
||||
|
||||
namespace Rat
|
||||
|
||||
open Dyadic
|
||||
|
||||
/--
|
||||
Convert a rational number `x` to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
-/
|
||||
def toDyadic (x : Rat) (prec : Int) : Dyadic :=
|
||||
def _root_.Rat.toDyadic (x : Rat) (prec : Int) : Dyadic :=
|
||||
match prec with
|
||||
| (n : Nat) => .ofIntWithPrec ((x.num <<< n) / x.den) prec
|
||||
| -(n + 1 : Nat) => .ofIntWithPrec (x.num / (x.den <<< (n + 1))) prec
|
||||
|
||||
theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
theorem _root_.Rat.toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
Rat.toDyadic (mkRat a b) prec =
|
||||
.ofIntWithPrec ((a <<< prec.toNat) / (b <<< (-prec).toNat)) prec := by
|
||||
by_cases hb : b = 0
|
||||
@@ -438,96 +432,15 @@ theorem toDyadic_mkRat (a : Int) (b : Nat) (prec : Int) :
|
||||
rcases h : mkRat a b with ⟨n, d, hnz, hr⟩
|
||||
obtain ⟨m, hm, rfl, rfl⟩ := Rat.mkRat_num_den hb h
|
||||
cases prec
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast,
|
||||
· simp only [Rat.toDyadic, Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_nat,
|
||||
shiftLeft_zero, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.ediv_ediv (by simp), ← Int.shiftLeft_mul,
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
· simp only [Rat.toDyadic, Int.natCast_shiftLeft, Int.negSucc_eq, ← Int.natCast_add_one,
|
||||
Int.toNat_neg_natCast, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
Int.toNat_neg_nat, Int.shiftLeft_zero, Int.neg_neg, Int.toNat_natCast, Int.natCast_mul]
|
||||
rw [Int.mul_comm d, ← Int.mul_shiftLeft, ← Int.ediv_ediv (by simp),
|
||||
Int.mul_ediv_cancel _ (by simpa using hm)]
|
||||
|
||||
theorem toDyadic_eq_ofIntWithPrec (x : Rat) (prec : Int) :
|
||||
x.toDyadic prec = .ofIntWithPrec ((x.num <<< prec.toNat) / (x.den <<< (-prec).toNat)) prec := by
|
||||
conv => lhs; rw [← Rat.mkRat_self x]
|
||||
rw [Rat.toDyadic_mkRat]
|
||||
|
||||
/--
|
||||
Converting a rational to a dyadic at a given precision and then back to a rational
|
||||
gives the same result as taking the floor of the rational at precision `2 ^ prec`.
|
||||
-/
|
||||
theorem toRat_toDyadic (x : Rat) (prec : Int) :
|
||||
(x.toDyadic prec).toRat = (x * 2 ^ prec).floor / 2 ^ prec := by
|
||||
rw [Rat.toDyadic_eq_ofIntWithPrec, toRat_ofIntWithPrec_eq_mul_two_pow, Rat.zpow_neg, Rat.div_def]
|
||||
congr 2
|
||||
rw [Rat.floor_def, Int.shiftLeft_eq, Nat.shiftLeft_eq]
|
||||
match prec with
|
||||
| .ofNat prec =>
|
||||
simp only [Int.ofNat_eq_coe, Int.toNat_natCast, Int.toNat_neg_natCast, Nat.pow_zero,
|
||||
Nat.mul_one]
|
||||
have : (2 ^ prec : Rat) = ((2 ^ prec : Nat) : Rat) := by simp
|
||||
rw [Rat.zpow_natCast, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [Rat.natCast_pow, Rat.natCast_ofNat, Rat.num_pow, Rat.num_ofNat, Rat.den_pow,
|
||||
Rat.den_ofNat, Nat.one_pow, Nat.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
| .negSucc prec =>
|
||||
simp only [Int.toNat_negSucc, Int.pow_zero, Int.mul_one, Int.neg_negSucc, Int.natCast_mul,
|
||||
Int.natCast_pow, Int.cast_ofNat_Int]
|
||||
have : (2 ^ ((prec : Int) + 1)) = ((2 ^ (prec + 1) : Nat) : Rat) := by simp; rfl
|
||||
rw [Int.negSucc_eq, Rat.zpow_neg, this, Rat.mul_def']
|
||||
simp only [Rat.num_mkRat, Rat.den_mkRat]
|
||||
simp only [natCast_pow, natCast_ofNat, den_inv, num_pow, num_ofNat, Int.natAbs_pow,
|
||||
Int.reduceAbs, num_inv, den_pow, den_ofNat, Nat.one_pow, Int.cast_ofNat_Int, Int.mul_one]
|
||||
have : ¬ (2 ^ (prec + 1) : Int) = 0 := NeZero.out
|
||||
simp only [if_neg this]
|
||||
have : (2 ^ (prec + 1) : Int).sign = 1 := by simpa using Int.pow_pos (by decide)
|
||||
simp only [this]
|
||||
have : x.den * 2 ^ (prec + 1) = 0 ↔ x.den = 0 := by
|
||||
rw [Nat.mul_eq_zero]
|
||||
simp_all
|
||||
simp only [this, Int.mul_one]
|
||||
split
|
||||
· simp_all
|
||||
· rw [Int.ediv_ediv (Int.ofNat_zero_le _)]
|
||||
congr 1
|
||||
rw [Int.natCast_ediv, Int.mul_ediv_cancel']
|
||||
· simp
|
||||
· rw [Int.natCast_dvd_natCast]
|
||||
apply gcd_dvd_left
|
||||
|
||||
theorem toRat_toDyadic_le {x : Rat} {prec : Int} : (x.toDyadic prec).toRat ≤ x := by
|
||||
rw [toRat_toDyadic]
|
||||
have : (x * 2 ^ prec).floor ≤ x * 2 ^ prec := Rat.floor_le _
|
||||
apply Rat.le_of_mul_le_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.div_mul_cancel]
|
||||
exact this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_pos (by decide)
|
||||
|
||||
theorem lt_toRat_toDyadic_add {x : Rat} {prec : Int} :
|
||||
x < (x.toDyadic prec + ofIntWithPrec 1 prec).toRat := by
|
||||
rw [toRat_add, toRat_toDyadic, toRat_ofIntWithPrec_eq_mul_two_pow]
|
||||
have := Rat.lt_floor_add_one (x * 2 ^ prec)
|
||||
rw [Rat.zpow_neg, Rat.div_def, ← Rat.add_mul]
|
||||
apply Rat.lt_of_mul_lt_mul_right (c := 2 ^ prec)
|
||||
rw [Rat.mul_assoc, Rat.inv_mul_cancel, Rat.mul_one]
|
||||
exact mod_cast this
|
||||
· apply Rat.ne_of_gt (Rat.zpow_pos (by decide))
|
||||
· exact Rat.zpow_nonneg (by decide)
|
||||
|
||||
-- TODO: `x.toDyadic prec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Rat
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Rounds a dyadic rational `x` down to the greatest dyadic number with precision at most `prec`
|
||||
which is less than or equal to `x`.
|
||||
@@ -566,11 +479,10 @@ theorem toDyadic_toRat (x : Dyadic) (prec : Int) :
|
||||
rw [this]
|
||||
cases h : k - prec
|
||||
· simp
|
||||
· simp only [Int.neg_negSucc, Int.natCast_add, Int.cast_ofNat_Int, Int.toNat_natCast_add_one,
|
||||
Int.toNat_negSucc, Int.shiftRight_zero]
|
||||
· simp
|
||||
rw [Int.negSucc_eq, Int.eq_neg_comm, Int.neg_sub, eq_comm, Int.sub_eq_iff_eq_add] at h
|
||||
simp only [h, ← Int.natCast_add_one, Int.add_comm _ k, ofIntWithPrec_shiftLeft_add,
|
||||
ofOdd_eq_ofIntWithPrec]
|
||||
simp only [Int.neg_negSucc, h, ← Int.natCast_add_one, Int.add_comm _ k,
|
||||
Nat.succ_eq_add_one, Int.toNat_natCast, ofIntWithPrec_shiftLeft_add, ofOdd_eq_ofIntWithPrec]
|
||||
|
||||
theorem toRat_inj {x y : Dyadic} : x.toRat = y.toRat ↔ x = y := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
@@ -666,7 +578,7 @@ theorem blt_eq_false_iff : blt x y = false ↔ ble y x = true := by
|
||||
rcases k₁ - k₂ with (_ | _) | _
|
||||
· simp
|
||||
· simp [← Int.negSucc_eq]
|
||||
· simp only [Int.neg_negSucc, decide_eq_false_iff_not, Int.not_lt,
|
||||
· simp only [Int.neg_negSucc, succ_eq_add_one, decide_eq_false_iff_not, Int.not_lt,
|
||||
decide_eq_true_eq]
|
||||
|
||||
theorem ble_iff_toRat : ble x y ↔ x.toRat ≤ y.toRat := by
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
import Init.Data.Dyadic.Basic
|
||||
import Init.Data.Dyadic.Round
|
||||
import Init.Grind.Ordered.Ring
|
||||
|
||||
/-!
|
||||
# Inversion for dyadic numbers
|
||||
-/
|
||||
|
||||
namespace Dyadic
|
||||
|
||||
/--
|
||||
Inverts a dyadic number at a given (maximum) precision.
|
||||
Returns the greatest dyadic number with precision at most `prec` which is less than or equal to `1/x`.
|
||||
For `x = 0`, returns `0`.
|
||||
-/
|
||||
def invAtPrec (x : Dyadic) (prec : Int) : Dyadic :=
|
||||
match x with
|
||||
| .zero => .zero
|
||||
| _ => x.toRat.inv.toDyadic prec
|
||||
|
||||
/-- For a positive dyadic `x`, `invAtPrec x prec * x ≤ 1`. -/
|
||||
theorem invAtPrec_mul_le_one {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
invAtPrec x prec * x ≤ 1 := by
|
||||
rw [le_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat ≤ (ofOdd n k hn).toRat.inv := Rat.toRat_toDyadic_le
|
||||
have h_pos : 0 ≤ (ofOdd n k hn).toRat := by
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.le_of_lt hx
|
||||
calc ((ofOdd n k hn).toRat.inv.toDyadic prec).toRat * (ofOdd n k hn).toRat
|
||||
≤ (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := Rat.mul_le_mul_of_nonneg_right h_le h_pos
|
||||
_ = 1 := by
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
|
||||
/-- For a positive dyadic `x`, `1 < (invAtPrec x prec + 2^(-prec)) * x`. -/
|
||||
theorem one_lt_invAtPrec_add_inc_mul {x : Dyadic} (hx : 0 < x) (prec : Int) :
|
||||
1 < (invAtPrec x prec + ofIntWithPrec 1 prec) * x := by
|
||||
rw [lt_iff_toRat]
|
||||
rw [toRat_mul]
|
||||
rw [show (1 : Dyadic).toRat = (1 : Rat) from rfl]
|
||||
unfold invAtPrec
|
||||
cases x with
|
||||
| zero =>
|
||||
exfalso
|
||||
contradiction
|
||||
| ofOdd n k hn =>
|
||||
simp only
|
||||
have h_le : (ofOdd n k hn).toRat.inv < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat :=
|
||||
Rat.lt_toRat_toDyadic_add
|
||||
have h_pos : 0 < (ofOdd n k hn).toRat := by
|
||||
rwa [lt_iff_toRat, toRat_zero] at hx
|
||||
calc
|
||||
1 = (ofOdd n k hn).toRat.inv * (ofOdd n k hn).toRat := by
|
||||
symm
|
||||
apply Rat.inv_mul_cancel
|
||||
rw [lt_iff_toRat, toRat_zero] at hx
|
||||
exact Rat.ne_of_gt hx
|
||||
_ < ((ofOdd n k hn).toRat.inv.toDyadic prec + ofIntWithPrec 1 prec).toRat * (ofOdd n k hn).toRat :=
|
||||
Rat.mul_lt_mul_of_pos_right h_le h_pos
|
||||
|
||||
-- TODO: `invAtPrec` is the unique dyadic with the given precision satisfying the two inequalities above.
|
||||
|
||||
end Dyadic
|
||||
@@ -51,11 +51,6 @@ The assumption `NeZero n` ensures that `Fin n` is nonempty.
|
||||
@[expose] protected def ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
⟨a % n, Nat.mod_lt _ (pos_of_neZero n)⟩
|
||||
|
||||
@[simp]
|
||||
theorem Internal.ofNat_eq_ofNat {n : Nat} {hn} {a : Nat} :
|
||||
letI : NeZero n := ⟨Nat.pos_iff_ne_zero.1 hn⟩
|
||||
Fin.Internal.ofNat n hn a = Fin.ofNat n a := rfl
|
||||
|
||||
@[deprecated Fin.ofNat (since := "2025-05-28")]
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
Fin.ofNat n a
|
||||
|
||||
@@ -122,7 +122,7 @@ private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i
|
||||
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
|
||||
else
|
||||
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
rw [foldlM_loop_lt]
|
||||
congr; funext
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@@ -25,12 +25,12 @@ namespace Fin
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a.val * b.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b.val) + a.val) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.pos) := rfl
|
||||
|
||||
theorem pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.pos
|
||||
|
||||
@@ -81,7 +81,7 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
|
||||
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
|
||||
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x) = x := by
|
||||
ext
|
||||
rw [val_ofNat, Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
@@ -121,6 +121,8 @@ Non-trivial loops lead to undesirable and counterintuitive elaboration behavior.
|
||||
For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
|
||||
Note: as of 2025-06-03, Mathlib has such a coercion for `Fin n` anyway!
|
||||
-/
|
||||
@[expose]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
@@ -263,7 +265,7 @@ instance : LawfulOrderLT (Fin n) where
|
||||
lt_iff := by
|
||||
simp [← Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
|
||||
|
||||
@[simp, grind =] theorem val_rev (i : Fin n) : (rev i).val = n - (i + 1) := rfl
|
||||
@[simp, grind =] 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
|
||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||
@@ -498,11 +500,9 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
||||
ext
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem cast_cast {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
@[simp] theorem cast_trans {k : Nat} (h : n = m) (h' : m = k) {i : Fin n} :
|
||||
(i.cast h).cast h' = i.cast (Eq.trans h h') := rfl
|
||||
|
||||
@[deprecated cast_cast (since := "2025-09-03")] abbrev cast_trans := @cast_cast
|
||||
|
||||
theorem castLE_of_eq {m n : Nat} (h : m = n) {h' : m ≤ n} : castLE h' = Fin.cast h := rfl
|
||||
|
||||
@[simp] theorem coe_castAdd (m : Nat) (i : Fin n) : (castAdd m i : Nat) = i := rfl
|
||||
@@ -531,7 +531,7 @@ theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||
(i.castAdd m').cast h = i.castAdd m := rfl
|
||||
|
||||
theorem castAdd_castAdd {m n p : Nat} (i : Fin m) :
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
(i.castAdd n).castAdd p = (i.castAdd (n + p)).cast (Nat.add_assoc ..).symm := rfl
|
||||
|
||||
/-- The cast of the successor is the successor of the cast. See `Fin.succ_cast_eq` for rewriting in
|
||||
the reverse direction. -/
|
||||
|
||||
@@ -30,6 +30,7 @@ opaque floatSpec : FloatSpec := {
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
64-bit floating-point numbers.
|
||||
|
||||
@@ -500,3 +501,5 @@ This function does not reduce in the kernel.
|
||||
-/
|
||||
@[extern "lean_float_scaleb"]
|
||||
opaque Float.scaleB (x : Float) (i : @& Int) : Float
|
||||
|
||||
gen_injective_theorems% Float
|
||||
|
||||
@@ -23,6 +23,7 @@ opaque float32Spec : FloatSpec := {
|
||||
decLe := fun _ _ => inferInstanceAs (Decidable True)
|
||||
}
|
||||
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
32-bit floating-point numbers.
|
||||
|
||||
@@ -513,3 +514,5 @@ This may lose precision.
|
||||
This function does not reduce in the kernel.
|
||||
-/
|
||||
@[extern "lean_float_to_float32"] opaque Float.toFloat32 : Float → Float32
|
||||
|
||||
gen_injective_theorems% Float32
|
||||
|
||||
@@ -15,12 +15,15 @@ public import Init.Data.Array.DecidableEq
|
||||
public section
|
||||
universe u
|
||||
|
||||
set_option genInjectivity false in
|
||||
structure FloatArray where
|
||||
data : Array Float
|
||||
|
||||
attribute [extern "lean_float_array_mk"] FloatArray.mk
|
||||
attribute [extern "lean_float_array_data"] FloatArray.data
|
||||
|
||||
gen_injective_theorems% FloatArray
|
||||
|
||||
namespace FloatArray
|
||||
|
||||
deriving instance BEq for FloatArray
|
||||
|
||||
@@ -8,7 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Control.State
|
||||
public import Init.Data.Int.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
@@ -168,8 +168,8 @@ private def spaceUptoLine : Format → Bool → Int → Nat → SpaceResult
|
||||
else
|
||||
{ foundLine := true }
|
||||
| text s, flatten, _, _ =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let off := String.Internal.offsetOfPos s p
|
||||
let p := s.posOf '\n'
|
||||
let off := s.offsetOfPos p
|
||||
{ foundLine := p != s.endPos, foundFlattenedHardLine := flatten && p != s.endPos, space := off }
|
||||
| append f₁ f₂, flatten, m, w => merge w (spaceUptoLine f₁ flatten m w) (spaceUptoLine f₂ flatten m)
|
||||
| nest n f, flatten, m, w => spaceUptoLine f flatten (m - n) w
|
||||
@@ -263,15 +263,15 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
| append f₁ f₂ => be w (gs' ({ i with f := f₁, activeTags := 0 }::{ i with f := f₂ }::is))
|
||||
| nest n f => be w (gs' ({ i with f, indent := i.indent + n }::is))
|
||||
| text s =>
|
||||
let p := String.Internal.posOf s '\n'
|
||||
let p := s.posOf '\n'
|
||||
if p == s.endPos then
|
||||
pushOutput s
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
pushOutput (String.Internal.extract s {} p)
|
||||
pushOutput (s.extract {} p)
|
||||
pushNewline i.indent.toNat
|
||||
let is := { i with f := text (String.Internal.extract s (String.Internal.next s p) s.endPos) }::is
|
||||
let is := { i with f := text (s.extract (s.next p) s.endPos) }::is
|
||||
-- after a hard line break, re-evaluate whether to flatten the remaining group
|
||||
-- note that we shouldn't start flattening after a hard break outside a group
|
||||
if g.fla == .disallow then
|
||||
@@ -298,7 +298,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
pushGroup FlattenBehavior.fill is gs w >>= be w
|
||||
-- if preceding fill item fit in a single line, try to fit next one too
|
||||
if g.fla.shouldFlatten then
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - String.Internal.length " ")
|
||||
let gs'@(g'::_) ← pushGroup FlattenBehavior.fill is gs (w - " ".length)
|
||||
| panic "unreachable"
|
||||
if g'.fla.shouldFlatten then
|
||||
pushOutput " "
|
||||
@@ -316,7 +316,7 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
|
||||
else
|
||||
let k ← currColumn
|
||||
if k < i.indent then
|
||||
pushOutput (String.Internal.pushn "" ' ' (i.indent - k).toNat)
|
||||
pushOutput ("".pushn ' ' (i.indent - k).toNat)
|
||||
endTags i.activeTags
|
||||
be w (gs' is)
|
||||
else
|
||||
@@ -350,7 +350,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `allOrNone`; for `fill` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracket (l : String) (f : Format) (r : String) : Format :=
|
||||
group (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
group (nest l.length $ l ++ f ++ r)
|
||||
|
||||
/--
|
||||
Creates the format `"(" ++ f ++ ")"` with a flattening group, nesting by one space.
|
||||
@@ -372,7 +372,7 @@ Creates a format `l ++ f ++ r` with a flattening group, nesting the contents by
|
||||
The group's `FlattenBehavior` is `fill`; for `allOrNone` use `Std.Format.bracketFill`.
|
||||
-/
|
||||
@[inline] def bracketFill (l : String) (f : Format) (r : String) : Format :=
|
||||
fill (nest (String.Internal.length l) $ l ++ f ++ r)
|
||||
fill (nest l.length $ l ++ f ++ r)
|
||||
|
||||
/-- The default indentation level, which is two spaces. -/
|
||||
def defIndent := 2
|
||||
@@ -397,8 +397,8 @@ private structure State where
|
||||
|
||||
private instance : MonadPrettyFormat (StateM State) where
|
||||
-- We avoid a structure instance update, and write these functions using pattern matching because of issue #316
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨String.Internal.append out s, col + (String.Internal.length s)⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨String.Internal.append out (String.Internal.pushn "\n" ' ' indent), indent⟩
|
||||
pushOutput s := modify fun ⟨out, col⟩ => ⟨out ++ s, col + s.length⟩
|
||||
pushNewline indent := modify fun ⟨out, _⟩ => ⟨out ++ "\n".pushn ' ' indent, indent⟩
|
||||
currColumn := return (← get).column
|
||||
startTag _ := return ()
|
||||
endTags _ := return ()
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.Data.Format.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.ToString.Basic
|
||||
import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ prelude
|
||||
public import Init.Data.Format.Macro
|
||||
public import Init.Data.Format.Instances
|
||||
public import Init.Meta
|
||||
import Init.Data.String.Basic
|
||||
import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -3,11 +3,15 @@ Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.Grind.Tactics
|
||||
|
||||
public section
|
||||
|
||||
namespace Function
|
||||
|
||||
/--
|
||||
@@ -30,108 +34,20 @@ Examples:
|
||||
@[inline, expose]
|
||||
def uncurry : (α → β → φ) → α × β → φ := fun f a => f a.1 a.2
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem curry_uncurry (f : α → β → φ) : curry (uncurry f) = f :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem uncurry_curry (f : α × β → φ) : uncurry (curry f) = f :=
|
||||
funext fun ⟨_a, _b⟩ => rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem uncurry_apply_pair {α β γ} (f : α → β → γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f x y = f (x, y) :=
|
||||
rfl
|
||||
|
||||
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
|
||||
@[expose]
|
||||
def Injective (f : α → β) : Prop :=
|
||||
∀ ⦃a₁ a₂⦄, f a₁ = f a₂ → a₁ = a₂
|
||||
|
||||
theorem Injective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Injective g) (hf : Injective f) :
|
||||
Injective (g ∘ f) := fun _a₁ _a₂ => fun h => hf (hg h)
|
||||
|
||||
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
|
||||
for some `a : α`. -/
|
||||
@[expose]
|
||||
def Surjective (f : α → β) : Prop :=
|
||||
∀ b, Exists fun a => f a = b
|
||||
|
||||
theorem Surjective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Surjective g) (hf : Surjective f) :
|
||||
Surjective (g ∘ f) := fun c : γ =>
|
||||
Exists.elim (hg c) fun b hb =>
|
||||
Exists.elim (hf b) fun a ha =>
|
||||
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
|
||||
|
||||
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
|
||||
@[expose, grind]
|
||||
def LeftInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
∀ x, g (f x) = x
|
||||
|
||||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||||
@[expose]
|
||||
def HasLeftInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => LeftInverse finv f
|
||||
|
||||
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
|
||||
@[expose, grind]
|
||||
def RightInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
LeftInverse f g
|
||||
|
||||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||||
@[expose]
|
||||
def HasRightInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => RightInverse finv f
|
||||
|
||||
theorem LeftInverse.injective {α β} {g : β → α} {f : α → β} : LeftInverse g f → Injective f :=
|
||||
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
|
||||
|
||||
theorem HasLeftInverse.injective {α β} {f : α → β} : HasLeftInverse f → Injective f := fun h =>
|
||||
Exists.elim h fun _finv inv => inv.injective
|
||||
|
||||
theorem rightInverse_of_injective_of_leftInverse {α β} {f : α → β} {g : β → α} (injf : Injective f)
|
||||
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
|
||||
have h : f (g (f x)) = f x := lfg (f x)
|
||||
injf h
|
||||
|
||||
theorem RightInverse.surjective {α β} {f : α → β} {g : β → α} (h : RightInverse g f) : Surjective f :=
|
||||
fun y => ⟨g y, h y⟩
|
||||
|
||||
theorem HasRightInverse.surjective {α β} {f : α → β} : HasRightInverse f → Surjective f
|
||||
| ⟨_finv, inv⟩ => inv.surjective
|
||||
|
||||
theorem leftInverse_of_surjective_of_rightInverse {α β} {f : α → β} {g : β → α} (surjf : Surjective f)
|
||||
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
|
||||
Exists.elim (surjf y) fun x hx => ((hx ▸ rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) ▸ rfl)).trans hx
|
||||
|
||||
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
|
||||
|
||||
theorem surjective_id : Surjective (@id α) := fun a => ⟨a, rfl⟩
|
||||
|
||||
variable {f : α → β}
|
||||
|
||||
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b ↔ a = b :=
|
||||
⟨@I _ _, congrArg f⟩
|
||||
|
||||
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c ↔ a = b :=
|
||||
h ▸ I.eq_iff
|
||||
|
||||
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ ≠ a₂ → f a₁ ≠ f a₂ :=
|
||||
mt fun h ↦ hf h
|
||||
|
||||
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x ≠ f y ↔ x ≠ y :=
|
||||
⟨mt <| congrArg f, hf.ne⟩
|
||||
|
||||
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x ≠ z ↔ x ≠ y :=
|
||||
h ▸ hf.ne_iff
|
||||
|
||||
protected theorem LeftInverse.id {α β} {g : β → α} {f : α → β} (h : LeftInverse g f) : g ∘ f = id :=
|
||||
funext h
|
||||
|
||||
protected theorem RightInverse.id {α β} {g : β → α} {f : α → β} (h : RightInverse g f) : f ∘ g = id :=
|
||||
funext h
|
||||
|
||||
end Function
|
||||
|
||||
@@ -31,7 +31,7 @@ This file defines the `Int` type as well as
|
||||
Division and modulus operations are defined in `Init.Data.Int.DivMod.Basic`.
|
||||
-/
|
||||
|
||||
set_option genCtorIdx false in
|
||||
set_option genInjectivity false in
|
||||
/--
|
||||
The integers.
|
||||
|
||||
@@ -321,7 +321,7 @@ def natAbs (m : @& Int) : Nat :=
|
||||
| ofNat m => m
|
||||
| -[m +1] => m.succ
|
||||
|
||||
attribute [gen_constructor_elims] Int
|
||||
gen_injective_theorems% Int
|
||||
|
||||
/-! ## sign -/
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ theorem ofNat_emod (m n : Nat) : (↑(m % n) : Int) = m % n := natCast_emod m n
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem emod_add_mul_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
theorem emod_add_ediv : ∀ a b : Int, a % b + b * (a / b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -111,35 +111,19 @@ where
|
||||
← Int.neg_neg (_-_), Int.neg_sub, Int.sub_sub_self, Int.add_right_comm]
|
||||
exact congrArg (fun x => -(ofNat x + 1)) (Nat.mod_add_div ..)
|
||||
|
||||
@[deprecated emod_add_mul_ediv (since := "2025-09-01")]
|
||||
def emod_add_ediv := @emod_add_mul_ediv
|
||||
/-- Variant of `emod_add_ediv` with the multiplication written the other way around. -/
|
||||
theorem emod_add_ediv' (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_ediv ..
|
||||
|
||||
theorem emod_add_ediv_mul (a b : Int) : a % b + a / b * b = a := by
|
||||
rw [Int.mul_comm]; exact emod_add_mul_ediv ..
|
||||
theorem ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_ediv ..
|
||||
|
||||
@[deprecated emod_add_ediv_mul (since := "2025-09-01")]
|
||||
def emod_add_ediv' := @emod_add_ediv_mul
|
||||
|
||||
theorem mul_ediv_add_emod (a b : Int) : b * (a / b) + a % b = a := by
|
||||
rw [Int.add_comm]; exact emod_add_mul_ediv ..
|
||||
|
||||
@[deprecated mul_ediv_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod := @mul_ediv_add_emod
|
||||
|
||||
theorem ediv_mul_add_emod (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact mul_ediv_add_emod ..
|
||||
|
||||
@[deprecated ediv_mul_add_emod (since := "2025-09-01")]
|
||||
def ediv_add_emod' := @ediv_mul_add_emod
|
||||
/-- Variant of `ediv_add_emod` with the multiplication written the other way around. -/
|
||||
theorem ediv_add_emod' (a b : Int) : a / b * b + a % b = a := by
|
||||
rw [Int.mul_comm]; exact ediv_add_emod ..
|
||||
|
||||
theorem emod_def (a b : Int) : a % b = a - b * (a / b) := by
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_mul_ediv]
|
||||
|
||||
theorem mul_ediv_self (a b : Int) : b * (a / b) = a - a % b := by
|
||||
rw [emod_def, Int.sub_sub_self]
|
||||
|
||||
theorem ediv_mul_self (a b : Int) : a / b * b = a - a % b := by
|
||||
rw [Int.mul_comm, emod_def, Int.sub_sub_self]
|
||||
rw [← Int.add_sub_cancel (a % b), emod_add_ediv]
|
||||
|
||||
/-! ### `/` ediv -/
|
||||
|
||||
@@ -206,6 +190,9 @@ theorem ediv_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : 0 ≤ a / b ↔ 0 ≤ a
|
||||
| Int.ofNat (b+1), _ =>
|
||||
rcases a with ⟨a⟩ <;> simp [Int.ediv, -natCast_ediv]
|
||||
|
||||
@[deprecated ediv_nonneg_iff_of_pos (since := "2025-02-28")]
|
||||
abbrev div_nonneg_iff_of_pos := @ediv_nonneg_iff_of_pos
|
||||
|
||||
/-! ### emod -/
|
||||
|
||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||
@@ -239,7 +226,7 @@ theorem add_mul_emod_self {a b c : Int} : (a + b * c) % c = a % c :=
|
||||
|
||||
@[simp] theorem emod_add_emod (m n k : Int) : (m % n + k) % n = (m + k) % n := by
|
||||
have := (add_mul_emod_self_left (m % n + k) n (m / n)).symm
|
||||
rwa [Int.add_right_comm, emod_add_mul_ediv] at this
|
||||
rwa [Int.add_right_comm, emod_add_ediv] at this
|
||||
|
||||
@[simp] theorem add_emod_emod (m n k : Int) : (m + n % k) % k = (m + n) % k := by
|
||||
rw [Int.add_comm, emod_add_emod, Int.add_comm]
|
||||
@@ -265,7 +252,7 @@ theorem emod_add_cancel_right {m n k : Int} (i) : (m + i) % n = (k + i) % n ↔
|
||||
|
||||
theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
conv => lhs; rw [
|
||||
← emod_add_mul_ediv a n, ← emod_add_ediv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← emod_add_ediv a n, ← emod_add_ediv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_emod_self_left,
|
||||
← Int.mul_assoc, add_mul_emod_self_right]
|
||||
|
||||
@@ -274,7 +261,7 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
||||
|
||||
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n % k) % m = n % m := by
|
||||
conv => rhs; rw [← emod_add_mul_ediv n k]
|
||||
conv => rhs; rw [← emod_add_ediv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_emod_self_left]
|
||||
|
||||
@@ -288,7 +275,7 @@ theorem sub_emod (a b n : Int) : (a - b) % n = (a % n - b % n) % n := by
|
||||
/-! ### properties of `/` and `%` -/
|
||||
|
||||
theorem mul_ediv_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : b * (a / b) = a := by
|
||||
have := emod_add_mul_ediv a b; rwa [H, Int.zero_add] at this
|
||||
have := emod_add_ediv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem ediv_mul_cancel_of_emod_eq_zero {a b : Int} (H : a % b = 0) : a / b * b = a := by
|
||||
rw [Int.mul_comm, mul_ediv_cancel_of_emod_eq_zero H]
|
||||
@@ -339,11 +326,11 @@ theorem emod_pos_of_not_dvd {a b : Int} (h : ¬ a ∣ b) : a = 0 ∨ 0 < b % a :
|
||||
theorem mul_ediv_self_le {x k : Int} (h : k ≠ 0) : k * (x / k) ≤ x :=
|
||||
calc k * (x / k)
|
||||
_ ≤ k * (x / k) + x % k := Int.le_add_of_nonneg_right (emod_nonneg x h)
|
||||
_ = x := mul_ediv_add_emod _ _
|
||||
_ = x := ediv_add_emod _ _
|
||||
|
||||
theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
||||
calc x
|
||||
_ = k * (x / k) + x % k := (mul_ediv_add_emod _ _).symm
|
||||
_ = k * (x / k) + x % k := (ediv_add_emod _ _).symm
|
||||
_ < k * (x / k) + k := Int.add_lt_add_left (emod_lt_of_pos x h) _
|
||||
|
||||
/-! ### bmod -/
|
||||
|
||||
@@ -334,7 +334,7 @@ theorem fdiv_eq_ediv_of_dvd {a b : Int} (h : b ∣ a) : a.fdiv b = a / b := by
|
||||
|
||||
/-! ### mod definitions -/
|
||||
|
||||
theorem tmod_add_mul_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
theorem tmod_add_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
| ofNat _, ofNat _ => congrArg ofNat (Nat.mod_add_div ..)
|
||||
| ofNat m, -[n+1] => by
|
||||
change (m % succ n + -↑(succ n) * -↑(m / succ n) : Int) = m
|
||||
@@ -351,37 +351,21 @@ theorem tmod_add_mul_tdiv : ∀ a b : Int, tmod a b + b * (a.tdiv b) = a
|
||||
rw [Int.neg_mul, ← Int.neg_add]
|
||||
exact congrArg (-ofNat ·) (Nat.mod_add_div ..)
|
||||
|
||||
@[deprecated tmod_add_mul_tdiv (since := "2025-09-01")]
|
||||
def tmod_add_tdiv := @tmod_add_mul_tdiv
|
||||
theorem tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_tdiv ..
|
||||
|
||||
theorem mul_tdiv_add_tmod (a b : Int) : b * a.tdiv b + tmod a b = a := by
|
||||
rw [Int.add_comm]; apply tmod_add_mul_tdiv ..
|
||||
/-- Variant of `tmod_add_tdiv` with the multiplication written the other way around. -/
|
||||
theorem tmod_add_tdiv' (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_tdiv
|
||||
|
||||
@[deprecated mul_tdiv_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod := @mul_tdiv_add_tmod
|
||||
|
||||
theorem tmod_add_tdiv_mul (m k : Int) : tmod m k + m.tdiv k * k = m := by
|
||||
rw [Int.mul_comm]; apply tmod_add_mul_tdiv
|
||||
|
||||
@[deprecated tmod_add_tdiv_mul (since := "2025-09-01")]
|
||||
def tmod_add_tdiv' := @tmod_add_mul_tdiv
|
||||
|
||||
theorem tdiv_mul_add_tmod (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply mul_tdiv_add_tmod
|
||||
|
||||
@[deprecated tdiv_mul_add_tmod (since := "2025-09-01")]
|
||||
def tdiv_add_tmod' := @tdiv_mul_add_tmod
|
||||
/-- Variant of `tdiv_add_tmod` with the multiplication written the other way around. -/
|
||||
theorem tdiv_add_tmod' (m k : Int) : m.tdiv k * k + tmod m k = m := by
|
||||
rw [Int.mul_comm]; apply tdiv_add_tmod
|
||||
|
||||
theorem tmod_def (a b : Int) : tmod a b = a - b * a.tdiv b := by
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_mul_tdiv]
|
||||
rw [← Int.add_sub_cancel (tmod a b), tmod_add_tdiv]
|
||||
|
||||
theorem mul_tdiv_self (a b : Int) : b * (a.tdiv b) = a - a.tmod b := by
|
||||
rw [tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem tdiv_mul_self (a b : Int) : a.tdiv b * b = a - a.tmod b := by
|
||||
rw [Int.mul_comm, tmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fmod_add_mul_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
theorem fmod_add_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
| 0, ofNat _ | 0, -[_+1] => congrArg ofNat <| by simp
|
||||
| succ _, ofNat _ => congrArg ofNat <| Nat.mod_add_div ..
|
||||
| succ m, -[n+1] => by
|
||||
@@ -398,35 +382,19 @@ theorem fmod_add_mul_fdiv : ∀ a b : Int, a.fmod b + b * a.fdiv b = a
|
||||
change -(↑(succ m % succ n) : Int) + -↑(succ n * (succ m / succ n)) = -↑(succ m)
|
||||
rw [← Int.neg_add]; exact congrArg (-ofNat ·) <| Nat.mod_add_div ..
|
||||
|
||||
@[deprecated fmod_add_mul_fdiv (since := "2025-09-01")]
|
||||
def fmod_add_fdiv := @fmod_add_mul_fdiv
|
||||
/-- Variant of `fmod_add_fdiv` with the multiplication written the other way around. -/
|
||||
theorem fmod_add_fdiv' (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
theorem fmod_add_fdiv_mul (a b : Int) : a.fmod b + (a.fdiv b) * b = a := by
|
||||
rw [Int.mul_comm]; exact fmod_add_mul_fdiv ..
|
||||
theorem fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_fdiv ..
|
||||
|
||||
@[deprecated fmod_add_fdiv_mul (since := "2025-09-01")]
|
||||
def fmod_add_fdiv' := @fmod_add_fdiv_mul
|
||||
|
||||
theorem mul_fdiv_add_fmod (a b : Int) : b * a.fdiv b + a.fmod b = a := by
|
||||
rw [Int.add_comm]; exact fmod_add_mul_fdiv ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod := @mul_fdiv_add_fmod
|
||||
|
||||
theorem fdiv_mul_add_fmod (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact mul_fdiv_add_fmod ..
|
||||
|
||||
@[deprecated mul_fdiv_add_fmod (since := "2025-09-01")]
|
||||
def fdiv_add_fmod' := @mul_fdiv_add_fmod
|
||||
/-- Variant of `fdiv_add_fmod` with the multiplication written the other way around. -/
|
||||
theorem fdiv_add_fmod' (a b : Int) : (a.fdiv b) * b + a.fmod b = a := by
|
||||
rw [Int.mul_comm]; exact fdiv_add_fmod ..
|
||||
|
||||
theorem fmod_def (a b : Int) : a.fmod b = a - b * a.fdiv b := by
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_mul_fdiv]
|
||||
|
||||
theorem mul_fdiv_self (a b : Int) : b * (a.fdiv b) = a - a.fmod b := by
|
||||
rw [fmod_def, Int.sub_sub_self]
|
||||
|
||||
theorem fdiv_mul_self (a b : Int) : a.fdiv b * b = a - a.fmod b := by
|
||||
rw [Int.mul_comm, fmod_def, Int.sub_sub_self]
|
||||
rw [← Int.add_sub_cancel (a.fmod b), fmod_add_fdiv]
|
||||
|
||||
/-! ### mod equivalences -/
|
||||
|
||||
@@ -805,7 +773,7 @@ protected theorem ediv_emod_unique {a b r q : Int} (h : 0 < b) :
|
||||
a / b = q ∧ a % b = r ↔ r + b * q = a ∧ 0 ≤ r ∧ r < b := by
|
||||
constructor
|
||||
· intro ⟨rfl, rfl⟩
|
||||
exact ⟨emod_add_mul_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
exact ⟨emod_add_ediv a b, emod_nonneg _ (Int.ne_of_gt h), emod_lt_of_pos _ h⟩
|
||||
· intro ⟨rfl, hz, hb⟩
|
||||
constructor
|
||||
· rw [Int.add_mul_ediv_left r q (Int.ne_of_gt h), ediv_eq_zero_of_lt hz hb]
|
||||
@@ -829,7 +797,7 @@ theorem neg_ediv {a b : Int} : (-a) / b = -(a / b) - if b ∣ a then 0 else b.si
|
||||
if hb : b = 0 then
|
||||
simp [hb]
|
||||
else
|
||||
conv => lhs; rw [← mul_ediv_add_emod a b]
|
||||
conv => lhs; rw [← ediv_add_emod a b]
|
||||
rw [Int.neg_add, ← Int.mul_neg, mul_add_ediv_left _ _ hb, Int.add_comm]
|
||||
split <;> rename_i h
|
||||
· rw [emod_eq_zero_of_dvd h]
|
||||
@@ -1119,10 +1087,6 @@ theorem emod_natAbs_of_neg {x : Int} (h : x < 0) {n : Nat} (w : n ≠ 0) :
|
||||
protected theorem ediv_mul_le (a : Int) {b : Int} (H : b ≠ 0) : a / b * b ≤ a :=
|
||||
Int.le_of_sub_nonneg <| by rw [Int.mul_comm, ← emod_def]; apply emod_nonneg _ H
|
||||
|
||||
protected theorem lt_ediv_mul (a : Int) {b : Int} (H : 0 < b) : a - b < a / b * b := by
|
||||
rw [ediv_mul_self, Int.sub_lt_sub_left_iff]
|
||||
exact emod_lt_of_pos a H
|
||||
|
||||
theorem le_of_mul_le_mul_left {a b c : Int} (w : a * b ≤ a * c) (h : 0 < a) : b ≤ c := by
|
||||
have w := Int.sub_nonneg_of_le w
|
||||
rw [← Int.mul_sub] at w
|
||||
@@ -1213,9 +1177,9 @@ theorem ediv_eq_iff_of_pos {k x y : Int} (h : 0 < k) : x / k = y ↔ y * k ≤ x
|
||||
theorem add_ediv_of_pos {a b c : Int} (h : 0 < c) :
|
||||
(a + b) / c = a / c + b / c + if c ≤ a % c + b % c then 1 else 0 := by
|
||||
have h' : c ≠ 0 := by omega
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod a c]
|
||||
conv => lhs; rw [← Int.ediv_add_emod a c]
|
||||
rw [Int.add_assoc, Int.mul_add_ediv_left _ _ h']
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod b c]
|
||||
conv => lhs; rw [← Int.ediv_add_emod b c]
|
||||
rw [Int.add_comm (a % c), Int.add_assoc, Int.mul_add_ediv_left _ _ h',
|
||||
← Int.add_assoc, Int.add_comm (b % c)]
|
||||
congr
|
||||
@@ -1246,7 +1210,7 @@ theorem not_dvd_iff_lt_mul_succ (m : Int) (hn : 0 < n) :
|
||||
¬n ∣ m ↔ (∃ k, n * k < m ∧ m < n * (k + 1)) := by
|
||||
refine ⟨fun h ↦ ?_, ?_⟩
|
||||
· rw [dvd_iff_emod_eq_zero, ← Ne] at h
|
||||
rw [← emod_add_mul_ediv m n]
|
||||
rw [← emod_add_ediv m n]
|
||||
refine ⟨m / n, Int.lt_add_of_pos_left _ ?_, ?_⟩
|
||||
· have := emod_nonneg m (Int.ne_of_gt hn)
|
||||
omega
|
||||
@@ -1521,7 +1485,7 @@ theorem sign_tmod (a b : Int) : sign (tmod a b) = if b ∣ a then 0 else sign a
|
||||
-- Analogues of statements about `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_tdiv_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : b * (a.tdiv b) = a := by
|
||||
have := tmod_add_mul_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := tmod_add_tdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem tdiv_mul_cancel_of_tmod_eq_zero {a b : Int} (H : a.tmod b = 0) : a.tdiv b * b = a := by
|
||||
rw [Int.mul_comm, mul_tdiv_cancel_of_tmod_eq_zero H]
|
||||
@@ -2246,7 +2210,7 @@ theorem fmod_add_cancel_right {m n k : Int} (i) : (m + i).fmod n = (k + i).fmod
|
||||
|
||||
theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n := by
|
||||
conv => lhs; rw [
|
||||
← fmod_add_mul_fdiv a n, ← fmod_add_fdiv_mul b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
← fmod_add_fdiv a n, ← fmod_add_fdiv' b n, Int.add_mul, Int.mul_add, Int.mul_add,
|
||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_fmod_self_left,
|
||||
← Int.mul_assoc, add_mul_fmod_self_right]
|
||||
|
||||
@@ -2255,7 +2219,7 @@ theorem mul_fmod (a b n : Int) : (a * b).fmod n = (a.fmod n * b.fmod n).fmod n :
|
||||
|
||||
@[simp] theorem fmod_fmod_of_dvd (n : Int) {m k : Int}
|
||||
(h : m ∣ k) : (n.fmod k).fmod m = n.fmod m := by
|
||||
conv => rhs; rw [← fmod_add_mul_fdiv n k]
|
||||
conv => rhs; rw [← fmod_add_fdiv n k]
|
||||
match k, h with
|
||||
| _, ⟨t, rfl⟩ => rw [Int.mul_assoc, add_mul_fmod_self_left]
|
||||
|
||||
@@ -2285,7 +2249,7 @@ theorem fmod_eq_of_lt {a b : Int} (H1 : 0 ≤ a) (H2 : a < b) : a.fmod b = a :=
|
||||
-- Analogues of properties of `ediv` and `emod` from `Bootstrap.lean`
|
||||
|
||||
theorem mul_fdiv_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : b * (a.fdiv b) = a := by
|
||||
have := fmod_add_mul_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
have := fmod_add_fdiv a b; rwa [H, Int.zero_add] at this
|
||||
|
||||
theorem fdiv_mul_cancel_of_fmod_eq_zero {a b : Int} (H : a.fmod b = 0) : (a.fdiv b) * b= a := by
|
||||
rw [Int.mul_comm, mul_fdiv_cancel_of_fmod_eq_zero H]
|
||||
@@ -2527,9 +2491,9 @@ theorem bdiv_add_bmod (x : Int) (m : Nat) : m * bdiv x m + bmod x m = x := by
|
||||
ite_self]
|
||||
· dsimp only
|
||||
split
|
||||
· exact mul_ediv_add_emod x m
|
||||
· exact ediv_add_emod x m
|
||||
· rw [Int.mul_add, Int.mul_one, Int.add_assoc, Int.add_comm m, Int.sub_add_cancel]
|
||||
exact mul_ediv_add_emod x m
|
||||
exact ediv_add_emod x m
|
||||
|
||||
theorem bmod_add_bdiv (x : Int) (m : Nat) : bmod x m + m * bdiv x m = x := by
|
||||
rw [Int.add_comm]; exact bdiv_add_bmod x m
|
||||
@@ -2786,7 +2750,7 @@ theorem le_bmod {x : Int} {m : Nat} (h : 0 < m) : - (m/2) ≤ Int.bmod x m := by
|
||||
· exact Int.ne_of_gt (natCast_pos.mpr h)
|
||||
· simp [Int.not_lt] at w
|
||||
refine Int.le_trans ?_ (Int.sub_le_sub_right w _)
|
||||
rw [← mul_ediv_add_emod m 2]
|
||||
rw [← ediv_add_emod m 2]
|
||||
generalize (m : Int) / 2 = q
|
||||
generalize h : (m : Int) % 2 = r at *
|
||||
rcases v with rfl | rfl
|
||||
@@ -2947,7 +2911,7 @@ theorem neg_bmod {a : Int} {b : Nat} :
|
||||
simp only [gt_iff_lt, Nat.zero_lt_succ, Nat.mul_pos_iff_of_pos_left, Int.natCast_mul,
|
||||
cast_ofNat_Int, Int.not_lt] at *
|
||||
rw [Int.mul_dvd_mul_iff_left (by omega)]
|
||||
have := mul_ediv_add_emod a (2 * c)
|
||||
have := ediv_add_emod a (2 * c)
|
||||
rw [(by omega : a % (2 * c) = c)] at this
|
||||
rw [← this]
|
||||
apply Int.dvd_add _ (by simp)
|
||||
|
||||
@@ -40,7 +40,7 @@ theorem ofNat_succ (n : Nat) : (succ n : Int) = n + 1 := rfl
|
||||
|
||||
theorem neg_ofNat_zero : -((0 : Nat) : Int) = 0 := rfl
|
||||
theorem neg_ofNat_succ (n : Nat) : -(succ n : Int) = -[n+1] := rfl
|
||||
@[simp] theorem neg_negSucc (n : Nat) : -(-[n+1]) = ((n + 1 : Nat) : Int) := rfl
|
||||
theorem neg_negSucc (n : Nat) : -(-[n+1]) = succ n := rfl
|
||||
|
||||
theorem negOfNat_eq : negOfNat n = -ofNat n := rfl
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import all Init.Data.Int.Gcd
|
||||
public import Init.Data.RArray
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -55,7 +54,7 @@ def Expr.denote (ctx : Context) : Expr → Int
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving @[expose] BEq, ReflBEq, LawfulBEq
|
||||
deriving @[expose] BEq
|
||||
|
||||
@[expose]
|
||||
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
@@ -248,7 +247,7 @@ def cmod (a b : Int) : Int :=
|
||||
|
||||
theorem cdiv_add_cmod (a b : Int) : b*(cdiv a b) + cmod a b = a := by
|
||||
unfold cdiv cmod
|
||||
have := Int.mul_ediv_add_emod (-a) b
|
||||
have := Int.ediv_add_emod (-a) b
|
||||
have := congrArg (Neg.neg) this
|
||||
simp at this
|
||||
conv => rhs; rw[← this]
|
||||
@@ -273,7 +272,7 @@ private abbrev div_mul_cancel_of_mod_zero :=
|
||||
theorem cdiv_eq_div_of_divides {a b : Int} (h : a % b = 0) : a/b = cdiv a b := by
|
||||
replace h := div_mul_cancel_of_mod_zero h
|
||||
have hz : a % b = 0 := by
|
||||
have := Int.mul_ediv_add_emod a b
|
||||
have := Int.ediv_add_emod a b
|
||||
conv at this => rhs; rw [← Int.add_zero a]
|
||||
rw [Int.mul_comm, h] at this
|
||||
exact Int.add_left_cancel this
|
||||
@@ -380,11 +379,8 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
p₁)
|
||||
fuel
|
||||
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) (p₁ p₂ : Poly) : Poly :=
|
||||
Bool.rec
|
||||
(Bool.rec (combine_mul_k' hugeFuel a b p₁ p₂) (p₁.mul_k a) (Int.beq' b 0))
|
||||
(p₂.mul_k b)
|
||||
(Int.beq' a 0)
|
||||
@[expose] noncomputable def Poly.combine_mul_k (a b : Int) : Poly → Poly → Poly :=
|
||||
combine_mul_k' hugeFuel a b
|
||||
|
||||
@[simp] theorem Poly.denote_mul (ctx : Context) (p : Poly) (k : Int) : (p.mul k).denote ctx = k * p.denote ctx := by
|
||||
simp [mul]
|
||||
@@ -428,36 +424,34 @@ theorem Poly.denote_combine (ctx : Context) (p₁ p₂ : Poly) : (p₁.combine p
|
||||
|
||||
theorem Poly.denote_combine_mul_k (ctx : Context) (a b : Int) (p₁ p₂ : Poly) : (p₁.combine_mul_k a b p₂).denote ctx = a * p₁.denote ctx + b * p₂.denote ctx := by
|
||||
unfold combine_mul_k
|
||||
cases h₁ : Int.beq' a 0 <;> simp at h₁ <;> simp [*]
|
||||
cases h₂ : Int.beq' b 0 <;> simp at h₂ <;> simp [*]
|
||||
generalize hugeFuel = fuel
|
||||
induction fuel generalizing p₁ p₂
|
||||
next => show ((p₁.mul a).append (p₂.mul b)).denote ctx = _; simp
|
||||
next fuel ih =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
cases p₁ <;> cases p₂ <;> simp [combine_mul_k']
|
||||
next k₁ k₂ v₂ p₂ =>
|
||||
show _ + (combine_mul_k' fuel a b (.num k₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (.num k₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next k₁ v₁ p₁ k₂ v₂ p₂ =>
|
||||
cases h₁ : Nat.beq v₁ v₂ <;> simp
|
||||
next =>
|
||||
cases h₂ : Nat.blt v₂ v₁ <;> simp
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b (add k₁ v₁ p₁) p₂).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
show _ + (combine_mul_k' fuel a b p₁ (add k₂ v₂ p₂)).denote ctx = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
simp at h₁; subst v₂
|
||||
cases h₂ : (a * k₁ + b * k₂).beq' 0 <;> simp
|
||||
next =>
|
||||
show a * k₁ * v₁.denote ctx + (b * k₂ * v₁.denote ctx + (combine_mul_k' fuel a b p₁ p₂).denote ctx) = _
|
||||
simp [ih, Int.mul_assoc]
|
||||
next =>
|
||||
next =>
|
||||
simp at h₂
|
||||
show (combine_mul_k' fuel a b p₁ p₂).denote ctx = _
|
||||
simp [ih, ← Int.mul_assoc, ← Int.add_mul, h₂]
|
||||
@@ -526,6 +520,18 @@ theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.deno
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go]
|
||||
|
||||
attribute [local simp] Expr.denote_norm
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next ih =>
|
||||
intro _ _ h
|
||||
exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
|
||||
attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm.beq' p) : e.denote ctx = p.denote' ctx := by
|
||||
@@ -1747,7 +1753,7 @@ theorem cooper_right_split_dvd (ctx : Context) (p₁ p₂ : Poly) (k : Nat) (b :
|
||||
intros; subst b p'; simp; assumption
|
||||
|
||||
private theorem one_emod_eq_one {a : Int} (h : a > 1) : 1 % a = 1 := by
|
||||
have aux₁ := Int.mul_ediv_add_emod 1 a
|
||||
have aux₁ := Int.ediv_add_emod 1 a
|
||||
have : 1 / a = 0 := Int.ediv_eq_zero_of_lt (by decide) h
|
||||
simp [this] at aux₁
|
||||
assumption
|
||||
@@ -1774,7 +1780,7 @@ private theorem ex_of_dvd {α β a b d x : Int}
|
||||
rw [Int.mul_emod, aux₁, Int.one_mul, Int.emod_emod] at this
|
||||
assumption
|
||||
have : x = (x / d)*d + (- α * b) % d := by
|
||||
conv => lhs; rw [← Int.mul_ediv_add_emod x d]
|
||||
conv => lhs; rw [← Int.ediv_add_emod x d]
|
||||
rw [Int.mul_comm, this]
|
||||
exists x / d
|
||||
|
||||
@@ -1857,7 +1863,7 @@ theorem cooper_unsat (ctx : Context) (p₁ p₂ p₃ : Poly) (d : Int) (α β :
|
||||
exact cooper_unsat' h₁ h₂ h₃ h₄ h₅ h₆
|
||||
|
||||
theorem ediv_emod (x y : Int) : -1 * x + y * (x / y) + x % y = 0 := by
|
||||
rw [Int.add_assoc, Int.mul_ediv_add_emod x y, Int.add_comm]
|
||||
rw [Int.add_assoc, Int.ediv_add_emod x y, Int.add_comm]
|
||||
simp
|
||||
rw [Int.add_neg_eq_sub, Int.sub_self]
|
||||
|
||||
|
||||
@@ -701,13 +701,10 @@ theorem toNat_sub_toNat_neg : ∀ n : Int, ↑n.toNat - ↑(-n).toNat = n
|
||||
| (_+1:Nat) => Nat.add_zero _
|
||||
| -[_+1] => Nat.zero_add _
|
||||
|
||||
@[simp] theorem toNat_neg_natCast : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
@[simp] theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0
|
||||
| 0 => rfl
|
||||
| _+1 => rfl
|
||||
|
||||
@[deprecated toNat_neg_natCast (since := "2025-08-29")]
|
||||
theorem toNat_neg_nat : ∀ n : Nat, (-(n : Int)).toNat = 0 := toNat_neg_natCast
|
||||
|
||||
/-! ### toNat? -/
|
||||
|
||||
theorem mem_toNat? : ∀ {a : Int} {n : Nat}, toNat? a = some n ↔ a = n
|
||||
@@ -1347,6 +1344,8 @@ theorem neg_of_sign_eq_neg_one : ∀ {a : Int}, sign a = -1 → a < 0
|
||||
| 0 => Int.mul_zero _
|
||||
| -[_+1] => Int.mul_neg_one _
|
||||
|
||||
@[deprecated mul_sign_self (since := "2025-02-24")] abbrev mul_sign := @mul_sign_self
|
||||
|
||||
@[simp] theorem sign_mul_self (i : Int) : sign i * i = natAbs i := by
|
||||
rw [Int.mul_comm, mul_sign_self]
|
||||
|
||||
|
||||
@@ -50,9 +50,14 @@ protected theorem pow_ne_zero {n : Int} {m : Nat} : n ≠ 0 → n ^ m ≠ 0 := b
|
||||
|
||||
instance {n : Int} {m : Nat} [NeZero n] : NeZero (n ^ m) := ⟨Int.pow_ne_zero (NeZero.ne _)⟩
|
||||
|
||||
-- This can't be removed until the next update-stage0
|
||||
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
|
||||
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev _root_.Nat.pos_pow_of_pos := @Nat.pow_pos
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp, norm_cast]
|
||||
protected theorem natCast_pow (b n : Nat) : ((b^n : Nat) : Int) = (b : Int) ^ n := by
|
||||
|
||||
@@ -19,7 +19,6 @@ universe v u v' u'
|
||||
section ULiftT
|
||||
|
||||
/-- `ULiftT.{v, u}` shrinks a monad on `Type max u v` to a monad on `Type u`. -/
|
||||
@[expose] -- for codegen
|
||||
def ULiftT (n : Type max u v → Type v') (α : Type u) := n (ULift.{v} α)
|
||||
|
||||
/-- Returns the underlying `n`-monadic representation of a `ULiftT n α` value. -/
|
||||
|
||||
@@ -139,7 +139,7 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc IterM.size]
|
||||
@[always_inline, inline, inherit_doc IterM.size]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSize.size it.toIterM).run.down
|
||||
|
||||
@@ -57,6 +57,6 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
|
||||
rw [← toArray_toList, ← toArray_toList, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
simp [-map_unattach_toList_attachWith]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -53,6 +53,6 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
it.uLift.toArray = it.toArray.map ULift.up := by
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp [-toArray_toList]
|
||||
simp
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -44,13 +44,11 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
it.toIter.toListRev = it.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray.toList = it.toList := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.toArray = it.toArray := by
|
||||
|
||||
@@ -14,7 +14,6 @@ public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -44,20 +43,6 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
f out acc) := by
|
||||
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
|
||||
|
||||
@[congr] theorem Iter.forIn'_congr {α β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
{ita itb : Iter (α := α) β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' Id (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -203,13 +188,6 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
obtain ⟨step, h₁, rfl⟩ := h₁
|
||||
simp [heq, IterStep.successor] at h₁
|
||||
|
||||
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toArray ↔ it.IsPlausibleIndirectOutput out := by
|
||||
rw [← Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
|
||||
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -244,17 +222,6 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [ihs h (f := fun out h acc => f out (this ▸ h) acc)]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
simp only [← Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -267,18 +234,6 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [forIn'_toList]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toArray]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -305,15 +260,6 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
|
||||
simp only [← Iter.toArray_toList, List.forIn_toArray, forIn_toList]
|
||||
|
||||
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
@@ -355,14 +301,6 @@ theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [F
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toArray]
|
||||
simp only [Array.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -386,12 +324,6 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
|
||||
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
@@ -412,38 +344,6 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f (it.fold g₁ init) := by
|
||||
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
|
||||
-- w.r.t. the universe of the output.
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
|
||||
|
||||
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom (List.toArray)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
@@ -452,14 +352,6 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
|
||||
it.toList.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
|
||||
@@ -67,17 +67,15 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.toArray = it.toList := by
|
||||
simp [IterM.toList]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.toList = it.toArray := by
|
||||
simp [IterM.toList, -toList_toArray]
|
||||
simp [IterM.toList]
|
||||
|
||||
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
@@ -155,6 +153,6 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
|
||||
simp [IterM.toList, toArray_eq]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -60,20 +60,6 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
simp only [ForIn.forIn, forIn'_eq]
|
||||
|
||||
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m m]
|
||||
{ita itb : IterM (α := α) m β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' m (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
@@ -214,23 +200,6 @@ theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [I
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem IterM.fold_hom {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f <$> (it.fold g₁ init) := by
|
||||
induction it using IterM.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
rw [bind_pure_comp]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
@@ -254,15 +223,6 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
|
||||
simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom]
|
||||
simp
|
||||
|
||||
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=
|
||||
|
||||
@@ -149,6 +149,9 @@ theorem attach_map_val {l : List α} {f : α → β} :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
rw [attach, attachWith, map_pmap]; exact pmap_eq_map _
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
-- The argument `l : List α` is explicit to allow rewriting from right to left.
|
||||
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
|
||||
attach_map_val.trans (List.map_id _)
|
||||
@@ -157,18 +160,21 @@ theorem attachWith_map_val {p : α → Prop} {f : α → β} {l : List α} (H :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
rw [attachWith, map_pmap]; exact pmap_eq_map _
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} {l : List α} (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_val _).trans (List.map_id _)
|
||||
|
||||
@[simp, grind ←]
|
||||
@[simp, grind]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem mem_attachWith {l : List α} {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
induction l with
|
||||
@@ -186,13 +192,12 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f l H, a ∈ l
|
||||
|
||||
@[simp, grind =]
|
||||
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : (pmap f l H).length = l.length := by
|
||||
induction l
|
||||
@@ -248,6 +253,13 @@ theorem getElem?_pmap {p : α → Prop} {f : ∀ a, p a → β} {l : List α} (h
|
||||
· simp
|
||||
· simp only [pmap, getElem?_cons_succ, hl]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated List.getElem?_pmap (since := "2025-02-12")]
|
||||
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (mem_of_get? H) := by
|
||||
simp only [get?_eq_getElem?]
|
||||
simp [getElem?_pmap]
|
||||
|
||||
-- The argument `f` is explicit to allow rewriting from right to left.
|
||||
@[simp, grind =]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {i : Nat}
|
||||
@@ -264,6 +276,15 @@ theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h
|
||||
· simp
|
||||
· simp [hl]
|
||||
|
||||
@[deprecated getElem_pmap (since := "2025-02-13")]
|
||||
theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||
(hn : n < (pmap f l h).length) :
|
||||
get (pmap f l h) ⟨n, hn⟩ =
|
||||
f (get l ⟨n, @length_pmap _ _ p f l h ▸ hn⟩)
|
||||
(h _ (getElem_mem (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||
simp only [get_eq_getElem]
|
||||
simp [getElem_pmap]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem getElem?_attachWith {xs : List α} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
@@ -349,13 +370,13 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach.tail = xs.tail.attach.map (fun ⟨x, h⟩ => ⟨x, mem_of_mem_tail h⟩) := by
|
||||
cases xs <;> simp
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem foldl_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem foldr_pmap {l : List α} {P : α → Prop} {f : (a : α) → P a → β}
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
@@ -444,6 +465,9 @@ theorem map_attach_eq_pmap {l : List α} {f : { x // x ∈ l } → β} :
|
||||
apply pmap_congr_left
|
||||
simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[grind =]
|
||||
theorem attach_filterMap {l : List α} {f : α → Option β} :
|
||||
(l.filterMap f).attach = l.attach.filterMap
|
||||
|
||||
@@ -80,17 +80,17 @@ namespace List
|
||||
|
||||
/-! ### length -/
|
||||
|
||||
@[simp, grind =] theorem length_nil : length ([] : List α) = 0 :=
|
||||
@[simp, grind] theorem length_nil : length ([] : List α) = 0 :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_singleton {a : α} : length [a] = 1 := rfl
|
||||
|
||||
@[simp, grind =] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
@[simp, grind] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
|
||||
rfl
|
||||
|
||||
/-! ### set -/
|
||||
|
||||
@[simp, grind =] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
@[simp, grind] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
|
||||
induction as generalizing i with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
@@ -101,8 +101,8 @@ namespace List
|
||||
/-! ### foldl -/
|
||||
|
||||
-- As `List.foldl` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
|
||||
@[simp, grind =] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind =] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
@[simp, grind] theorem foldl_nil : [].foldl f b = b := rfl
|
||||
@[simp, grind] theorem foldl_cons {l : List α} {f : β → α → β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
|
||||
|
||||
/-! ### concat -/
|
||||
|
||||
@@ -289,6 +289,16 @@ theorem cons_lex_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false :
|
||||
@[simp] theorem lex_nil [BEq α] {as : List α} : lex as [] lt = false := by
|
||||
cases as <;> simp [nil_lex_nil, cons_lex_nil]
|
||||
|
||||
@[deprecated nil_lex_nil (since := "2025-02-10")]
|
||||
theorem lex_nil_nil [BEq α] : lex ([] : List α) [] lt = false := rfl
|
||||
@[deprecated nil_lex_cons (since := "2025-02-10")]
|
||||
theorem lex_nil_cons [BEq α] {b} {bs : List α} : lex [] (b :: bs) lt = true := rfl
|
||||
@[deprecated cons_lex_nil (since := "2025-02-10")]
|
||||
theorem lex_cons_nil [BEq α] {a} {as : List α} : lex (a :: as) [] lt = false := rfl
|
||||
@[deprecated cons_lex_cons (since := "2025-02-10")]
|
||||
theorem lex_cons_cons [BEq α] {a b} {as bs : List α} :
|
||||
lex (a :: as) (b :: bs) lt = (lt a b || (a == b && lex as bs lt)) := rfl
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
/-! ### getLast -/
|
||||
@@ -322,7 +332,7 @@ def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
|
||||
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
@[simp, grind] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
|
||||
/-! ### getLastD -/
|
||||
|
||||
@@ -355,7 +365,7 @@ Returns the first element of a non-empty list.
|
||||
def head : (as : List α) → as ≠ [] → α
|
||||
| a::_, _ => a
|
||||
|
||||
@[simp, grind =] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
@[simp, grind] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
|
||||
|
||||
/-! ### head? -/
|
||||
|
||||
@@ -373,8 +383,8 @@ def head? : List α → Option α
|
||||
| [] => none
|
||||
| a::_ => some a
|
||||
|
||||
@[simp, grind =] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
@[simp, grind] theorem head?_nil : head? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
|
||||
|
||||
/-! ### headD -/
|
||||
|
||||
@@ -410,8 +420,8 @@ def tail : List α → List α
|
||||
| [] => []
|
||||
| _::as => as
|
||||
|
||||
@[simp, grind =] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind =] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
@[simp, grind] theorem tail_nil : tail ([] : List α) = [] := rfl
|
||||
@[simp, grind] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
|
||||
|
||||
/-! ### tail? -/
|
||||
|
||||
@@ -431,8 +441,8 @@ def tail? : List α → Option (List α)
|
||||
| [] => none
|
||||
| _::as => some as
|
||||
|
||||
@[simp, grind =] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind =] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
@[simp, grind] theorem tail?_nil : tail? ([] : List α) = none := rfl
|
||||
@[simp, grind] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
|
||||
|
||||
/-! ### tailD -/
|
||||
|
||||
@@ -465,8 +475,23 @@ We define the basic functional programming operations on `List`:
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
@[simp, grind =] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind =] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
/--
|
||||
Applies a function to each element of the list, returning the resulting list of values.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].map f = [f a, f b, f c]`
|
||||
* `[].map Nat.succ = []`
|
||||
* `["one", "two", "three"].map (·.length) = [3, 3, 5]`
|
||||
* `["one", "two", "three"].map (·.reverse) = ["eno", "owt", "eerht"]`
|
||||
-/
|
||||
@[specialize] def map (f : α → β) : (l : List α) → List β
|
||||
| [] => []
|
||||
| a::as => f a :: map f as
|
||||
|
||||
@[simp, grind] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@@ -486,7 +511,7 @@ def filter (p : α → Bool) : (l : List α) → List α
|
||||
| true => a :: filter p as
|
||||
| false => filter p as
|
||||
|
||||
@[simp, grind =] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
@[simp, grind] theorem filter_nil {p : α → Bool} : filter p [] = [] := rfl
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@@ -512,8 +537,8 @@ Example:
|
||||
| none => filterMap f as
|
||||
| some b => b :: filterMap f as
|
||||
|
||||
@[simp, grind =] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind =] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
@[simp, grind] theorem filterMap_nil {f : α → Option β} : filterMap f [] = [] := rfl
|
||||
@[grind] theorem filterMap_cons {f : α → Option β} {a : α} {l : List α} :
|
||||
filterMap f (a :: l) =
|
||||
match f a with
|
||||
| none => filterMap f l
|
||||
@@ -536,8 +561,8 @@ Examples:
|
||||
| [] => init
|
||||
| a :: l => f a (foldr f init l)
|
||||
|
||||
@[simp, grind =] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind =] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
@[simp, grind] theorem foldr_nil : [].foldr f b = b := rfl
|
||||
@[simp, grind] theorem foldr_cons {a} {l : List α} {f : α → β → β} {b} :
|
||||
(a :: l).foldr f b = f a (l.foldr f b) := rfl
|
||||
|
||||
/-! ### reverse -/
|
||||
@@ -566,7 +591,7 @@ Examples:
|
||||
@[expose] def reverse (as : List α) : List α :=
|
||||
reverseAux as []
|
||||
|
||||
@[simp, grind =] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
@[simp, grind] theorem reverse_nil : reverse ([] : List α) = [] := rfl
|
||||
|
||||
theorem reverseAux_reverseAux {as bs cs : List α} :
|
||||
reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
|
||||
@@ -581,6 +606,20 @@ Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
|
||||
* `[] ++ [4, 5] = [4, 5]`.
|
||||
* `[1, 2, 3] ++ [] = [1, 2, 3]`.
|
||||
-/
|
||||
protected def append : (xs ys : List α) → List α
|
||||
| [], bs => bs
|
||||
| a::as, bs => a :: List.append as bs
|
||||
|
||||
/--
|
||||
Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
This is a tail-recursive version of `List.append`.
|
||||
|
||||
Examples:
|
||||
@@ -606,10 +645,10 @@ instance : Append (List α) := ⟨List.append⟩
|
||||
|
||||
@[simp] theorem append_eq {as bs : List α} : List.append as bs = as ++ bs := rfl
|
||||
|
||||
@[simp, grind =] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind] theorem nil_append (as : List α) : [] ++ as = as := rfl
|
||||
@[simp, grind _=_] theorem cons_append {a : α} {as bs : List α} : (a::as) ++ bs = a::(as ++ bs) := rfl
|
||||
|
||||
@[simp, grind =] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
@[simp, grind] theorem append_nil (as : List α) : as ++ [] = as := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
@@ -619,7 +658,7 @@ instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
|
||||
left_id := nil_append
|
||||
right_id := append_nil
|
||||
|
||||
@[simp, grind =] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
@[simp, grind] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons _ as ih => simp [ih, Nat.succ_add]
|
||||
@@ -646,15 +685,27 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
|
||||
rw [ih (bs := a :: bs), ih (bs := [a]), append_assoc]
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
@[simp, grind] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
|
||||
simp [reverse, reverseAux]
|
||||
rw [← reverseAux_eq_append]
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
/--
|
||||
Concatenates a list of lists into a single list, preserving the order of the elements.
|
||||
|
||||
@[simp, grind =] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind =] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
`O(|flatten L|)`.
|
||||
|
||||
Examples:
|
||||
* `[["a"], ["b", "c"]].flatten = ["a", "b", "c"]`
|
||||
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flatten = ["a", "b", "c", "d", "e", "f"]`
|
||||
-/
|
||||
def flatten : List (List α) → List α
|
||||
| [] => []
|
||||
| l :: L => l ++ flatten L
|
||||
|
||||
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
|
||||
/-! ### singleton -/
|
||||
|
||||
@@ -670,13 +721,19 @@ Examples:
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
@[simp, grind =] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind =] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
/--
|
||||
Applies a function that returns a list to each element of a list, and concatenates the resulting
|
||||
lists.
|
||||
|
||||
@[simp, grind _=_] theorem flatMap_append {xs ys : List α} {f : α → List β} :
|
||||
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
|
||||
induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
|
||||
Examples:
|
||||
* `[2, 3, 2].flatMap List.range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
* `["red", "blue"].flatMap String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
@[simp, grind] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
@@ -691,10 +748,10 @@ def replicate : (n : Nat) → (a : α) → List α
|
||||
| 0, _ => []
|
||||
| n+1, a => a :: replicate n a
|
||||
|
||||
@[simp, grind =] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind =] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
@[simp, grind] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
|
||||
@[grind] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
|
||||
|
||||
@[simp, grind =] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih => simp only [ih, replicate_succ, length_cons]
|
||||
@@ -762,8 +819,8 @@ def isEmpty : List α → Bool
|
||||
| [] => true
|
||||
| _ :: _ => false
|
||||
|
||||
@[simp, grind =] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind =] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
@[simp, grind] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
|
||||
@[simp, grind] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
|
||||
|
||||
/-! ### elem -/
|
||||
|
||||
@@ -785,7 +842,7 @@ def elem [BEq α] (a : α) : (l : List α) → Bool
|
||||
| true => true
|
||||
| false => elem a bs
|
||||
|
||||
@[simp, grind =] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
@[simp, grind] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
|
||||
theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
@@ -901,9 +958,9 @@ def take : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, a::as => a :: take n as
|
||||
|
||||
@[simp, grind =] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind =] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind =] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
@[simp, grind] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
|
||||
@[simp, grind] theorem take_zero {l : List α} : l.take 0 = [] := rfl
|
||||
@[simp, grind] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
|
||||
/-! ### drop -/
|
||||
|
||||
@@ -923,10 +980,10 @@ def drop : (n : Nat) → (xs : List α) → List α
|
||||
| _+1, [] => []
|
||||
| n+1, _::as => drop n as
|
||||
|
||||
@[simp, grind =] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
@[simp, grind] theorem drop_nil : ([] : List α).drop i = [] := by
|
||||
cases i <;> rfl
|
||||
@[simp, grind =] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind =] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
@[simp, grind] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
|
||||
@[simp, grind] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
|
||||
|
||||
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length ≤ i) : as.drop i = [] := by
|
||||
match as, i with
|
||||
@@ -1037,13 +1094,13 @@ def dropLast {α} : List α → List α
|
||||
| [_] => []
|
||||
| a::as => a :: dropLast as
|
||||
|
||||
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
@[simp, grind] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
|
||||
@[deprecated dropLast_singleton (since := "2025-04-16")]
|
||||
theorem dropLast_single : [x].dropLast = [] := dropLast_singleton
|
||||
|
||||
@[simp, grind =] theorem dropLast_cons₂ :
|
||||
@[simp, grind] theorem dropLast_cons₂ :
|
||||
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
|
||||
|
||||
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
|
||||
@@ -1382,8 +1439,8 @@ def replace [BEq α] : (l : List α) → (a : α) → (b : α) → List α
|
||||
| true => c::as
|
||||
| false => a :: replace as b c
|
||||
|
||||
@[simp, grind =] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind =] theorem replace_cons [BEq α] {a : α} :
|
||||
@[simp, grind] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
|
||||
@[grind] theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
@@ -1591,8 +1648,8 @@ def findSome? (f : α → Option β) : List α → Option β
|
||||
| some b => some b
|
||||
| none => findSome? f as
|
||||
|
||||
@[simp, grind =] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind =] theorem findSome?_cons {f : α → Option β} :
|
||||
@[simp, grind] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
|
||||
@[grind] theorem findSome?_cons {f : α → Option β} :
|
||||
(a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f :=
|
||||
rfl
|
||||
|
||||
@@ -1849,8 +1906,8 @@ def any : (l : List α) → (p : α → Bool) → Bool
|
||||
| [], _ => false
|
||||
| h :: t, p => p h || any t p
|
||||
|
||||
@[simp, grind =] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind =] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
@[simp, grind] theorem any_nil : [].any f = false := rfl
|
||||
@[simp, grind] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
|
||||
|
||||
/-! ### all -/
|
||||
|
||||
@@ -1868,8 +1925,8 @@ def all : List α → (α → Bool) → Bool
|
||||
| [], _ => true
|
||||
| h :: t, p => p h && all t p
|
||||
|
||||
@[simp, grind =] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind =] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
@[simp, grind] theorem all_nil : [].all f = true := rfl
|
||||
@[simp, grind] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
|
||||
|
||||
/-! ### or -/
|
||||
|
||||
@@ -2009,8 +2066,8 @@ Examples:
|
||||
def sum {α} [Add α] [Zero α] : List α → α :=
|
||||
foldr (· + ·) 0
|
||||
|
||||
@[simp, grind =] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
|
||||
@[simp, grind =] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
@[simp, grind] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
|
||||
@[simp, grind] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
|
||||
@@ -21,6 +21,65 @@ namespace List
|
||||
|
||||
/-! ## Alternative getters -/
|
||||
|
||||
/-! ### get? -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
|
||||
Also see `get`, `getD` and `get!`.
|
||||
-/
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), expose]
|
||||
def get? : (as : List α) → (i : Nat) → Option α
|
||||
| a::_, 0 => some a
|
||||
| _::as, n+1 => get? as n
|
||||
| _, _ => none
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_nil : @get? α [] n = none := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_cons_zero : @get? α (a::l) 0 = some a := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
|
||||
theorem get?_cons_succ : @get? α (a::l) (n+1) = get? l n := rfl
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `List.ext_getElem?`." (since := "2025-02-12")]
|
||||
theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n) → l₁ = l₂
|
||||
| [], [], _ => rfl
|
||||
| _ :: _, [], h => nomatch h 0
|
||||
| [], _ :: _, 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_get? fun n => h (n+1)]
|
||||
|
||||
/-! ### get! -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function panics when executed, and returns
|
||||
`default`. See `get?` and `getD` for safer alternatives.
|
||||
-/
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12"), expose]
|
||||
def get! [Inhabited α] : (as : List α) → (i : Nat) → α
|
||||
| a::_, 0 => a
|
||||
| _::as, n+1 => get! as n
|
||||
| _, _ => panic! "invalid index"
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_nil [Inhabited α] (n : Nat) : [].get! n = (default : α) := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_cons_succ [Inhabited α] (l : List α) (a : α) (n : Nat) :
|
||||
(a::l).get! (n+1) = get! l n := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
|
||||
theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a := rfl
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
/--
|
||||
@@ -222,6 +281,17 @@ theorem getElem_append_right {as bs : List α} {i : Nat} (h₁ : as.length ≤ i
|
||||
cases i with simp [Nat.succ_sub_succ] <;> simp at h₁
|
||||
| succ i => apply ih; simp [h₁]
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2025-02-13")]
|
||||
theorem get_last {as : List α} {i : Fin (length (as ++ [a]))} (h : ¬ i.1 < as.length) : (as ++ [a] : List _).get i = a := by
|
||||
cases i; rename_i i h'
|
||||
induction as generalizing i with
|
||||
| nil => cases i with
|
||||
| zero => simp [List.get]
|
||||
| succ => simp +arith at h'
|
||||
| cons a as ih =>
|
||||
cases i with simp at h
|
||||
| succ i => apply ih; simp [h]
|
||||
|
||||
theorem sizeOf_lt_of_mem [SizeOf α] {as : List α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
||||
induction h with
|
||||
| head => simp +arith
|
||||
|
||||
@@ -223,7 +223,7 @@ variable [BEq α]
|
||||
|
||||
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem count_cons {a b : α} {l : List α} :
|
||||
count a (b :: l) = count a l + if b == a then 1 else 0 := by
|
||||
simp [count, countP_cons]
|
||||
@@ -237,7 +237,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
|
||||
simp [count, countP_eq_length_filter]
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem count_tail : ∀ {l : List α} {a : α},
|
||||
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
|
||||
| [], a => by simp
|
||||
@@ -380,7 +380,7 @@ theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List
|
||||
theorem count_flatMap {α} [BEq β] {l : List α} {f : α → List β} {x : β} :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap
|
||||
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem count_erase {a b : α} :
|
||||
∀ {l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
|
||||
| [] => by simp
|
||||
|
||||
@@ -130,7 +130,7 @@ theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length :=
|
||||
@[grind →]
|
||||
theorem mem_of_mem_eraseP {l : List α} : a ∈ l.eraseP p → a ∈ l := (eraseP_subset ·)
|
||||
|
||||
@[simp, grind =] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
@[simp, grind] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a ∈ l.eraseP p ↔ a ∈ l := by
|
||||
refine ⟨mem_of_mem_eraseP, fun al => ?_⟩
|
||||
match exists_or_eq_self_of_eraseP p l with
|
||||
| .inl h => rw [h]; assumption
|
||||
@@ -265,18 +265,14 @@ theorem eraseP_eq_iff {p} {l : List α} :
|
||||
subst p
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) :=
|
||||
Pairwise.sublist <| eraseP_sublist
|
||||
|
||||
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
|
||||
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
|
||||
|
||||
@[grind ←]
|
||||
theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) :=
|
||||
Pairwise.eraseP p
|
||||
|
||||
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
|
||||
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
|
||||
@@ -397,7 +393,7 @@ theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤
|
||||
@[grind →]
|
||||
theorem mem_of_mem_erase {a b : α} {l : List α} (h : a ∈ l.erase b) : a ∈ l := erase_subset h
|
||||
|
||||
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a ≠ b) :
|
||||
a ∈ l.erase b ↔ a ∈ l :=
|
||||
erase_eq_eraseP b l ▸ mem_eraseP_of_neg (mt eq_of_beq ab.symm)
|
||||
|
||||
@@ -512,12 +508,10 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
|
||||
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
|
||||
grind_pattern List.Nodup.not_mem_erase => a ∈ l.erase a, l.Nodup
|
||||
|
||||
@[grind]
|
||||
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l → Nodup (l.erase a) :=
|
||||
Pairwise.erase a
|
||||
|
||||
grind_pattern Nodup.erase => Nodup (l.erase a)
|
||||
grind_pattern Nodup.erase => Nodup l, l.erase a
|
||||
|
||||
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs :=
|
||||
erase_sublist.head_mem h
|
||||
|
||||
@@ -584,21 +578,21 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
|
||||
| [a]
|
||||
| a::b::l => simp
|
||||
|
||||
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_sublist : ∀ (l : List α) (k : Nat), eraseIdx l k <+ l
|
||||
| [], _ => by simp
|
||||
| a::l, 0 => by simp
|
||||
| a::l, k + 1 => by simp [eraseIdx_sublist]
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ <+ l
|
||||
|
||||
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a ∈ l.eraseIdx i) : a ∈ l :=
|
||||
(eraseIdx_sublist _ _).mem h
|
||||
|
||||
@[grind]
|
||||
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k ⊆ l :=
|
||||
(eraseIdx_sublist _ _).subset
|
||||
|
||||
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ ⊆ l
|
||||
|
||||
@[simp]
|
||||
theorem eraseIdx_eq_self : ∀ {l : List α} {k : Nat}, eraseIdx l k = l ↔ length l ≤ k
|
||||
| [], _ => by simp
|
||||
@@ -655,18 +649,15 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
exact m.2
|
||||
· rw [eraseIdx_of_length_le (by simpa using h)]
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) :=
|
||||
Pairwise.sublist <| eraseIdx_sublist _ _
|
||||
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) :=
|
||||
Pairwise.eraseIdx k
|
||||
|
||||
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
|
||||
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
eraseIdx l k <+: eraseIdx l' k := by
|
||||
rcases h with ⟨t, rfl⟩
|
||||
@@ -676,10 +667,6 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
rw [Nat.not_lt] at hkl
|
||||
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
|
||||
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
|
||||
|
||||
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
|
||||
-- `Init/Data/List/Nat/Basic.lean`.
|
||||
|
||||
@@ -699,4 +686,6 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -293,6 +293,7 @@ theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
|
||||
· exact H ▸ .head _
|
||||
· exact .tail _ (mem_of_find?_eq_some H)
|
||||
|
||||
@[grind]
|
||||
theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h ∈ xs := by
|
||||
induction xs with
|
||||
| nil => simp at h
|
||||
@@ -304,8 +305,6 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
|
||||
right
|
||||
apply ih
|
||||
|
||||
grind_pattern get_find?_mem => (xs.find? p).get h
|
||||
|
||||
@[simp, grind =] theorem find?_filter {xs : List α} {p : α → Bool} {q : α → Bool} :
|
||||
(xs.filter p).find? q = xs.find? (fun a => p a ∧ q a) := by
|
||||
induction xs with
|
||||
@@ -360,6 +359,9 @@ theorem find?_flatten_eq_none_iff {xs : List (List α)} {p : α → Bool} :
|
||||
xs.flatten.find? p = none ↔ ∀ ys ∈ xs, ∀ x ∈ ys, !p x := by
|
||||
simp
|
||||
|
||||
@[deprecated find?_flatten_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_none := @find?_flatten_eq_none_iff
|
||||
|
||||
/--
|
||||
If `find? p` returns `some a` from `xs.flatten`, then `p a` holds, and
|
||||
some list in `xs` contains `a`, and no earlier element of that list satisfies `p`.
|
||||
@@ -400,6 +402,9 @@ theorem find?_flatten_eq_some_iff {xs : List (List α)} {p : α → Bool} {a :
|
||||
· exact h₁ l ml a m
|
||||
· exact h₂ a m
|
||||
|
||||
@[deprecated find?_flatten_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_flatten_eq_some := @find?_flatten_eq_some_iff
|
||||
|
||||
@[simp, grind =] theorem find?_flatMap {xs : List α} {f : α → List β} {p : β → Bool} :
|
||||
(xs.flatMap f).find? p = xs.findSome? (fun x => (f x).find? p) := by
|
||||
simp [flatMap_def, findSome?_map]; rfl
|
||||
@@ -428,10 +433,16 @@ theorem find?_replicate_eq_none_iff {n : Nat} {a : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = none ↔ n = 0 ∨ !p a := by
|
||||
simp [Classical.or_iff_not_imp_left]
|
||||
|
||||
@[deprecated find?_replicate_eq_none_iff (since := "2025-02-03")]
|
||||
abbrev find?_replicate_eq_none := @find?_replicate_eq_none_iff
|
||||
|
||||
@[simp] theorem find?_replicate_eq_some_iff {n : Nat} {a b : α} {p : α → Bool} :
|
||||
(replicate n a).find? p = some b ↔ n ≠ 0 ∧ p a ∧ a = b := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated find?_replicate_eq_some_iff (since := "2025-02-03")]
|
||||
abbrev find?_replicate_eq_some := @find?_replicate_eq_some_iff
|
||||
|
||||
@[simp] theorem get_find?_replicate {n : Nat} {a : α} {p : α → Bool} (h) : ((replicate n a).find? p).get h = a := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
@@ -547,6 +558,7 @@ where
|
||||
@[simp] theorem findIdx_singleton {a : α} {p : α → Bool} : [a].findIdx p = if p a then 0 else 1 := by
|
||||
simp [findIdx_cons, findIdx_nil]
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
@@ -824,6 +836,9 @@ theorem of_findIdx?_eq_some {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
simp_all only [findIdx?_cons]
|
||||
split at w <;> cases i <;> simp_all
|
||||
|
||||
@[deprecated of_findIdx?_eq_some (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_some := @of_findIdx?_eq_some
|
||||
|
||||
theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p = none) :
|
||||
∀ i : Nat, match xs[i]? with | some a => ¬ p a | none => true := by
|
||||
intro i
|
||||
@@ -839,6 +854,9 @@ theorem of_findIdx?_eq_none {xs : List α} {p : α → Bool} (w : xs.findIdx? p
|
||||
apply ih
|
||||
split at w <;> simp_all
|
||||
|
||||
@[deprecated of_findIdx?_eq_none (since := "2025-02-02")]
|
||||
abbrev findIdx?_of_eq_none := @of_findIdx?_eq_none
|
||||
|
||||
@[simp, grind _=_] theorem findIdx?_map {f : β → α} {l : List β} : findIdx? p (l.map f) = l.findIdx? (p ∘ f) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -105,6 +105,9 @@ theorem length_leftpad {n : Nat} {a : α} {l : List α} :
|
||||
(leftpad n a l).length = max n l.length := by
|
||||
simp only [leftpad, length_append, length_replicate, Nat.sub_add_eq_max]
|
||||
|
||||
@[deprecated length_leftpad (since := "2025-02-24")]
|
||||
abbrev leftpad_length := @length_leftpad
|
||||
|
||||
theorem length_rightpad {n : Nat} {a : α} {l : List α} :
|
||||
(rightpad n a l).length = max n l.length := by
|
||||
simp [rightpad]
|
||||
|
||||
@@ -196,6 +196,9 @@ theorem getElem_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (hn : i < j)
|
||||
| zero => omega
|
||||
| succ j => simp
|
||||
|
||||
@[deprecated getElem_insertIdx_of_gt (since := "2025-02-04")]
|
||||
abbrev getElem_insertIdx_of_ge := @getElem_insertIdx_of_gt
|
||||
|
||||
@[grind =]
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {i j : Nat} (h : j < (l.insertIdx i x).length) :
|
||||
(l.insertIdx i x)[j] =
|
||||
@@ -258,6 +261,9 @@ theorem getElem?_insertIdx_of_gt {l : List α} {x : α} {i j : Nat} (h : i < j)
|
||||
(l.insertIdx i x)[j]? = l[j - 1]? := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
|
||||
|
||||
@[deprecated getElem?_insertIdx_of_gt (since := "2025-02-04")]
|
||||
abbrev getElem?_insertIdx_of_ge := @getElem?_insertIdx_of_gt
|
||||
|
||||
end InsertIdx
|
||||
|
||||
end List
|
||||
|
||||
@@ -248,10 +248,11 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
|
||||
theorem nodup_range {n : Nat} : Nodup (range n) := by
|
||||
simp +decide only [range_eq_range', nodup_range']
|
||||
|
||||
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = some i ↔ p i ∧ i ∈ range n ∧ ∀ j, j < i → !p j := by
|
||||
simp [range_eq_range']
|
||||
|
||||
@[grind]
|
||||
theorem find?_range_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(range n).find? p = none ↔ ∀ i, i < n → !p i := by
|
||||
simp
|
||||
|
||||
@@ -117,6 +117,9 @@ theorem take_set_of_le {a : α} {i j : Nat} {l : List α} (h : j ≤ i) :
|
||||
next h' => rw [getElem?_set_ne (by omega)]
|
||||
· rfl
|
||||
|
||||
@[deprecated take_set_of_le (since := "2025-02-04")]
|
||||
abbrev take_set_of_lt := @take_set_of_le
|
||||
|
||||
@[simp, grind =] theorem take_replicate {a : α} : ∀ {i n : Nat}, take i (replicate n a) = replicate (min i n) a
|
||||
| n, 0 => by simp
|
||||
| 0, m => by simp
|
||||
@@ -162,6 +165,9 @@ theorem take_eq_take_iff :
|
||||
| x :: xs, 0, j + 1 => by simp [succ_min_succ]
|
||||
| x :: xs, i + 1, j + 1 => by simp [succ_min_succ, take_eq_take_iff]
|
||||
|
||||
@[deprecated take_eq_take_iff (since := "2025-02-16")]
|
||||
abbrev take_eq_take := @take_eq_take_iff
|
||||
|
||||
@[grind =]
|
||||
theorem take_add {l : List α} {i j : Nat} : l.take (i + j) = l.take i ++ (l.drop i).take j := by
|
||||
suffices take (i + j) (take i l ++ drop i l) = take i l ++ take j (drop i l) by
|
||||
@@ -561,10 +567,9 @@ theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
|
||||
f (l[i]'(lt_length_left_of_zipWith h))
|
||||
(l'[i]'(lt_length_right_of_zipWith h)) := by
|
||||
rw [← Option.some_inj, ← getElem?_eq_getElem, getElem?_zipWith_eq_some]
|
||||
have := lt_length_right_of_zipWith h
|
||||
exact
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i],
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem this]; exact ⟨rfl, rfl⟩⟩
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact ⟨rfl, rfl⟩⟩
|
||||
|
||||
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))
|
||||
|
||||
@@ -43,7 +43,7 @@ theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l →
|
||||
(pairwise_cons.1 p).2
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
@[grind ←] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
@[grind] theorem Pairwise.tail : ∀ {l : List α} (h : Pairwise R l), Pairwise R l.tail
|
||||
| [], h => h
|
||||
| _ :: _, h => h.of_cons
|
||||
|
||||
@@ -103,7 +103,7 @@ theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pa
|
||||
· exact h₃.1 _ hx
|
||||
· exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy
|
||||
|
||||
@[grind ←] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
|
||||
|
||||
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] ↔ R a b := by simp
|
||||
|
||||
@@ -117,7 +117,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
(p : Pairwise S (map f l)) : Pairwise R l :=
|
||||
(pairwise_map.1 p).imp (H _ _)
|
||||
|
||||
@[grind <=] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
@[grind] theorem Pairwise.map {S : β → β → Prop} (f : α → β) (H : ∀ a b : α, R a b → S (f a) (f b))
|
||||
(p : Pairwise R l) : Pairwise S (map f l) :=
|
||||
pairwise_map.2 <| p.imp (H _ _)
|
||||
|
||||
@@ -136,7 +136,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
simpa [IH, e] using fun _ =>
|
||||
⟨fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab⟩
|
||||
|
||||
@[grind <=] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
@[grind] theorem Pairwise.filterMap {S : β → β → Prop} (f : α → Option β)
|
||||
(H : ∀ a a' : α, R a a' → ∀ b, f a = some b → ∀ b', f a' = some b' → S b b') {l : List α} (p : Pairwise R l) :
|
||||
Pairwise S (filterMap f l) :=
|
||||
pairwise_filterMap.2 <| p.imp (H _ _)
|
||||
@@ -146,7 +146,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
|
||||
rw [← filterMap_eq_filter, pairwise_filterMap]
|
||||
simp
|
||||
|
||||
@[grind ←] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
@[grind] theorem Pairwise.filter (p : α → Bool) : Pairwise R l → Pairwise R (filter p l) :=
|
||||
Pairwise.sublist filter_sublist
|
||||
|
||||
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
|
||||
@@ -171,7 +171,7 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
induction L with
|
||||
| nil => simp
|
||||
| cons l L IH =>
|
||||
simp only [flatten_cons, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
simp only [flatten, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
pairwise_cons, and_assoc, and_congr_right_iff]
|
||||
rw [and_comm, and_congr_left_iff]
|
||||
intros; exact ⟨fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e⟩
|
||||
@@ -207,10 +207,10 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
simp
|
||||
· exact ⟨fun _ => h, Or.inr h⟩
|
||||
|
||||
@[grind ←] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
@[grind] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
|
||||
h.sublist (drop_sublist _ _)
|
||||
|
||||
@[grind ←] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
|
||||
h.sublist (take_sublist _ _)
|
||||
|
||||
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
|
||||
@@ -266,7 +266,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
rintro H _ b hb rfl
|
||||
exact H b hb _ _
|
||||
|
||||
@[grind <=] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
@[grind] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β}
|
||||
(h : ∀ x ∈ l, p x) {S : β → β → Prop}
|
||||
(hS : ∀ ⦃x⦄ (hx : p x) ⦃y⦄ (hy : p y), R x y → S (f x hx) (f y hy)) :
|
||||
Pairwise S (l.pmap f h) := by
|
||||
@@ -277,12 +277,10 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
|
||||
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l ↔ List.Pairwise (· ≠ ·) l := Iff.rfl
|
||||
|
||||
@[simp]
|
||||
@[simp, grind]
|
||||
theorem nodup_nil : @Nodup α [] :=
|
||||
Pairwise.nil
|
||||
|
||||
grind_pattern nodup_nil => @Nodup α []
|
||||
|
||||
@[simp, grind =]
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
@@ -151,11 +151,11 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
|
||||
|
||||
/-! ### Sublist and isSublist -/
|
||||
|
||||
@[simp, grind ←] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
@[simp, grind] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (nil_sublist l).cons a
|
||||
|
||||
@[simp, grind ←] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
@[simp, grind] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (Sublist.refl l).cons₂ a
|
||||
|
||||
@@ -172,7 +172,7 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
|
||||
|
||||
instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩
|
||||
|
||||
attribute [simp, grind ←] Sublist.cons
|
||||
attribute [simp, grind] Sublist.cons
|
||||
|
||||
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
|
||||
|
||||
@@ -202,18 +202,12 @@ theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l
|
||||
protected theorem Sublist.mem (hx : a ∈ l₁) (hl : l₁ <+ l₂) : a ∈ l₂ :=
|
||||
hl.subset hx
|
||||
|
||||
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
@[grind] theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h ∈ xs :=
|
||||
s.mem (List.head_mem h)
|
||||
|
||||
grind_pattern Sublist.head_mem => ys <+ xs, ys.head h
|
||||
grind_pattern Sublist.head_mem => ys.head h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
@[grind] theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h ∈ xs :=
|
||||
s.mem (List.getLast_mem h)
|
||||
|
||||
grind_pattern Sublist.getLast_mem => ys <+ xs, ys.getLast h
|
||||
grind_pattern Sublist.getLast_mem => ys.getLast h ∈ xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
|
||||
|
||||
instance : Trans (@Sublist α) Subset Subset :=
|
||||
⟨fun h₁ h₂ => trans h₁.subset h₂⟩
|
||||
|
||||
@@ -254,13 +248,12 @@ theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l
|
||||
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ ↔ l₁ = l₂ :=
|
||||
⟨s.eq_of_length, congrArg _⟩
|
||||
|
||||
@[grind]
|
||||
theorem tail_sublist : ∀ l : List α, tail l <+ l
|
||||
| [] => .slnil
|
||||
| a::l => sublist_cons_self a l
|
||||
|
||||
grind_pattern tail_sublist => tail l <+ _
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂
|
||||
| _, _, slnil => .slnil
|
||||
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
|
||||
@@ -270,7 +263,7 @@ protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tai
|
||||
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
|
||||
h.tail
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
|
||||
induction s with
|
||||
| slnil => simp
|
||||
@@ -282,7 +275,7 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
filterMap f l₁ <+ filterMap f l₂ := by
|
||||
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons]
|
||||
@@ -290,7 +283,7 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₁
|
||||
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₂
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
protected theorem Sublist.filter (p : α → Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
|
||||
rw [← filterMap_eq_filter]; apply s.filterMap
|
||||
|
||||
@@ -488,7 +481,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
|
||||
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
|
||||
rw [sublist_append_iff] at h
|
||||
obtain ⟨l₁', l₂', rfl, h₁, h₂⟩ := h
|
||||
@@ -631,28 +624,22 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
|
||||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||||
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀ i, l₁.drop i <+ l₂.drop i
|
||||
| _, _, h, 0 => h
|
||||
| _, _, h, i + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop i
|
||||
|
||||
/-! ### IsPrefix / IsSuffix / IsInfix -/
|
||||
|
||||
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
|
||||
grind_pattern prefix_append => l₁ <+: l₁ ++ l₂
|
||||
|
||||
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
|
||||
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
|
||||
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
|
||||
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩
|
||||
|
||||
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
rw [← List.append_assoc]; apply infix_append
|
||||
|
||||
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
|
||||
|
||||
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := ⟨[], l₂, rfl⟩
|
||||
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := ⟨l₁, [], by simp⟩
|
||||
|
||||
@@ -664,24 +651,22 @@ theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ =>
|
||||
|
||||
grind_pattern IsSuffix.isInfix => l₁ <:+ l₂, IsInfix
|
||||
|
||||
@[simp, grind ←] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
@[simp, grind] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
|
||||
@[simp, grind ←] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
@[simp, grind] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
|
||||
@[simp, grind ←] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
@[simp, grind] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
|
||||
theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩
|
||||
@[simp, grind ←] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
@[simp, grind] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
|
||||
theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
@[simp, grind ←] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
@[simp, grind] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
|
||||
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
|
||||
@[simp, grind ←] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
|
||||
@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
|
||||
grind_pattern suffix_cons => _ <:+ a :: l
|
||||
@[simp, grind] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
|
||||
theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨l₁', l₂', h⟩ => ⟨a :: l₁', l₂', h ▸ rfl⟩
|
||||
|
||||
@@ -1123,36 +1108,24 @@ theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flat
|
||||
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ ↔ l₁ <+: l₂ :=
|
||||
prefix_append_right_inj [a]
|
||||
|
||||
theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
@[grind] theorem take_prefix (i) (l : List α) : take i l <+: l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
grind_pattern take_prefix => take i l <+: _
|
||||
|
||||
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
@[grind] theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
|
||||
⟨_, take_append_drop _ _⟩
|
||||
|
||||
grind_pattern drop_suffix => drop i l <+: _
|
||||
|
||||
theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
@[grind] theorem take_sublist (i) (l : List α) : take i l <+ l :=
|
||||
(take_prefix i l).sublist
|
||||
|
||||
grind_pattern take_sublist => take i l <+ l
|
||||
|
||||
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
@[grind] theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
|
||||
(drop_suffix i l).sublist
|
||||
|
||||
grind_pattern drop_sublist => drop i l <+ l
|
||||
|
||||
theorem take_subset (i) (l : List α) : take i l ⊆ l :=
|
||||
(take_sublist i l).subset
|
||||
|
||||
grind_pattern take_subset => take i l ⊆ l
|
||||
|
||||
theorem drop_subset (i) (l : List α) : drop i l ⊆ l :=
|
||||
(drop_sublist i l).subset
|
||||
|
||||
grind_pattern drop_subset => drop i l ⊆ l
|
||||
|
||||
theorem mem_of_mem_take {l : List α} (h : a ∈ l.take i) : a ∈ l :=
|
||||
take_subset _ _ h
|
||||
|
||||
@@ -1165,84 +1138,64 @@ theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l
|
||||
|
||||
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
|
||||
|
||||
@[grind ←] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
@[grind] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l <+ drop i l :=
|
||||
(drop_suffix_drop_left l h).sublist
|
||||
|
||||
@[grind ←] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
@[grind] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l ⊆ drop i l :=
|
||||
(drop_sublist_drop_left l h).subset
|
||||
|
||||
theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
@[grind] theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l :=
|
||||
⟨l.dropWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
grind_pattern takeWhile_prefix => l.takeWhile p <+: _
|
||||
|
||||
theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
@[grind] theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l :=
|
||||
⟨l.takeWhile p, takeWhile_append_dropWhile⟩
|
||||
|
||||
grind_pattern dropWhile_suffix => l.dropWhile p <+: _
|
||||
|
||||
theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
@[grind] theorem takeWhile_sublist (p : α → Bool) : l.takeWhile p <+ l :=
|
||||
(takeWhile_prefix p).sublist
|
||||
|
||||
grind_pattern takeWhile_sublist => l.takeWhile p <+ _
|
||||
|
||||
theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
@[grind] theorem dropWhile_sublist (p : α → Bool) : l.dropWhile p <+ l :=
|
||||
(dropWhile_suffix p).sublist
|
||||
|
||||
grind_pattern dropWhile_sublist => l.dropWhile p <+ _
|
||||
|
||||
theorem takeWhile_subset {l : List α} (p : α → Bool) : l.takeWhile p ⊆ l :=
|
||||
(takeWhile_sublist p).subset
|
||||
|
||||
grind_pattern takeWhile_subset => l.takeWhile p ⊆ _
|
||||
|
||||
theorem dropWhile_subset {l : List α} (p : α → Bool) : l.dropWhile p ⊆ l :=
|
||||
(dropWhile_sublist p).subset
|
||||
|
||||
grind_pattern dropWhile_subset => l.dropWhile p ⊆ _
|
||||
|
||||
theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
@[grind] theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l
|
||||
| [] => ⟨nil, by rw [dropLast, List.append_nil]⟩
|
||||
| a :: l => ⟨_, dropLast_concat_getLast (cons_ne_nil a l)⟩
|
||||
|
||||
grind_pattern dropLast_prefix => l.dropLast <+: _
|
||||
|
||||
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
@[grind] theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
|
||||
(dropLast_prefix l).sublist
|
||||
|
||||
grind_pattern dropLast_sublist => l.dropLast <+ _
|
||||
|
||||
theorem dropLast_subset (l : List α) : l.dropLast ⊆ l :=
|
||||
(dropLast_sublist l).subset
|
||||
|
||||
grind_pattern dropLast_subset => l.dropLast ⊆ _
|
||||
@[grind] theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
|
||||
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix
|
||||
|
||||
grind_pattern tail_suffix => tail l <+: _
|
||||
|
||||
@[grind ←] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
@[grind] theorem IsPrefix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply prefix_append
|
||||
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₁.map f
|
||||
grind_pattern IsPrefix.map => l₁ <+: l₂, l₂.map f
|
||||
|
||||
@[grind ←] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
@[grind] theorem IsSuffix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
|
||||
obtain ⟨r, rfl⟩ := h
|
||||
rw [map_append]; apply suffix_append
|
||||
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₁.map f
|
||||
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₂.map f
|
||||
|
||||
@[grind ←] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
@[grind] theorem IsInfix.map {β} (f : α → β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
|
||||
obtain ⟨r₁, r₂, rfl⟩ := h
|
||||
rw [map_append, map_append]; apply infix_append
|
||||
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₁.map f
|
||||
grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
|
||||
@[grind ←] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind] theorem IsPrefix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
l₁.filter p <+: l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply prefix_append
|
||||
@@ -1250,7 +1203,7 @@ grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₁.filter p
|
||||
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
|
||||
@[grind ←] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind] theorem IsSuffix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
l₁.filter p <:+ l₂.filter p := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filter_append]; apply suffix_append
|
||||
@@ -1258,7 +1211,7 @@ grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₁.filter p
|
||||
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
|
||||
@[grind ←] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind] theorem IsInfix.filter (p : α → Bool) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
l₁.filter p <:+: l₂.filter p := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filter_append, filter_append]; apply infix_append _
|
||||
@@ -1266,7 +1219,7 @@ grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₁.filter p
|
||||
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
|
||||
@[grind ←] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
@[grind] theorem IsPrefix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <+: l₂) :
|
||||
filterMap f l₁ <+: filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply prefix_append
|
||||
@@ -1274,7 +1227,7 @@ grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₁
|
||||
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
|
||||
@[grind ←] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
@[grind] theorem IsSuffix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+ l₂) :
|
||||
filterMap f l₁ <:+ filterMap f l₂ := by
|
||||
obtain ⟨xs, rfl⟩ := h
|
||||
rw [filterMap_append]; apply suffix_append
|
||||
@@ -1282,7 +1235,7 @@ grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₁
|
||||
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₂
|
||||
|
||||
@[grind ←] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
@[grind] theorem IsInfix.filterMap {β} (f : α → Option β) ⦃l₁ l₂ : List α⦄ (h : l₁ <:+: l₂) :
|
||||
filterMap f l₁ <:+: filterMap f l₂ := by
|
||||
obtain ⟨xs, ys, rfl⟩ := h
|
||||
rw [filterMap_append, filterMap_append]; apply infix_append
|
||||
|
||||
@@ -165,6 +165,9 @@ theorem take_set {l : List α} {i j : Nat} {a : α} :
|
||||
| nil => simp
|
||||
| cons hd tl => cases j <;> simp_all
|
||||
|
||||
@[deprecated take_set (since := "2025-02-17")]
|
||||
abbrev set_take := @take_set
|
||||
|
||||
theorem drop_set {l : List α} {i j : Nat} {a : α} :
|
||||
(l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a := by
|
||||
induction i generalizing l j with
|
||||
|
||||
@@ -12,6 +12,7 @@ public import Init.Data.List.Impl
|
||||
public import Init.Data.List.Nat.Erase
|
||||
public import Init.Data.List.Monadic
|
||||
public import Init.Data.List.Nat.InsertIdx
|
||||
public import Init.Data.Array.Lex.Basic
|
||||
public import Init.Data.Array.Basic
|
||||
import all Init.Data.Array.Basic
|
||||
public import Init.Data.Array.Set
|
||||
|
||||
@@ -257,6 +257,8 @@ attribute [simp] Nat.le_refl
|
||||
|
||||
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
|
||||
@@ -269,15 +271,37 @@ theorem not_add_one_le_self : (n : Nat) → ¬ n + 1 ≤ n := Nat.not_succ_le_se
|
||||
|
||||
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
|
||||
| zero => Nat.le.refl
|
||||
| succ _ => le_succ _
|
||||
|
||||
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
|
||||
induction m with
|
||||
| zero => exact Nat.le_refl (n - 0)
|
||||
| succ m ih => apply Nat.le_trans (pred_le (n - m)) ih
|
||||
|
||||
theorem sub_lt_of_lt {a b c : Nat} (h : a < c) : a - b < c :=
|
||||
Nat.lt_of_le_of_lt (Nat.sub_le _ _) h
|
||||
|
||||
theorem sub_lt : ∀ {n m : Nat}, 0 < n → 0 < m → n - m < n
|
||||
| 0, _, h1, _ => absurd h1 (Nat.lt_irrefl 0)
|
||||
| _+1, 0, _, h2 => absurd h2 (Nat.lt_irrefl 0)
|
||||
| n+1, m+1, _, _ =>
|
||||
Eq.symm (succ_sub_succ_eq_sub n m) ▸
|
||||
show n - m < succ n from
|
||||
lt_succ_of_le (sub_le n m)
|
||||
|
||||
theorem sub_succ (n m : Nat) : n - succ m = pred (n - m) := rfl
|
||||
|
||||
theorem succ_sub_succ (n m : Nat) : succ n - succ m = n - m :=
|
||||
@@ -292,6 +316,9 @@ theorem sub_add_eq (a b c : Nat) : a - (b + c) = a - b - c := by
|
||||
| zero => simp
|
||||
| succ c ih => simp only [Nat.add_succ, Nat.sub_succ, ih]
|
||||
|
||||
protected theorem lt_of_lt_of_le {n m k : Nat} : n < m → m ≤ k → n < k :=
|
||||
Nat.le_trans
|
||||
|
||||
protected theorem lt_of_lt_of_eq {n m k : Nat} : n < m → m = k → n < k :=
|
||||
fun h₁ h₂ => h₂ ▸ h₁
|
||||
|
||||
@@ -329,10 +356,12 @@ protected theorem pos_of_ne_zero {n : Nat} : n ≠ 0 → 0 < n := (eq_zero_or_po
|
||||
|
||||
theorem pos_of_neZero (n : Nat) [NeZero n] : 0 < n := Nat.pos_of_ne_zero (NeZero.ne _)
|
||||
|
||||
attribute [simp] Nat.lt_add_one
|
||||
|
||||
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
|
||||
|
||||
protected theorem le_total (m n : Nat) : m ≤ n ∨ n ≤ m :=
|
||||
match Nat.lt_or_ge m n with
|
||||
| Or.inl h => Or.inl (Nat.le_of_lt h)
|
||||
@@ -428,6 +457,7 @@ protected theorem le_lt_asymm : ∀{a b : Nat}, a ≤ b → ¬(b < a) := flip Na
|
||||
|
||||
theorem gt_of_not_le {n m : Nat} (h : ¬ n ≤ m) : n > m := (Nat.lt_or_ge m n).resolve_right h
|
||||
protected theorem lt_of_not_ge : ∀{a b : Nat}, ¬(b ≥ a) → b < a := Nat.gt_of_not_le
|
||||
protected theorem lt_of_not_le : ∀{a b : Nat}, ¬(a ≤ b) → b < a := Nat.gt_of_not_le
|
||||
|
||||
theorem ge_of_not_lt {n m : Nat} (h : ¬ n < m) : n ≥ m := (Nat.lt_or_ge n m).resolve_left h
|
||||
protected theorem le_of_not_gt : ∀{a b : Nat}, ¬(b > a) → b ≤ a := Nat.ge_of_not_lt
|
||||
@@ -740,6 +770,10 @@ protected theorem mul_lt_mul_of_pos_left {n m k : Nat} (h : n < m) (hk : k > 0)
|
||||
protected theorem mul_lt_mul_of_pos_right {n m k : Nat} (h : n < m) (hk : k > 0) : n * k < m * k :=
|
||||
Nat.mul_comm k m ▸ Nat.mul_comm k n ▸ Nat.mul_lt_mul_of_pos_left h hk
|
||||
|
||||
protected theorem mul_pos {n m : Nat} (ha : n > 0) (hb : m > 0) : n * m > 0 :=
|
||||
have h : 0 * m < n * m := Nat.mul_lt_mul_of_pos_right ha hb
|
||||
Nat.zero_mul m ▸ h
|
||||
|
||||
protected theorem le_of_mul_le_mul_left {a b c : Nat} (h : c * a ≤ c * b) (hc : 0 < c) : a ≤ b :=
|
||||
Nat.ge_of_not_lt fun hlt : b < a =>
|
||||
have h' : c * b < c * a := Nat.mul_lt_mul_of_pos_left hlt hc
|
||||
@@ -791,6 +825,23 @@ protected theorem pow_le_pow_right {n : Nat} (hx : n > 0) {i : Nat} : ∀ {j}, i
|
||||
| Or.inr h =>
|
||||
h.symm ▸ Nat.le_refl _
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_left (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_left := @Nat.pow_le_pow_left
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_le_pow_right (since := "2025-02-17")]
|
||||
abbrev pow_le_pow_of_le_right := @Nat.pow_le_pow_right
|
||||
|
||||
protected theorem pow_pos (h : 0 < a) : 0 < a^n :=
|
||||
match n with
|
||||
| 0 => Nat.zero_lt_one
|
||||
| _ + 1 => Nat.mul_pos (Nat.pow_pos h) h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Nat.pow_pos (since := "2025-02-17")]
|
||||
abbrev pos_pow_of_pos := @Nat.pow_pos
|
||||
|
||||
@[simp] theorem zero_pow_of_pos (n : Nat) (h : 0 < n) : 0 ^ n = 0 := by
|
||||
cases n with
|
||||
| zero => cases h
|
||||
@@ -870,6 +921,9 @@ protected theorem ne_zero_of_lt (h : b < a) : a ≠ 0 := by
|
||||
exact absurd h (Nat.not_lt_zero _)
|
||||
apply Nat.noConfusion
|
||||
|
||||
@[deprecated Nat.ne_zero_of_lt (since := "2025-02-06")]
|
||||
theorem not_eq_zero_of_lt (h : b < a) : a ≠ 0 := Nat.ne_zero_of_lt h
|
||||
|
||||
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
|
||||
pred_lt (Nat.ne_zero_of_lt h)
|
||||
|
||||
@@ -1145,8 +1199,6 @@ 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]
|
||||
|
||||
attribute [simp] sub_le
|
||||
|
||||
protected theorem sub_one_sub_lt_of_lt (h : a < b) : b - 1 - a < b := by
|
||||
rw [← Nat.sub_add_eq]
|
||||
exact sub_lt (zero_lt_of_lt h) (Nat.lt_add_right a Nat.one_pos)
|
||||
|
||||
@@ -24,6 +24,47 @@ there is some `c` such that `b = a * c`.
|
||||
instance : Dvd Nat where
|
||||
dvd a b := Exists (fun c => b = a * c)
|
||||
|
||||
theorem div_rec_lemma {x y : Nat} : 0 < y ∧ y ≤ x → x - y < x :=
|
||||
fun ⟨ypos, ylex⟩ => sub_lt (Nat.lt_of_lt_of_le ypos ylex) ypos
|
||||
|
||||
theorem div_rec_fuel_lemma {x y fuel : Nat} (hy : 0 < y) (hle : y ≤ x) (hfuel : x < fuel + 1) :
|
||||
x - y < fuel :=
|
||||
Nat.lt_of_lt_of_le (div_rec_lemma ⟨hy, hle⟩) (Nat.le_of_lt_succ hfuel)
|
||||
|
||||
/--
|
||||
Division of natural numbers, discarding the remainder. Division by `0` returns `0`. Usually accessed
|
||||
via the `/` operator.
|
||||
|
||||
This operation is sometimes called “floor division.”
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is
|
||||
the logical model.
|
||||
|
||||
Examples:
|
||||
* `21 / 3 = 7`
|
||||
* `21 / 5 = 4`
|
||||
* `0 / 22 = 0`
|
||||
* `5 / 0 = 0`
|
||||
-/
|
||||
@[extern "lean_nat_div", irreducible]
|
||||
protected def div (x y : @& Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel) + 1
|
||||
else
|
||||
0
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
0
|
||||
|
||||
instance instDiv : Div Nat := ⟨Nat.div⟩
|
||||
|
||||
private theorem div.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.div.go y hy fuel1 x h1 = Nat.div.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -113,6 +154,36 @@ protected def divExact (x y : @& Nat) (h : y ∣ x) : Nat :=
|
||||
@[simp]
|
||||
theorem divExact_eq_div {x y : Nat} (h : y ∣ x) : x.divExact y h = x / y := rfl
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
This is the core implementation of `Nat.mod`. It computes the correct result for any two closed
|
||||
natural numbers, but it does not have some convenient [definitional
|
||||
reductions](lean-manual://section/type-system) when the `Nat`s contain free variables. The wrapper
|
||||
`Nat.mod` handles those cases specially and then calls `Nat.modCore`.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
-/
|
||||
@[extern "lean_nat_mod", irreducible]
|
||||
protected noncomputable def modCore (x y : Nat) : Nat :=
|
||||
if hy : 0 < y then
|
||||
let rec
|
||||
go (fuel : Nat) (x : Nat) (hfuel : x < fuel) : Nat :=
|
||||
match fuel with
|
||||
| 0 => by contradiction
|
||||
| succ fuel =>
|
||||
if h : y ≤ x then
|
||||
go fuel (x - y) (div_rec_fuel_lemma hy h hfuel)
|
||||
else
|
||||
x
|
||||
termination_by structural fuel
|
||||
go (x + 1) x (Nat.lt_succ_self _)
|
||||
else
|
||||
x
|
||||
|
||||
private theorem modCore.go.fuel_congr (x y fuel1 fuel2 : Nat) (hy : 0 < y) (h1 : x < fuel1) (h2 : x < fuel2) :
|
||||
Nat.modCore.go y hy fuel1 x h1 = Nat.modCore.go y hy fuel2 x h2 := by
|
||||
match fuel1, fuel2 with
|
||||
@@ -143,6 +214,51 @@ protected theorem modCore_eq (x y : Nat) : Nat.modCore x y =
|
||||
next =>
|
||||
simp only [false_and, ↓reduceIte, *]
|
||||
|
||||
|
||||
/--
|
||||
The modulo operator, which computes the remainder when dividing one natural number by another.
|
||||
Usually accessed via the `%` operator. When the divisor is `0`, the result is the dividend rather
|
||||
than an error.
|
||||
|
||||
`Nat.mod` is a wrapper around `Nat.modCore` that special-cases two situations, giving better
|
||||
definitional reductions:
|
||||
* `Nat.mod 0 m` should reduce to `m`, for all terms `m : Nat`.
|
||||
* `Nat.mod n (m + n + 1)` should reduce to `n` for concrete `Nat` literals `n`.
|
||||
|
||||
These reductions help `Fin n` literals work well, because the `OfNat` instance for `Fin` uses
|
||||
`Nat.mod`. In particular, `(0 : Fin (n + 1)).val` should reduce definitionally to `0`. `Nat.modCore`
|
||||
can handle all numbers, but its definitional reductions are not as convenient.
|
||||
|
||||
This function is overridden at runtime with an efficient implementation. This definition is the
|
||||
logical model.
|
||||
|
||||
Examples:
|
||||
* `7 % 2 = 1`
|
||||
* `9 % 3 = 0`
|
||||
* `5 % 7 = 5`
|
||||
* `5 % 0 = 5`
|
||||
* `show ∀ (n : Nat), 0 % n = 0 from fun _ => rfl`
|
||||
* `show ∀ (m : Nat), 5 % (m + 6) = 5 from fun _ => rfl`
|
||||
-/
|
||||
@[extern "lean_nat_mod"]
|
||||
protected def mod : @& Nat → @& Nat → Nat
|
||||
/-
|
||||
Nat.modCore is defined with fuel and thus does not reduce with open terms very well.
|
||||
Nevertheless it is desirable for trivial `Nat.mod` calculations, namely
|
||||
* `Nat.mod 0 m` for all `m`
|
||||
* `Nat.mod n (m + n + 1)` for concrete literals `n`,
|
||||
to reduce definitionally.
|
||||
This property is desirable for `Fin n` literals, as it means `(ofNat 0 : Fin n).val = 0` by
|
||||
definition.
|
||||
-/
|
||||
| 0, _ => 0
|
||||
| n@(_ + 1), m =>
|
||||
if m ≤ n -- NB: if n < m does not reduce as well as `m ≤ n`!
|
||||
then Nat.modCore n m
|
||||
else n
|
||||
|
||||
instance instMod : Mod Nat := ⟨Nat.mod⟩
|
||||
|
||||
protected theorem modCore_eq_mod (n m : Nat) : Nat.modCore n m = n % m := by
|
||||
change Nat.modCore n m = Nat.mod n m
|
||||
match n, m with
|
||||
@@ -199,6 +315,24 @@ theorem mod_eq_sub_mod {a b : Nat} (h : a ≥ b) : a % b = (a - b) % b :=
|
||||
| Or.inl h₁ => h₁.symm ▸ (Nat.sub_zero a).symm ▸ rfl
|
||||
| Or.inr h₁ => (mod_eq a b).symm ▸ if_pos ⟨h₁, h⟩
|
||||
|
||||
theorem mod_lt (x : Nat) {y : Nat} : y > 0 → x % y < y := by
|
||||
induction x, y using mod.inductionOn with
|
||||
| base x y h₁ =>
|
||||
intro h₂
|
||||
have h₁ : ¬ 0 < y ∨ ¬ y ≤ x := Decidable.not_and_iff_or_not.mp h₁
|
||||
match h₁ with
|
||||
| Or.inl h₁ => exact absurd h₂ h₁
|
||||
| Or.inr h₁ =>
|
||||
have hgt : y > x := gt_of_not_le h₁
|
||||
have heq : x % y = x := mod_eq_of_lt hgt
|
||||
rw [← heq] at hgt
|
||||
exact hgt
|
||||
| ind x y h h₂ =>
|
||||
intro h₃
|
||||
have ⟨_, h₁⟩ := h
|
||||
rw [mod_eq_sub_mod h₁]
|
||||
exact h₂ h₃
|
||||
|
||||
@[simp] protected theorem sub_mod_add_mod_cancel (a b : Nat) [NeZero a] : a - b % a + b % a = a := by
|
||||
rw [Nat.sub_add_cancel]
|
||||
cases a with
|
||||
|
||||
@@ -264,6 +264,9 @@ protected theorem pos_of_lt_add_left : n < k + n → 0 < k := by
|
||||
protected theorem add_pos_left (h : 0 < m) (n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_right ..)
|
||||
|
||||
protected theorem add_pos_right (m) (h : 0 < n) : 0 < m + n :=
|
||||
Nat.lt_of_lt_of_le h (Nat.le_add_left ..)
|
||||
|
||||
protected theorem add_self_ne_one : ∀ n, n + n ≠ 1
|
||||
| n+1, h => by rw [Nat.succ_add, Nat.succ.injEq] at h; contradiction
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.ByCases
|
||||
public import Init.Data.Prod
|
||||
public import Init.Data.RArray
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -139,7 +138,21 @@ structure PolyCnstr where
|
||||
eq : Bool
|
||||
lhs : Poly
|
||||
rhs : Poly
|
||||
deriving BEq, ReflBEq, LawfulBEq
|
||||
deriving BEq
|
||||
|
||||
-- TODO: implement LawfulBEq generator companion for BEq
|
||||
instance : LawfulBEq PolyCnstr where
|
||||
eq_of_beq {a b} h := by
|
||||
cases a; rename_i eq₁ lhs₁ rhs₁
|
||||
cases b; rename_i eq₂ lhs₂ rhs₂
|
||||
have h : eq₁ == eq₂ && (lhs₁ == lhs₂ && rhs₁ == rhs₂) := h
|
||||
simp at h
|
||||
have ⟨h₁, h₂, h₃⟩ := h
|
||||
rw [h₁, h₂, h₃]
|
||||
rfl {a} := by
|
||||
cases a; rename_i eq lhs rhs
|
||||
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
simp
|
||||
|
||||
structure ExprCnstr where
|
||||
eq : Bool
|
||||
|
||||
@@ -15,30 +15,30 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
@[simp, grind] theorem mem_toArray {a : α} {o : Option α} : a ∈ o.toArray ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind =] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toArray → β → m (ForInStep β)) :
|
||||
forIn' o.toArray b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind =] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toArray b f = forIn o b f := by
|
||||
cases o <;> simp <;> rfl
|
||||
|
||||
@[simp, grind =] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toArray.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toArray.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind] theorem foldl_toArray (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toArray.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind] theorem foldr_toArray (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@ theorem attach_map_val (o : Option α) (f : α → β) :
|
||||
(o.attach.map fun (i : {i // o = some i}) => f i) = o.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated attach_map_val (since := "2025-02-17")]
|
||||
abbrev attach_map_coe := @attach_map_val
|
||||
|
||||
@[simp, grind =]theorem attach_map_subtype_val (o : Option α) :
|
||||
o.attach.map Subtype.val = o :=
|
||||
(attach_map_val _ _).trans (congrFun Option.map_id _)
|
||||
@@ -83,6 +86,9 @@ theorem attachWith_map_val {p : α → Prop} (f : α → β) (o : Option α) (H
|
||||
((o.attachWith p H).map fun (i : { i // p i}) => f i.val) = o.map f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated attachWith_map_val (since := "2025-02-17")]
|
||||
abbrev attachWith_map_coe := @attachWith_map_val
|
||||
|
||||
@[simp, grind =] theorem attachWith_map_subtype_val {p : α → Prop} (o : Option α) (H : ∀ a, o = some a → p a) :
|
||||
(o.attachWith p H).map Subtype.val = o :=
|
||||
(attachWith_map_val _ _ _).trans (congrFun Option.map_id _)
|
||||
@@ -91,7 +97,7 @@ theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach =
|
||||
| none, ⟨x, h⟩ => by simp at h
|
||||
| some a, ⟨x, h⟩ => by simpa using h
|
||||
|
||||
@[grind ←]
|
||||
@[grind]
|
||||
theorem mem_attach : ∀ (o : Option α) (x : {x // o = some x}), x ∈ o.attach :=
|
||||
attach_eq_some
|
||||
|
||||
@@ -181,6 +187,9 @@ theorem toArray_attachWith {p : α → Prop} {o : Option α} {h} :
|
||||
o.attach.map f = o.pmap (fun a (h : o = some a) => f ⟨a, h⟩) (fun _ h => h) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[deprecated map_attach_eq_pmap (since := "2025-02-09")]
|
||||
abbrev map_attach := @map_attach_eq_pmap
|
||||
|
||||
@[simp, grind =] theorem map_attachWith {l : Option α} {P : α → Prop} {H : ∀ (a : α), l = some a → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f = l.attach.map fun ⟨x, h⟩ => f ⟨x, H _ h⟩ := by
|
||||
|
||||
@@ -18,27 +18,27 @@ namespace Option
|
||||
deriving instance DecidableEq for Option
|
||||
deriving instance BEq for Option
|
||||
|
||||
@[simp, grind =] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind =] theorem getD_some : getD (some a) b = a := rfl
|
||||
@[simp, grind] theorem getD_none : getD none a = a := rfl
|
||||
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
|
||||
|
||||
@[simp, grind =] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind =] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
@[simp, grind] theorem map_none (f : α → β) : none.map f = none := rfl
|
||||
@[simp, grind] theorem map_some (a) (f : α → β) : (some a).map f = some (f a) := rfl
|
||||
|
||||
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
|
||||
def getM [Alternative m] : Option α → m α
|
||||
| none => failure
|
||||
| some a => pure a
|
||||
|
||||
@[simp, grind =] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind =] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
|
||||
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
|
||||
|
||||
/-- Returns `true` on `some x` and `false` on `none`. -/
|
||||
@[inline] def isSome : Option α → Bool
|
||||
| some _ => true
|
||||
| none => false
|
||||
|
||||
@[simp, grind =] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind =] theorem isSome_some : isSome (some a) = true := rfl
|
||||
@[simp, grind] theorem isSome_none : @isSome α none = false := rfl
|
||||
@[simp, grind] theorem isSome_some : isSome (some a) = true := rfl
|
||||
|
||||
/--
|
||||
Returns `true` on `none` and `false` on `some x`.
|
||||
@@ -53,8 +53,8 @@ Examples:
|
||||
| some _ => false
|
||||
| none => true
|
||||
|
||||
@[simp, grind =] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind =] theorem isNone_some : isNone (some a) = false := rfl
|
||||
@[simp, grind] theorem isNone_none : @isNone α none = true := rfl
|
||||
@[simp, grind] theorem isNone_some : isNone (some a) = false := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is both present and equal to some other value.
|
||||
@@ -89,8 +89,8 @@ Examples:
|
||||
| none, _ => none
|
||||
| some a, f => f a
|
||||
|
||||
@[simp, grind =] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind =] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
@[simp, grind] theorem bind_none (f : α → Option β) : none.bind f = none := rfl
|
||||
@[simp, grind] theorem bind_some (a) (f : α → Option β) : (some a).bind f = f a := rfl
|
||||
|
||||
@[deprecated bind_none (since := "2025-05-03")]
|
||||
abbrev none_bind := @bind_none
|
||||
@@ -125,8 +125,8 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
|
||||
| none => pure none
|
||||
| some x => some <$> f x
|
||||
|
||||
@[simp, grind =] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind =] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
@[simp, grind] theorem mapM_none [Applicative m] (f : α → m β) : none.mapM f = pure none := rfl
|
||||
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α → m β) : (some x).mapM f = some <$> f x := rfl
|
||||
|
||||
/--
|
||||
Applies a function in some applicative functor to an optional value, returning `none` with no
|
||||
@@ -138,9 +138,9 @@ This is an alias for `Option.mapM`, which already works for applicative functors
|
||||
Option.mapM f
|
||||
|
||||
/-- For verification purposes, we replace `mapA` with `mapM`. -/
|
||||
@[simp, grind =] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α → m β} : Option.mapA f o = Option.mapM f o := rfl
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem map_id : (Option.map id : Option α → Option α) = id :=
|
||||
funext (fun o => match o with | none => rfl | some _ => rfl)
|
||||
|
||||
@@ -182,8 +182,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => true
|
||||
|
||||
@[simp, grind =] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind =] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
@[simp, grind] theorem all_none : Option.all p none = true := rfl
|
||||
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
|
||||
@@ -197,8 +197,8 @@ Examples:
|
||||
| some a => p a
|
||||
| none => false
|
||||
|
||||
@[simp, grind =] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind =] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
@[simp, grind] theorem any_none : Option.any p none = false := rfl
|
||||
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
|
||||
|
||||
/--
|
||||
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
|
||||
@@ -210,8 +210,8 @@ See also `or` for a version that is strict in the second argument.
|
||||
| some a, _ => some a
|
||||
| none, b => b ()
|
||||
|
||||
@[simp, grind =] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind =] theorem orElse_none : none.orElse b = b () := rfl
|
||||
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
|
||||
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
|
||||
|
||||
instance : OrElse (Option α) where
|
||||
orElse := Option.orElse
|
||||
@@ -351,9 +351,9 @@ Extracts the value from an option that can be proven to be `some`.
|
||||
@[inline] def get {α : Type u} : (o : Option α) → isSome o → α
|
||||
| some x, _ => x
|
||||
|
||||
@[simp, grind =] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
@[simp, grind] theorem some_get : ∀ {x : Option α} (h : isSome x), some (x.get h) = x
|
||||
| some _, _ => rfl
|
||||
@[simp, grind =] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
|
||||
|
||||
/--
|
||||
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
|
||||
@@ -431,8 +431,8 @@ Examples:
|
||||
-/
|
||||
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
|
||||
|
||||
@[simp, grind =] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind =] theorem join_some : (some o).join = o := rfl
|
||||
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
|
||||
@[simp, grind] theorem join_some : (some o).join = o := rfl
|
||||
|
||||
/--
|
||||
Converts an optional monadic computation into a monadic computation of an optional value.
|
||||
@@ -457,8 +457,8 @@ some "world"
|
||||
| none => pure none
|
||||
| some f => some <$> f
|
||||
|
||||
@[simp, grind =] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind =] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
|
||||
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
|
||||
|
||||
/--
|
||||
A monadic case analysis function for `Option`.
|
||||
@@ -483,8 +483,8 @@ This is the monadic analogue of `Option.getD`.
|
||||
| some a => pure a
|
||||
| none => y
|
||||
|
||||
@[simp, grind =] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind =] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
|
||||
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
|
||||
|
||||
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
|
||||
rfl {x} := private
|
||||
@@ -520,10 +520,10 @@ protected def min [Min α] : Option α → Option α → Option α
|
||||
|
||||
instance [Min α] : Min (Option α) where min := Option.min
|
||||
|
||||
@[simp, grind =] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind =] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
|
||||
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind =] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated min_none_right (since := "2025-05-12")]
|
||||
@@ -553,10 +553,10 @@ protected def max [Max α] : Option α → Option α → Option α
|
||||
|
||||
instance [Max α] : Max (Option α) where max := Option.max
|
||||
|
||||
@[simp, grind =] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind =] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
|
||||
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
|
||||
cases o <;> rfl
|
||||
@[simp, grind =] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[deprecated max_none_right (since := "2025-05-12")]
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Option
|
||||
@[deprecated mem_def (since := "2025-04-07")]
|
||||
theorem mem_iff {a : α} {b : Option α} : a ∈ b ↔ b = some a := .rfl
|
||||
|
||||
@[grind =] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
@[grind] theorem mem_some {a b : α} : a ∈ some b ↔ b = a := by simp
|
||||
|
||||
theorem mem_some_iff {a b : α} : a ∈ some b ↔ b = a := mem_some
|
||||
|
||||
@@ -52,7 +52,7 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
|
||||
theorem get_of_eq_some : ∀ {o : Option α} (h : isSome o), o = some a → o.get h = a
|
||||
| _, _, rfl => rfl
|
||||
|
||||
@[simp, grind ←] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
@[simp, grind] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
|
||||
theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.getD y) = x := by
|
||||
cases x; {contradiction}; rw [getD_some]
|
||||
|
||||
@@ -16,38 +16,38 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind =] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a ∈ o.toList ↔ o = some a := by
|
||||
cases o <;> simp [eq_comm]
|
||||
|
||||
@[simp, grind =] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) → a ∈ o.toList → β → m (ForInStep β)) :
|
||||
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind =] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn o.toList b f = forIn o b f := by
|
||||
cases o <;> rfl
|
||||
|
||||
@[simp, grind =] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α → β → m α) :
|
||||
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β → α → m α) :
|
||||
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α → β → α) :
|
||||
o.toList.foldl f a = o.elim a (fun b => f a b) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β → α → α) :
|
||||
o.toList.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind ←]
|
||||
@[simp, grind]
|
||||
theorem pairwise_toList {P : α → α → Prop} {o : Option α} : o.toList.Pairwise P := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem head?_toList {o : Option α} : o.toList.head? = o := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -16,20 +16,20 @@ public section
|
||||
|
||||
namespace Option
|
||||
|
||||
@[simp, grind =] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind =] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
@[simp, grind] theorem bindM_none [Pure m] (f : α → m (Option β)) : none.bindM f = pure none := rfl
|
||||
@[simp, grind] theorem bindM_some [Pure m] (a) (f : α → m (Option β)) : (some a).bindM f = f a := by
|
||||
simp [Option.bindM]
|
||||
|
||||
-- We simplify `Option.forM` to `forM`.
|
||||
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
|
||||
|
||||
@[simp, grind =] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
@[simp, grind] theorem forM_none [Monad m] (f : α → m PUnit) :
|
||||
forM none f = pure .unit := rfl
|
||||
|
||||
@[simp, grind =] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
@[simp, grind] theorem forM_some [Monad m] (f : α → m PUnit) (a : α) :
|
||||
forM (some a) f = f a := rfl
|
||||
|
||||
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α → β) (f : β → m PUnit) :
|
||||
forM (o.map g) f = forM o (fun a => f (g a)) := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -37,11 +37,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
forM o.join f = forM o (forM · f) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind =] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) → a ∈ none → β → m (ForInStep β)) :
|
||||
forIn' none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) → a' ∈ some a → β → m (ForInStep β)) :
|
||||
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -49,11 +49,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α →
|
||||
funext x
|
||||
split <;> simp
|
||||
|
||||
@[simp, grind =] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn none b f = pure b := by
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α → β → m (ForInStep β)) :
|
||||
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
|
||||
simp only [forIn, forIn', bind_pure_comp]
|
||||
rw [map_eq_pure_bind]
|
||||
@@ -106,7 +106,7 @@ theorem forIn'_id_yield_eq_pelim
|
||||
o.pelim b (fun a h => f a h b) :=
|
||||
forIn'_pure_yield_eq_pelim _ _ _
|
||||
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : (b : β) → b ∈ o.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
|
||||
cases o <;> simp
|
||||
@@ -149,7 +149,7 @@ theorem forIn_id_yield_eq_elim
|
||||
o.elim b (fun a => f a b) :=
|
||||
forIn_pure_yield_eq_elim _ _ _
|
||||
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
(o : Option α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
|
||||
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
|
||||
cases o <;> simp
|
||||
|
||||
@@ -349,13 +349,13 @@ theorem LawfulEqCmp.compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
|
||||
beq_iff_eq.trans compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_eq_iff_eq` -/
|
||||
@[simp, grind =]
|
||||
@[simp, grind]
|
||||
theorem LawfulEqOrd.compare_eq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b = .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_eq_iff_eq
|
||||
|
||||
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_beq_iff_eq` -/
|
||||
@[grind =]
|
||||
@[grind]
|
||||
theorem LawfulEqOrd.compare_beq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
|
||||
compare a b == .eq ↔ a = b :=
|
||||
LawfulEqCmp.compare_beq_iff_eq
|
||||
|
||||
@@ -67,20 +67,20 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Classical.Order.instLT
|
||||
| exact Classical.Order.instLT
|
||||
beq :
|
||||
let := le; let := decidableLE
|
||||
BEq α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.beqOfDecidableLE
|
||||
| exact FactoryInstances.beqOfDecidableLE
|
||||
lt_iff :
|
||||
let := le; let := lt
|
||||
∀ a b : α, a < b ↔ a ≤ b ∧ ¬ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderLT.lt_iff
|
||||
| exact LawfulOrderLT.lt_iff
|
||||
| fail "Failed to automatically prove that the `LE` and `LT` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -89,10 +89,10 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
haveI := @LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.decidableLTOfLE
|
||||
| exact FactoryInstances.decidableLTOfLE
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -101,7 +101,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b : α, a == b ↔ a ≤ b ∧ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| exact LawfulOrderBEq.beq_iff_le_and_ge
|
||||
| fail "Failed to automatically prove that the `LE` and `BEq` instances are compatible. \
|
||||
Please ensure that a `LawfulOrderBEq` instance can be synthesized or \
|
||||
manually provide the field `beq_iff_le_and_ge`."
|
||||
@@ -110,7 +110,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a : α, a ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.Refl.refl (r := (· ≤ ·))
|
||||
| exact Std.Refl.refl (r := (· ≤ ·))
|
||||
| fail "Failed to automatically prove that the `LE` instance is reflexive. \
|
||||
Please ensure that a `Refl` instance can be synthesized or \
|
||||
manually provide the field `le_refl`."
|
||||
@@ -119,7 +119,7 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
∀ a b c : α, a ≤ b → b ≤ c → a ≤ c := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ _ hab hbc => _root_.Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| exact fun _ _ _ hab hbc => Trans.trans (r := (· ≤ ·)) (s := (· ≤ ·)) (t := (· ≤ ·)) hab hbc
|
||||
| fail "Failed to automatically prove that the `LE` instance is transitive. \
|
||||
Please ensure that a `Trans` instance can be synthesized or \
|
||||
manually provide the field `le_trans`."
|
||||
@@ -202,7 +202,7 @@ public structure Packages.PartialOrderOfLEArgs (α : Type u) extends Packages.Pr
|
||||
∀ a b : α, a ≤ b → b ≤ a → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.Antisymm.antisymm
|
||||
| exact Antisymm.antisymm
|
||||
| fail "Failed to automatically prove that the `LE` instance is antisymmetric. \
|
||||
Please ensure that a `Antisymm` instance can be synthesized or \
|
||||
manually provide the field `le_antisymm`."
|
||||
@@ -310,11 +310,11 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instOrdOfDecidableLE
|
||||
| exact FactoryInstances.instOrdOfDecidableLE
|
||||
le_total :
|
||||
∀ a b : α, a ≤ b ∨ b ≤ a := by
|
||||
first
|
||||
| exact _root_.Std.Total.total
|
||||
| exact Total.total
|
||||
| fail "Failed to automatically prove that the `LE` instance is total. \
|
||||
Please ensure that a `Total` instance can be synthesized or \
|
||||
manually provide the field `le_total`."
|
||||
@@ -324,7 +324,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isLE ↔ a ≤ b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderOrd.isLE_compare
|
||||
| exact LawfulOrderOrd.isLE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isLE` is equivalent to `a ≤ b`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isLE_compare`."
|
||||
@@ -333,7 +333,7 @@ public structure Packages.LinearPreorderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, (compare a b).isGE ↔ b ≤ a := by
|
||||
extract_lets
|
||||
first
|
||||
| exact _root_.Std.LawfulOrderOrd.isGE_compare
|
||||
| exact LawfulOrderOrd.isGE_compare
|
||||
| fail "Failed to automatically prove that `(compare a b).isGE` is equivalent to `b ≤ a`. \
|
||||
Please ensure that a `LawfulOrderOrd` instance can be synthesized or \
|
||||
manually provide the field `isGE_compare`."
|
||||
@@ -411,20 +411,20 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Min.leftLeaningOfLE _
|
||||
| exact Min.leftLeaningOfLE _
|
||||
max :
|
||||
let := le; let := decidableLE
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Max.leftLeaningOfLE _
|
||||
| exact Max.leftLeaningOfLE _
|
||||
min_eq :
|
||||
let := le; let := decidableLE; let := min
|
||||
∀ a b : α, Min.min a b = if a ≤ b then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.min_eq_if (a := a) (b := b)
|
||||
| exact fun a b => Std.min_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -433,7 +433,7 @@ public structure Packages.LinearOrderOfLEArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if b ≤ a then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.max_eq_if (a := a) (b := b)
|
||||
| exact fun a b => Std.max_eq_if (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
@@ -538,7 +538,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.LE.ofOrd _
|
||||
| exact LE.ofOrd _
|
||||
lawfulOrderOrd :
|
||||
let := ord; let := transOrd; let := le
|
||||
LawfulOrderOrd α := by
|
||||
@@ -554,7 +554,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.DecidableLE.ofOrd _
|
||||
| exact DecidableLE.ofOrd _
|
||||
| fail "Failed to automatically derive that `LE` is decidable.\
|
||||
Please ensure that a `DecidableLE` instance can be synthesized or \
|
||||
manually provide the field `decidableLE`."
|
||||
@@ -570,7 +570,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
∀ a b : α, a < b ↔ compare a b = .lt := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => _root_.Std.compare_eq_lt.symm
|
||||
| exact fun _ _ => Std.compare_eq_lt.symm
|
||||
| fail "Failed to automatically derive that `LT` and `Ord` are compatible. \
|
||||
Please ensure that a `LawfulOrderLT` instance can be synthesized or \
|
||||
manually provide the field `lt_iff`."
|
||||
@@ -580,7 +580,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_DecidableLT.ofOrd _
|
||||
| exact DecidableLT.ofOrd _
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -589,7 +589,7 @@ public structure Packages.LinearPreorderOfOrdArgs (α : Type u) where
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.BEq.ofOrd _
|
||||
| exact BEq.ofOrd _
|
||||
beq_iff :
|
||||
let := ord; let := le; have := lawfulOrderOrd; let := beq
|
||||
∀ a b : α, a == b ↔ compare a b = .eq := by
|
||||
@@ -708,7 +708,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, compare a b = .eq → a = b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun _ _ => _root_.Std.LawfulEqOrd.eq_of_compare
|
||||
| exact LawfulEqOrd.eq_of_compare
|
||||
| fail "Failed to derive a `LawfulEqOrd` instance. \
|
||||
Please make sure that it can be synthesized or \
|
||||
manually provide the field `eq_of_compare`."
|
||||
@@ -718,20 +718,20 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instMinOfOrd
|
||||
| exact FactoryInstances.instMinOfOrd
|
||||
max :
|
||||
let := ord
|
||||
Max α := by
|
||||
extract_lets
|
||||
first
|
||||
| infer_instance
|
||||
| exact _root_.Std.FactoryInstances.instMaxOfOrd
|
||||
| exact FactoryInstances.instMaxOfOrd
|
||||
min_eq :
|
||||
let := ord; let := le; let := min; have := lawfulOrderOrd
|
||||
∀ a b : α, Min.min a b = if (compare a b).isLE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| exact fun a b => Std.min_eq_if_isLE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `min` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMin` instance can be synthesized or \
|
||||
manually provide the field `min_eq`."
|
||||
@@ -740,7 +740,7 @@ public structure Packages.LinearOrderOfOrdArgs (α : Type u) extends
|
||||
∀ a b : α, Max.max a b = if (compare a b).isGE then a else b := by
|
||||
extract_lets
|
||||
first
|
||||
| exact fun a b => _root_.Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| exact fun a b => Std.max_eq_if_isGE_compare (a := a) (b := b)
|
||||
| fail "Failed to automatically prove that `max` is left-leaning. \
|
||||
Please ensure that a `LawfulOrderLeftLeaningMax` instance can be synthesized or \
|
||||
manually provide the field `max_eq`."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user