mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-18 10:54:09 +00:00
Compare commits
3 Commits
align_zip
...
array_appe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdcb5780b9 | ||
|
|
fa78cf7275 | ||
|
|
f276a7c4db |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -238,7 +238,7 @@ jobs:
|
||||
"name": "Linux 32bit",
|
||||
"os": "ubuntu-latest",
|
||||
// Use 32bit on stage0 and stage1 to keep oleans compatible
|
||||
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DPKG_CONFIG_EXECUTABLE=/usr/bin/i386-linux-gnu-pkg-config",
|
||||
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/",
|
||||
"cmultilib": true,
|
||||
"release": true,
|
||||
"check-level": 2,
|
||||
@@ -327,7 +327,7 @@ jobs:
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-multilib g++-multilib ccache libuv1-dev:i386 pkgconf:i386
|
||||
sudo apt-get install -y gcc-multilib g++-multilib ccache libuv1-dev:i386
|
||||
if: matrix.cmultilib
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
|
||||
@@ -18,9 +18,6 @@ foreach(var ${vars})
|
||||
if("${var}" MATCHES "LLVM*")
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
if("${var}" MATCHES "PKG_CONFIG*")
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
elseif(("${var}" MATCHES "CMAKE_.*") AND NOT ("${var}" MATCHES "CMAKE_BUILD_TYPE") AND NOT ("${var}" MATCHES "CMAKE_HOME_DIRECTORY"))
|
||||
list(APPEND PLATFORM_ARGS "-D${var}=${${var}}")
|
||||
endif()
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"displayName": "Sanitize build config",
|
||||
"cacheVariables": {
|
||||
"LEAN_EXTRA_CXX_FLAGS": "-fsanitize=address,undefined",
|
||||
"LEANC_EXTRA_CC_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
|
||||
"LEANC_EXTRA_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
|
||||
"SMALL_ALLOCATOR": "OFF",
|
||||
"BSYMBOLIC": "OFF"
|
||||
},
|
||||
|
||||
@@ -590,9 +590,9 @@ This table should be read as follows:
|
||||
* No other proofs were attempted, either because the parameter has a type without a non-trivial ``WellFounded`` instance (parameter 3), or because it is already clear that no decreasing measure can be found.
|
||||
|
||||
|
||||
Lean will print the termination measure it found if ``set_option showInferredTerminationBy true`` is set.
|
||||
Lean will print the termination argument it found if ``set_option showInferredTerminationBy true`` is set.
|
||||
|
||||
If Lean does not find the termination measure, or if you want to be explicit, you can append a `termination_by` clause to the function definition, after the function's body, but before the `where` clause if present. It is of the form
|
||||
If Lean does not find the termination argument, or if you want to be explicit, you can append a `termination_by` clause to the function definition, after the function's body, but before the `where` clause if present. It is of the form
|
||||
```
|
||||
termination_by e
|
||||
```
|
||||
@@ -672,7 +672,7 @@ def num_consts_lst : List Term → Nat
|
||||
end
|
||||
```
|
||||
|
||||
In a set of mutually recursive function, either all or no functions must have an explicit termination measure (``termination_by``). A change of the default termination tactic (``decreasing_by``) only affects the proofs about the recursive calls of that function, not the other functions in the group.
|
||||
In a set of mutually recursive function, either all or no functions must have an explicit termination argument (``termination_by``). A change of the default termination tactic (``decreasing_by``) only affects the proofs about the recursive calls of that function, not the other functions in the group.
|
||||
|
||||
```
|
||||
mutual
|
||||
|
||||
@@ -33,9 +33,6 @@ Format of the commit message
|
||||
- chore (maintain, ex: travis-ci)
|
||||
- perf (performance improvement, optimization, ...)
|
||||
|
||||
Every `feat` or `fix` commit must have a `changelog-*` label, and a commit message
|
||||
beginning with "This PR " that will be included in the changelog.
|
||||
|
||||
``<subject>`` has the following constraints:
|
||||
|
||||
- use imperative, present tense: "change" not "changed" nor "changes"
|
||||
@@ -47,7 +44,6 @@ beginning with "This PR " that will be included in the changelog.
|
||||
- just as in ``<subject>``, use imperative, present tense
|
||||
- includes motivation for the change and contrasts with previous
|
||||
behavior
|
||||
- If a `changelog-*` label is present, the body must begin with "This PR ".
|
||||
|
||||
``<footer>`` is optional and may contain two items:
|
||||
|
||||
@@ -64,21 +60,17 @@ Examples
|
||||
|
||||
fix: add declarations for operator<<(std::ostream&, expr const&) and operator<<(std::ostream&, context const&) in the kernel
|
||||
|
||||
This PR adds declarations `operator<<` for raw printing.
|
||||
The actual implementation of these two operators is outside of the
|
||||
kernel. They are implemented in the file 'library/printer.cpp'.
|
||||
|
||||
We declare them in the kernel to prevent the following problem.
|
||||
Suppose there is a file 'foo.cpp' that does not include 'library/printer.h',
|
||||
kernel. They are implemented in the file 'library/printer.cpp'. We
|
||||
declare them in the kernel to prevent the following problem. Suppose
|
||||
there is a file 'foo.cpp' that does not include 'library/printer.h',
|
||||
but contains
|
||||
```cpp
|
||||
expr a;
|
||||
...
|
||||
std::cout << a << "\n";
|
||||
...
|
||||
```
|
||||
|
||||
expr a;
|
||||
...
|
||||
std::cout << a << "\n";
|
||||
...
|
||||
|
||||
The compiler does not generate an error message. It silently uses the
|
||||
operator bool() to coerce the expression into a Boolean. This produces
|
||||
counter-intuitive behavior, and may confuse developers.
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ lean_object * initialize_C(uint8_t builtin, lean_object *);
|
||||
...
|
||||
|
||||
lean_initialize_runtime_module();
|
||||
//lean_initialize(); // necessary (and replaces `lean_initialize_runtime_module`) if you (indirectly) access the `Lean` package
|
||||
//lean_initialize(); // necessary if you (indirectly) access the `Lean` package
|
||||
|
||||
lean_object * res;
|
||||
// use same default as for Lean executables
|
||||
|
||||
@@ -80,10 +80,3 @@ Unlike most Lean projects, all submodules of the `Lean` module begin with the
|
||||
`prelude` keyword. This disables the automated import of `Init`, meaning that
|
||||
developers need to figure out their own subset of `Init` to import. This is done
|
||||
such that changing files in `Init` doesn't force a full rebuild of `Lean`.
|
||||
|
||||
### Testing against Mathlib/Batteries
|
||||
You can test a Lean PR against Mathlib and Batteries by rebasing your PR
|
||||
on to `nightly-with-mathlib` branch. (It is fine to force push after rebasing.)
|
||||
CI will generate a branch of Mathlib and Batteries called `lean-pr-testing-NNNN`
|
||||
that uses the toolchain for your PR, and will report back to the Lean PR with results from Mathlib CI.
|
||||
See https://leanprover-community.github.io/contribute/tags_and_branches.html for more details.
|
||||
|
||||
@@ -61,7 +61,7 @@ Parts of atomic names can be escaped by enclosing them in pairs of French double
|
||||
letterlike_symbols: [℀-⅏]
|
||||
escaped_ident_part: "«" [^«»\r\n\t]* "»"
|
||||
atomic_ident_rest: atomic_ident_start | [0-9'ⁿ] | subscript
|
||||
subscript: [₀-₉ₐ-ₜᵢ-ᵪⱼ]
|
||||
subscript: [₀-₉ₐ-ₜᵢ-ᵪ]
|
||||
```
|
||||
|
||||
String Literals
|
||||
|
||||
@@ -32,13 +32,12 @@ following to use `g++`.
|
||||
cmake -DCMAKE_CXX_COMPILER=g++ ...
|
||||
```
|
||||
|
||||
## Required Packages: CMake, GMP, libuv, pkgconf
|
||||
## Required Packages: CMake, GMP, libuv
|
||||
|
||||
```bash
|
||||
brew install cmake
|
||||
brew install gmp
|
||||
brew install libuv
|
||||
brew install pkgconf
|
||||
```
|
||||
|
||||
## Recommended Packages: CCache
|
||||
|
||||
@@ -8,5 +8,5 @@ follow the [generic build instructions](index.md).
|
||||
## Basic packages
|
||||
|
||||
```bash
|
||||
sudo apt-get install git libgmp-dev libuv1-dev cmake ccache clang pkgconf
|
||||
sudo apt-get install git libgmp-dev libuv1-dev cmake ccache clang
|
||||
```
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Please take some time to familiarize yourself with the stylistic conventions of
|
||||
the project and the specific part of the library you are planning to contribute
|
||||
to. While the Lean compiler may not enforce strict formatting rules,
|
||||
consistently formatted code is much easier for others to read and maintain.
|
||||
Attention to formatting is more than a cosmetic concern—it reflects the same
|
||||
level of precision and care required to meet the deeper standards of the Lean 4
|
||||
standard library.
|
||||
|
||||
A full style guide and naming convention are currently under construction and
|
||||
will be added here soon.
|
||||
@@ -1,97 +0,0 @@
|
||||
# The Lean 4 standard library
|
||||
|
||||
Maintainer team (in alphabetical order): Henrik Böving, Markus Himmel
|
||||
(community contact & external contribution coordinator), Kim Morrison, Paul
|
||||
Reichert, Sofia Rodrigues.
|
||||
|
||||
The Lean 4 standard library is a core part of the Lean distribution, providing
|
||||
essential building blocks for functional programming, verified software
|
||||
development, and software verification. Unlike the standard libraries of most
|
||||
other languages, many of its components are formally verified and can be used
|
||||
as part of verified applications.
|
||||
|
||||
The standard library is a public API that contains the components listed in the
|
||||
standard library outline below. Not all public APIs in the Lean distribution
|
||||
are part of the standard library, and the standard library does not correspond
|
||||
to a certain directory within the Lean source repository. For example, the
|
||||
metaprogramming framework is not part of the standard library.
|
||||
|
||||
The standard library is under active development. Our guiding principles are:
|
||||
|
||||
* Provide comprehensive, verified building blocks for real-world software.
|
||||
* Build a public API of the highest quality with excellent internal consistency.
|
||||
* Carefully optimize components that may be used in performance-critical software.
|
||||
* Ensure smooth adoption and maintenance for users.
|
||||
* Offer excellent documentation, example projects, and guides.
|
||||
* Provide a reliable and extensible basis that libraries for software
|
||||
development, software verification and mathematics can build on.
|
||||
|
||||
The standard library is principally developed by the Lean FRO. Community
|
||||
contributions are welcome. If you would like to contribute, please refer to the
|
||||
call for contributions below.
|
||||
|
||||
### Standard library outline
|
||||
|
||||
1. Core types and operations
|
||||
1. Basic types
|
||||
2. Numeric types, including floating point numbers
|
||||
3. Containers
|
||||
4. Strings and formatting
|
||||
2. Language constructs
|
||||
1. Ranges and iterators
|
||||
2. Comparison, ordering, hashing and related type classes
|
||||
3. Basic monad infrastructure
|
||||
3. Libraries
|
||||
1. Random numbers
|
||||
2. Dates and times
|
||||
4. Operating system abstractions
|
||||
1. Concurrency and parallelism primitives
|
||||
2. Asynchronous I/O
|
||||
3. FFI helpers
|
||||
4. Environment, file system, processes
|
||||
5. Locales
|
||||
|
||||
The material covered in the first three sections (core types and operations,
|
||||
language constructs and libraries) will be verified, with the exception of
|
||||
floating point numbers and the parts of the libraries that interface with the
|
||||
operating system (e.g., sources of operating system randomness or time zone
|
||||
database access).
|
||||
|
||||
### Call for contributions
|
||||
|
||||
Thank you for taking interest in contributing to the Lean standard library\!
|
||||
There are two main ways for community members to contribute to the Lean
|
||||
standard library: by contributing experience reports or by contributing code
|
||||
and lemmas.
|
||||
|
||||
**If you are using Lean for software verification or verified software
|
||||
development:** hearing about your experiences using Lean and its standard
|
||||
library for software verification is extremely valuable to us. We are committed
|
||||
to building a standard library suitable for real-world applications and your
|
||||
input will directly influence the continued evolution of the Lean standard
|
||||
library. Please reach out to the standard library maintainer team via Zulip
|
||||
(either in a public thread in the \#lean4 channel or via direct message). Even
|
||||
just a link to your code helps. Thanks\!
|
||||
|
||||
**If you have code that you believe could enhance the Lean 4 standard
|
||||
library:** we encourage you to initiate a discussion in the \#lean4 channel on
|
||||
Zulip. This is the most effective way to receive preliminary feedback on your
|
||||
contribution. The Lean standard library has a very precise scope and it has
|
||||
very high quality standards, so at the moment we are mostly interested in
|
||||
contributions that expand upon existing material rather than introducing novel
|
||||
concepts.
|
||||
|
||||
**If you would like to contribute code to the standard library but don’t know
|
||||
what to work on:** we are always excited to meet motivated community members
|
||||
who would like to contribute, and there is always impactful work that is
|
||||
suitable for new contributors. Please reach out to Markus Himmel on Zulip to
|
||||
discuss possible contributions.
|
||||
|
||||
As laid out in the [project-wide External Contribution
|
||||
Guidelines](../../CONTRIBUTING.md),
|
||||
PRs are much more likely to be merged if they are preceded by an RFC or if you
|
||||
discussed your planned contribution with a member of the standard library
|
||||
maintainer team. When in doubt, introducing yourself is always a good idea.
|
||||
|
||||
All code in the standard library is expected to strictly adhere to the
|
||||
[standard library coding conventions](./style.md).
|
||||
@@ -28,7 +28,7 @@
|
||||
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
||||
} ({
|
||||
buildInputs = with pkgs; [
|
||||
cmake gmp libuv ccache cadical pkg-config
|
||||
cmake gmp libuv ccache cadical
|
||||
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||
gdb
|
||||
tree # for CI
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
||||
stdenv, lib, cmake, pkg-config, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
||||
stdenv, lib, cmake, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
||||
... } @ args:
|
||||
with builtins;
|
||||
lib.warn "The Nix-based build is deprecated" rec {
|
||||
inherit stdenv;
|
||||
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
|
||||
buildCMake = args: stdenv.mkDerivation ({
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
nativeBuildInputs = [ cmake ];
|
||||
buildInputs = [ gmp libuv llvmPackages.llvm ];
|
||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||
hardeningDisable = [ "all" ];
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import subprocess
|
||||
import requests
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
print("Usage: ./push_repo_release_tag.py <repo> <branch> <version_tag>")
|
||||
sys.exit(1)
|
||||
|
||||
repo, branch, version_tag = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
|
||||
if branch not in {"master", "main"}:
|
||||
print(f"Error: Branch '{branch}' is not 'master' or 'main'.")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the `lean-toolchain` file content
|
||||
lean_toolchain_url = f"https://raw.githubusercontent.com/{repo}/{branch}/lean-toolchain"
|
||||
try:
|
||||
response = requests.get(lean_toolchain_url)
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error fetching 'lean-toolchain' file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
lean_toolchain_content = response.text.strip()
|
||||
expected_prefix = "leanprover/lean4:"
|
||||
if not lean_toolchain_content.startswith(expected_prefix) or lean_toolchain_content != f"{expected_prefix}{version_tag}":
|
||||
print(f"Error: 'lean-toolchain' content does not match '{expected_prefix}{version_tag}'.")
|
||||
sys.exit(1)
|
||||
|
||||
# Create and push the tag using `gh`
|
||||
try:
|
||||
# Check if the tag already exists
|
||||
list_tags_cmd = ["gh", "api", f"repos/{repo}/git/matching-refs/tags/v4", "--jq", ".[].ref"]
|
||||
list_tags_output = subprocess.run(list_tags_cmd, capture_output=True, text=True)
|
||||
|
||||
if list_tags_output.returncode == 0:
|
||||
existing_tags = list_tags_output.stdout.strip().splitlines()
|
||||
if f"refs/tags/{version_tag}" in existing_tags:
|
||||
print(f"Error: Tag '{version_tag}' already exists.")
|
||||
print("Existing tags starting with 'v4':")
|
||||
for tag in existing_tags:
|
||||
print(tag.replace("refs/tags/", ""))
|
||||
sys.exit(1)
|
||||
|
||||
# Get the SHA of the branch
|
||||
get_sha_cmd = [
|
||||
"gh", "api", f"repos/{repo}/git/ref/heads/{branch}", "--jq", ".object.sha"
|
||||
]
|
||||
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True, check=True)
|
||||
sha = sha_result.stdout.strip()
|
||||
|
||||
# Create the tag
|
||||
create_tag_cmd = [
|
||||
"gh", "api", f"repos/{repo}/git/refs",
|
||||
"-X", "POST",
|
||||
"-F", f"ref=refs/tags/{version_tag}",
|
||||
"-F", f"sha={sha}"
|
||||
]
|
||||
subprocess.run(create_tag_cmd, capture_output=True, text=True, check=True)
|
||||
|
||||
print(f"Successfully created and pushed tag '{version_tag}' to {repo}.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error while creating/pushing tag: {e.stderr.strip() if e.stderr else e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -22,36 +22,6 @@ def get_github_token():
|
||||
print("Warning: 'gh' CLI not found. Some API calls may be rate-limited.")
|
||||
return None
|
||||
|
||||
def strip_rc_suffix(toolchain):
|
||||
"""Remove -rcX suffix from the toolchain."""
|
||||
return toolchain.split("-")[0]
|
||||
|
||||
def branch_exists(repo_url, branch, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/branches/{branch}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
return response.status_code == 200
|
||||
|
||||
def tag_exists(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/git/refs/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
return response.status_code == 200
|
||||
|
||||
def release_page_exists(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/releases/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
return response.status_code == 200
|
||||
|
||||
def get_release_notes(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/releases/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
return response.json().get("body", "").strip()
|
||||
return None
|
||||
|
||||
def get_branch_content(repo_url, branch, file_path, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/contents/{file_path}?ref={branch}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
@@ -65,20 +35,11 @@ def get_branch_content(repo_url, branch, file_path, github_token):
|
||||
return None
|
||||
return None
|
||||
|
||||
def parse_version(version_str):
|
||||
# Remove 'v' prefix and extract version and release candidate suffix
|
||||
if ':' in version_str:
|
||||
version_str = version_str.split(':')[1]
|
||||
version = version_str.lstrip('v')
|
||||
parts = version.split('-')
|
||||
base_version = tuple(map(int, parts[0].split('.')))
|
||||
rc_part = parts[1] if len(parts) > 1 and parts[1].startswith('rc') else None
|
||||
rc_number = int(rc_part[2:]) if rc_part else float('inf') # Treat non-rc as higher than rc
|
||||
return base_version + (rc_number,)
|
||||
|
||||
def is_version_gte(version1, version2):
|
||||
"""Check if version1 >= version2, including proper handling of release candidates."""
|
||||
return parse_version(version1) >= parse_version(version2)
|
||||
def tag_exists(repo_url, tag_name, github_token):
|
||||
api_url = repo_url.replace("https://github.com/", "https://api.github.com/repos/") + f"/git/refs/tags/{tag_name}"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
return response.status_code == 200
|
||||
|
||||
def is_merged_into_stable(repo_url, tag_name, stable_branch, github_token):
|
||||
# First get the commit SHA for the tag
|
||||
@@ -103,38 +64,23 @@ def is_merged_into_stable(repo_url, tag_name, stable_branch, github_token):
|
||||
stable_commits = [commit['sha'] for commit in commits_response.json()]
|
||||
return tag_sha in stable_commits
|
||||
|
||||
def parse_version(version_str):
|
||||
# Remove 'v' prefix and split into components
|
||||
# Handle Lean toolchain format (leanprover/lean4:v4.x.y)
|
||||
if ':' in version_str:
|
||||
version_str = version_str.split(':')[1]
|
||||
version = version_str.lstrip('v')
|
||||
# Handle release candidates by removing -rc part for comparison
|
||||
version = version.split('-')[0]
|
||||
return tuple(map(int, version.split('.')))
|
||||
|
||||
def is_version_gte(version1, version2):
|
||||
"""Check if version1 >= version2"""
|
||||
return parse_version(version1) >= parse_version(version2)
|
||||
|
||||
def is_release_candidate(version):
|
||||
return "-rc" in version
|
||||
|
||||
def check_cmake_version(repo_url, branch, version_major, version_minor, github_token):
|
||||
"""Verify the CMake version settings in src/CMakeLists.txt."""
|
||||
cmake_file_path = "src/CMakeLists.txt"
|
||||
content = get_branch_content(repo_url, branch, cmake_file_path, github_token)
|
||||
if content is None:
|
||||
print(f" ❌ Could not retrieve {cmake_file_path} from {branch}")
|
||||
return False
|
||||
|
||||
expected_lines = [
|
||||
f"set(LEAN_VERSION_MAJOR {version_major})",
|
||||
f"set(LEAN_VERSION_MINOR {version_minor})",
|
||||
f"set(LEAN_VERSION_PATCH 0)",
|
||||
f"set(LEAN_VERSION_IS_RELEASE 1)"
|
||||
]
|
||||
|
||||
for line in expected_lines:
|
||||
if not any(l.strip().startswith(line) for l in content.splitlines()):
|
||||
print(f" ❌ Missing or incorrect line in {cmake_file_path}: {line}")
|
||||
return False
|
||||
|
||||
print(f" ✅ CMake version settings are correct in {cmake_file_path}")
|
||||
return True
|
||||
|
||||
def extract_org_repo_from_url(repo_url):
|
||||
"""Extract the 'org/repo' part from a GitHub URL."""
|
||||
if repo_url.startswith("https://github.com/"):
|
||||
return repo_url.replace("https://github.com/", "").rstrip("/")
|
||||
return repo_url
|
||||
|
||||
def main():
|
||||
github_token = get_github_token()
|
||||
|
||||
@@ -143,47 +89,6 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
toolchain = sys.argv[1]
|
||||
stripped_toolchain = strip_rc_suffix(toolchain)
|
||||
lean_repo_url = "https://github.com/leanprover/lean4"
|
||||
|
||||
# Preliminary checks
|
||||
print("\nPerforming preliminary checks...")
|
||||
|
||||
# Check for branch releases/v4.Y.0
|
||||
version_major, version_minor, _ = map(int, stripped_toolchain.lstrip('v').split('.'))
|
||||
branch_name = f"releases/v{version_major}.{version_minor}.0"
|
||||
if branch_exists(lean_repo_url, branch_name, github_token):
|
||||
print(f" ✅ Branch {branch_name} exists")
|
||||
|
||||
# Check CMake version settings
|
||||
check_cmake_version(lean_repo_url, branch_name, version_major, version_minor, github_token)
|
||||
else:
|
||||
print(f" ❌ Branch {branch_name} does not exist")
|
||||
|
||||
# Check for tag v4.X.Y(-rcZ)
|
||||
if tag_exists(lean_repo_url, toolchain, github_token):
|
||||
print(f" ✅ Tag {toolchain} exists")
|
||||
else:
|
||||
print(f" ❌ Tag {toolchain} does not exist.")
|
||||
|
||||
# Check for release page
|
||||
if release_page_exists(lean_repo_url, toolchain, github_token):
|
||||
print(f" ✅ Release page for {toolchain} exists")
|
||||
|
||||
# Check the first line of the release notes
|
||||
release_notes = get_release_notes(lean_repo_url, toolchain, github_token)
|
||||
if release_notes and release_notes.splitlines()[0].strip() == toolchain:
|
||||
print(f" ✅ Release notes look good.")
|
||||
else:
|
||||
previous_minor_version = version_minor - 1
|
||||
previous_stable_branch = f"releases/v{version_major}.{previous_minor_version}.0"
|
||||
previous_release = f"v{version_major}.{previous_minor_version}.0"
|
||||
print(f" ❌ Release notes not published. Please run `script/release_notes.py {previous_release}` on branch `{previous_stable_branch}`.")
|
||||
else:
|
||||
print(f" ❌ Release page for {toolchain} does not exist")
|
||||
|
||||
# Load repositories and perform further checks
|
||||
print("\nChecking repositories...")
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "release_repos.yml")) as f:
|
||||
repos = yaml.safe_load(f)["repositories"]
|
||||
@@ -212,7 +117,7 @@ def main():
|
||||
# Only check for tag if toolchain-tag is true
|
||||
if check_tag:
|
||||
if not tag_exists(url, toolchain, github_token):
|
||||
print(f" ❌ Tag {toolchain} does not exist. Run `script/push_repo_release_tag.py {extract_org_repo_from_url(url)} {branch} {toolchain}`.")
|
||||
print(f" ❌ Tag {toolchain} does not exist")
|
||||
continue
|
||||
print(f" ✅ Tag {toolchain} exists")
|
||||
|
||||
|
||||
@@ -295,15 +295,14 @@ index 5e8e0166..f3b29134 100644
|
||||
PATCH_COMMAND git reset --hard HEAD && printf "${LIBUV_PATCH}" > patch.diff && git apply patch.diff
|
||||
BUILD_IN_SOURCE ON
|
||||
INSTALL_COMMAND "")
|
||||
set(LIBUV_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/libuv/src/libuv/include")
|
||||
set(LIBUV_LDFLAGS "${CMAKE_BINARY_DIR}/libuv/src/libuv/libuv.a")
|
||||
set(LIBUV_INCLUDE_DIR "${CMAKE_BINARY_DIR}/libuv/src/libuv/include")
|
||||
set(LIBUV_LIBRARIES "${CMAKE_BINARY_DIR}/libuv/src/libuv/libuv.a")
|
||||
else()
|
||||
find_package(LibUV 1.0.0 REQUIRED)
|
||||
endif()
|
||||
include_directories(${LIBUV_INCLUDE_DIRS})
|
||||
include_directories(${LIBUV_INCLUDE_DIR})
|
||||
if(NOT LEAN_STANDALONE)
|
||||
string(JOIN " " LIBUV_LDFLAGS ${LIBUV_LDFLAGS})
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LDFLAGS}")
|
||||
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
# Windows SDK (for ICU)
|
||||
@@ -699,12 +698,12 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
add_custom_target(lake_lib
|
||||
add_custom_target(lake_lib ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS leanshared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Lake
|
||||
VERBATIM)
|
||||
add_custom_target(lake_shared
|
||||
add_custom_target(lake_shared ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS lake_lib
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make libLake_shared
|
||||
|
||||
@@ -136,23 +136,6 @@ theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y
|
||||
theorem Functor.map_unit [Monad m] [LawfulMonad m] {a : m PUnit} : (fun _ => PUnit.unit) <$> a = a := by
|
||||
simp [map]
|
||||
|
||||
/--
|
||||
This is just a duplicate of `LawfulApplicative.map_pure`,
|
||||
but sometimes applies when that doesn't.
|
||||
|
||||
It is named with a prime to avoid conflict with the inherited field `LawfulMonad.map_pure`.
|
||||
-/
|
||||
@[simp] theorem LawfulMonad.map_pure' [Monad m] [LawfulMonad m] {a : α} :
|
||||
(f <$> pure a : m β) = pure (f a) := by
|
||||
simp only [map_pure]
|
||||
|
||||
/--
|
||||
This is just a duplicate of `Functor.map_map`, but sometimes applies when that doesn't.
|
||||
-/
|
||||
@[simp] theorem LawfulMonad.map_map {m} [Monad m] [LawfulMonad m] {x : m α} :
|
||||
g <$> f <$> x = (fun a => g (f a)) <$> x := by
|
||||
simp only [Functor.map_map]
|
||||
|
||||
/--
|
||||
An alternative constructor for `LawfulMonad` which has more
|
||||
defaultable fields in the common case.
|
||||
|
||||
@@ -516,17 +516,8 @@ The tasks have an overridden representation in the runtime.
|
||||
structure Task (α : Type u) : Type u where
|
||||
/-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
|
||||
pure ::
|
||||
/--
|
||||
Blocks the current thread until the given task has finished execution, and then returns the result
|
||||
of the task. If the current thread is itself executing a (non-dedicated) task, the maximum
|
||||
threadpool size is temporarily increased by one while waiting so as to ensure the process cannot
|
||||
be deadlocked by threadpool starvation. Note that when the current thread is unblocked, more tasks
|
||||
than the configured threadpool size may temporarily be running at the same time until sufficiently
|
||||
many tasks have finished.
|
||||
|
||||
`Task.map` and `Task.bind` should be preferred over `Task.get` for setting up task dependencies
|
||||
where possible as they do not require temporarily growing the threadpool in this way.
|
||||
-/
|
||||
/-- If `task : Task α` then `task.get : α` blocks the current thread until the
|
||||
value is available, and then returns the result of the task. -/
|
||||
get : α
|
||||
deriving Inhabited, Nonempty
|
||||
|
||||
@@ -1384,43 +1375,21 @@ instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) :=
|
||||
| isTrue h => isTrue (propext h)
|
||||
| isFalse h => isFalse fun heq => h (heq ▸ Iff.rfl)
|
||||
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% BitVec
|
||||
gen_injective_theorems% Char
|
||||
gen_injective_theorems% DoResultBC
|
||||
gen_injective_theorems% DoResultPR
|
||||
gen_injective_theorems% DoResultPRBC
|
||||
gen_injective_theorems% DoResultSBC
|
||||
gen_injective_theorems% EStateM.Result
|
||||
gen_injective_theorems% Except
|
||||
gen_injective_theorems% Prod
|
||||
gen_injective_theorems% PProd
|
||||
gen_injective_theorems% MProd
|
||||
gen_injective_theorems% Subtype
|
||||
gen_injective_theorems% Fin
|
||||
gen_injective_theorems% ForInStep
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% Sum
|
||||
gen_injective_theorems% PSum
|
||||
gen_injective_theorems% Option
|
||||
gen_injective_theorems% List
|
||||
gen_injective_theorems% Except
|
||||
gen_injective_theorems% EStateM.Result
|
||||
gen_injective_theorems% Lean.Name
|
||||
gen_injective_theorems% Lean.Syntax
|
||||
gen_injective_theorems% List
|
||||
gen_injective_theorems% MProd
|
||||
gen_injective_theorems% NonScalar
|
||||
gen_injective_theorems% Option
|
||||
gen_injective_theorems% PLift
|
||||
gen_injective_theorems% PNonScalar
|
||||
gen_injective_theorems% PProd
|
||||
gen_injective_theorems% Prod
|
||||
gen_injective_theorems% PSigma
|
||||
gen_injective_theorems% PSum
|
||||
gen_injective_theorems% Sigma
|
||||
gen_injective_theorems% String
|
||||
gen_injective_theorems% String.Pos
|
||||
gen_injective_theorems% Substring
|
||||
gen_injective_theorems% Subtype
|
||||
gen_injective_theorems% Sum
|
||||
gen_injective_theorems% Task
|
||||
gen_injective_theorems% Thunk
|
||||
gen_injective_theorems% UInt16
|
||||
gen_injective_theorems% UInt32
|
||||
gen_injective_theorems% UInt64
|
||||
gen_injective_theorems% UInt8
|
||||
gen_injective_theorems% ULift
|
||||
gen_injective_theorems% USize
|
||||
gen_injective_theorems% BitVec
|
||||
|
||||
theorem Nat.succ.inj {m n : Nat} : m.succ = n.succ → m = n :=
|
||||
fun x => Nat.noConfusion x id
|
||||
|
||||
@@ -23,4 +23,3 @@ import Init.Data.Array.FinRange
|
||||
import Init.Data.Array.Perm
|
||||
import Init.Data.Array.Find
|
||||
import Init.Data.Array.Lex
|
||||
import Init.Data.Array.Zip
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Joachim Breitner, Mario Carneiro
|
||||
prelude
|
||||
import Init.Data.Array.Mem
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Count
|
||||
import Init.Data.List.Attach
|
||||
|
||||
namespace Array
|
||||
@@ -143,16 +142,10 @@ theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||
cases l
|
||||
simp [List.pmap_eq_map_attach]
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_attachWith {p q : α → Prop} (f : ∀ a, p a → q a) (l H) :
|
||||
pmap (fun a h => ⟨a, f a h⟩) l H = l.attachWith q (fun x h => f x (H x h)) := by
|
||||
cases l
|
||||
simp [List.pmap_eq_attachWith]
|
||||
|
||||
theorem attach_map_coe (l : Array α) (f : α → β) :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
cases l
|
||||
simp
|
||||
simp [List.attach_map_coe]
|
||||
|
||||
theorem attach_map_val (l : Array α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
@@ -179,12 +172,6 @@ theorem mem_attach (l : Array α) : ∀ x, x ∈ l.attach
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
theorem mem_attachWith (l : Array α) {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
@@ -236,16 +223,16 @@ theorem attachWith_ne_empty_iff {l : Array α} {P : α → Prop} {H : ∀ a ∈
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) (i : Nat) :
|
||||
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) {i : Nat}
|
||||
(hi : i < (pmap f l h).size) :
|
||||
(pmap f l h)[i] =
|
||||
f (l[i]'(@size_pmap _ _ p f l h ▸ hi))
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f l h ▸ hi))) := by
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Array α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||
(hn : n < (pmap f l h).size) :
|
||||
(pmap f l h)[n] =
|
||||
f (l[n]'(@size_pmap _ _ p f l h ▸ hn))
|
||||
(h _ (getElem_mem (@size_pmap _ _ p f l h ▸ hn))) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
@@ -269,18 +256,6 @@ theorem getElem_attach {xs : Array α} {i : Nat} (h : i < xs.attach.size) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem pmap_attach (l : Array α) {p : {x // x ∈ l} → Prop} (f : ∀ a, p a → β) (H) :
|
||||
pmap f l.attach H =
|
||||
l.pmap (P := fun a => ∃ h : a ∈ l, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem pmap_attachWith (l : Array α) {p : {x // q x} → Prop} (f : ∀ a, p a → β) (H₁ H₂) :
|
||||
pmap f (l.attachWith q H₁) H₂ =
|
||||
l.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
theorem foldl_pmap (l : Array α) {P : α → Prop} (f : (a : α) → P a → β)
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
@@ -338,7 +313,11 @@ theorem attachWith_map {l : Array α} (f : α → β) {P : β → Prop} {H : ∀
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases l
|
||||
simp [List.attachWith_map]
|
||||
ext
|
||||
· simp
|
||||
· simp only [List.map_toArray, List.attachWith_toArray, List.getElem_toArray,
|
||||
List.getElem_attachWith, List.getElem_map, Function.comp_apply]
|
||||
erw [List.getElem_attachWith] -- Why is `erw` needed here?
|
||||
|
||||
theorem map_attachWith {l : Array α} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
(f : { x // P x } → β) :
|
||||
@@ -368,23 +347,7 @@ theorem attach_filter {l : Array α} (p : α → Bool) :
|
||||
simp [List.attach_filter, List.map_filterMap, Function.comp_def]
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
|
||||
@[simp]
|
||||
theorem filterMap_attachWith {q : α → Prop} {l : Array α} {f : {x // q x} → Option β} (H)
|
||||
(w : stop = (l.attachWith q H).size) :
|
||||
(l.attachWith q H).filterMap f 0 stop = l.attach.filterMap (fun ⟨x, h⟩ => f ⟨x, H _ h⟩) := by
|
||||
subst w
|
||||
cases l
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
theorem filter_attachWith {q : α → Prop} {l : Array α} {p : {x // q x} → Bool} (H)
|
||||
(w : stop = (l.attachWith q H).size) :
|
||||
(l.attachWith q H).filter p 0 stop =
|
||||
(l.attach.filter (fun ⟨x, h⟩ => p ⟨x, H _ h⟩)).map (fun ⟨x, h⟩ => ⟨x, H _ h⟩) := by
|
||||
subst w
|
||||
cases l
|
||||
simp [Function.comp_def, List.filter_map]
|
||||
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
@@ -464,48 +427,16 @@ theorem reverse_attach (xs : Array α) :
|
||||
|
||||
@[simp] theorem back?_attachWith {P : α → Prop} {xs : Array α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back? h)⟩) := by
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back?_eq_some h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem back?_attach {xs : Array α} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back? h⟩ := by
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back?_eq_some h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem countP_attach (l : Array α) (p : α → Bool) :
|
||||
l.attach.countP (fun a : {x // x ∈ l} => p a) = l.countP p := by
|
||||
cases l
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
theorem countP_attachWith {p : α → Prop} (l : Array α) (H : ∀ a ∈ l, p a) (q : α → Bool) :
|
||||
(l.attachWith p H).countP (fun a : {x // p x} => q a) = l.countP q := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] (l : Array α) (a : {x // x ∈ l}) :
|
||||
l.attach.count a = l.count ↑a := by
|
||||
rcases l with ⟨l⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.count_toArray]
|
||||
rw [List.map_attach, List.count_eq_countP]
|
||||
simp only [Subtype.beq_iff]
|
||||
rw [List.countP_pmap, List.countP_attach (p := (fun x => x == a.1)), List.count]
|
||||
|
||||
@[simp]
|
||||
theorem count_attachWith [DecidableEq α] {p : α → Prop} (l : Array α) (H : ∀ a ∈ l, p a) (a : {x // p x}) :
|
||||
(l.attachWith p H).count a = l.count ↑a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_pmap {p : α → Prop} (g : ∀ a, p a → β) (f : β → Bool) (l : Array α) (H₁) :
|
||||
(l.pmap g H₁).countP f =
|
||||
l.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`Array.unattach` is the (one-sided) inverse of `Array.attach`. It is a synonym for `Array.map Subtype.val`.
|
||||
@@ -524,7 +455,7 @@ and is ideally subsequently simplified away by `unattach_attach`.
|
||||
|
||||
If not, usually the right approach is `simp [Array.unattach, -Array.map_subtype]` to unfold.
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) : Array α := l.map (·.val)
|
||||
def unattach {α : Type _} {p : α → Prop} (l : Array { x // p x }) := l.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := rfl
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {l : Array { x // p x }} :
|
||||
@@ -647,16 +578,4 @@ and simplifies these to the function directly taking the value.
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem unattach_flatten {p : α → Prop} {l : Array (Array { x // p x })} :
|
||||
l.flatten.unattach = (l.map unattach).flatten := by
|
||||
unfold unattach
|
||||
cases l using array₂_induction
|
||||
simp only [flatten_toArray, List.map_map, Function.comp_def, List.map_id_fun', id_eq,
|
||||
List.map_toArray, List.map_flatten, map_subtype, map_id_fun', List.unattach_toArray, mk.injEq]
|
||||
simp only [List.unattach]
|
||||
|
||||
@[simp] theorem unattach_mkArray {p : α → Prop} {n : Nat} {x : { x // p x }} :
|
||||
(Array.mkArray n x).unattach = Array.mkArray n x.1 := by
|
||||
simp [unattach]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -455,7 +455,7 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
||||
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
|
||||
@[inline]
|
||||
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
(as : Array α) (f : (i : Nat) → α → (h : i < as.size) → m β) : m (Array β) :=
|
||||
(as : Array α) (f : Fin as.size → α → m β) : m (Array β) :=
|
||||
let rec @[specialize] map (i : Nat) (j : Nat) (inv : i + j = as.size) (bs : Array β) : m (Array β) := do
|
||||
match i, inv with
|
||||
| 0, _ => pure bs
|
||||
@@ -464,12 +464,12 @@ def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
rw [← inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
|
||||
apply Nat.le_add_right
|
||||
have : i + (j + 1) = as.size := by rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
|
||||
map i (j+1) this (bs.push (← f j (as.get j j_lt) j_lt))
|
||||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get j j_lt)))
|
||||
map as.size 0 rfl (mkEmpty as.size)
|
||||
|
||||
@[inline]
|
||||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β) :=
|
||||
as.mapFinIdxM fun i a _ => f i a
|
||||
as.mapFinIdxM fun i a => f i a
|
||||
|
||||
@[inline]
|
||||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) := do
|
||||
@@ -576,28 +576,13 @@ def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : A
|
||||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Array α) (start := as.size) (stop := 0) : β :=
|
||||
Id.run <| as.foldrM f init start stop
|
||||
|
||||
/-- Sum of an array.
|
||||
|
||||
`Array.sum #[a, b, c] = a + (b + (c + 0))` -/
|
||||
@[inline]
|
||||
def sum {α} [Add α] [Zero α] : Array α → α :=
|
||||
foldr (· + ·) 0
|
||||
|
||||
@[inline]
|
||||
def countP {α : Type u} (p : α → Bool) (as : Array α) : Nat :=
|
||||
as.foldr (init := 0) fun a acc => bif p a then acc + 1 else acc
|
||||
|
||||
@[inline]
|
||||
def count {α : Type u} [BEq α] (a : α) (as : Array α) : Nat :=
|
||||
countP (· == a) as
|
||||
|
||||
@[inline]
|
||||
def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :=
|
||||
Id.run <| as.mapM f
|
||||
|
||||
/-- Variant of `mapIdx` which receives the index as a `Fin as.size`. -/
|
||||
@[inline]
|
||||
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β) : Array β :=
|
||||
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size → α → β) : Array β :=
|
||||
Id.run <| as.mapFinIdxM f
|
||||
|
||||
@[inline]
|
||||
@@ -605,10 +590,8 @@ def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) :
|
||||
Id.run <| as.mapIdxM f
|
||||
|
||||
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
|
||||
def zipIdx (arr : Array α) (start := 0) : Array (α × Nat) :=
|
||||
arr.mapIdx fun i a => (a, i + start)
|
||||
|
||||
@[deprecated zipIdx (since := "2025-01-21")] abbrev zipWithIndex := @zipIdx
|
||||
def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
||||
arr.mapIdx fun i a => (a, i)
|
||||
|
||||
@[inline]
|
||||
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||||
@@ -856,19 +839,12 @@ it has to backshift all elements at positions greater than `i`. -/
|
||||
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
|
||||
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
|
||||
|
||||
/-- Remove a specified element from an array, or do nothing if it is not present.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all later elements. -/
|
||||
def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||||
match as.indexOf? a with
|
||||
| none => as
|
||||
| some i => as.eraseIdx i
|
||||
|
||||
/-- Erase the first element that satisfies the predicate `p`.
|
||||
|
||||
This function takes worst case O(n) time because
|
||||
it has to backshift all later elements. -/
|
||||
/-- Erase the first element that satisfies the predicate `p`. -/
|
||||
def eraseP (as : Array α) (p : α → Bool) : Array α :=
|
||||
match as.findIdx? p with
|
||||
| none => as
|
||||
@@ -941,13 +917,13 @@ def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat)
|
||||
cs
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[inline] def zipWith (f : α → β → γ) (as : Array α) (bs : Array β) : Array γ :=
|
||||
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : Array γ :=
|
||||
zipWithAux as bs f 0 #[]
|
||||
|
||||
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
|
||||
zipWith Prod.mk as bs
|
||||
zipWith as bs Prod.mk
|
||||
|
||||
def zipWithAll (f : Option α → Option β → γ) (as : Array α) (bs : Array β) : Array γ :=
|
||||
def zipWithAll (as : Array α) (bs : Array β) (f : Option α → Option β → γ) : Array γ :=
|
||||
go as bs 0 #[]
|
||||
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
|
||||
if i < max as.size bs.size then
|
||||
|
||||
@@ -81,18 +81,12 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] (f : α → β → m β) (init
|
||||
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp] theorem append_empty (as : Array α) : as ++ #[] = as := by
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[deprecated append_empty (since := "2025-01-13")]
|
||||
abbrev append_nil := @append_empty
|
||||
|
||||
@[simp] theorem empty_append (as : Array α) : #[] ++ as = as := by
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[deprecated empty_append (since := "2025-01-13")]
|
||||
abbrev nil_append := @empty_append
|
||||
|
||||
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
|
||||
@@ -1,270 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.Nat.Count
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.countP` and `Array.count`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ### countP -/
|
||||
section countP
|
||||
|
||||
variable (p q : α → Bool)
|
||||
|
||||
@[simp] theorem countP_empty : countP p #[] = 0 := rfl
|
||||
|
||||
@[simp] theorem countP_push_of_pos (l) (pa : p a) : countP p (l.push a) = countP p l + 1 := by
|
||||
rcases l with ⟨l⟩
|
||||
simp_all
|
||||
|
||||
@[simp] theorem countP_push_of_neg (l) (pa : ¬p a) : countP p (l.push a) = countP p l := by
|
||||
rcases l with ⟨l⟩
|
||||
simp_all
|
||||
|
||||
theorem countP_push (a : α) (l) : countP p (l.push a) = countP p l + if p a then 1 else 0 := by
|
||||
rcases l with ⟨l⟩
|
||||
simp_all
|
||||
|
||||
@[simp] theorem countP_singleton (a : α) : countP p #[a] = if p a then 1 else 0 := by
|
||||
simp [countP_push]
|
||||
|
||||
theorem size_eq_countP_add_countP (l) : l.size = countP p l + countP (fun a => ¬p a) l := by
|
||||
cases l
|
||||
simp [List.length_eq_countP_add_countP (p := p)]
|
||||
|
||||
theorem countP_eq_size_filter (l) : countP p l = (filter p l).size := by
|
||||
cases l
|
||||
simp [List.countP_eq_length_filter]
|
||||
|
||||
theorem countP_eq_size_filter' : countP p = size ∘ filter p := by
|
||||
funext l
|
||||
apply countP_eq_size_filter
|
||||
|
||||
theorem countP_le_size : countP p l ≤ l.size := by
|
||||
simp only [countP_eq_size_filter]
|
||||
apply size_filter_le
|
||||
|
||||
@[simp] theorem countP_append (l₁ l₂) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_pos_iff {p} : 0 < countP p l ↔ ∃ a ∈ l, p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem one_le_countP_iff {p} : 1 ≤ countP p l ↔ ∃ a ∈ l, p a :=
|
||||
countP_pos_iff
|
||||
|
||||
@[simp] theorem countP_eq_zero {p} : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_eq_size {p} : countP p l = l.size ↔ ∀ a ∈ l, p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem countP_mkArray (p : α → Bool) (a : α) (n : Nat) :
|
||||
countP p (mkArray n a) = if p a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.countP_replicate]
|
||||
|
||||
theorem boole_getElem_le_countP (p : α → Bool) (l : Array α) (i : Nat) (h : i < l.size) :
|
||||
(if p l[i] then 1 else 0) ≤ l.countP p := by
|
||||
cases l
|
||||
simp [List.boole_getElem_le_countP]
|
||||
|
||||
theorem countP_set (p : α → Bool) (l : Array α) (i : Nat) (a : α) (h : i < l.size) :
|
||||
(l.set i a).countP p = l.countP p - (if p l[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||||
cases l
|
||||
simp [List.countP_set, h]
|
||||
|
||||
theorem countP_filter (l : Array α) :
|
||||
countP p (filter q l) = countP (fun a => p a && q a) l := by
|
||||
cases l
|
||||
simp [List.countP_filter]
|
||||
|
||||
@[simp] theorem countP_true : (countP fun (_ : α) => true) = size := by
|
||||
funext l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_false : (countP fun (_ : α) => false) = Function.const _ 0 := by
|
||||
funext l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_map (p : β → Bool) (f : α → β) (l : Array α) :
|
||||
countP p (map f l) = countP (p ∘ f) l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem size_filterMap_eq_countP (f : α → Option β) (l : Array α) :
|
||||
(filterMap f l).size = countP (fun a => (f a).isSome) l := by
|
||||
cases l
|
||||
simp [List.length_filterMap_eq_countP]
|
||||
|
||||
theorem countP_filterMap (p : β → Bool) (f : α → Option β) (l : Array α) :
|
||||
countP p (filterMap f l) = countP (fun a => ((f a).map p).getD false) l := by
|
||||
cases l
|
||||
simp [List.countP_filterMap]
|
||||
|
||||
@[simp] theorem countP_flatten (l : Array (Array α)) :
|
||||
countP p l.flatten = (l.map (countP p)).sum := by
|
||||
cases l using array₂_induction
|
||||
simp [List.countP_flatten, Function.comp_def]
|
||||
|
||||
theorem countP_flatMap (p : β → Bool) (l : Array α) (f : α → Array β) :
|
||||
countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by
|
||||
cases l
|
||||
simp [List.countP_flatMap, Function.comp_def]
|
||||
|
||||
@[simp] theorem countP_reverse (l : Array α) : countP p l.reverse = countP p l := by
|
||||
cases l
|
||||
simp [List.countP_reverse]
|
||||
|
||||
variable {p q}
|
||||
|
||||
theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by
|
||||
cases l
|
||||
simpa using List.countP_mono_left (by simpa using h)
|
||||
|
||||
theorem countP_congr (h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l :=
|
||||
Nat.le_antisymm
|
||||
(countP_mono_left fun x hx => (h x hx).1)
|
||||
(countP_mono_left fun x hx => (h x hx).2)
|
||||
|
||||
end countP
|
||||
|
||||
/-! ### count -/
|
||||
section count
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem count_empty (a : α) : count a #[] = 0 := rfl
|
||||
|
||||
theorem count_push (a b : α) (l : Array α) :
|
||||
count a (l.push b) = count a l + if b == a then 1 else 0 := by
|
||||
simp [count, countP_push]
|
||||
|
||||
theorem count_eq_countP (a : α) (l : Array α) : count a l = countP (· == a) l := rfl
|
||||
theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
|
||||
funext l
|
||||
apply count_eq_countP
|
||||
|
||||
theorem count_le_size (a : α) (l : Array α) : count a l ≤ l.size := countP_le_size _
|
||||
|
||||
theorem count_le_count_push (a b : α) (l : Array α) : count a l ≤ count a (l.push b) := by
|
||||
simp [count_push]
|
||||
|
||||
@[simp] theorem count_singleton (a b : α) : count a #[b] = if b == a then 1 else 0 := by
|
||||
simp [count_eq_countP]
|
||||
|
||||
@[simp] theorem count_append (a : α) : ∀ l₁ l₂, count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
|
||||
countP_append _
|
||||
|
||||
@[simp] theorem count_flatten (a : α) (l : Array (Array α)) :
|
||||
count a l.flatten = (l.map (count a)).sum := by
|
||||
cases l using array₂_induction
|
||||
simp [List.count_flatten, Function.comp_def]
|
||||
|
||||
@[simp] theorem count_reverse (a : α) (l : Array α) : count a l.reverse = count a l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem boole_getElem_le_count (a : α) (l : Array α) (i : Nat) (h : i < l.size) :
|
||||
(if l[i] == a then 1 else 0) ≤ l.count a := by
|
||||
rw [count_eq_countP]
|
||||
apply boole_getElem_le_countP (· == a)
|
||||
|
||||
theorem count_set (a b : α) (l : Array α) (i : Nat) (h : i < l.size) :
|
||||
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
simp [count_eq_countP, countP_set, h]
|
||||
|
||||
variable [LawfulBEq α]
|
||||
|
||||
@[simp] theorem count_push_self (a : α) (l : Array α) : count a (l.push a) = count a l + 1 := by
|
||||
simp [count_push]
|
||||
|
||||
@[simp] theorem count_push_of_ne (h : b ≠ a) (l : Array α) : count a (l.push b) = count a l := by
|
||||
simp_all [count_push, h]
|
||||
|
||||
theorem count_singleton_self (a : α) : count a #[a] = 1 := by simp
|
||||
|
||||
@[simp]
|
||||
theorem count_pos_iff {a : α} {l : Array α} : 0 < count a l ↔ a ∈ l := by
|
||||
simp only [count, countP_pos_iff, beq_iff_eq, exists_eq_right]
|
||||
|
||||
@[simp] theorem one_le_count_iff {a : α} {l : Array α} : 1 ≤ count a l ↔ a ∈ l :=
|
||||
count_pos_iff
|
||||
|
||||
theorem count_eq_zero_of_not_mem {a : α} {l : Array α} (h : a ∉ l) : count a l = 0 :=
|
||||
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
|
||||
|
||||
theorem not_mem_of_count_eq_zero {a : α} {l : Array α} (h : count a l = 0) : a ∉ l :=
|
||||
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
|
||||
|
||||
theorem count_eq_zero {l : Array α} : count a l = 0 ↔ a ∉ l :=
|
||||
⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩
|
||||
|
||||
theorem count_eq_size {l : Array α} : count a l = l.size ↔ ∀ b ∈ l, a = b := by
|
||||
rw [count, countP_eq_size]
|
||||
refine ⟨fun h b hb => Eq.symm ?_, fun h b hb => ?_⟩
|
||||
· simpa using h b hb
|
||||
· rw [h b hb, beq_self_eq_true]
|
||||
|
||||
@[simp] theorem count_mkArray_self (a : α) (n : Nat) : count a (mkArray n a) = n := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
theorem count_mkArray (a b : α) (n : Nat) : count a (mkArray n b) = if b == a then n else 0 := by
|
||||
simp [← List.toArray_replicate, List.count_replicate]
|
||||
|
||||
theorem filter_beq (l : Array α) (a : α) : l.filter (· == a) = mkArray (count a l) a := by
|
||||
cases l
|
||||
simp [List.filter_beq]
|
||||
|
||||
theorem filter_eq {α} [DecidableEq α] (l : Array α) (a : α) : l.filter (· = a) = mkArray (count a l) a :=
|
||||
filter_beq l a
|
||||
|
||||
theorem mkArray_count_eq_of_count_eq_size {l : Array α} (h : count a l = l.size) :
|
||||
mkArray (count a l) a = l := by
|
||||
cases l
|
||||
rw [← toList_inj]
|
||||
simp [List.replicate_count_eq_of_count_eq_length (by simpa using h)]
|
||||
|
||||
@[simp] theorem count_filter {l : Array α} (h : p a) : count a (filter p l) = count a l := by
|
||||
cases l
|
||||
simp [List.count_filter, h]
|
||||
|
||||
theorem count_le_count_map [DecidableEq β] (l : Array α) (f : α → β) (x : α) :
|
||||
count x l ≤ count (f x) (map f l) := by
|
||||
cases l
|
||||
simp [List.count_le_count_map, countP_map]
|
||||
|
||||
theorem count_filterMap {α} [BEq β] (b : β) (f : α → Option β) (l : Array α) :
|
||||
count b (filterMap f l) = countP (fun a => f a == some b) l := by
|
||||
cases l
|
||||
simp [List.count_filterMap, countP_filterMap]
|
||||
|
||||
theorem count_flatMap {α} [BEq β] (l : Array α) (f : α → Array β) (x : β) :
|
||||
count x (l.flatMap f) = sum (map (count x ∘ f) l) := by
|
||||
simp [count_eq_countP, countP_flatMap, Function.comp_def]
|
||||
|
||||
-- FIXME these theorems can be restored once `List.erase` and `Array.erase` have been related.
|
||||
|
||||
-- theorem count_erase (a b : α) (l : Array α) : count a (l.erase b) = count a l - if b == a then 1 else 0 := by
|
||||
-- sorry
|
||||
|
||||
-- @[simp] theorem count_erase_self (a : α) (l : Array α) :
|
||||
-- count a (l.erase a) = count a l - 1 := by rw [count_erase, if_pos (by simp)]
|
||||
|
||||
-- @[simp] theorem count_erase_of_ne (ab : a ≠ b) (l : Array α) : count a (l.erase b) = count a l := by
|
||||
-- rw [count_erase, if_neg (by simpa using ab.symm), Nat.sub_zero]
|
||||
|
||||
end count
|
||||
@@ -11,7 +11,7 @@ import Init.ByCases
|
||||
|
||||
namespace Array
|
||||
|
||||
private theorem rel_of_isEqvAux
|
||||
theorem rel_of_isEqvAux
|
||||
{r : α → α → Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i ≤ a.size)
|
||||
(heqv : Array.isEqvAux a b hsz r i hi)
|
||||
{j : Nat} (hj : j < i) : r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz ▸ hi))) := by
|
||||
@@ -27,7 +27,7 @@ private theorem rel_of_isEqvAux
|
||||
subst hj'
|
||||
exact heqv.left
|
||||
|
||||
private theorem isEqvAux_of_rel {r : α → α → Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i ≤ a.size)
|
||||
theorem isEqvAux_of_rel {r : α → α → Bool} {a b : Array α} (hsz : a.size = b.size) {i : Nat} (hi : i ≤ a.size)
|
||||
(w : ∀ j, (hj : j < i) → r (a[j]'(Nat.lt_of_lt_of_le hj hi)) (b[j]'(Nat.lt_of_lt_of_le hj (hsz ▸ hi)))) : Array.isEqvAux a b hsz r i hi := by
|
||||
induction i with
|
||||
| zero => simp [Array.isEqvAux]
|
||||
@@ -35,8 +35,7 @@ private theorem isEqvAux_of_rel {r : α → α → Bool} {a b : Array α} (hsz :
|
||||
simp only [isEqvAux, Bool.and_eq_true]
|
||||
exact ⟨w i (Nat.lt_add_one i), ih _ fun j hj => w j (Nat.lt_add_right 1 hj)⟩
|
||||
|
||||
-- This is private as the forward direction of `isEqv_iff_rel` may be used.
|
||||
private theorem rel_of_isEqv {r : α → α → Bool} {a b : Array α} :
|
||||
theorem rel_of_isEqv {r : α → α → Bool} {a b : Array α} :
|
||||
Array.isEqv a b r → ∃ h : a.size = b.size, ∀ (i : Nat) (h' : i < a.size), r (a[i]) (b[i]'(h ▸ h')) := by
|
||||
simp only [isEqv]
|
||||
split <;> rename_i h
|
||||
@@ -70,7 +69,7 @@ theorem eq_of_isEqv [DecidableEq α] (a b : Array α) (h : Array.isEqv a b (fun
|
||||
have ⟨h, h'⟩ := rel_of_isEqv h
|
||||
exact ext _ _ h (fun i lt _ => by simpa using h' i lt)
|
||||
|
||||
private theorem isEqvAux_self (r : α → α → Bool) (hr : ∀ a, r a a) (a : Array α) (i : Nat) (h : i ≤ a.size) :
|
||||
theorem isEqvAux_self (r : α → α → Bool) (hr : ∀ a, r a a) (a : Array α) (i : Nat) (h : i ≤ a.size) :
|
||||
Array.isEqvAux a a rfl r i h = true := by
|
||||
induction i with
|
||||
| zero => simp [Array.isEqvAux]
|
||||
|
||||
@@ -74,12 +74,12 @@ theorem findSome?_append {l₁ l₂ : Array α} : (l₁ ++ l₂).findSome? f = (
|
||||
|
||||
theorem getElem?_zero_flatten (L : Array (Array α)) :
|
||||
(flatten L)[0]? = L.findSome? fun l => l[0]? := by
|
||||
cases L using array₂_induction
|
||||
cases L using array_array_induction
|
||||
simp [← List.head?_eq_getElem?, List.head?_flatten, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem getElem_zero_flatten.proof {L : Array (Array α)} (h : 0 < L.flatten.size) :
|
||||
(L.findSome? fun l => l[0]?).isSome := by
|
||||
cases L using array₂_induction
|
||||
cases L using array_array_induction
|
||||
simp only [List.findSome?_toArray, List.findSome?_map, Function.comp_def, List.getElem?_toArray,
|
||||
List.findSome?_isSome_iff, isSome_getElem?]
|
||||
simp only [flatten_toArray_map_toArray, size_toArray, List.length_flatten,
|
||||
@@ -95,7 +95,7 @@ theorem getElem_zero_flatten {L : Array (Array α)} (h) :
|
||||
|
||||
theorem back?_flatten {L : Array (Array α)} :
|
||||
(flatten L).back? = (L.findSomeRev? fun l => l.back?) := by
|
||||
cases L using array₂_induction
|
||||
cases L using array_array_induction
|
||||
simp [List.getLast?_flatten, ← List.map_reverse, List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem findSome?_mkArray : findSome? f (mkArray n a) = if n = 0 then none else f a := by
|
||||
@@ -203,7 +203,7 @@ theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h ∈ xs := by
|
||||
|
||||
@[simp] theorem find?_flatten (xs : Array (Array α)) (p : α → Bool) :
|
||||
xs.flatten.find? p = xs.findSome? (·.find? p) := by
|
||||
cases xs using array₂_induction
|
||||
cases xs using array_array_induction
|
||||
simp [List.findSome?_map, Function.comp_def]
|
||||
|
||||
theorem find?_flatten_eq_none {xs : Array (Array α)} {p : α → Bool} :
|
||||
@@ -220,7 +220,7 @@ theorem find?_flatten_eq_some {xs : Array (Array α)} {p : α → Bool} {a : α}
|
||||
p a ∧ ∃ (as : Array (Array α)) (ys zs : Array α) (bs : Array (Array α)),
|
||||
xs = as.push (ys.push a ++ zs) ++ bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
cases xs using array₂_induction
|
||||
cases xs using array_array_induction
|
||||
simp only [flatten_toArray_map_toArray, List.find?_toArray, List.find?_flatten_eq_some]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@ Authors: Mario Carneiro, Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
import Init.Data.List.MapIdx
|
||||
|
||||
namespace Array
|
||||
@@ -13,84 +12,81 @@ namespace Array
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
|
||||
theorem mapFinIdx_induction (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β)
|
||||
theorem mapFinIdx_induction (as : Array α) (f : Fin as.size → α → β)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : (i : Nat) → β → (h : i < as.size) → Prop)
|
||||
(hs : ∀ i h, motive i → p i (f i as[i] h) h ∧ motive (i + 1)) :
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (Array.mapFinIdx as f).size = as.size,
|
||||
∀ i h, p i ((Array.mapFinIdx as f)[i]) h := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p i bs[i] h) (hm : motive j) :
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapFinIdx as f)[i]) := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ bs[i]) (hm : motive j) :
|
||||
let arr : Array β := Array.mapFinIdxM.map (m := Id) as f i j h bs
|
||||
motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p i arr[i] h := by
|
||||
motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i] := by
|
||||
induction i generalizing j bs with simp [mapFinIdxM.map]
|
||||
| zero =>
|
||||
have := (Nat.zero_add _).symm.trans h
|
||||
exact ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩
|
||||
| succ i ih =>
|
||||
apply @ih (bs.push (f j as[j] (by omega))) (j + 1) (by omega) (by simp; omega)
|
||||
apply @ih (bs.push (f ⟨j, by omega⟩ as[j])) (j + 1) (by omega) (by simp; omega)
|
||||
· intro i i_lt h'
|
||||
rw [getElem_push]
|
||||
split
|
||||
· apply h₂
|
||||
· simp only [size_push] at h'
|
||||
obtain rfl : i = j := by omega
|
||||
apply (hs i (by omega) hm).1
|
||||
· exact (hs j (by omega) hm).2
|
||||
apply (hs ⟨i, by omega⟩ hm).1
|
||||
· exact (hs ⟨j, by omega⟩ hm).2
|
||||
simp [mapFinIdx, mapFinIdxM]; exact go rfl nofun h0
|
||||
|
||||
theorem mapFinIdx_spec (as : Array α) (f : (i : Nat) → α → (h : i < as.size) → β)
|
||||
(p : (i : Nat) → β → (h : i < as.size) → Prop) (hs : ∀ i h, p i (f i as[i] h) h) :
|
||||
theorem mapFinIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (Array.mapFinIdx as f).size = as.size,
|
||||
∀ i h, p i ((Array.mapFinIdx as f)[i]) h :=
|
||||
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapFinIdx as f)[i]) :=
|
||||
(mapFinIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapFinIdx (a : Array α) (f : (i : Nat) → α → (h : i < a.size) → β) :
|
||||
(a.mapFinIdx f).size = a.size :=
|
||||
(mapFinIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
@[simp] theorem size_mapFinIdx (a : Array α) (f : Fin a.size → α → β) : (a.mapFinIdx f).size = a.size :=
|
||||
(mapFinIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem size_zipIdx (as : Array α) (k : Nat) : (as.zipIdx k).size = as.size :=
|
||||
@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size :=
|
||||
Array.size_mapFinIdx _ _
|
||||
|
||||
@[deprecated size_zipIdx (since := "2025-01-21")] abbrev size_zipWithIndex := @size_zipIdx
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : (i : Nat) → α → (h : i < a.size) → β) (i : Nat)
|
||||
@[simp] theorem getElem_mapFinIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat)
|
||||
(h : i < (mapFinIdx a f).size) :
|
||||
(a.mapFinIdx f)[i] = f i (a[i]'(by simp_all)) (by simp_all) :=
|
||||
(mapFinIdx_spec _ _ (fun i b h => b = f i a[i] h) fun _ _ => rfl).2 i _
|
||||
(a.mapFinIdx f)[i] = f ⟨i, by simp_all⟩ (a[i]'(by simp_all)) :=
|
||||
(mapFinIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : (i : Nat) → α → (h : i < a.size) → β) (i : Nat) :
|
||||
@[simp] theorem getElem?_mapFinIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat) :
|
||||
(a.mapFinIdx f)[i]? =
|
||||
a[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
|
||||
a[i]?.pbind fun b h => f ⟨i, (getElem?_eq_some_iff.1 h).1⟩ b := by
|
||||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem toList_mapFinIdx (a : Array α) (f : (i : Nat) → α → (h : i < a.size) → β) :
|
||||
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
|
||||
@[simp] theorem toList_mapFinIdx (a : Array α) (f : Fin a.size → α → β) :
|
||||
(a.mapFinIdx f).toList = a.toList.mapFinIdx (fun i a => f ⟨i, by simp⟩ a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
theorem mapIdx_induction (f : Nat → α → β) (as : Array α)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : (i : Nat) → β → (h : i < as.size) → Prop)
|
||||
(hs : ∀ i h, motive i → p i (f i as[i]) h ∧ motive (i + 1)) :
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p i ((as.mapIdx f)[i]) h :=
|
||||
mapFinIdx_induction as (fun i a _ => f i a) motive h0 p hs
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
mapFinIdx_induction as (fun i a => f i a) motive h0 p hs
|
||||
|
||||
theorem mapIdx_spec (f : Nat → α → β) (as : Array α)
|
||||
(p : (i : Nat) → β → (h : i < as.size) → Prop) (hs : ∀ i h, p i (f i as[i]) h) :
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (as.mapIdx f).size = as.size,
|
||||
∀ i h, p i ((as.mapIdx f)[i]) h :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ _ => ⟨hs .., trivial⟩).2
|
||||
∀ i h, p ⟨i, h⟩ ((as.mapIdx f)[i]) :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx (f : Nat → α → β) (as : Array α) : (as.mapIdx f).size = as.size :=
|
||||
(mapIdx_spec (p := fun _ _ _ => True) (hs := fun _ _ => trivial)).1
|
||||
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem getElem_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat)
|
||||
(h : i < (as.mapIdx f).size) :
|
||||
(as.mapIdx f)[i] = f i (as[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b h => b = f i as[i]) fun _ _ => rfl).2 i (by simp_all)
|
||||
(mapIdx_spec _ _ (fun i b => b = f i as[i]) fun _ => rfl).2 i (by simp_all)
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (f : Nat → α → β) (as : Array α) (i : Nat) :
|
||||
(as.mapIdx f)[i]? =
|
||||
@@ -105,7 +101,7 @@ end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp] theorem mapFinIdx_toArray (l : List α) (f : (i : Nat) → α → (h : i < l.length) → β) :
|
||||
@[simp] theorem mapFinIdx_toArray (l : List α) (f : Fin l.length → α → β) :
|
||||
l.toArray.mapFinIdx f = (l.mapFinIdx f).toArray := by
|
||||
ext <;> simp
|
||||
|
||||
@@ -114,323 +110,3 @@ namespace List
|
||||
ext <;> simp
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp] theorem getElem_zipIdx (a : Array α) (k : Nat) (i : Nat) (h : i < (a.zipIdx k).size) :
|
||||
(a.zipIdx k)[i] = (a[i]'(by simp_all), i + k) := by
|
||||
simp [zipIdx]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21")]
|
||||
abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
|
||||
@[simp] theorem zipIdx_toArray {l : List α} {k : Nat} :
|
||||
l.toArray.zipIdx k = (l.zipIdx k).toArray := by
|
||||
ext i hi₁ hi₂ <;> simp [Nat.add_comm]
|
||||
|
||||
@[deprecated zipIdx_toArray (since := "2025-01-21")]
|
||||
abbrev zipWithIndex_toArray := @zipIdx_toArray
|
||||
|
||||
@[simp] theorem toList_zipIdx (a : Array α) (k : Nat) :
|
||||
(a.zipIdx k).toList = a.toList.zipIdx k := by
|
||||
rcases a with ⟨a⟩
|
||||
simp
|
||||
|
||||
@[deprecated toList_zipIdx (since := "2025-01-21")]
|
||||
abbrev toList_zipWithIndex := @toList_zipIdx
|
||||
|
||||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {l : Array α} :
|
||||
(x, i) ∈ zipIdx l k ↔ k ≤ i ∧ l[i - k]? = some x := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {l : Array α} :
|
||||
(x, i) ∈ l.zipIdx ↔ l[i]? = x := by
|
||||
rw [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
simp
|
||||
|
||||
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : Array α} {k : Nat} :
|
||||
x ∈ zipIdx l k ↔ k ≤ x.2 ∧ l[x.2 - k]? = some x.1 := by
|
||||
cases x
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {l : Array α} :
|
||||
x ∈ l.zipIdx ↔ l[x.2]? = some x.1 := by
|
||||
rw [mk_mem_zipIdx_iff_getElem?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mk_mem_zipWithIndex_iff_getElem? := @mk_mem_zipIdx_iff_getElem?
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[congr] theorem mapFinIdx_congr {xs ys : Array α} (w : xs = ys)
|
||||
(f : (i : Nat) → α → (h : i < xs.size) → β) :
|
||||
mapFinIdx xs f = mapFinIdx ys (fun i a h => f i a (by simp [w]; omega)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_empty {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx #[] f = #[] :=
|
||||
rfl
|
||||
|
||||
theorem mapFinIdx_eq_ofFn {as : Array α} {f : (i : Nat) → α → (h : i < as.size) → β} :
|
||||
as.mapFinIdx f = Array.ofFn fun i : Fin as.size => f i as[i] i.2 := by
|
||||
cases as
|
||||
simp [List.mapFinIdx_eq_ofFn]
|
||||
|
||||
theorem mapFinIdx_append {K L : Array α} {f : (i : Nat) → α → (h : i < (K ++ L).size) → β} :
|
||||
(K ++ L).mapFinIdx f =
|
||||
K.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||||
L.mapFinIdx (fun i a h => f (i + K.size) a (by simp; omega)) := by
|
||||
cases K
|
||||
cases L
|
||||
simp [List.mapFinIdx_append]
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_push {l : Array α} {a : α} {f : (i : Nat) → α → (h : i < (l.push a).size) → β} :
|
||||
mapFinIdx (l.push a) f =
|
||||
(mapFinIdx l (fun i a h => f i a (by simp; omega))).push (f l.size a (by simp)) := by
|
||||
simp [← append_singleton, mapFinIdx_append]
|
||||
|
||||
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) → α → (h : i < 1) → β} :
|
||||
#[a].mapFinIdx f = #[f 0 a (by simp)] := by
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_zipIdx_map {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f = l.zipIdx.attach.map
|
||||
fun ⟨⟨x, i⟩, m⟩ =>
|
||||
f i x (by simp [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_empty_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f = #[] ↔ l = #[] := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_ne_empty_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f ≠ #[] ↔ l ≠ #[] := by
|
||||
simp
|
||||
|
||||
theorem exists_of_mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β}
|
||||
(h : b ∈ l.mapFinIdx f) : ∃ (i : Nat) (h : i < l.size), f i l[i] h = b := by
|
||||
rcases l with ⟨l⟩
|
||||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Nat) (h : i < l.size), f i l[i] h = b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f = l' ↔ ∃ h : l'.size = l.size, ∀ (i : Nat) (h : i < l.size), l'[i] = f i l[i] h := by
|
||||
rcases l with ⟨l⟩
|
||||
rcases l' with ⟨l'⟩
|
||||
simpa using List.mapFinIdx_eq_iff
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_singleton_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} {b : β} :
|
||||
l.mapFinIdx f = #[b] ↔ ∃ (a : α) (w : l = #[a]), f 0 a (by simp [w]) = b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_append_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} {l₁ l₂ : Array β} :
|
||||
l.mapFinIdx f = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : Array α) (l₂' : Array α) (w : l = l₁' ++ l₂'),
|
||||
l₁'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₁ ∧
|
||||
l₂'.mapFinIdx (fun i a h => f (i + l₁'.size) a (by simp [w]; omega)) = l₂ := by
|
||||
rcases l with ⟨l⟩
|
||||
rcases l₁ with ⟨l₁⟩
|
||||
rcases l₂ with ⟨l₂⟩
|
||||
simp only [List.mapFinIdx_toArray, List.append_toArray, mk.injEq, List.mapFinIdx_eq_append_iff,
|
||||
toArray_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||||
refine ⟨l₁.toArray, l₂.toArray, by simp_all⟩
|
||||
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
|
||||
simp [← toList_inj] at h₁ h₂
|
||||
obtain rfl := h₁
|
||||
obtain rfl := h₂
|
||||
refine ⟨l₁, l₂, by simp_all⟩
|
||||
|
||||
theorem mapFinIdx_eq_push_iff {l : Array α} {b : β} {f : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f = l₂.push b ↔
|
||||
∃ (l₁ : Array α) (a : α) (w : l = l₁.push a),
|
||||
l₁.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₂ ∧ b = f (l.size - 1) a (by simp [w]) := by
|
||||
rw [push_eq_append, mapFinIdx_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, h₂⟩
|
||||
simp only [mapFinIdx_eq_singleton_iff, Nat.zero_add] at h₂
|
||||
obtain ⟨a, rfl, rfl⟩ := h₂
|
||||
exact ⟨l₁, a, by simp⟩
|
||||
· rintro ⟨l₁, a, rfl, rfl, rfl⟩
|
||||
exact ⟨l₁, #[a], by simp⟩
|
||||
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : Array α} {f g : (i : Nat) → α → (h : i < l.size) → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Nat) (h : i < l.size), f i l[i] h = g i l[i] h := by
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : Array α}
|
||||
{f : (i : Nat) → α → (h : i < l.size) → β}
|
||||
{g : (i : Nat) → β → (h : i < (l.mapFinIdx f).size) → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa using h)) := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapFinIdx_eq_mkArray_iff {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} {b : β} :
|
||||
l.mapFinIdx f = mkArray l.size b ↔ ∀ (i : Nat) (h : i < l.size), f i l[i] h = b := by
|
||||
rcases l with ⟨l⟩
|
||||
rw [← toList_inj]
|
||||
simp [List.mapFinIdx_eq_replicate_iff]
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {l : Array α} {f : (i : Nat) → α → (h : i < l.reverse.size) → β} :
|
||||
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i a h => f (l.size - 1 - i) a (by simp; omega))).reverse := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapFinIdx_reverse]
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #[] = #[] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_mapIdx {l : Array α} {f : (i : Nat) → α → (h : i < l.size) → β} {g : Nat → α → β}
|
||||
(h : ∀ (i : Nat) (h : i < l.size), f i l[i] h = g i l[i]) :
|
||||
l.mapFinIdx f = l.mapIdx g := by
|
||||
simp_all [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mapFinIdx {l : Array α} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
|
||||
simp [mapFinIdx_eq_mapIdx]
|
||||
|
||||
theorem mapIdx_eq_zipIdx_map {l : Array α} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.zipIdx.map fun ⟨a, i⟩ => f i a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
theorem mapIdx_append {K L : Array α} :
|
||||
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.size) := by
|
||||
rcases K with ⟨K⟩
|
||||
rcases L with ⟨L⟩
|
||||
simp [List.mapIdx_append]
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_push {l : Array α} {a : α} :
|
||||
mapIdx f (l.push a) = (mapIdx f l).push (f l.size a) := by
|
||||
simp [← append_singleton, mapIdx_append]
|
||||
|
||||
theorem mapIdx_singleton {a : α} : mapIdx f #[a] = #[f 0 a] := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_eq_empty_iff {l : Array α} : mapIdx f l = #[] ↔ l = #[] := by
|
||||
rcases l with ⟨l⟩
|
||||
simp
|
||||
|
||||
theorem mapIdx_ne_empty_iff {l : Array α} :
|
||||
mapIdx f l ≠ #[] ↔ l ≠ #[] := by
|
||||
simp
|
||||
|
||||
theorem exists_of_mem_mapIdx {b : β} {l : Array α}
|
||||
(h : b ∈ mapIdx f l) : ∃ (i : Nat) (h : i < l.size), f i l[i] = b := by
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {l : Array α} :
|
||||
b ∈ mapIdx f l ↔ ∃ (i : Nat) (h : i < l.size), f i l[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
exact exists_of_mem_mapIdx h
|
||||
· rintro ⟨i, h, rfl⟩
|
||||
rw [mem_iff_getElem]
|
||||
exact ⟨i, by simpa using h, by simp⟩
|
||||
|
||||
theorem mapIdx_eq_push_iff {l : Array α} {b : β} :
|
||||
mapIdx f l = l₂.push b ↔
|
||||
∃ (a : α) (l₁ : Array α), l = l₁.push a ∧ mapIdx f l₁ = l₂ ∧ f l₁.size a = b := by
|
||||
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
|
||||
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
|
||||
constructor
|
||||
· rintro ⟨l₁, rfl, a, rfl, rfl⟩
|
||||
exact ⟨a, l₁, by simp⟩
|
||||
· rintro ⟨a, l₁, rfl, rfl, rfl⟩
|
||||
exact ⟨l₁, rfl, a, by simp⟩
|
||||
|
||||
@[simp] theorem mapIdx_eq_singleton_iff {l : Array α} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f l = #[b] ↔ ∃ (a : α), l = #[a] ∧ f 0 a = b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapIdx_eq_singleton_iff]
|
||||
|
||||
theorem mapIdx_eq_append_iff {l : Array α} {f : Nat → α → β} {l₁ l₂ : Array β} :
|
||||
mapIdx f l = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : Array α) (l₂' : Array α), l = l₁' ++ l₂' ∧
|
||||
l₁'.mapIdx f = l₁ ∧
|
||||
l₂'.mapIdx (fun i => f (i + l₁'.size)) = l₂ := by
|
||||
rcases l with ⟨l⟩
|
||||
rcases l₁ with ⟨l₁⟩
|
||||
rcases l₂ with ⟨l₂⟩
|
||||
simp only [List.mapIdx_toArray, List.append_toArray, mk.injEq, List.mapIdx_eq_append_iff,
|
||||
toArray_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||||
exact ⟨l₁.toArray, l₂.toArray, by simp⟩
|
||||
· rintro ⟨⟨l₁⟩, ⟨l₂⟩, rfl, h₁, h₂⟩
|
||||
simp only [List.mapIdx_toArray, mk.injEq, size_toArray] at h₁ h₂
|
||||
obtain rfl := h₁
|
||||
obtain rfl := h₂
|
||||
exact ⟨l₁, l₂, by simp⟩
|
||||
|
||||
theorem mapIdx_eq_iff {l : Array α} : mapIdx f l = l' ↔ ∀ i : Nat, l'[i]? = l[i]?.map (f i) := by
|
||||
rcases l with ⟨l⟩
|
||||
rcases l' with ⟨l'⟩
|
||||
simp [List.mapIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mapIdx_iff {l : Array α} :
|
||||
mapIdx f l = mapIdx g l ↔ ∀ i : Nat, (h : i < l.size) → f i l[i] = g i l[i] := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapIdx_eq_mapIdx_iff]
|
||||
|
||||
@[simp] theorem mapIdx_set {l : Array α} {i : Nat} {h : i < l.size} {a : α} :
|
||||
(l.set i a).mapIdx f = (l.mapIdx f).set i (f i a) (by simpa) := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapIdx_set]
|
||||
|
||||
@[simp] theorem mapIdx_setIfInBounds {l : Array α} {i : Nat} {a : α} :
|
||||
(l.setIfInBounds i a).mapIdx f = (l.mapIdx f).setIfInBounds i (f i a) := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapIdx_set]
|
||||
|
||||
@[simp] theorem back?_mapIdx {l : Array α} {f : Nat → α → β} :
|
||||
(mapIdx f l).back? = (l.back?).map (f (l.size - 1)) := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.getLast?_mapIdx]
|
||||
|
||||
@[simp] theorem mapIdx_mapIdx {l : Array α} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(l.mapIdx f).mapIdx g = l.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mkArray_iff {l : Array α} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f l = mkArray l.size b ↔ ∀ (i : Nat) (h : i < l.size), f i l[i] = b := by
|
||||
rcases l with ⟨l⟩
|
||||
rw [← toList_inj]
|
||||
simp [List.mapIdx_eq_replicate_iff]
|
||||
|
||||
@[simp] theorem mapIdx_reverse {l : Array α} {f : Nat → α → β} :
|
||||
l.reverse.mapIdx f = (mapIdx (fun i => f (l.size - 1 - i)) l).reverse := by
|
||||
rcases l with ⟨l⟩
|
||||
simp [List.mapIdx_reverse]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.OfFn
|
||||
|
||||
/-!
|
||||
# Theorems about `Array.ofFn`
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
|
||||
rw [← Array.toList_inj]
|
||||
simp
|
||||
|
||||
@[simp 500]
|
||||
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
obtain ⟨i, h, rfl⟩ := getElem_of_mem w
|
||||
exact ⟨⟨i, by simpa using h⟩, by simp⟩
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
end Array
|
||||
@@ -1,363 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.TakeDrop
|
||||
import Init.Data.List.Zip
|
||||
|
||||
/-!
|
||||
# Lemmas about `Array.zip`, `Array.zipWith`, `Array.zipWithAll`, and `Array.unzip`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ## Zippers -/
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
theorem zipWith_comm (f : α → β → γ) (la : Array α) (lb : Array β) :
|
||||
zipWith f la lb = zipWith (fun b a => f a b) lb la := by
|
||||
cases la
|
||||
cases lb
|
||||
simpa using List.zipWith_comm _ _ _
|
||||
|
||||
theorem zipWith_comm_of_comm (f : α → α → β) (comm : ∀ x y : α, f x y = f y x) (l l' : Array α) :
|
||||
zipWith f l l' = zipWith f l' l := by
|
||||
rw [zipWith_comm]
|
||||
simp only [comm]
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_self (f : α → α → δ) (l : Array α) : zipWith f l l = l.map fun a => f a a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
/--
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
using `Option.map` and `Option.bind` rather than a `match`.
|
||||
-/
|
||||
theorem getElem?_zipWith {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.getElem?_zipWith]
|
||||
rfl
|
||||
|
||||
/-- Variant of `getElem?_zipWith` using `Option.map` and `Option.bind` rather than a `match`. -/
|
||||
theorem getElem?_zipWith' {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f l₁ l₂)[i]? = (l₁[i]?.map f).bind fun g => l₂[i]?.map g := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.getElem?_zipWith']
|
||||
|
||||
theorem getElem?_zipWith_eq_some {f : α → β → γ} {l₁ : Array α} {l₂ : Array β} {z : γ} {i : Nat} :
|
||||
(zipWith f l₁ l₂)[i]? = some z ↔
|
||||
∃ x y, l₁[i]? = some x ∧ l₂[i]? = some y ∧ f x y = z := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.getElem?_zipWith_eq_some]
|
||||
|
||||
theorem getElem?_zip_eq_some {l₁ : Array α} {l₂ : Array β} {z : α × β} {i : Nat} :
|
||||
(zip l₁ l₂)[i]? = some z ↔ l₁[i]? = some z.1 ∧ l₂[i]? = some z.2 := by
|
||||
cases z
|
||||
rw [zip, getElem?_zipWith_eq_some]; constructor
|
||||
· rintro ⟨x, y, h₀, h₁, h₂⟩
|
||||
simpa [h₀, h₁] using h₂
|
||||
· rintro ⟨h₀, h₁⟩
|
||||
exact ⟨_, _, h₀, h₁, rfl⟩
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_map {μ} (f : γ → δ → μ) (g : α → γ) (h : β → δ) (l₁ : Array α) (l₂ : Array β) :
|
||||
zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWith_map]
|
||||
|
||||
theorem zipWith_map_left (l₁ : Array α) (l₂ : Array β) (f : α → α') (g : α' → β → γ) :
|
||||
zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWith_map_left]
|
||||
|
||||
theorem zipWith_map_right (l₁ : Array α) (l₂ : Array β) (f : β → β') (g : α → β' → γ) :
|
||||
zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWith_map_right]
|
||||
|
||||
theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} (i : δ):
|
||||
(zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWith_foldr_eq_zip_foldr]
|
||||
|
||||
theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} (i : δ):
|
||||
(zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWith_foldl_eq_zip_foldl]
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_eq_empty_iff {f : α → β → γ} {l l'} : zipWith f l l' = #[] ↔ l = #[] ∨ l' = #[] := by
|
||||
cases l <;> cases l' <;> simp
|
||||
|
||||
theorem map_zipWith {δ : Type _} (f : α → β) (g : γ → δ → α) (l : Array γ) (l' : Array δ) :
|
||||
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.map_zipWith]
|
||||
|
||||
theorem take_zipWith : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.take_zipWith]
|
||||
|
||||
theorem extract_zipWith : (zipWith f l l').extract m n = zipWith f (l.extract m n) (l'.extract m n) := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.drop_zipWith, List.take_zipWith]
|
||||
|
||||
theorem zipWith_append (f : α → β → γ) (l la : Array α) (l' lb : Array β)
|
||||
(h : l.size = l'.size) :
|
||||
zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by
|
||||
cases l
|
||||
cases l'
|
||||
cases la
|
||||
cases lb
|
||||
simp at h
|
||||
simp [List.zipWith_append, h]
|
||||
|
||||
theorem zipWith_eq_append_iff {f : α → β → γ} {l₁ : Array α} {l₂ : Array β} :
|
||||
zipWith f l₁ l₂ = l₁' ++ l₂' ↔
|
||||
∃ w x y z, w.size = y.size ∧ l₁ = w ++ x ∧ l₂ = y ++ z ∧ l₁' = zipWith f w y ∧ l₂' = zipWith f x z := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
cases l₁'
|
||||
cases l₂'
|
||||
simp only [List.zipWith_toArray, List.append_toArray, mk.injEq, List.zipWith_eq_append_iff,
|
||||
toArray_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨w, x, y, z, h, rfl, rfl, rfl, rfl⟩
|
||||
exact ⟨w.toArray, x.toArray, y.toArray, z.toArray, by simp [h]⟩
|
||||
· rintro ⟨⟨w⟩, ⟨x⟩, ⟨y⟩, ⟨z⟩, h, rfl, rfl, h₁, h₂⟩
|
||||
exact ⟨w, x, y, z, by simp_all⟩
|
||||
|
||||
@[simp] theorem zipWith_mkArray {a : α} {b : β} {m n : Nat} :
|
||||
zipWith f (mkArray m a) (mkArray n b) = mkArray (min m n) (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
theorem map_uncurry_zip_eq_zipWith (f : α → β → γ) (l : Array α) (l' : Array β) :
|
||||
map (Function.uncurry f) (l.zip l') = zipWith f l l' := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.map_uncurry_zip_eq_zipWith]
|
||||
|
||||
theorem map_zip_eq_zipWith (f : α × β → γ) (l : Array α) (l' : Array β) :
|
||||
map f (l.zip l') = zipWith (Function.curry f) l l' := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.map_zip_eq_zipWith]
|
||||
|
||||
theorem lt_size_left_of_zipWith {f : α → β → γ} {i : Nat} {l : Array α} {l' : Array β}
|
||||
(h : i < (zipWith f l l').size) : i < l.size := by rw [size_zipWith] at h; omega
|
||||
|
||||
theorem lt_size_right_of_zipWith {f : α → β → γ} {i : Nat} {l : Array α} {l' : Array β}
|
||||
(h : i < (zipWith f l l').size) : i < l'.size := by rw [size_zipWith] at h; omega
|
||||
|
||||
theorem zipWith_eq_zipWith_take_min (l₁ : Array α) (l₂ : Array β) :
|
||||
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
rw [List.zipWith_eq_zipWith_take_min]
|
||||
|
||||
theorem reverse_zipWith (h : l.size = l'.size) :
|
||||
(zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.reverse_zipWith (by simpa using h)]
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
theorem lt_size_left_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
|
||||
i < l.size :=
|
||||
lt_size_left_of_zipWith h
|
||||
|
||||
theorem lt_size_right_of_zip {i : Nat} {l : Array α} {l' : Array β} (h : i < (zip l l').size) :
|
||||
i < l'.size :=
|
||||
lt_size_right_of_zipWith h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_zip {l : Array α} {l' : Array β} {i : Nat} {h : i < (zip l l').size} :
|
||||
(zip l l')[i] =
|
||||
(l[i]'(lt_size_left_of_zip h), l'[i]'(lt_size_right_of_zip h)) :=
|
||||
getElem_zipWith (hi := by simpa using h)
|
||||
|
||||
theorem zip_eq_zipWith (l₁ : Array α) (l₂ : Array β) : zip l₁ l₂ = zipWith Prod.mk l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zip_eq_zipWith]
|
||||
|
||||
theorem zip_map (f : α → γ) (g : β → δ) (l₁ : Array α) (l₂ : Array β) :
|
||||
zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zip_map]
|
||||
|
||||
theorem zip_map_left (f : α → γ) (l₁ : Array α) (l₂ : Array β) :
|
||||
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
theorem zip_map_right (f : β → γ) (l₁ : Array α) (l₂ : Array β) :
|
||||
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
theorem zip_append {l₁ r₁ : Array α} {l₂ r₂ : Array β} (_h : l₁.size = l₂.size) :
|
||||
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
cases r₁
|
||||
cases r₂
|
||||
simp_all [List.zip_append]
|
||||
|
||||
theorem zip_map' (f : α → β) (g : α → γ) (l : Array α) :
|
||||
zip (l.map f) (l.map g) = l.map fun a => (f a, g a) := by
|
||||
cases l
|
||||
simp [List.zip_map']
|
||||
|
||||
theorem of_mem_zip {a b} {l₁ : Array α} {l₂ : Array β} : (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simpa using List.of_mem_zip
|
||||
|
||||
theorem map_fst_zip (l₁ : Array α) (l₂ : Array β) (h : l₁.size ≤ l₂.size) :
|
||||
map Prod.fst (zip l₁ l₂) = l₁ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all [List.map_fst_zip]
|
||||
|
||||
theorem map_snd_zip (l₁ : Array α) (l₂ : Array β) (h : l₂.size ≤ l₁.size) :
|
||||
map Prod.snd (zip l₁ l₂) = l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all [List.map_snd_zip]
|
||||
|
||||
theorem map_prod_left_eq_zip {l : Array α} (f : α → β) :
|
||||
(l.map fun x => (x, f x)) = l.zip (l.map f) := by
|
||||
rw [← zip_map']
|
||||
congr
|
||||
simp
|
||||
|
||||
theorem map_prod_right_eq_zip {l : Array α} (f : α → β) :
|
||||
(l.map fun x => (f x, x)) = (l.map f).zip l := by
|
||||
rw [← zip_map']
|
||||
congr
|
||||
simp
|
||||
|
||||
@[simp] theorem zip_eq_empty_iff {l₁ : Array α} {l₂ : Array β} :
|
||||
zip l₁ l₂ = #[] ↔ l₁ = #[] ∨ l₂ = #[] := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zip_eq_nil_iff]
|
||||
|
||||
theorem zip_eq_append_iff {l₁ : Array α} {l₂ : Array β} :
|
||||
zip l₁ l₂ = l₁' ++ l₂' ↔
|
||||
∃ w x y z, w.size = y.size ∧ l₁ = w ++ x ∧ l₂ = y ++ z ∧ l₁' = zip w y ∧ l₂' = zip x z := by
|
||||
simp [zip_eq_zipWith, zipWith_eq_append_iff]
|
||||
|
||||
@[simp] theorem zip_mkArray {a : α} {b : β} {m n : Nat} :
|
||||
zip (mkArray m a) (mkArray n b) = mkArray (min m n) (a, b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
theorem zip_eq_zip_take_min (l₁ : Array α) (l₂ : Array β) :
|
||||
zip l₁ l₂ = zip (l₁.take (min l₁.size l₂.size)) (l₂.take (min l₁.size l₂.size)) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp only [List.zip_toArray, size_toArray, List.take_toArray, mk.injEq]
|
||||
rw [List.zip_eq_zip_take_min]
|
||||
|
||||
|
||||
/-! ### zipWithAll -/
|
||||
|
||||
theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
(zipWithAll f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [List.getElem?_zipWithAll]
|
||||
rfl
|
||||
|
||||
theorem zipWithAll_map {μ} (f : Option γ → Option δ → μ) (g : α → γ) (h : β → δ) (l₁ : Array α) (l₂ : Array β) :
|
||||
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWithAll_map]
|
||||
|
||||
theorem zipWithAll_map_left (l₁ : Array α) (l₂ : Array β) (f : α → α') (g : Option α' → Option β → γ) :
|
||||
zipWithAll g (l₁.map f) l₂ = zipWithAll (fun a b => g (f <$> a) b) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWithAll_map_left]
|
||||
|
||||
theorem zipWithAll_map_right (l₁ : Array α) (l₂ : Array β) (f : β → β') (g : Option α → Option β' → γ) :
|
||||
zipWithAll g l₁ (l₂.map f) = zipWithAll (fun a b => g a (f <$> b)) l₁ l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [List.zipWithAll_map_right]
|
||||
|
||||
theorem map_zipWithAll {δ : Type _} (f : α → β) (g : Option γ → Option δ → α) (l : Array γ) (l' : Array δ) :
|
||||
map f (zipWithAll g l l') = zipWithAll (fun x y => f (g x y)) l l' := by
|
||||
cases l
|
||||
cases l'
|
||||
simp [List.map_zipWithAll]
|
||||
|
||||
|
||||
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
zipWithAll f (mkArray n a) (mkArray n b) = mkArray n (f a b) := by
|
||||
simp [← List.toArray_replicate]
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem unzip_eq_map (l : Array (α × β)) : unzip l = (l.map Prod.fst, l.map Prod.snd) := by
|
||||
cases l
|
||||
simp [List.unzip_eq_map]
|
||||
|
||||
theorem zip_unzip (l : Array (α × β)) : zip (unzip l).1 (unzip l).2 = l := by
|
||||
cases l
|
||||
simp only [List.unzip_toArray, Prod.map_fst, Prod.map_snd, List.zip_toArray, List.zip_unzip]
|
||||
|
||||
theorem unzip_zip_left {l₁ : Array α} {l₂ : Array β} (h : l₁.size ≤ l₂.size) :
|
||||
(unzip (zip l₁ l₂)).1 = l₁ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all only [size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_fst,
|
||||
List.unzip_zip_left]
|
||||
|
||||
theorem unzip_zip_right {l₁ : Array α} {l₂ : Array β} (h : l₂.size ≤ l₁.size) :
|
||||
(unzip (zip l₁ l₂)).2 = l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all only [size_toArray, List.zip_toArray, List.unzip_toArray, Prod.map_snd,
|
||||
List.unzip_zip_right]
|
||||
|
||||
theorem unzip_zip {l₁ : Array α} {l₂ : Array β} (h : l₁.size = l₂.size) :
|
||||
unzip (zip l₁ l₂) = (l₁, l₂) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all only [size_toArray, List.zip_toArray, List.unzip_toArray, List.unzip_zip, Prod.map_apply]
|
||||
|
||||
theorem zip_of_prod {l : Array α} {l' : Array β} {lp : Array (α × β)} (hl : lp.map Prod.fst = l)
|
||||
(hr : lp.map Prod.snd = l') : lp = l.zip l' := by
|
||||
rw [← hl, ← hr, ← zip_unzip lp, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem unzip_mkArray {n : Nat} {a : α} {b : β} :
|
||||
unzip (mkArray n (a, b)) = (mkArray n a, mkArray n b) := by
|
||||
ext1 <;> simp
|
||||
@@ -379,8 +379,7 @@ SMT-Lib name: `extract`.
|
||||
def extractLsb (hi lo : Nat) (x : BitVec n) : BitVec (hi - lo + 1) := extractLsb' lo _ x
|
||||
|
||||
/--
|
||||
A version of `setWidth` that requires a proof the new width is at least as large,
|
||||
and is a computational noop.
|
||||
A version of `setWidth` that requires a proof, but is a noop.
|
||||
-/
|
||||
def setWidth' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
||||
x.toNat#'(by
|
||||
@@ -670,11 +669,4 @@ def ofBoolListLE : (bs : List Bool) → BitVec bs.length
|
||||
| [] => 0#0
|
||||
| b :: bs => concat (ofBoolListLE bs) b
|
||||
|
||||
/- ### reverse -/
|
||||
|
||||
/-- Reverse the bits in a bitvector. -/
|
||||
def reverse : {w : Nat} → BitVec w → BitVec w
|
||||
| 0, x => x
|
||||
| w + 1, x => concat (reverse (x.truncate w)) (x.msb)
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -631,13 +631,6 @@ theorem getLsbD_mul (x y : BitVec w) (i : Nat) :
|
||||
· simp
|
||||
· omega
|
||||
|
||||
theorem getMsbD_mul (x y : BitVec w) (i : Nat) :
|
||||
(x * y).getMsbD i = (mulRec x y w).getMsbD i := by
|
||||
simp only [mulRec_eq_mul_signExtend_setWidth]
|
||||
rw [setWidth_setWidth_of_le]
|
||||
· simp
|
||||
· omega
|
||||
|
||||
theorem getElem_mul {x y : BitVec w} {i : Nat} (h : i < w) :
|
||||
(x * y)[i] = (mulRec x y w)[i] := by
|
||||
simp [mulRec_eq_mul_signExtend_setWidth]
|
||||
@@ -1091,21 +1084,6 @@ theorem divRec_succ' (m : Nat) (args : DivModArgs w) (qr : DivModState w) :
|
||||
divRec m args input := by
|
||||
simp [divRec_succ, divSubtractShift]
|
||||
|
||||
theorem getElem_udiv (n d : BitVec w) (hy : 0#w < d) (i : Nat) (hi : i < w) :
|
||||
(n / d)[i] = (divRec w {n, d} (DivModState.init w)).q[i] := by
|
||||
rw [udiv_eq_divRec (by assumption)]
|
||||
|
||||
theorem getLsbD_udiv (n d : BitVec w) (hy : 0#w < d) (i : Nat) :
|
||||
(n / d).getLsbD i = (decide (i < w) && (divRec w {n, d} (DivModState.init w)).q.getLsbD i) := by
|
||||
by_cases hi : i < w
|
||||
· simp [udiv_eq_divRec (by assumption)]
|
||||
omega
|
||||
· simp_all
|
||||
|
||||
theorem getMsbD_udiv (n d : BitVec w) (hd : 0#w < d) (i : Nat) :
|
||||
(n / d).getMsbD i = (decide (i < w) && (divRec w {n, d} (DivModState.init w)).q.getMsbD i) := by
|
||||
simp [getMsbD_eq_getLsbD, getLsbD_udiv, udiv_eq_divRec (by assumption)]
|
||||
|
||||
/- ### Arithmetic shift right (sshiftRight) recurrence -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -378,16 +378,6 @@ theorem getElem_ofBool {b : Bool} : (ofBool b)[0] = b := by simp
|
||||
@[simp] theorem msb_ofBool (b : Bool) : (ofBool b).msb = b := by
|
||||
cases b <;> simp [BitVec.msb]
|
||||
|
||||
@[simp] theorem one_eq_zero_iff : 1#w = 0#w ↔ w = 0 := by
|
||||
constructor
|
||||
· intro h
|
||||
cases w
|
||||
· rfl
|
||||
· replace h := congrArg BitVec.toNat h
|
||||
simp at h
|
||||
· rintro rfl
|
||||
simp
|
||||
|
||||
/-! ### msb -/
|
||||
|
||||
@[simp] theorem msb_zero : (0#w).msb = false := by simp [BitVec.msb, getMsbD]
|
||||
@@ -605,6 +595,12 @@ theorem zeroExtend_eq_setWidth {v : Nat} {x : BitVec w} :
|
||||
(x.setWidth v).toFin = Fin.ofNat' (2^v) x.toNat := by
|
||||
ext; simp
|
||||
|
||||
theorem setWidth'_eq {x : BitVec w} (h : w ≤ v) : x.setWidth' h = x.setWidth v := by
|
||||
apply eq_of_toNat_eq
|
||||
rw [toNat_setWidth, toNat_setWidth']
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
exact Nat.lt_of_lt_of_le x.isLt (Nat.pow_le_pow_right (Nat.zero_lt_two) h)
|
||||
|
||||
@[simp] theorem setWidth_eq (x : BitVec n) : setWidth n x = x := by
|
||||
apply eq_of_toNat_eq
|
||||
let ⟨x, lt_n⟩ := x
|
||||
@@ -659,10 +655,10 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
simp [getLsbD, toNat_setWidth']
|
||||
|
||||
@[simp] theorem getMsbD_setWidth' (ge : m ≥ n) (x : BitVec n) (i : Nat) :
|
||||
getMsbD (setWidth' ge x) i = (decide (m - n ≤ i) && getMsbD x (i + n - m)) := by
|
||||
getMsbD (setWidth' ge x) i = (decide (i ≥ m - n) && getMsbD x (i - (m - n))) := by
|
||||
simp only [getMsbD, getLsbD_setWidth', gt_iff_lt]
|
||||
by_cases h₁ : decide (i < m) <;> by_cases h₂ : decide (m - n ≤ i) <;> by_cases h₃ : decide (i + n - m < n) <;>
|
||||
by_cases h₄ : n - 1 - (i + n - m) = m - 1 - i
|
||||
by_cases h₁ : decide (i < m) <;> by_cases h₂ : decide (i ≥ m - n) <;> by_cases h₃ : decide (i - (m - n) < n) <;>
|
||||
by_cases h₄ : n - 1 - (i - (m - n)) = m - 1 - i
|
||||
all_goals
|
||||
simp only [h₁, h₂, h₃, h₄]
|
||||
simp_all only [ge_iff_le, decide_eq_true_eq, Nat.not_le, Nat.not_lt, Bool.true_and,
|
||||
@@ -675,7 +671,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
getLsbD (setWidth m x) i = (decide (i < m) && getLsbD x i) := by
|
||||
simp [getLsbD, toNat_setWidth, Nat.testBit_mod_two_pow]
|
||||
|
||||
@[simp] theorem getMsbD_setWidth {m : Nat} {x : BitVec n} {i : Nat} :
|
||||
theorem getMsbD_setWidth {m : Nat} {x : BitVec n} {i : Nat} :
|
||||
getMsbD (setWidth m x) i = (decide (m - n ≤ i) && getMsbD x (i + n - m)) := by
|
||||
unfold setWidth
|
||||
by_cases h : n ≤ m <;> simp only [h]
|
||||
@@ -689,15 +685,6 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
· simp [h']
|
||||
omega
|
||||
|
||||
-- This is a simp lemma as there is only a runtime difference between `setWidth'` and `setWidth`,
|
||||
-- and for verification purposes they are equivalent.
|
||||
@[simp]
|
||||
theorem setWidth'_eq {x : BitVec w} (h : w ≤ v) : x.setWidth' h = x.setWidth v := by
|
||||
apply eq_of_toNat_eq
|
||||
rw [toNat_setWidth, toNat_setWidth']
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
exact Nat.lt_of_lt_of_le x.isLt (Nat.pow_le_pow_right (Nat.zero_lt_two) h)
|
||||
|
||||
@[simp] theorem getMsbD_setWidth_add {x : BitVec w} (h : k ≤ i) :
|
||||
(x.setWidth (w + k)).getMsbD i = x.getMsbD (i - k) := by
|
||||
by_cases h : w = 0
|
||||
@@ -768,22 +755,6 @@ theorem setWidth_one {x : BitVec w} :
|
||||
rw [Nat.mod_mod_of_dvd]
|
||||
exact Nat.pow_dvd_pow_iff_le_right'.mpr h
|
||||
|
||||
/--
|
||||
Iterated `setWidth` agrees with the second `setWidth`
|
||||
except in the case the first `setWidth` is a non-trivial truncation,
|
||||
and the second `setWidth` is a non-trivial extension.
|
||||
-/
|
||||
-- Note that in the special cases `v = u` or `v = w`,
|
||||
-- `simp` can discharge the side condition itself.
|
||||
@[simp] theorem setWidth_setWidth {x : BitVec u} {w v : Nat} (h : ¬ (v < u ∧ v < w)) :
|
||||
setWidth w (setWidth v x) = setWidth w x := by
|
||||
ext
|
||||
simp_all only [getLsbD_setWidth, decide_true, Bool.true_and, Bool.and_iff_right_iff_imp,
|
||||
decide_eq_true_eq]
|
||||
intro h
|
||||
replace h := lt_of_getLsbD h
|
||||
omega
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp]
|
||||
@@ -934,16 +905,6 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ||| · ) (0#n) where
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem extractLsb'_or {x y : BitVec w} {start len : Nat} :
|
||||
(x ||| y).extractLsb' start len = (x.extractLsb' start len) ||| (y.extractLsb' start len) := by
|
||||
ext i hi
|
||||
simp [hi]
|
||||
|
||||
theorem extractLsb_or {x : BitVec w} {hi lo : Nat} :
|
||||
(x ||| y).extractLsb lo hi = (x.extractLsb lo hi) ||| (y.extractLsb lo hi) := by
|
||||
ext k hk
|
||||
simp [hk, show k ≤ lo - hi by omega]
|
||||
|
||||
/-! ### and -/
|
||||
|
||||
@[simp] theorem toNat_and (x y : BitVec v) :
|
||||
@@ -1017,16 +978,6 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· &&& · ) (allOnes n) wher
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
theorem extractLsb'_and {x y : BitVec w} {start len : Nat} :
|
||||
(x &&& y).extractLsb' start len = (x.extractLsb' start len) &&& (y.extractLsb' start len) := by
|
||||
ext i hi
|
||||
simp [hi]
|
||||
|
||||
theorem extractLsb_and {x : BitVec w} {hi lo : Nat} :
|
||||
(x &&& y).extractLsb lo hi = (x.extractLsb lo hi) &&& (y.extractLsb lo hi) := by
|
||||
ext k hk
|
||||
simp [hk, show k ≤ lo - hi by omega]
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@[simp] theorem toNat_xor (x y : BitVec v) :
|
||||
@@ -1092,16 +1043,6 @@ instance : Std.LawfulCommIdentity (α := BitVec n) (· ^^^ · ) (0#n) where
|
||||
ext i
|
||||
simp
|
||||
|
||||
theorem extractLsb'_xor {x y : BitVec w} {start len : Nat} :
|
||||
(x ^^^ y).extractLsb' start len = (x.extractLsb' start len) ^^^ (y.extractLsb' start len) := by
|
||||
ext i hi
|
||||
simp [hi]
|
||||
|
||||
theorem extractLsb_xor {x : BitVec w} {hi lo : Nat} :
|
||||
(x ^^^ y).extractLsb lo hi = (x.extractLsb lo hi) ^^^ (y.extractLsb lo hi) := by
|
||||
ext k hk
|
||||
simp [hk, show k ≤ lo - hi by omega]
|
||||
|
||||
/-! ### not -/
|
||||
|
||||
theorem not_def {x : BitVec v} : ~~~x = allOnes v ^^^ x := rfl
|
||||
@@ -1193,10 +1134,6 @@ theorem not_not {b : BitVec w} : ~~~(~~~b) = b := by
|
||||
ext i h
|
||||
simp [h]
|
||||
|
||||
@[simp] theorem and_not_self (x : BitVec n) : x &&& ~~~x = 0 := by
|
||||
ext i
|
||||
simp_all
|
||||
|
||||
theorem not_eq_comm {x y : BitVec w} : ~~~ x = y ↔ x = ~~~ y := by
|
||||
constructor
|
||||
· intro h
|
||||
@@ -1212,31 +1149,6 @@ theorem getMsb_not {x : BitVec w} :
|
||||
@[simp] theorem msb_not {x : BitVec w} : (~~~x).msb = (decide (0 < w) && !x.msb) := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
/--
|
||||
Negating `x` and then extracting [start..start+len) is the same as extracting and then negating,
|
||||
as long as the range [start..start+len) is in bounds.
|
||||
See that if the index is out-of-bounds, then `extractLsb` will return `false`,
|
||||
which makes the operation not commute.
|
||||
-/
|
||||
theorem extractLsb'_not_of_lt {x : BitVec w} {start len : Nat} (h : start + len < w) :
|
||||
(~~~ x).extractLsb' start len = ~~~ (x.extractLsb' start len) := by
|
||||
ext i hi
|
||||
simp [hi]
|
||||
omega
|
||||
|
||||
/--
|
||||
Negating `x` and then extracting [lo:hi] is the same as extracting and then negating.
|
||||
For the extraction to be well-behaved,
|
||||
we need the range [lo:hi] to be a valid closed interval inside the bitvector:
|
||||
1. `lo ≤ hi` for the interval to be a well-formed closed interval.
|
||||
2. `hi < w`, for the interval to be contained inside the bitvector.
|
||||
-/
|
||||
theorem extractLsb_not_of_lt {x : BitVec w} {hi lo : Nat} (hlo : lo ≤ hi) (hhi : hi < w) :
|
||||
(~~~ x).extractLsb hi lo = ~~~ (x.extractLsb hi lo) := by
|
||||
ext k hk
|
||||
simp [hk, show k ≤ hi - lo by omega]
|
||||
omega
|
||||
|
||||
/-! ### cast -/
|
||||
|
||||
@[simp] theorem not_cast {x : BitVec w} (h : w = w') : ~~~(x.cast h) = (~~~x).cast h := by
|
||||
@@ -1331,7 +1243,7 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
apply eq_of_toNat_eq
|
||||
rw [shiftLeftZeroExtend, setWidth]
|
||||
split
|
||||
· simp only [toNat_ofNatLt, toNat_shiftLeft, toNat_setWidth']
|
||||
· simp
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
rw [Nat.shiftLeft_eq, Nat.pow_add]
|
||||
exact Nat.mul_lt_mul_of_pos_right x.isLt (Nat.two_pow_pos _)
|
||||
@@ -1355,15 +1267,11 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
|
||||
@[simp] theorem getMsbD_shiftLeftZeroExtend (x : BitVec m) (n : Nat) :
|
||||
getMsbD (shiftLeftZeroExtend x n) i = getMsbD x i := by
|
||||
have : m + n - m ≤ i + n := by omega
|
||||
have : i + n + m - (m + n) = i := by omega
|
||||
simp_all [shiftLeftZeroExtend_eq]
|
||||
|
||||
@[simp] theorem msb_shiftLeftZeroExtend (x : BitVec w) (i : Nat) :
|
||||
(shiftLeftZeroExtend x i).msb = x.msb := by
|
||||
have : w + i - w ≤ i := by omega
|
||||
have : i + w - (w + i) = 0 := by omega
|
||||
simp_all [shiftLeftZeroExtend_eq, BitVec.msb]
|
||||
simp [shiftLeftZeroExtend_eq, BitVec.msb]
|
||||
|
||||
theorem shiftLeft_add {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
x <<< (n + m) = (x <<< n) <<< m := by
|
||||
@@ -1386,6 +1294,11 @@ theorem allOnes_shiftLeft_or_shiftLeft {x : BitVec w} {n : Nat} :
|
||||
BitVec.allOnes w <<< n ||| x <<< n = BitVec.allOnes w <<< n := by
|
||||
simp [← shiftLeft_or_distrib]
|
||||
|
||||
@[deprecated shiftLeft_add (since := "2024-06-02")]
|
||||
theorem shiftLeft_shiftLeft {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
(x <<< n) <<< m = x <<< (n + m) := by
|
||||
rw [shiftLeft_add]
|
||||
|
||||
/-! ### shiftLeft reductions from BitVec to Nat -/
|
||||
|
||||
@[simp]
|
||||
@@ -1405,20 +1318,8 @@ theorem getElem_shiftLeft' {x : BitVec w₁} {y : BitVec w₂} {i : Nat} (h : i
|
||||
(x <<< y)[i] = (!decide (i < y.toNat) && x.getLsbD (i - y.toNat)) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem shiftLeft_eq_zero {x : BitVec w} {n : Nat} (hn : w ≤ n) : x <<< n = 0#w := by
|
||||
ext i hi
|
||||
simp [hn, hi]
|
||||
omega
|
||||
|
||||
theorem shiftLeft_ofNat_eq {x : BitVec w} {k : Nat} : x <<< (BitVec.ofNat w k) = x <<< (k % 2^w) := rfl
|
||||
|
||||
/-! ### ushiftRight -/
|
||||
|
||||
@[simp] theorem ushiftRight_eq' (x : BitVec w₁) (y : BitVec w₂) :
|
||||
x >>> y = x >>> y.toNat := by rfl
|
||||
|
||||
theorem ushiftRight_ofNat_eq {x : BitVec w} {k : Nat} : x >>> (BitVec.ofNat w k) = x >>> (k % 2^w) := rfl
|
||||
|
||||
@[simp, bv_toNat] theorem toNat_ushiftRight (x : BitVec n) (i : Nat) :
|
||||
(x >>> i).toNat = x.toNat >>> i := rfl
|
||||
|
||||
@@ -1542,9 +1443,11 @@ theorem msb_ushiftRight {x : BitVec w} {n : Nat} :
|
||||
case succ nn ih =>
|
||||
simp [BitVec.ushiftRight_eq, getMsbD_ushiftRight, BitVec.msb, ih, show nn + 1 > 0 by omega]
|
||||
|
||||
/-! ### ushiftRight reductions from BitVec to Nat -/
|
||||
|
||||
@[simp]
|
||||
theorem ushiftRight_self (n : BitVec w) : n >>> n.toNat = 0#w := by
|
||||
simp [BitVec.toNat_eq, Nat.shiftRight_eq_div_pow, Nat.lt_two_pow_self, Nat.div_eq_of_lt]
|
||||
theorem ushiftRight_eq' (x : BitVec w₁) (y : BitVec w₂) :
|
||||
x >>> y = x >>> y.toNat := by rfl
|
||||
|
||||
/-! ### sshiftRight -/
|
||||
|
||||
@@ -1643,9 +1546,6 @@ theorem sshiftRight_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
<;> by_cases w ≤ i
|
||||
<;> simp [*]
|
||||
|
||||
|
||||
theorem sshiftRight'_ofNat_eq_sshiftRight {x : BitVec w} {k : Nat} : x.sshiftRight' (BitVec.ofNat w k) = x.sshiftRight (k % 2^w) := rfl
|
||||
|
||||
/-- The msb after arithmetic shifting right equals the original msb. -/
|
||||
@[simp]
|
||||
theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
||||
@@ -1926,9 +1826,8 @@ theorem getElem_append {x : BitVec n} {y : BitVec m} (h : i < n + m) :
|
||||
@[simp] theorem getMsbD_append {x : BitVec n} {y : BitVec m} :
|
||||
getMsbD (x ++ y) i = if n ≤ i then getMsbD y (i - n) else getMsbD x i := by
|
||||
simp only [append_def]
|
||||
have : i + m - (n + m) = i - n := by omega
|
||||
by_cases h : n ≤ i
|
||||
· simp_all
|
||||
· simp [h]
|
||||
· simp [h]
|
||||
|
||||
theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
@@ -2047,24 +1946,10 @@ theorem msb_shiftLeft {x : BitVec w} {n : Nat} :
|
||||
(x <<< n).msb = x.getMsbD n := by
|
||||
simp [BitVec.msb]
|
||||
|
||||
theorem ushiftRight_eq_extractLsb'_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
|
||||
x >>> n = ((0#n) ++ (x.extractLsb' n (w - n))).cast (by omega) := by
|
||||
ext i hi
|
||||
simp only [getLsbD_ushiftRight, getLsbD_cast, getLsbD_append, getLsbD_extractLsb', getLsbD_zero,
|
||||
Bool.if_false_right, Bool.and_self_left, Bool.iff_and_self, decide_eq_true_eq]
|
||||
intros h
|
||||
have := lt_of_getLsbD h
|
||||
omega
|
||||
|
||||
theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
|
||||
x <<< n = (x.extractLsb' 0 (w - n) ++ 0#n).cast (by omega) := by
|
||||
ext i hi
|
||||
simp only [getLsbD_shiftLeft, hi, decide_true, Bool.true_and, getLsbD_cast, getLsbD_append,
|
||||
getLsbD_zero, getLsbD_extractLsb', Nat.zero_add, Bool.if_false_left]
|
||||
by_cases hi' : i < n
|
||||
· simp [hi']
|
||||
· simp [hi']
|
||||
omega
|
||||
@[deprecated shiftRight_add (since := "2024-06-02")]
|
||||
theorem shiftRight_shiftRight {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
(x >>> n) >>> m = x >>> (n + m) := by
|
||||
rw [shiftRight_add]
|
||||
|
||||
/-! ### rev -/
|
||||
|
||||
@@ -2178,32 +2063,6 @@ theorem eq_msb_cons_setWidth (x : BitVec (w+1)) : x = (cons x.msb (x.setWidth w)
|
||||
ext i
|
||||
simp [cons]
|
||||
|
||||
|
||||
theorem cons_append (x : BitVec w₁) (y : BitVec w₂) (a : Bool) :
|
||||
(cons a x) ++ y = (cons a (x ++ y)).cast (by omega) := by
|
||||
apply eq_of_toNat_eq
|
||||
simp only [toNat_append, toNat_cons, toNat_cast]
|
||||
rw [Nat.shiftLeft_add, Nat.shiftLeft_or_distrib, Nat.or_assoc]
|
||||
|
||||
theorem cons_append_append (x : BitVec w₁) (y : BitVec w₂) (z : BitVec w₃) (a : Bool) :
|
||||
(cons a x) ++ y ++ z = (cons a (x ++ y ++ z)).cast (by omega) := by
|
||||
ext i h
|
||||
simp only [cons, getLsbD_append, getLsbD_cast, getLsbD_ofBool, cast_cast]
|
||||
by_cases h₀ : i < w₁ + w₂ + w₃
|
||||
· simp only [h₀, ↓reduceIte]
|
||||
by_cases h₁ : i < w₃
|
||||
· simp [h₁]
|
||||
· simp only [h₁, ↓reduceIte]
|
||||
by_cases h₂ : i - w₃ < w₂
|
||||
· simp [h₂]
|
||||
· simp [h₂]
|
||||
omega
|
||||
· simp only [show ¬i - w₃ - w₂ < w₁ by omega, ↓reduceIte, show i - w₃ - w₂ - w₁ = 0 by omega,
|
||||
decide_true, Bool.true_and, h₀, show i - (w₁ + w₂ + w₃) = 0 by omega]
|
||||
by_cases h₂ : i < w₃
|
||||
· simp [h₂]; omega
|
||||
· simp [h₂]; omega
|
||||
|
||||
/-! ### concat -/
|
||||
|
||||
@[simp] theorem toNat_concat (x : BitVec w) (b : Bool) :
|
||||
@@ -2741,40 +2600,6 @@ theorem not_lt_iff_le {x y : BitVec w} : (¬ x < y) ↔ y ≤ x := by
|
||||
constructor <;>
|
||||
(intro h; simp only [lt_def, Nat.not_lt, le_def] at h ⊢; omega)
|
||||
|
||||
@[simp]
|
||||
theorem not_lt_zero {x : BitVec w} : ¬x < 0#w := of_decide_eq_false rfl
|
||||
|
||||
@[simp]
|
||||
theorem le_zero_iff {x : BitVec w} : x ≤ 0#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro h
|
||||
have : x ≥ 0 := not_lt_iff_le.mp not_lt_zero
|
||||
exact Eq.symm (BitVec.le_antisymm this h)
|
||||
· simp_all
|
||||
|
||||
@[simp]
|
||||
theorem lt_one_iff {x : BitVec w} (h : 0 < w) : x < 1#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro h₂
|
||||
rw [lt_def, toNat_ofNat, ← Int.ofNat_lt, Int.ofNat_emod, Int.ofNat_one, Int.natCast_pow,
|
||||
Int.ofNat_two, @Int.emod_eq_of_lt 1 (2^w) (by omega) (by omega)] at h₂
|
||||
simp [toNat_eq, show x.toNat = 0 by omega]
|
||||
· simp_all
|
||||
|
||||
@[simp]
|
||||
theorem not_allOnes_lt {x : BitVec w} : ¬allOnes w < x := by
|
||||
have : 2^w ≠ 0 := Ne.symm (NeZero.ne' (2^w))
|
||||
rw [BitVec.not_lt, le_def, Nat.le_iff_lt_add_one, toNat_allOnes, Nat.sub_one_add_one this]
|
||||
exact isLt x
|
||||
|
||||
@[simp]
|
||||
theorem allOnes_le_iff {x : BitVec w} : allOnes w ≤ x ↔ x = allOnes w := by
|
||||
constructor
|
||||
· intro h
|
||||
have : x ≤ allOnes w := not_lt_iff_le.mp not_allOnes_lt
|
||||
exact Eq.symm (BitVec.le_antisymm h this)
|
||||
· simp_all
|
||||
|
||||
/-! ### udiv -/
|
||||
|
||||
theorem udiv_def {x y : BitVec n} : x / y = BitVec.ofNat n (x.toNat / y.toNat) := by
|
||||
@@ -3238,7 +3063,7 @@ theorem getMsbD_rotateLeft_of_lt {n w : Nat} {x : BitVec w} (hi : r < w):
|
||||
· simp only [h₁, decide_true, Bool.true_and]
|
||||
have h₂ : (r + n) < 2 * (w + 1) := by omega
|
||||
congr 1
|
||||
rw [← Nat.sub_mul_eq_mod_of_lt_of_le (n := 1) (by omega) (by omega)]
|
||||
rw [← Nat.sub_mul_eq_mod_of_lt_of_le (n := 1) (by omega) (by omega), Nat.mul_one]
|
||||
omega
|
||||
· simp [h₁]
|
||||
|
||||
@@ -3487,11 +3312,6 @@ theorem mul_twoPow_eq_shiftLeft (x : BitVec w) (i : Nat) :
|
||||
apply Nat.pow_dvd_pow 2 (by omega)
|
||||
simp [Nat.mul_mod, hpow]
|
||||
|
||||
theorem twoPow_mul_eq_shiftLeft (x : BitVec w) (i : Nat) :
|
||||
(twoPow w i) * x = x <<< i := by
|
||||
rw [BitVec.mul_comm, mul_twoPow_eq_shiftLeft]
|
||||
|
||||
|
||||
theorem twoPow_zero {w : Nat} : twoPow w 0 = 1#w := by
|
||||
apply eq_of_toNat_eq
|
||||
simp
|
||||
@@ -3501,12 +3321,6 @@ theorem shiftLeft_eq_mul_twoPow (x : BitVec w) (n : Nat) :
|
||||
ext i
|
||||
simp [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, mul_twoPow_eq_shiftLeft]
|
||||
|
||||
/-- 2^i * 2^j = 2^(i + j) with bitvectors as well -/
|
||||
theorem twoPow_mul_twoPow_eq {w : Nat} (i j : Nat) : twoPow w i * twoPow w j = twoPow w (i + j) := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
simp only [toNat_mul, toNat_twoPow]
|
||||
rw [← Nat.mul_mod, Nat.pow_add]
|
||||
|
||||
/--
|
||||
The unsigned division of `x` by `2^k` equals shifting `x` right by `k`,
|
||||
when `k` is less than the bitwidth `w`.
|
||||
@@ -3569,11 +3383,11 @@ theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||
ext (_ | i) h <;> simp [Bool.and_comm]
|
||||
|
||||
@[simp]
|
||||
theorem replicate_zero {x : BitVec w} : x.replicate 0 = 0#0 := by
|
||||
theorem replicate_zero_eq {x : BitVec w} : x.replicate 0 = 0#0 := by
|
||||
simp [replicate]
|
||||
|
||||
@[simp]
|
||||
theorem replicate_succ {x : BitVec w} :
|
||||
theorem replicate_succ_eq {x : BitVec w} :
|
||||
x.replicate (n + 1) =
|
||||
(x ++ replicate n x).cast (by rw [Nat.mul_succ]; omega) := by
|
||||
simp [replicate]
|
||||
@@ -3585,7 +3399,7 @@ theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
||||
induction n generalizing x
|
||||
case zero => simp
|
||||
case succ n ih =>
|
||||
simp only [replicate_succ, getLsbD_cast, getLsbD_append]
|
||||
simp only [replicate_succ_eq, getLsbD_cast, getLsbD_append]
|
||||
by_cases hi : i < w * (n + 1)
|
||||
· simp only [hi, decide_true, Bool.true_and]
|
||||
by_cases hi' : i < w * n
|
||||
@@ -3602,33 +3416,6 @@ theorem getElem_replicate {n w : Nat} (x : BitVec w) (h : i < w * n) :
|
||||
simp only [← getLsbD_eq_getElem, getLsbD_replicate]
|
||||
by_cases h' : w = 0 <;> simp [h'] <;> omega
|
||||
|
||||
theorem append_assoc {x₁ : BitVec w₁} {x₂ : BitVec w₂} {x₃ : BitVec w₃} :
|
||||
(x₁ ++ x₂) ++ x₃ = (x₁ ++ (x₂ ++ x₃)).cast (by omega) := by
|
||||
induction w₁ generalizing x₂ x₃
|
||||
case zero => simp
|
||||
case succ n ih =>
|
||||
specialize @ih (setWidth n x₁)
|
||||
rw [← cons_msb_setWidth x₁, cons_append_append, ih, cons_append]
|
||||
ext j h
|
||||
simp [getLsbD_cons, show n + w₂ + w₃ = n + (w₂ + w₃) by omega]
|
||||
|
||||
theorem replicate_append_self {x : BitVec w} :
|
||||
x ++ x.replicate n = (x.replicate n ++ x).cast (by omega) := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
rw [replicate_succ]
|
||||
conv => lhs; rw [ih]
|
||||
simp only [cast_cast, cast_eq]
|
||||
rw [← cast_append_left]
|
||||
· rw [append_assoc]; congr
|
||||
· rw [Nat.add_comm, Nat.mul_add, Nat.mul_one]; omega
|
||||
|
||||
theorem replicate_succ' {x : BitVec w} :
|
||||
x.replicate (n + 1) =
|
||||
(replicate n x ++ x).cast (by rw [Nat.mul_succ]) := by
|
||||
simp [replicate_append_self]
|
||||
|
||||
/-! ### intMin -/
|
||||
|
||||
/-- The bitvector of width `w` that has the smallest value when interpreted as an integer. -/
|
||||
@@ -3752,7 +3539,7 @@ theorem getLsbD_intMax (w : Nat) : (intMax w).getLsbD i = decide (i + 1 < w) :=
|
||||
|
||||
/-! ### Non-overflow theorems -/
|
||||
|
||||
/-- If `x.toNat + y.toNat < 2^w`, then the addition `(x + y)` does not overflow. -/
|
||||
/-- If `x.toNat * y.toNat < 2^w`, then the multiplication `(x * y)` does not overflow. -/
|
||||
theorem toNat_add_of_lt {w} {x y : BitVec w} (h : x.toNat + y.toNat < 2^w) :
|
||||
(x + y).toNat = x.toNat + y.toNat := by
|
||||
rw [BitVec.toNat_add, Nat.mod_eq_of_lt h]
|
||||
@@ -3914,57 +3701,6 @@ theorem toInt_abs_eq_natAbs_of_ne_intMin {x : BitVec w} (hx : x ≠ intMin w) :
|
||||
x.abs.toInt = x.toInt.natAbs := by
|
||||
simp [toInt_abs_eq_natAbs, hx]
|
||||
|
||||
/-! ### Reverse -/
|
||||
|
||||
theorem getLsbD_reverse {i : Nat} {x : BitVec w} :
|
||||
(x.reverse).getLsbD i = x.getMsbD i := by
|
||||
induction w generalizing i
|
||||
case zero => simp
|
||||
case succ n ih =>
|
||||
simp only [reverse, truncate_eq_setWidth, getLsbD_concat]
|
||||
rcases i with rfl | i
|
||||
· rfl
|
||||
· simp only [Nat.add_one_ne_zero, ↓reduceIte, Nat.add_one_sub_one, ih]
|
||||
rw [getMsbD_setWidth]
|
||||
simp only [show n - (n + 1) = 0 by omega, Nat.zero_le, decide_true, Bool.true_and]
|
||||
congr; omega
|
||||
|
||||
theorem getMsbD_reverse {i : Nat} {x : BitVec w} :
|
||||
(x.reverse).getMsbD i = x.getLsbD i := by
|
||||
simp only [getMsbD_eq_getLsbD, getLsbD_reverse]
|
||||
by_cases hi : i < w
|
||||
· simp only [hi, decide_true, show w - 1 - i < w by omega, Bool.true_and]
|
||||
congr; omega
|
||||
· simp [hi, show i ≥ w by omega]
|
||||
|
||||
theorem msb_reverse {x : BitVec w} :
|
||||
(x.reverse).msb = x.getLsbD 0 :=
|
||||
by rw [BitVec.msb, getMsbD_reverse]
|
||||
|
||||
theorem reverse_append {x : BitVec w} {y : BitVec v} :
|
||||
(x ++ y).reverse = (y.reverse ++ x.reverse).cast (by omega) := by
|
||||
ext i h
|
||||
simp only [getLsbD_append, getLsbD_reverse]
|
||||
by_cases hi : i < v
|
||||
· by_cases hw : w ≤ i
|
||||
· simp [getMsbD_append, getLsbD_cast, getLsbD_append, getLsbD_reverse, hw]
|
||||
· simp [getMsbD_append, getLsbD_cast, getLsbD_append, getLsbD_reverse, hw, show i < w by omega]
|
||||
· by_cases hw : w ≤ i
|
||||
· simp [getMsbD_append, getLsbD_cast, getLsbD_append, hw, show ¬ i < w by omega, getLsbD_reverse]
|
||||
· simp [getMsbD_append, getLsbD_cast, getLsbD_append, hw, show i < w by omega, getLsbD_reverse]
|
||||
|
||||
@[simp]
|
||||
theorem reverse_cast {w v : Nat} (h : w = v) (x : BitVec w) :
|
||||
(x.cast h).reverse = x.reverse.cast h := by
|
||||
subst h; simp
|
||||
|
||||
theorem reverse_replicate {n : Nat} {x : BitVec w} :
|
||||
(x.replicate n).reverse = (x.reverse).replicate n := by
|
||||
induction n with
|
||||
| zero => rfl
|
||||
| succ n ih =>
|
||||
conv => lhs; simp only [replicate_succ']
|
||||
simp [reverse_append, ih]
|
||||
|
||||
/-! ### Decidable quantifiers -/
|
||||
|
||||
@@ -4180,10 +3916,4 @@ abbrev shiftLeft_zero_eq := @shiftLeft_zero
|
||||
@[deprecated ushiftRight_zero (since := "2024-10-27")]
|
||||
abbrev ushiftRight_zero_eq := @ushiftRight_zero
|
||||
|
||||
@[deprecated replicate_zero (since := "2025-01-08")]
|
||||
abbrev replicate_zero_eq := @replicate_zero
|
||||
|
||||
@[deprecated replicate_succ (since := "2025-01-08")]
|
||||
abbrev replicate_succ_eq := @replicate_succ
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -620,12 +620,3 @@ but may be used locally.
|
||||
-/
|
||||
def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
coe r := fun a b => Eq (r a b) true
|
||||
|
||||
/-! ### subtypes -/
|
||||
|
||||
@[simp] theorem Subtype.beq_iff {α : Type u} [DecidableEq α] {p : α → Prop} {x y : {a : α // p a}} :
|
||||
(x == y) = (x.1 == y.1) := by
|
||||
cases x
|
||||
cases y
|
||||
rw [Bool.eq_iff_iff]
|
||||
simp [beq_iff_eq]
|
||||
|
||||
@@ -70,3 +70,5 @@ theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Siz
|
||||
rfl
|
||||
|
||||
end Char
|
||||
|
||||
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size
|
||||
|
||||
@@ -13,8 +13,6 @@ import Init.Omega
|
||||
|
||||
namespace Fin
|
||||
|
||||
@[simp] theorem ofNat'_zero (n : Nat) [NeZero n] : Fin.ofNat' n 0 = 0 := rfl
|
||||
|
||||
@[deprecated Fin.pos (since := "2024-11-11")]
|
||||
theorem size_pos (i : Fin n) : 0 < n := i.pos
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ theorem ofNat_fdiv : ∀ m n : Nat, ↑(m / n) = fdiv ↑m ↑n
|
||||
# `bmod` ("balanced" mod)
|
||||
|
||||
Balanced mod (and balanced div) are a division and modulus pair such
|
||||
that `b * (Int.bdiv a b) + Int.bmod a b = a` and `-b/2 ≤ Int.bmod a b <
|
||||
that `b * (Int.bdiv a b) + Int.bmod a b = a` and `b/2 ≤ Int.bmod a b <
|
||||
b/2` for all `a : Int` and `b > 0`.
|
||||
|
||||
This is used in Omega as well as signed bitvectors.
|
||||
@@ -266,26 +266,10 @@ This is used in Omega as well as signed bitvectors.
|
||||
/--
|
||||
Balanced modulus. This version of Integer modulus uses the
|
||||
balanced rounding convention, which guarantees that
|
||||
`-m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
|
||||
`m/2 ≤ bmod x m < m/2` for `m ≠ 0` and `bmod x m` is congruent
|
||||
to `x` modulo `m`.
|
||||
|
||||
If `m = 0`, then `bmod x m = x`.
|
||||
|
||||
Examples:
|
||||
```
|
||||
#eval (7 : Int).bdiv 0 -- 0
|
||||
#eval (0 : Int).bdiv 7 -- 0
|
||||
|
||||
#eval (12 : Int).bdiv 6 -- 2
|
||||
#eval (12 : Int).bdiv 7 -- 2
|
||||
#eval (12 : Int).bdiv 8 -- 2
|
||||
#eval (12 : Int).bdiv 9 -- 1
|
||||
|
||||
#eval (-12 : Int).bdiv 6 -- -2
|
||||
#eval (-12 : Int).bdiv 7 -- -2
|
||||
#eval (-12 : Int).bdiv 8 -- -1
|
||||
#eval (-12 : Int).bdiv 9 -- -1
|
||||
```
|
||||
-/
|
||||
def bmod (x : Int) (m : Nat) : Int :=
|
||||
let r := x % m
|
||||
@@ -297,22 +281,6 @@ def bmod (x : Int) (m : Nat) : Int :=
|
||||
/--
|
||||
Balanced division. This returns the unique integer so that
|
||||
`b * (Int.bdiv a b) + Int.bmod a b = a`.
|
||||
|
||||
Examples:
|
||||
```
|
||||
#eval (7 : Int).bmod 0 -- 7
|
||||
#eval (0 : Int).bmod 7 -- 0
|
||||
|
||||
#eval (12 : Int).bmod 6 -- 0
|
||||
#eval (12 : Int).bmod 7 -- -2
|
||||
#eval (12 : Int).bmod 8 -- -4
|
||||
#eval (12 : Int).bmod 9 -- 3
|
||||
|
||||
#eval (-12 : Int).bmod 6 -- 0
|
||||
#eval (-12 : Int).bmod 7 -- 2
|
||||
#eval (-12 : Int).bmod 8 -- -4
|
||||
#eval (-12 : Int).bmod 9 -- -3
|
||||
```
|
||||
-/
|
||||
def bdiv (x : Int) (m : Nat) : Int :=
|
||||
if m = 0 then
|
||||
|
||||
@@ -111,14 +111,6 @@ theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
rw [attach, attachWith, map_pmap]; exact pmap_congr_left l fun _ _ _ _ => rfl
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_attachWith {p q : α → Prop} (f : ∀ a, p a → q a) (l H) :
|
||||
pmap (fun a h => ⟨a, f a h⟩) l H = l.attachWith q (fun x h => f x (H x h)) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons a l ih =>
|
||||
simp [pmap, attachWith, ih]
|
||||
|
||||
theorem attach_map_coe (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 _ _ _ _
|
||||
@@ -144,23 +136,10 @@ theorem attachWith_map_subtype_val {p : α → Prop} (l : List α) (H : ∀ a
|
||||
@[simp]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
theorem mem_attachWith (l : List α) {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp [ih]
|
||||
constructor
|
||||
· rintro (_ | _) <;> simp_all
|
||||
· rintro (h | h)
|
||||
· simp [← h]
|
||||
· simp_all
|
||||
|
||||
@[simp]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
@@ -287,18 +266,6 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem pmap_attach (l : List α) {p : {x // x ∈ l} → Prop} (f : ∀ a, p a → β) (H) :
|
||||
pmap f l.attach H =
|
||||
l.pmap (P := fun a => ∃ h : a ∈ l, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem pmap_attachWith (l : List α) {p : {x // q x} → Prop} (f : ∀ a, p a → β) (H₁ H₂) :
|
||||
pmap f (l.attachWith q H₁) H₂ =
|
||||
l.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem head?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).head? = xs.attach.head?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
@@ -464,25 +431,7 @@ theorem attach_filter {l : List α} (p : α → Bool) :
|
||||
split <;> simp
|
||||
|
||||
-- We are still missing here `attachWith_filterMap` and `attachWith_filter`.
|
||||
|
||||
@[simp]
|
||||
theorem filterMap_attachWith {q : α → Prop} {l : List α} {f : {x // q x} → Option β} (H) :
|
||||
(l.attachWith q H).filterMap f = l.attach.filterMap (fun ⟨x, h⟩ => f ⟨x, H _ h⟩) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [attachWith_cons, filterMap_cons]
|
||||
split <;> simp_all [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
theorem filter_attachWith {q : α → Prop} {l : List α} {p : {x // q x} → Bool} (H) :
|
||||
(l.attachWith q H).filter p =
|
||||
(l.attach.filter (fun ⟨x, h⟩ => p ⟨x, H _ h⟩)).map (fun ⟨x, h⟩ => ⟨x, H _ h⟩) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [attachWith_cons, filter_cons]
|
||||
split <;> simp_all [Function.comp_def, filter_map]
|
||||
-- Also missing are `filterMap_attach`, `filter_attach`, `filterMap_attachWith` and `filter_attachWith`.
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
@@ -571,7 +520,7 @@ theorem reverse_attach (xs : List α) :
|
||||
|
||||
@[simp] theorem getLast?_attachWith {P : α → Prop} {xs : List α}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).getLast? = xs.getLast?.pbind (fun a h => some ⟨a, H _ (mem_of_getLast? h)⟩) := by
|
||||
(xs.attachWith P H).getLast? = xs.getLast?.pbind (fun a h => some ⟨a, H _ (mem_of_getLast?_eq_some h)⟩) := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attachWith, head?_attachWith]
|
||||
simp
|
||||
|
||||
@@ -582,7 +531,7 @@ theorem reverse_attach (xs : List α) :
|
||||
|
||||
@[simp]
|
||||
theorem getLast?_attach {xs : List α} :
|
||||
xs.attach.getLast? = xs.getLast?.pbind fun a h => some ⟨a, mem_of_getLast? h⟩ := by
|
||||
xs.attach.getLast? = xs.getLast?.pbind fun a h => some ⟨a, mem_of_getLast?_eq_some h⟩ := by
|
||||
rw [getLast?_eq_head?_reverse, reverse_attach, head?_map, head?_attach]
|
||||
simp
|
||||
|
||||
@@ -611,11 +560,6 @@ theorem count_attachWith [DecidableEq α] {p : α → Prop} (l : List α) (H :
|
||||
(l.attachWith p H).count a = l.count ↑a :=
|
||||
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attachWith _ _ _
|
||||
|
||||
@[simp] theorem countP_pmap {p : α → Prop} (g : ∀ a, p a → β) (f : β → Bool) (l : List α) (H₁) :
|
||||
(l.pmap g H₁).countP f =
|
||||
l.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
simp [pmap_eq_map_attach, countP_map, Function.comp_def]
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`List.unattach` is the (one-sided) inverse of `List.attach`. It is a synonym for `List.map Subtype.val`.
|
||||
@@ -634,7 +578,7 @@ and is ideally subsequently simplified away by `unattach_attach`.
|
||||
|
||||
If not, usually the right approach is `simp [List.unattach, -List.map_subtype]` to unfold.
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) : List α := l.map (·.val)
|
||||
def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) := l.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : ([] : List { x // p x }).unattach = [] := rfl
|
||||
@[simp] theorem unattach_cons {p : α → Prop} {a : { x // p x }} {l : List { x // p x }} :
|
||||
|
||||
@@ -43,7 +43,7 @@ The operations are organized as follow:
|
||||
`countP`, `count`, and `lookup`.
|
||||
* Logic: `any`, `all`, `or`, and `and`.
|
||||
* Zippers: `zipWith`, `zip`, `zipWithAll`, and `unzip`.
|
||||
* Ranges and enumeration: `range`, `zipIdx`.
|
||||
* Ranges and enumeration: `range`, `iota`, `enumFrom`, and `enum`.
|
||||
* Minima and maxima: `min?` and `max?`.
|
||||
* Other functions: `intersperse`, `intercalate`, `eraseDups`, `eraseReps`, `span`, `splitBy`,
|
||||
`removeAll`
|
||||
@@ -74,7 +74,7 @@ namespace List
|
||||
@[simp] theorem length_nil : length ([] : List α) = 0 :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_singleton (a : α) : length [a] = 1 := rfl
|
||||
@[simp 1100] theorem length_singleton (a : α) : length [a] = 1 := rfl
|
||||
|
||||
@[simp] theorem length_cons {α} (a : α) (as : List α) : (cons a as).length = as.length + 1 :=
|
||||
rfl
|
||||
@@ -258,6 +258,9 @@ theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n)
|
||||
have h0 : some a = some a' := h 0
|
||||
injection h0 with aa; simp only [aa, ext_get? fun n => h (n+1)]
|
||||
|
||||
/-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
|
||||
@[deprecated ext_get? (since := "2024-06-07")] abbrev ext := @ext_get?
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
/--
|
||||
@@ -352,8 +355,8 @@ def headD : (as : List α) → (fallback : α) → α
|
||||
| [], fallback => fallback
|
||||
| a::_, _ => a
|
||||
|
||||
@[simp] theorem headD_nil : @headD α [] d = d := rfl
|
||||
@[simp] theorem headD_cons : @headD α (a::l) d = a := rfl
|
||||
@[simp 1100] theorem headD_nil : @headD α [] d = d := rfl
|
||||
@[simp 1100] theorem headD_cons : @headD α (a::l) d = a := rfl
|
||||
|
||||
/-! ### tail -/
|
||||
|
||||
@@ -393,8 +396,8 @@ def tailD (list fallback : List α) : List α :=
|
||||
| [] => fallback
|
||||
| _ :: tl => tl
|
||||
|
||||
@[simp] theorem tailD_nil : @tailD α [] l' = l' := rfl
|
||||
@[simp] theorem tailD_cons : @tailD α (a::l) l' = l := rfl
|
||||
@[simp 1100] theorem tailD_nil : @tailD α [] l' = l' := rfl
|
||||
@[simp 1100] theorem tailD_cons : @tailD α (a::l) l' = l := rfl
|
||||
|
||||
/-! ## Basic `List` operations.
|
||||
|
||||
@@ -603,11 +606,11 @@ set_option linter.missingDocs false in
|
||||
to get a list of lists, and then concatenates them all together.
|
||||
* `[2, 3, 2].bind range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (a : List α) : List β := flatten (map b a)
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (a : List α) (b : α → List β) : List β := flatten (map b a)
|
||||
|
||||
@[simp] theorem flatMap_nil (f : α → List β) : List.flatMap f [] = [] := by simp [flatten, List.flatMap]
|
||||
@[simp] theorem flatMap_nil (f : α → List β) : List.flatMap [] f = [] := by simp [flatten, List.flatMap]
|
||||
@[simp] theorem flatMap_cons x xs (f : α → List β) :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [flatten, List.flatMap]
|
||||
List.flatMap (x :: xs) f = f x ++ List.flatMap xs f := by simp [flatten, List.flatMap]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated flatMap (since := "2024-10-16")] abbrev bind := @flatMap
|
||||
@@ -616,6 +619,11 @@ set_option linter.missingDocs false in
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated flatMap_cons (since := "2024-10-16")] abbrev cons_flatMap := @flatMap_cons
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated flatMap_nil (since := "2024-06-15")] abbrev nil_bind := @flatMap_nil
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated flatMap_cons (since := "2024-06-15")] abbrev cons_bind := @flatMap_cons
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
/--
|
||||
@@ -705,6 +713,11 @@ def elem [BEq α] (a : α) : List α → Bool
|
||||
theorem elem_cons [BEq α] {a : α} :
|
||||
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
|
||||
|
||||
/-- `notElem a l` is `!(elem a l)`. -/
|
||||
@[deprecated "Use `!(elem a l)` instead."(since := "2024-06-15")]
|
||||
def notElem [BEq α] (a : α) (as : List α) : Bool :=
|
||||
!(as.elem a)
|
||||
|
||||
/-! ### contains -/
|
||||
|
||||
@[inherit_doc elem] abbrev contains [BEq α] (as : List α) (a : α) : Bool :=
|
||||
@@ -1520,61 +1533,35 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
|
||||
`O(n)`. `iota n` is the numbers from `1` to `n` inclusive, in decreasing order.
|
||||
* `iota 5 = [5, 4, 3, 2, 1]`
|
||||
-/
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iota : Nat → List Nat
|
||||
| 0 => []
|
||||
| m@(n+1) => m :: iota n
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_zero : iota 0 = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[simp] theorem iota_succ : iota (i+1) = (i+1) :: iota i := rfl
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `zipIdx l` zips a list with its indices, optionally starting from a given index.
|
||||
* `zipIdx [a, b, c] = [(a, 0), (b, 1), (c, 2)]`
|
||||
* `zipIdx [a, b, c] 5 = [(a, 5), (b, 6), (c, 7)]`
|
||||
-/
|
||||
def zipIdx : List α → (n : Nat := 0) → List (α × Nat)
|
||||
| [], _ => nil
|
||||
| x :: xs, n => (x, n) :: zipIdx xs (n + 1)
|
||||
|
||||
@[simp] theorem zipIdx_nil : ([] : List α).zipIdx i = [] := rfl
|
||||
@[simp] theorem zipIdx_cons : (a::as).zipIdx i = (a, i) :: as.zipIdx (i+1) := rfl
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/--
|
||||
`O(|l|)`. `enumFrom n l` is like `enum` but it allows you to specify the initial index.
|
||||
* `enumFrom 5 [a, b, c] = [(5, a), (6, b), (7, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enumFrom : Nat → List α → List (Nat × α)
|
||||
| _, [] => nil
|
||||
| n, x :: xs => (n, x) :: enumFrom (n + 1) xs
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_nil : ([] : List α).enumFrom i = [] := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons : (a::as).enumFrom i = (i, a) :: as.enumFrom (i+1) := rfl
|
||||
@[simp] theorem enumFrom_nil : ([] : List α).enumFrom i = [] := rfl
|
||||
@[simp] theorem enumFrom_cons : (a::as).enumFrom i = (i, a) :: as.enumFrom (i+1) := rfl
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
set_option linter.deprecated false in
|
||||
/--
|
||||
`O(|l|)`. `enum l` pairs up each element with its index in the list.
|
||||
* `enum [a, b, c] = [(0, a), (1, b), (2, c)]`
|
||||
-/
|
||||
@[deprecated "Use `zipIdx` instead; note the signature change." (since := "2025-01-21")]
|
||||
def enum : List α → List (Nat × α) := enumFrom 0
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_nil (since := "2025-01-21"), simp]
|
||||
theorem enum_nil : ([] : List α).enum = [] := rfl
|
||||
@[simp] theorem enum_nil : ([] : List α).enum = [] := rfl
|
||||
|
||||
/-! ## Minima and maxima -/
|
||||
|
||||
@@ -1874,14 +1861,12 @@ def unzipTR (l : List (α × β)) : List α × List β :=
|
||||
/-! ### iota -/
|
||||
|
||||
/-- Tail-recursive version of `List.iota`. -/
|
||||
@[deprecated "Use `List.range' 1 n` instead of `iota n`." (since := "2025-01-20")]
|
||||
def iotaTR (n : Nat) : List Nat :=
|
||||
let rec go : Nat → List Nat → List Nat
|
||||
| 0, r => r.reverse
|
||||
| m@(n+1), r => go n (m::r)
|
||||
go n []
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[csimp]
|
||||
theorem iota_eq_iotaTR : @iota = @iotaTR :=
|
||||
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by
|
||||
|
||||
@@ -254,7 +254,6 @@ theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] (p : α → m Bool) (as :
|
||||
| [], b, _ => pure b
|
||||
| a::as', b, h => do
|
||||
have : a ∈ as := by
|
||||
clear f
|
||||
have ⟨bs, h⟩ := h
|
||||
subst h
|
||||
exact mem_append_right _ (Mem.head ..)
|
||||
|
||||
@@ -40,7 +40,7 @@ protected theorem countP_go_eq_add (l) : countP.go p l n = n + countP.go p l 0 :
|
||||
theorem countP_cons (a : α) (l) : countP p (a :: l) = countP p l + if p a then 1 else 0 := by
|
||||
by_cases h : p a <;> simp [h]
|
||||
|
||||
@[simp] theorem countP_singleton (a : α) : countP p [a] = if p a then 1 else 0 := by
|
||||
theorem countP_singleton (a : α) : countP p [a] = if p a then 1 else 0 := by
|
||||
simp [countP_cons]
|
||||
|
||||
theorem length_eq_countP_add_countP (l) : length l = countP p l + countP (fun a => ¬p a) l := by
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, M
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Pairwise
|
||||
import Init.Data.List.Find
|
||||
|
||||
/-!
|
||||
# Lemmas about `List.eraseP` and `List.erase`.
|
||||
@@ -271,20 +270,6 @@ theorem head_eraseP_mem (xs : List α) (p : α → Bool) (h) : (xs.eraseP p).hea
|
||||
theorem getLast_eraseP_mem (xs : List α) (p : α → Bool) (h) : (xs.eraseP p).getLast h ∈ xs :=
|
||||
(eraseP_sublist xs).getLast_mem h
|
||||
|
||||
theorem eraseP_eq_eraseIdx {xs : List α} {p : α → Bool} :
|
||||
xs.eraseP p = match xs.findIdx? p with
|
||||
| none => xs
|
||||
| some i => xs.eraseIdx i := by
|
||||
induction xs with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
rw [eraseP_cons, findIdx?_cons]
|
||||
by_cases h : p x
|
||||
· simp [h]
|
||||
· simp only [h]
|
||||
rw [ih]
|
||||
split <;> simp [*]
|
||||
|
||||
/-! ### erase -/
|
||||
section erase
|
||||
variable [BEq α]
|
||||
@@ -471,19 +456,6 @@ theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs
|
||||
theorem getLast_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).getLast h ∈ xs :=
|
||||
(erase_sublist a xs).getLast_mem h
|
||||
|
||||
theorem erase_eq_eraseIdx [LawfulBEq α] (l : List α) (a : α) :
|
||||
l.erase a = match l.indexOf? a with
|
||||
| none => l
|
||||
| some i => l.eraseIdx i := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
rw [erase_cons, indexOf?_cons]
|
||||
split
|
||||
· simp
|
||||
· simp [ih]
|
||||
split <;> simp [*]
|
||||
|
||||
end erase
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
@@ -600,20 +572,4 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
|
||||
-- `Init/Data/List/Nat/Basic.lean`.
|
||||
|
||||
theorem erase_eq_eraseIdx_of_indexOf [BEq α] [LawfulBEq α]
|
||||
(l : List α) (a : α) (i : Nat) (w : l.indexOf a = i) :
|
||||
l.erase a = l.eraseIdx i := by
|
||||
subst w
|
||||
rw [erase_eq_iff]
|
||||
by_cases h : a ∈ l
|
||||
· right
|
||||
obtain ⟨as, bs, rfl, h'⟩ := eq_append_cons_of_mem h
|
||||
refine ⟨as, bs, h', by simp, ?_⟩
|
||||
rw [indexOf_append, if_neg h', indexOf_cons_self, eraseIdx_append_of_length_le] <;>
|
||||
simp
|
||||
· left
|
||||
refine ⟨h, ?_⟩
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (indexOf_eq_length h).symm
|
||||
|
||||
end List
|
||||
|
||||
@@ -822,28 +822,28 @@ theorem findIdx?_flatten {l : List (List α)} {p : α → Bool} :
|
||||
simp only [replicate, findIdx?_cons, Nat.zero_add, findIdx?_succ, zero_lt_succ, true_and]
|
||||
split <;> simp_all
|
||||
|
||||
theorem findIdx?_eq_findSome?_zipIdx {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = xs.zipIdx.findSome? fun ⟨a, i⟩ => if p a then some i else none := by
|
||||
theorem findIdx?_eq_findSome?_enum {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = xs.enum.findSome? fun ⟨i, a⟩ => if p a then some i else none := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, zipIdx]
|
||||
simp only [findIdx?_cons, Nat.zero_add, findIdx?_succ, enum]
|
||||
split
|
||||
· simp_all
|
||||
· simp_all only [zipIdx_cons, ite_false, Option.isNone_none, findSome?_cons_of_isNone, reduceCtorEq]
|
||||
rw [← map_snd_add_zipIdx_eq_zipIdx (n := 1) (k := 0)]
|
||||
simp [Function.comp_def, findSome?_map]
|
||||
· simp_all only [enumFrom_cons, ite_false, Option.isNone_none, findSome?_cons_of_isNone, reduceCtorEq]
|
||||
simp [Function.comp_def, ← map_fst_add_enum_eq_enumFrom, findSome?_map]
|
||||
|
||||
theorem findIdx?_eq_fst_find?_zipIdx {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = (xs.zipIdx.find? fun ⟨x, _⟩ => p x).map (·.2) := by
|
||||
theorem findIdx?_eq_fst_find?_enum {xs : List α} {p : α → Bool} :
|
||||
xs.findIdx? p = (xs.enum.find? fun ⟨_, x⟩ => p x).map (·.1) := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [findIdx?_cons, Nat.zero_add, findIdx?_start_succ, zipIdx_cons]
|
||||
simp only [findIdx?_cons, Nat.zero_add, findIdx?_start_succ, enum_cons]
|
||||
split
|
||||
· simp_all
|
||||
· rw [ih, ← map_snd_add_zipIdx_eq_zipIdx (n := 1) (k := 0)]
|
||||
simp [Function.comp_def, *]
|
||||
· simp only [Option.map_map, enumFrom_eq_map_enum, Bool.false_eq_true, not_false_eq_true,
|
||||
find?_cons_of_neg, find?_map, *]
|
||||
congr
|
||||
|
||||
-- See also `findIdx_le_findIdx`.
|
||||
theorem findIdx?_eq_none_of_findIdx?_eq_none {xs : List α} {p q : α → Bool} (w : ∀ x ∈ xs, p x → q x) :
|
||||
@@ -884,74 +884,14 @@ theorem IsInfix.findIdx?_eq_none {l₁ l₂ : List α} {p : α → Bool} (h : l
|
||||
List.findIdx? p l₂ = none → List.findIdx? p l₁ = none :=
|
||||
h.sublist.findIdx?_eq_none
|
||||
|
||||
/-! ### indexOf
|
||||
|
||||
The verification API for `indexOf` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx` (and proved using them).
|
||||
-/
|
||||
/-! ### indexOf -/
|
||||
|
||||
theorem indexOf_cons [BEq α] :
|
||||
(x :: xs : List α).indexOf y = bif x == y then 0 else xs.indexOf y + 1 := by
|
||||
dsimp [indexOf]
|
||||
simp [findIdx_cons]
|
||||
|
||||
@[simp] theorem indexOf_cons_self [BEq α] [ReflBEq α] {l : List α} : (a :: l).indexOf a = 0 := by
|
||||
simp [indexOf_cons]
|
||||
|
||||
theorem indexOf_append [BEq α] [LawfulBEq α] {l₁ l₂ : List α} {a : α} :
|
||||
(l₁ ++ l₂).indexOf a = if a ∈ l₁ then l₁.indexOf a else l₂.indexOf a + l₁.length := by
|
||||
rw [indexOf, findIdx_append]
|
||||
split <;> rename_i h
|
||||
· rw [if_pos]
|
||||
simpa using h
|
||||
· rw [if_neg]
|
||||
simpa using h
|
||||
|
||||
theorem indexOf_eq_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∉ l) : l.indexOf a = l.length := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [mem_cons, not_or] at h
|
||||
simp only [indexOf_cons, cond_eq_if, beq_iff_eq]
|
||||
split <;> simp_all
|
||||
|
||||
theorem indexOf_lt_length [BEq α] [LawfulBEq α] {l : List α} (h : a ∈ l) : l.indexOf a < l.length := by
|
||||
induction l with
|
||||
| nil => simp at h
|
||||
| cons x xs ih =>
|
||||
simp only [mem_cons] at h
|
||||
obtain rfl | h := h
|
||||
· simp
|
||||
· simp only [indexOf_cons, cond_eq_if, beq_iff_eq, length_cons]
|
||||
specialize ih h
|
||||
split
|
||||
· exact zero_lt_succ xs.length
|
||||
· exact Nat.add_lt_add_right ih 1
|
||||
|
||||
/-! ### indexOf?
|
||||
|
||||
The verification API for `indexOf?` is still incomplete.
|
||||
The lemmas below should be made consistent with those for `findIdx?` (and proved using them).
|
||||
-/
|
||||
|
||||
@[simp] theorem indexOf?_nil [BEq α] [LawfulBEq α] : ([] : List α).indexOf? a = none := rfl
|
||||
|
||||
theorem indexOf?_cons [BEq α] [LawfulBEq α] (a : α) (xs : List α) (b : α) :
|
||||
(a :: xs).indexOf? b = if a == b then some 0 else (xs.indexOf? b).map (· + 1) := by
|
||||
simp [indexOf?]
|
||||
|
||||
@[simp] theorem indexOf?_eq_none_iff [BEq α] [LawfulBEq α] {l : List α} {a : α} :
|
||||
l.indexOf? a = none ↔ a ∉ l := by
|
||||
simp only [indexOf?, findIdx?_eq_none_iff, beq_eq_false_iff_ne, ne_eq]
|
||||
constructor
|
||||
· intro w h
|
||||
specialize w _ h
|
||||
simp at w
|
||||
· rintro w x h rfl
|
||||
contradiction
|
||||
|
||||
/-! ### lookup -/
|
||||
|
||||
section lookup
|
||||
variable [BEq α] [LawfulBEq α]
|
||||
|
||||
|
||||
@@ -96,14 +96,14 @@ The following operations are given `@[csimp]` replacements below:
|
||||
/-! ### flatMap -/
|
||||
|
||||
/-- Tail recursive version of `List.flatMap`. -/
|
||||
@[inline] def flatMapTR (f : α → List β) (as : List α) : List β := go as #[] where
|
||||
@[inline] def flatMapTR (as : List α) (f : α → List β) : List β := go as #[] where
|
||||
/-- Auxiliary for `flatMap`: `flatMap.go f as = acc.toList ++ bind f as` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
| [], acc => acc.toList
|
||||
| x::xs, acc => go xs (acc ++ f x)
|
||||
|
||||
@[csimp] theorem flatMap_eq_flatMapTR : @List.flatMap = @flatMapTR := by
|
||||
funext α β f as
|
||||
funext α β as f
|
||||
let rec go : ∀ as acc, flatMapTR.go f as acc = acc.toList ++ as.flatMap f
|
||||
| [], acc => by simp [flatMapTR.go, flatMap]
|
||||
| x::xs, acc => by simp [flatMapTR.go, flatMap, go xs]
|
||||
@@ -112,7 +112,7 @@ The following operations are given `@[csimp]` replacements below:
|
||||
/-! ### flatten -/
|
||||
|
||||
/-- Tail recursive version of `List.flatten`. -/
|
||||
@[inline] def flattenTR (l : List (List α)) : List α := l.flatMapTR id
|
||||
@[inline] def flattenTR (l : List (List α)) : List α := flatMapTR l id
|
||||
|
||||
@[csimp] theorem flatten_eq_flattenTR : @flatten = @flattenTR := by
|
||||
funext α l; rw [← List.flatMap_id, List.flatMap_eq_flatMapTR]; rfl
|
||||
@@ -316,35 +316,14 @@ theorem insertIdxTR_go_eq : ∀ n l, insertIdxTR.go a n l acc = acc.toList ++ in
|
||||
|
||||
/-! ## Ranges and enumeration -/
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
/-- Tail recursive version of `List.zipIdx`. -/
|
||||
def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
|
||||
let arr := l.toArray
|
||||
(arr.foldr (fun a (n, acc) => (n-1, (a, n-1) :: acc)) (n + arr.size, [])).2
|
||||
|
||||
@[csimp] theorem zipIdx_eq_zipIdxTR : @zipIdx = @zipIdxTR := by
|
||||
funext α l n; simp [zipIdxTR, -Array.size_toArray]
|
||||
let f := fun (a : α) (n, acc) => (n-1, (a, n-1) :: acc)
|
||||
let rec go : ∀ l n, l.foldr f (n + l.length, []) = (n, zipIdx l n)
|
||||
| [], n => rfl
|
||||
| a::as, n => by
|
||||
rw [← show _ + as.length = n + (a::as).length from Nat.succ_add .., foldr, go as]
|
||||
simp [zipIdx, f]
|
||||
rw [← Array.foldr_toList]
|
||||
simp +zetaDelta [go]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
/-- Tail recursive version of `List.enumFrom`. -/
|
||||
@[deprecated zipIdxTR (since := "2025-01-21")]
|
||||
def enumFromTR (n : Nat) (l : List α) : List (Nat × α) :=
|
||||
let arr := l.toArray
|
||||
(arr.foldr (fun a (n, acc) => (n-1, (n-1, a) :: acc)) (n + arr.size, [])).2
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated zipIdx_eq_zipIdxTR (since := "2025-01-21"), csimp]
|
||||
theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
||||
@[csimp] theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
||||
funext α n l; simp [enumFromTR, -Array.size_toArray]
|
||||
let f := fun (a : α) (n, acc) => (n-1, (n-1, a) :: acc)
|
||||
let rec go : ∀ l n, l.foldr f (n + l.length, []) = (n, enumFrom n l)
|
||||
|
||||
@@ -379,7 +379,7 @@ theorem eq_nil_iff_forall_not_mem {l : List α} : l = [] ↔ ∀ a, a ∉ l := b
|
||||
theorem eq_of_mem_singleton : a ∈ [b] → a = b
|
||||
| .head .. => rfl
|
||||
|
||||
@[simp] theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b :=
|
||||
@[simp 1100] theorem mem_singleton {a b : α} : a ∈ [b] ↔ a = b :=
|
||||
⟨eq_of_mem_singleton, (by simp [·])⟩
|
||||
|
||||
theorem forall_mem_cons {p : α → Prop} {a : α} {l : List α} :
|
||||
@@ -436,10 +436,6 @@ theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ i : Nat, l[i]? = s
|
||||
let ⟨n, _, e⟩ := getElem_of_mem h
|
||||
exact ⟨n, e ▸ getElem?_eq_getElem _⟩
|
||||
|
||||
theorem mem_of_getElem {l : List α} {i : Nat} {h} {a : α} (e : l[i] = a) : a ∈ l := by
|
||||
subst e
|
||||
simp
|
||||
|
||||
theorem mem_of_getElem? {l : List α} {i : Nat} {a : α} (e : l[i]? = some a) : a ∈ l :=
|
||||
let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
|
||||
|
||||
@@ -817,6 +813,11 @@ theorem getElem_cons_length (x : α) (xs : List α) (i : Nat) (h : i = xs.length
|
||||
(x :: xs)[i]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
|
||||
rw [getLast_eq_getElem]; cases h; rfl
|
||||
|
||||
@[deprecated getElem_cons_length (since := "2024-06-12")]
|
||||
theorem get_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
|
||||
(x :: xs).get ⟨n, by simp [h]⟩ = (x :: xs).getLast (cons_ne_nil x xs) := by
|
||||
simp [getElem_cons_length, h]
|
||||
|
||||
/-! ### getLast? -/
|
||||
|
||||
@[simp] theorem getLast?_singleton (a : α) : getLast? [a] = a := rfl
|
||||
@@ -1025,10 +1026,21 @@ theorem getLast?_tail (l : List α) : (tail l).getLast? = if l.length = 1 then n
|
||||
| _ :: _, 0 => by simp
|
||||
| _ :: l, i+1 => by simp [getElem?_map f l i]
|
||||
|
||||
@[deprecated getElem?_map (since := "2024-06-12")]
|
||||
theorem get?_map (f : α → β) : ∀ l i, (map f l).get? i = (l.get? i).map f
|
||||
| [], _ => rfl
|
||||
| _ :: _, 0 => rfl
|
||||
| _ :: l, i+1 => get?_map f l i
|
||||
|
||||
@[simp] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
|
||||
(map f l)[i] = f (l[i]'(length_map l f ▸ h)) :=
|
||||
Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
|
||||
|
||||
@[deprecated getElem_map (since := "2024-06-12")]
|
||||
theorem get_map (f : α → β) {l i} :
|
||||
get (map f l) i = f (get l ⟨i, length_map l f ▸ i.2⟩) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem map_id_fun : map (id : α → α) = id := by
|
||||
funext l
|
||||
induction l <;> simp_all
|
||||
@@ -1050,9 +1062,7 @@ theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l =
|
||||
|
||||
theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl
|
||||
|
||||
-- We use a lower priority here as there are more specific lemmas in downstream libraries
|
||||
-- which should be able to fire first.
|
||||
@[simp 500] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
|
||||
@[simp] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
|
||||
| [] => by simp
|
||||
| _ :: l => by simp [mem_map (l := l), eq_comm (a := b)]
|
||||
|
||||
@@ -1066,31 +1076,9 @@ theorem forall_mem_map {f : α → β} {l : List α} {P : β → Prop} :
|
||||
|
||||
@[deprecated forall_mem_map (since := "2024-07-25")] abbrev forall_mem_map_iff := @forall_mem_map
|
||||
|
||||
@[simp] theorem map_eq_nil_iff {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
@[deprecated map_eq_nil_iff (since := "2024-09-05")] abbrev map_eq_nil := @map_eq_nil_iff
|
||||
|
||||
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
|
||||
map_eq_nil_iff.mp h
|
||||
|
||||
@[simp] theorem map_inj_left {f g : α → β} : map f l = map g l ↔ ∀ a ∈ l, f a = g a := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem map_inj_right {f : α → β} (w : ∀ x y, f x = f y → x = y) : map f l = map f l' ↔ l = l' := by
|
||||
induction l generalizing l' with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [map_cons]
|
||||
cases l' with
|
||||
| nil => simp
|
||||
| cons a' l' =>
|
||||
simp only [map_cons, cons.injEq, ih, and_congr_left_iff]
|
||||
intro h
|
||||
constructor
|
||||
· apply w
|
||||
· simp +contextual
|
||||
|
||||
theorem map_congr_left (h : ∀ a ∈ l, f a = g a) : map f l = map g l :=
|
||||
map_inj_left.2 h
|
||||
|
||||
@@ -1099,6 +1087,14 @@ theorem map_inj : map f = map g ↔ f = g := by
|
||||
· intro h; ext a; replace h := congrFun h [a]; simpa using h
|
||||
· intro h; subst h; rfl
|
||||
|
||||
@[simp] theorem map_eq_nil_iff {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
@[deprecated map_eq_nil_iff (since := "2024-09-05")] abbrev map_eq_nil := @map_eq_nil_iff
|
||||
|
||||
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
|
||||
map_eq_nil_iff.mp h
|
||||
|
||||
theorem map_eq_cons_iff {f : α → β} {l : List α} :
|
||||
map f l = b :: l₂ ↔ ∃ a l₁, l = a :: l₁ ∧ f a = b ∧ map f l₁ = l₂ := by
|
||||
cases l
|
||||
@@ -1276,6 +1272,8 @@ theorem filter_map (f : β → α) (l : List β) : filter p (map f l) = map f (f
|
||||
| nil => rfl
|
||||
| cons a l IH => by_cases h : p (f a) <;> simp [*]
|
||||
|
||||
@[deprecated filter_map (since := "2024-06-15")] abbrev map_filter := @filter_map
|
||||
|
||||
theorem map_filter_eq_foldr (f : α → β) (p : α → Bool) (as : List α) :
|
||||
map f (filter p as) = foldr (fun a bs => bif p a then f a :: bs else bs) [] as := by
|
||||
induction as with
|
||||
@@ -1320,6 +1318,8 @@ theorem filter_congr {p q : α → Bool} :
|
||||
· simp [pa, h.1 ▸ pa, filter_congr h.2]
|
||||
· simp [pa, h.1 ▸ pa, filter_congr h.2]
|
||||
|
||||
@[deprecated filter_congr (since := "2024-06-20")] abbrev filter_congr' := @filter_congr
|
||||
|
||||
theorem head_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p (l.head w)) :
|
||||
(filter p l).head ((ne_nil_of_mem (mem_filter.2 ⟨head_mem w, h⟩))) = l.head w := by
|
||||
cases l with
|
||||
@@ -1494,34 +1494,6 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
|
||||
@[simp] theorem cons_append_fun (a : α) (as : List α) :
|
||||
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
|
||||
|
||||
@[simp] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
induction s <;> simp_all [or_assoc]
|
||||
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
|
||||
|
||||
@[deprecated mem_append (since := "2025-01-13")]
|
||||
theorem mem_append_eq (a : α) (s t : List α) : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
|
||||
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
|
||||
|
||||
/--
|
||||
See also `eq_append_cons_of_mem`, which proves a stronger version
|
||||
in which the initial list must not contain the element.
|
||||
-/
|
||||
theorem append_of_mem {a : α} {l : List α} : a ∈ l → ∃ s t : List α, l = s ++ a :: t
|
||||
| .head l => ⟨[], l, rfl⟩
|
||||
| .tail b h => let ⟨s, t, h'⟩ := append_of_mem h; ⟨b::s, t, by rw [h', cons_append]⟩
|
||||
|
||||
theorem mem_iff_append {a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t :=
|
||||
⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩
|
||||
|
||||
theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
|
||||
(∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
theorem getElem_append {l₁ l₂ : List α} (i : Nat) (h : i < (l₁ ++ l₂).length) :
|
||||
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
|
||||
split <;> rename_i h'
|
||||
@@ -1547,6 +1519,11 @@ theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
|
||||
· exact getElem?_append_left h
|
||||
· exact getElem?_append_right (by simpa using h)
|
||||
|
||||
@[deprecated getElem?_append_right (since := "2024-06-12")]
|
||||
theorem get?_append_right {l₁ l₂ : List α} {i : Nat} (h : l₁.length ≤ i) :
|
||||
(l₁ ++ l₂).get? i = l₂.get? (i - l₁.length) := by
|
||||
simp [getElem?_append_right, h]
|
||||
|
||||
/-- Variant of `getElem_append_left` useful for rewriting from the small list to the big list. -/
|
||||
theorem getElem_append_left' (l₂ : List α) {l₁ : List α} {i : Nat} (hi : i < l₁.length) :
|
||||
l₁[i] = (l₁ ++ l₂)[i]'(by simpa using Nat.lt_add_right l₂.length hi) := by
|
||||
@@ -1557,12 +1534,42 @@ theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {i : Nat} (hi :
|
||||
l₂[i] = (l₁ ++ l₂)[i + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _) := by
|
||||
rw [getElem_append_right] <;> simp [*, le_add_left]
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_append_right_aux {l₁ l₂ : List α} {i : Nat}
|
||||
(h₁ : l₁.length ≤ i) (h₂ : i < (l₁ ++ l₂).length) : i - l₁.length < l₂.length := by
|
||||
rw [length_append] at h₂
|
||||
exact Nat.sub_lt_left_of_lt_add h₁ h₂
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem_append_right (since := "2024-06-12")]
|
||||
theorem get_append_right' {l₁ l₂ : List α} {i : Nat} (h₁ : l₁.length ≤ i) (h₂) :
|
||||
(l₁ ++ l₂).get ⟨i, h₂⟩ = l₂.get ⟨i - l₁.length, get_append_right_aux h₁ h₂⟩ :=
|
||||
Option.some.inj <| by rw [← get?_eq_get, ← get?_eq_get, get?_append_right h₁]
|
||||
|
||||
theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
|
||||
l[i]'(eq ▸ h ▸ by simp_arith) = a := Option.some.inj <| by
|
||||
rw [← getElem?_eq_getElem, eq, getElem?_append_right (h ▸ Nat.le_refl _), h]
|
||||
simp
|
||||
|
||||
@[simp] theorem singleton_append : [x] ++ l = x :: l := rfl
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-06-12")]
|
||||
theorem get_of_append_proof {l : List α}
|
||||
(eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) : i < length l := eq ▸ h ▸ by simp_arith
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem_of_append (since := "2024-06-12")]
|
||||
theorem get_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
|
||||
l.get ⟨i, get_of_append_proof eq h⟩ = a := Option.some.inj <| by
|
||||
rw [← get?_eq_get, eq, get?_append_right (h ▸ Nat.le_refl _), h, Nat.sub_self]; rfl
|
||||
|
||||
/--
|
||||
See also `eq_append_cons_of_mem`, which proves a stronger version
|
||||
in which the initial list must not contain the element.
|
||||
-/
|
||||
theorem append_of_mem {a : α} {l : List α} : a ∈ l → ∃ s t : List α, l = s ++ a :: t
|
||||
| .head l => ⟨[], l, rfl⟩
|
||||
| .tail b h => let ⟨s, t, h'⟩ := append_of_mem h; ⟨b::s, t, by rw [h', cons_append]⟩
|
||||
|
||||
@[simp 1100] theorem singleton_append : [x] ++ l = x :: l := rfl
|
||||
|
||||
theorem append_inj :
|
||||
∀ {s₁ s₂ t₁ t₂ : List α}, s₁ ++ t₁ = s₂ ++ t₂ → length s₁ = length s₂ → s₁ = s₂ ∧ t₁ = t₂
|
||||
@@ -1578,8 +1585,8 @@ theorem append_inj_left (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length s₁ = le
|
||||
|
||||
/-- Variant of `append_inj` instead requiring equality of the lengths of the second lists. -/
|
||||
theorem append_inj' (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : s₁ = s₂ ∧ t₁ = t₂ :=
|
||||
append_inj h <| @Nat.add_right_cancel _ t₁.length _ <| by
|
||||
let hap := congrArg length h; simp only [length_append, ← hl] at hap; exact hap
|
||||
append_inj h <| @Nat.add_right_cancel _ (length t₁) _ <| by
|
||||
let hap := congrArg length h; simp only [length_append, ← hl] at hap; exact hap
|
||||
|
||||
/-- Variant of `append_inj_right` instead requiring equality of the lengths of the second lists. -/
|
||||
theorem append_inj_right' (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : t₁ = t₂ :=
|
||||
@@ -1607,58 +1614,33 @@ theorem append_left_inj {s₁ s₂ : List α} (t) : s₁ ++ t = s₂ ++ t ↔ s
|
||||
@[simp] theorem self_eq_append_right {x y : List α} : x = x ++ y ↔ y = [] := by
|
||||
rw [eq_comm, append_right_eq_self]
|
||||
|
||||
@[simp] theorem append_eq_nil : p ++ q = [] ↔ p = [] ∧ q = [] := by
|
||||
cases p <;> simp
|
||||
|
||||
theorem getLast_concat {a : α} : ∀ (l : List α), getLast (l ++ [a]) (by simp) = a
|
||||
| [] => rfl
|
||||
| a::t => by
|
||||
simp [getLast_cons _, getLast_concat t]
|
||||
|
||||
@[simp] theorem append_eq_nil_iff : p ++ q = [] ↔ p = [] ∧ q = [] := by
|
||||
cases p <;> simp
|
||||
@[deprecated getElem_append (since := "2024-06-12")]
|
||||
theorem get_append {l₁ l₂ : List α} (n : Nat) (h : n < l₁.length) :
|
||||
(l₁ ++ l₂).get ⟨n, length_append .. ▸ Nat.lt_add_right _ h⟩ = l₁.get ⟨n, h⟩ := by
|
||||
simp [getElem_append, h]
|
||||
|
||||
@[deprecated append_eq_nil_iff (since := "2025-01-13")] abbrev append_eq_nil := @append_eq_nil_iff
|
||||
@[deprecated getElem_append_left (since := "2024-06-12")]
|
||||
theorem get_append_left (as bs : List α) (h : i < as.length) {h'} :
|
||||
(as ++ bs).get ⟨i, h'⟩ = as.get ⟨i, h⟩ := by
|
||||
simp [getElem_append_left, h, h']
|
||||
|
||||
@[simp] theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
rw [eq_comm, append_eq_nil_iff]
|
||||
@[deprecated getElem_append_right (since := "2024-06-12")]
|
||||
theorem get_append_right (as bs : List α) (h : as.length ≤ i) {h' h''} :
|
||||
(as ++ bs).get ⟨i, h'⟩ = bs.get ⟨i - as.length, h''⟩ := by
|
||||
simp [getElem_append_right, h, h', h'']
|
||||
|
||||
@[deprecated nil_eq_append_iff (since := "2024-07-24")] abbrev nil_eq_append := @nil_eq_append_iff
|
||||
|
||||
theorem append_ne_nil_of_left_ne_nil {s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ [] := by simp_all
|
||||
theorem append_ne_nil_of_right_ne_nil (s : List α) : t ≠ [] → s ++ t ≠ [] := by simp_all
|
||||
|
||||
@[deprecated append_ne_nil_of_left_ne_nil (since := "2024-07-24")]
|
||||
theorem append_ne_nil_of_ne_nil_left {s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ [] := by simp_all
|
||||
@[deprecated append_ne_nil_of_right_ne_nil (since := "2024-07-24")]
|
||||
theorem append_ne_nil_of_ne_nil_right (s : List α) : t ≠ [] → s ++ t ≠ [] := by simp_all
|
||||
|
||||
theorem append_eq_cons_iff :
|
||||
a ++ b = x :: c ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by
|
||||
cases a with simp | cons a as => ?_
|
||||
exact ⟨fun h => ⟨as, by simp [h]⟩, fun ⟨a', ⟨aeq, aseq⟩, h⟩ => ⟨aeq, by rw [aseq, h]⟩⟩
|
||||
|
||||
@[deprecated append_eq_cons_iff (since := "2024-07-24")] abbrev append_eq_cons := @append_eq_cons_iff
|
||||
|
||||
theorem cons_eq_append_iff :
|
||||
x :: c = a ++ b ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by
|
||||
rw [eq_comm, append_eq_cons_iff]
|
||||
|
||||
@[deprecated cons_eq_append_iff (since := "2024-07-24")] abbrev cons_eq_append := @cons_eq_append_iff
|
||||
|
||||
theorem append_eq_singleton_iff :
|
||||
a ++ b = [x] ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = []) := by
|
||||
cases a <;> cases b <;> simp
|
||||
|
||||
theorem singleton_eq_append_iff :
|
||||
[x] = a ++ b ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = []) := by
|
||||
cases a <;> cases b <;> simp [eq_comm]
|
||||
|
||||
theorem append_eq_append_iff {a b c d : List α} :
|
||||
a ++ b = c ++ d ↔ (∃ a', c = a ++ a' ∧ b = a' ++ d) ∨ ∃ c', a = c ++ c' ∧ d = c' ++ b := by
|
||||
induction a generalizing c with
|
||||
| nil => simp_all
|
||||
| cons a as ih => cases c <;> simp [eq_comm, and_assoc, ih, and_or_left]
|
||||
|
||||
@[deprecated append_inj (since := "2024-07-24")] abbrev append_inj_of_length_left := @append_inj
|
||||
@[deprecated append_inj' (since := "2024-07-24")] abbrev append_inj_of_length_right := @append_inj'
|
||||
@[deprecated getElem?_append_left (since := "2024-06-12")]
|
||||
theorem get?_append {l₁ l₂ : List α} {n : Nat} (hn : n < l₁.length) :
|
||||
(l₁ ++ l₂).get? n = l₁.get? n := by
|
||||
simp [getElem?_append_left hn]
|
||||
|
||||
@[simp] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
|
||||
head (l ++ l') w₁ = head l w₂ := by
|
||||
@@ -1709,6 +1691,60 @@ theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tai
|
||||
|
||||
@[deprecated tail_append_of_ne_nil (since := "2024-07-24")] abbrev tail_append_left := @tail_append_of_ne_nil
|
||||
|
||||
theorem nil_eq_append_iff : [] = a ++ b ↔ a = [] ∧ b = [] := by
|
||||
rw [eq_comm, append_eq_nil]
|
||||
|
||||
@[deprecated nil_eq_append_iff (since := "2024-07-24")] abbrev nil_eq_append := @nil_eq_append_iff
|
||||
|
||||
theorem append_ne_nil_of_left_ne_nil {s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ [] := by simp_all
|
||||
theorem append_ne_nil_of_right_ne_nil (s : List α) : t ≠ [] → s ++ t ≠ [] := by simp_all
|
||||
|
||||
@[deprecated append_ne_nil_of_left_ne_nil (since := "2024-07-24")]
|
||||
theorem append_ne_nil_of_ne_nil_left {s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ [] := by simp_all
|
||||
@[deprecated append_ne_nil_of_right_ne_nil (since := "2024-07-24")]
|
||||
theorem append_ne_nil_of_ne_nil_right (s : List α) : t ≠ [] → s ++ t ≠ [] := by simp_all
|
||||
|
||||
theorem append_eq_cons_iff :
|
||||
a ++ b = x :: c ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by
|
||||
cases a with simp | cons a as => ?_
|
||||
exact ⟨fun h => ⟨as, by simp [h]⟩, fun ⟨a', ⟨aeq, aseq⟩, h⟩ => ⟨aeq, by rw [aseq, h]⟩⟩
|
||||
|
||||
@[deprecated append_eq_cons_iff (since := "2024-07-24")] abbrev append_eq_cons := @append_eq_cons_iff
|
||||
|
||||
theorem cons_eq_append_iff :
|
||||
x :: c = a ++ b ↔ (a = [] ∧ b = x :: c) ∨ (∃ a', a = x :: a' ∧ c = a' ++ b) := by
|
||||
rw [eq_comm, append_eq_cons_iff]
|
||||
|
||||
@[deprecated cons_eq_append_iff (since := "2024-07-24")] abbrev cons_eq_append := @cons_eq_append_iff
|
||||
|
||||
theorem append_eq_append_iff {a b c d : List α} :
|
||||
a ++ b = c ++ d ↔ (∃ a', c = a ++ a' ∧ b = a' ++ d) ∨ ∃ c', a = c ++ c' ∧ d = c' ++ b := by
|
||||
induction a generalizing c with
|
||||
| nil => simp_all
|
||||
| cons a as ih => cases c <;> simp [eq_comm, and_assoc, ih, and_or_left]
|
||||
|
||||
@[deprecated append_inj (since := "2024-07-24")] abbrev append_inj_of_length_left := @append_inj
|
||||
@[deprecated append_inj' (since := "2024-07-24")] abbrev append_inj_of_length_right := @append_inj'
|
||||
|
||||
@[simp] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
|
||||
induction s <;> simp_all [or_assoc]
|
||||
|
||||
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
|
||||
mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
|
||||
|
||||
theorem mem_append_eq (a : α) (s t : List α) : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t) :=
|
||||
propext mem_append
|
||||
|
||||
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
|
||||
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
|
||||
|
||||
theorem mem_iff_append {a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t :=
|
||||
⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩
|
||||
|
||||
theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
|
||||
(∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
|
||||
simp only [mem_append, or_imp, forall_and]
|
||||
|
||||
theorem set_append {s t : List α} :
|
||||
(s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
|
||||
induction s generalizing i with
|
||||
@@ -1837,7 +1873,7 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ L b, l = concat L b
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
@[simp] theorem length_flatten (L : List (List α)) : L.flatten.length = (L.map length).sum := by
|
||||
@[simp] theorem length_flatten (L : List (List α)) : (flatten L).length = (L.map length).sum := by
|
||||
induction L with
|
||||
| nil => rfl
|
||||
| cons =>
|
||||
@@ -1852,9 +1888,6 @@ theorem flatten_singleton (l : List α) : [l].flatten = l := by simp
|
||||
@[simp] theorem flatten_eq_nil_iff {L : List (List α)} : L.flatten = [] ↔ ∀ l ∈ L, l = [] := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[simp] theorem nil_eq_flatten_iff {L : List (List α)} : [] = L.flatten ↔ ∀ l ∈ L, l = [] := by
|
||||
rw [eq_comm, flatten_eq_nil_iff]
|
||||
|
||||
theorem flatten_ne_nil_iff {xs : List (List α)} : xs.flatten ≠ [] ↔ ∃ x, x ∈ xs ∧ x ≠ [] := by
|
||||
simp
|
||||
|
||||
@@ -1880,8 +1913,7 @@ theorem head?_flatten {L : List (List α)} : (flatten L).head? = L.findSome? fun
|
||||
-- `getLast?_flatten` is proved later, after the `reverse` section.
|
||||
-- `head_flatten` and `getLast_flatten` are proved in `Init.Data.List.Find`.
|
||||
|
||||
@[simp] theorem map_flatten (f : α → β) (L : List (List α)) :
|
||||
(flatten L).map f = (map (map f) L).flatten := by
|
||||
@[simp] theorem map_flatten (f : α → β) (L : List (List α)) : map f (flatten L) = flatten (map (map f) L) := by
|
||||
induction L <;> simp_all
|
||||
|
||||
@[simp] theorem filterMap_flatten (f : α → Option β) (L : List (List α)) :
|
||||
@@ -1934,26 +1966,6 @@ theorem flatten_eq_cons_iff {xs : List (List α)} {y : α} {ys : List α} :
|
||||
· rintro ⟨as, bs, cs, rfl, h₁, rfl⟩
|
||||
simp [flatten_eq_nil_iff.mpr h₁]
|
||||
|
||||
theorem cons_eq_flatten_iff {xs : List (List α)} {y : α} {ys : List α} :
|
||||
y :: ys = xs.flatten ↔
|
||||
∃ as bs cs, xs = as ++ (y :: bs) :: cs ∧ (∀ l, l ∈ as → l = []) ∧ ys = bs ++ cs.flatten := by
|
||||
rw [eq_comm, flatten_eq_cons_iff]
|
||||
|
||||
theorem flatten_eq_singleton_iff {xs : List (List α)} {y : α} :
|
||||
xs.flatten = [y] ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = []) := by
|
||||
rw [flatten_eq_cons_iff]
|
||||
constructor
|
||||
· rintro ⟨as, bs, cs, rfl, h₁, h₂⟩
|
||||
simp at h₂
|
||||
obtain ⟨rfl, h₂⟩ := h₂
|
||||
exact ⟨as, cs, by simp, h₁, h₂⟩
|
||||
· rintro ⟨as, bs, rfl, h₁, h₂⟩
|
||||
exact ⟨as, [], bs, rfl, h₁, by simpa⟩
|
||||
|
||||
theorem singleton_eq_flatten_iff {xs : List (List α)} {y : α} :
|
||||
[y] = xs.flatten ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = []) := by
|
||||
rw [eq_comm, flatten_eq_singleton_iff]
|
||||
|
||||
theorem flatten_eq_append_iff {xs : List (List α)} {ys zs : List α} :
|
||||
xs.flatten = ys ++ zs ↔
|
||||
(∃ as bs, xs = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨
|
||||
@@ -1962,8 +1974,8 @@ theorem flatten_eq_append_iff {xs : List (List α)} {ys zs : List α} :
|
||||
constructor
|
||||
· induction xs generalizing ys with
|
||||
| nil =>
|
||||
simp only [flatten_nil, nil_eq, append_eq_nil_iff, and_false, cons_append, false_and,
|
||||
exists_const, exists_false, or_false, and_imp, List.cons_ne_nil]
|
||||
simp only [flatten_nil, nil_eq, append_eq_nil, and_false, cons_append, false_and, exists_const,
|
||||
exists_false, or_false, and_imp, List.cons_ne_nil]
|
||||
rintro rfl rfl
|
||||
exact ⟨[], [], by simp⟩
|
||||
| cons x xs ih =>
|
||||
@@ -1982,13 +1994,6 @@ theorem flatten_eq_append_iff {xs : List (List α)} {ys zs : List α} :
|
||||
· simp
|
||||
· simp
|
||||
|
||||
theorem append_eq_flatten_iff {xs : List (List α)} {ys zs : List α} :
|
||||
ys ++ zs = xs.flatten ↔
|
||||
(∃ as bs, xs = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨
|
||||
∃ as bs c cs ds, xs = as ++ (bs ++ c :: cs) :: ds ∧ ys = as.flatten ++ bs ∧
|
||||
zs = c :: cs ++ ds.flatten := by
|
||||
rw [eq_comm, flatten_eq_append_iff]
|
||||
|
||||
/-- Two lists of sublists are equal iff their flattens coincide, as well as the lengths of the
|
||||
sublists. -/
|
||||
theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
|
||||
@@ -2009,14 +2014,12 @@ theorem eq_iff_flatten_eq : ∀ {L L' : List (List α)},
|
||||
|
||||
theorem flatMap_def (l : List α) (f : α → List β) : l.flatMap f = flatten (map f l) := by rfl
|
||||
|
||||
@[simp] theorem flatMap_id (l : List (List α)) : l.flatMap id = l.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp] theorem flatMap_id' (l : List (List α)) : l.flatMap (fun a => a) = l.flatten := by simp [flatMap_def]
|
||||
@[simp] theorem flatMap_id (l : List (List α)) : List.flatMap l id = l.flatten := by simp [flatMap_def]
|
||||
|
||||
@[simp]
|
||||
theorem length_flatMap (l : List α) (f : α → List β) :
|
||||
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
|
||||
length (l.flatMap f) = sum (map (length ∘ f) l) := by
|
||||
rw [List.flatMap, length_flatten, map_map]
|
||||
|
||||
@[simp] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
|
||||
simp [flatMap_def, mem_flatten]
|
||||
@@ -2029,7 +2032,7 @@ theorem mem_flatMap_of_mem {b : β} {l : List α} {f : α → List β} {a} (al :
|
||||
b ∈ l.flatMap f := mem_flatMap.2 ⟨a, al, h⟩
|
||||
|
||||
@[simp]
|
||||
theorem flatMap_eq_nil_iff {l : List α} {f : α → List β} : l.flatMap f = [] ↔ ∀ x ∈ l, f x = [] :=
|
||||
theorem flatMap_eq_nil_iff {l : List α} {f : α → List β} : List.flatMap l f = [] ↔ ∀ x ∈ l, f x = [] :=
|
||||
flatten_eq_nil_iff.trans <| by
|
||||
simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
|
||||
|
||||
@@ -2138,6 +2141,10 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
|
||||
(replicate n a)[m] = a :=
|
||||
eq_of_mem_replicate (getElem_mem _)
|
||||
|
||||
@[deprecated getElem_replicate (since := "2024-06-12")]
|
||||
theorem get_replicate (a : α) {n : Nat} (m : Fin _) : (replicate n a).get m = a := by
|
||||
simp
|
||||
|
||||
theorem getElem?_replicate : (replicate n a)[m]? = if m < n then some a else none := by
|
||||
by_cases h : m < n
|
||||
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
|
||||
@@ -2209,7 +2216,7 @@ theorem map_const' (l : List α) (b : β) : map (fun _ => b) l = replicate l.len
|
||||
· intro i h₁ h₂
|
||||
simp [getElem_set]
|
||||
|
||||
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
@[simp] theorem append_replicate_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
rw [eq_replicate_iff]
|
||||
constructor
|
||||
· simp
|
||||
@@ -2217,9 +2224,6 @@ theorem map_const' (l : List α) (b : β) : map (fun _ => b) l = replicate l.len
|
||||
simp only [mem_append, mem_replicate, ne_eq]
|
||||
rintro (⟨-, rfl⟩ | ⟨_, rfl⟩) <;> rfl
|
||||
|
||||
@[deprecated replicate_append_replicate (since := "2025-01-16")]
|
||||
abbrev append_replicate_replicate := @replicate_append_replicate
|
||||
|
||||
theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
|
||||
l₁ ++ l₂ = replicate n a ↔
|
||||
l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a := by
|
||||
@@ -2230,11 +2234,6 @@ theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
|
||||
|
||||
@[deprecated append_eq_replicate_iff (since := "2024-09-05")] abbrev append_eq_replicate := @append_eq_replicate_iff
|
||||
|
||||
theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
|
||||
replicate n a = l₁ ++ l₂ ↔
|
||||
l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a := by
|
||||
rw [eq_comm, append_eq_replicate_iff]
|
||||
|
||||
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
|
||||
ext1 n
|
||||
simp only [getElem?_map, getElem?_replicate]
|
||||
@@ -2286,7 +2285,7 @@ theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
simp only [replicate_succ, flatten_cons, ih, replicate_append_replicate, replicate_inj, or_true,
|
||||
simp only [replicate_succ, flatten_cons, ih, append_replicate_replicate, replicate_inj, or_true,
|
||||
and_true, add_one_mul, Nat.add_comm]
|
||||
|
||||
theorem flatMap_replicate {β} (f : α → List β) : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
|
||||
@@ -2338,9 +2337,6 @@ theorem replicateRecOn {α : Type _} {p : List α → Prop} (m : List α)
|
||||
exact hi _ _ _ _ h hn (replicateRecOn (b :: l') h0 hr hi)
|
||||
termination_by m.length
|
||||
|
||||
@[simp] theorem sum_replicate_nat (n : Nat) (a : Nat) : (replicate n a).sum = n * a := by
|
||||
induction n <;> simp_all [replicate_succ, Nat.add_mul, Nat.add_comm]
|
||||
|
||||
/-! ### reverse -/
|
||||
|
||||
@[simp] theorem length_reverse (as : List α) : (as.reverse).length = as.length := by
|
||||
@@ -2373,6 +2369,10 @@ theorem getElem?_reverse' : ∀ {l : List α} (i j), i + j + 1 = length l →
|
||||
rw [getElem?_append_left, getElem?_reverse' _ _ this]
|
||||
rw [length_reverse, ← this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
|
||||
|
||||
@[deprecated getElem?_reverse' (since := "2024-06-12")]
|
||||
theorem get?_reverse' {l : List α} (i j) (h : i + j + 1 = length l) : get? l.reverse i = get? l j := by
|
||||
simp [getElem?_reverse' _ _ h]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
|
||||
l.reverse[i]? = l[l.length - 1 - i]? :=
|
||||
@@ -2387,6 +2387,11 @@ theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
|
||||
rw [← getElem?_eq_getElem, ← getElem?_eq_getElem]
|
||||
rw [getElem?_reverse (by simpa using h)]
|
||||
|
||||
@[deprecated getElem?_reverse (since := "2024-06-12")]
|
||||
theorem get?_reverse {l : List α} {i} (h : i < length l) :
|
||||
get? l.reverse i = get? l (l.length - 1 - i) := by
|
||||
simp [getElem?_reverse h]
|
||||
|
||||
theorem reverseAux_reverseAux_nil (as bs : List α) : reverseAux (reverseAux as bs) [] = reverseAux bs as := by
|
||||
induction as generalizing bs with
|
||||
| nil => rfl
|
||||
@@ -2427,6 +2432,10 @@ theorem mem_of_mem_getLast? {l : List α} {a : α} (h : a ∈ getLast? l) : a
|
||||
@[simp] theorem map_reverse (f : α → β) (l : List α) : l.reverse.map f = (l.map f).reverse := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[deprecated map_reverse (since := "2024-06-20")]
|
||||
theorem reverse_map (f : α → β) (l : List α) : (l.map f).reverse = l.reverse.map f := by
|
||||
simp
|
||||
|
||||
@[simp] theorem filter_reverse (p : α → Bool) (l : List α) : (l.reverse.filter p) = (l.filter p).reverse := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -2552,24 +2561,20 @@ theorem foldr_filterMap (f : α → Option β) (g : β → γ → γ) (l : List
|
||||
simp only [filterMap_cons, foldr_cons]
|
||||
cases f a <;> simp [ih]
|
||||
|
||||
theorem foldl_map_hom (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldl_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
@[deprecated foldl_map_hom (since := "2025-01-20")] abbrev foldl_map' := @foldl_map_hom
|
||||
|
||||
theorem foldr_map_hom (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldr_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
@[deprecated foldr_map_hom (since := "2025-01-20")] abbrev foldr_map' := @foldr_map_hom
|
||||
|
||||
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] (f : α → β → m β) (b) (l l' : List α) :
|
||||
(l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
|
||||
induction l <;> simp [*]
|
||||
@@ -2756,12 +2761,10 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
|
||||
rw [getLast?_eq_head?_reverse, head?_isSome]
|
||||
simp
|
||||
|
||||
theorem mem_of_getLast? {xs : List α} {a : α} (h : xs.getLast? = some a) : a ∈ xs := by
|
||||
theorem mem_of_getLast?_eq_some {xs : List α} {a : α} (h : xs.getLast? = some a) : a ∈ xs := by
|
||||
obtain ⟨ys, rfl⟩ := getLast?_eq_some_iff.1 h
|
||||
exact mem_concat_self ys a
|
||||
|
||||
@[deprecated mem_of_getLast? (since := "2024-10-21")] abbrev mem_of_getLast?_eq_some := @mem_of_getLast?
|
||||
|
||||
@[simp] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
|
||||
l.reverse.getLast h = l.head (by simp_all) := by
|
||||
simp [getLast_eq_head_reverse]
|
||||
@@ -2896,6 +2899,11 @@ are often used for theorems about `Array.pop`.
|
||||
| _::_::_, 0, _ => rfl
|
||||
| _::_::_, i+1, h => getElem_dropLast _ i (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_dropLast (since := "2024-06-12")]
|
||||
theorem get_dropLast (xs : List α) (i : Fin xs.dropLast.length) :
|
||||
xs.dropLast.get i = xs.get ⟨i, Nat.lt_of_lt_of_le i.isLt (length_dropLast .. ▸ Nat.pred_le _)⟩ := by
|
||||
simp
|
||||
|
||||
theorem getElem?_dropLast (xs : List α) (i : Nat) :
|
||||
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
|
||||
split
|
||||
@@ -2971,7 +2979,7 @@ theorem dropLast_append {l₁ l₂ : List α} :
|
||||
theorem dropLast_append_cons : dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (b :: l₂) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
|
||||
@[simp 1100] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
|
||||
|
||||
@[simp] theorem dropLast_replicate (n) (a : α) : dropLast (replicate n a) = replicate (n - 1) a := by
|
||||
match n with
|
||||
@@ -3137,7 +3145,7 @@ variable [LawfulBEq α]
|
||||
| Or.inr h' => exact h'
|
||||
else rw [insert_of_not_mem h, mem_cons]
|
||||
|
||||
@[simp] theorem mem_insert_self (a : α) (l : List α) : a ∈ l.insert a :=
|
||||
@[simp 1100] theorem mem_insert_self (a : α) (l : List α) : a ∈ l.insert a :=
|
||||
mem_insert_iff.2 (Or.inl rfl)
|
||||
|
||||
theorem mem_insert_of_mem {l : List α} (h : a ∈ l) : a ∈ l.insert b :=
|
||||
@@ -3433,6 +3441,29 @@ theorem mem_iff_get? {a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a :=
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@[deprecated getD_eq_getElem?_getD (since := "2024-06-12")]
|
||||
theorem getD_eq_get? : ∀ l n (a : α), getD l n a = (get? l n).getD a := by simp
|
||||
@[deprecated getElem_singleton (since := "2024-06-12")]
|
||||
theorem get_singleton (a : α) (n : Fin 1) : get [a] n = a := by simp
|
||||
@[deprecated getElem?_concat_length (since := "2024-06-12")]
|
||||
theorem get?_concat_length (l : List α) (a : α) : (l ++ [a]).get? l.length = some a := by simp
|
||||
@[deprecated getElem_set_self (since := "2024-06-12")]
|
||||
theorem get_set_eq {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
|
||||
(l.set i a).get ⟨i, h⟩ = a := by
|
||||
simp
|
||||
@[deprecated getElem_set_ne (since := "2024-06-12")]
|
||||
theorem get_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
|
||||
(hj : j < (l.set i a).length) :
|
||||
(l.set i a).get ⟨j, hj⟩ = l.get ⟨j, by simp at hj; exact hj⟩ := by
|
||||
simp [h]
|
||||
@[deprecated getElem_set (since := "2024-06-12")]
|
||||
theorem get_set {l : List α} {m n} {a : α} (h) :
|
||||
(set l m a).get ⟨n, h⟩ = if m = n then a else l.get ⟨n, length_set .. ▸ h⟩ := by
|
||||
simp [getElem_set]
|
||||
@[deprecated cons_inj_right (since := "2024-06-15")] abbrev cons_inj := @cons_inj_right
|
||||
@[deprecated ne_nil_of_length_eq_add_one (since := "2024-06-16")]
|
||||
abbrev ne_nil_of_length_eq_succ := @ne_nil_of_length_eq_add_one
|
||||
|
||||
@[deprecated "Deprecated without replacement." (since := "2024-07-09")]
|
||||
theorem get_cons_cons_one : (a₁ :: a₂ :: as).get (1 : Fin (as.length + 2)) = a₂ := rfl
|
||||
|
||||
|
||||
@@ -17,19 +17,18 @@ namespace List
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
|
||||
/--
|
||||
Given a list `as = [a₀, a₁, ...]` function `f : Fin as.length → α → β`, returns the list
|
||||
`[f 0 a₀, f 1 a₁, ...]`.
|
||||
-/
|
||||
@[inline] def mapFinIdx (as : List α) (f : (i : Nat) → α → (h : i < as.length) → β) : List β :=
|
||||
go as #[] (by simp)
|
||||
where
|
||||
@[inline] def mapFinIdx (as : List α) (f : Fin as.length → α → β) : List β := go as #[] (by simp) where
|
||||
/-- Auxiliary for `mapFinIdx`:
|
||||
`mapFinIdx.go [a₀, a₁, ...] acc = acc.toList ++ [f 0 a₀, f 1 a₁, ...]` -/
|
||||
@[specialize] go : (bs : List α) → (acc : Array β) → bs.length + acc.size = as.length → List β
|
||||
| [], acc, h => acc.toList
|
||||
| a :: as, acc, h =>
|
||||
go as (acc.push (f acc.size a (by simp at h; omega))) (by simp at h ⊢; omega)
|
||||
go as (acc.push (f ⟨acc.size, by simp at h; omega⟩ a)) (by simp at h ⊢; omega)
|
||||
|
||||
/--
|
||||
Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list
|
||||
@@ -44,14 +43,8 @@ Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁,
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[congr] theorem mapFinIdx_congr {xs ys : List α} (w : xs = ys)
|
||||
(f : (i : Nat) → α → (h : i < xs.length) → β) :
|
||||
mapFinIdx xs f = mapFinIdx ys (fun i a h => f i a (by simp [w]; omega)) := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_nil {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx [] f = [] :=
|
||||
theorem mapFinIdx_nil {f : Fin 0 → α → β} : mapFinIdx [] f = [] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem length_mapFinIdx_go :
|
||||
@@ -60,16 +53,13 @@ theorem mapFinIdx_nil {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx
|
||||
| nil => simpa using h
|
||||
| cons _ _ ih => simp [mapFinIdx.go, ih]
|
||||
|
||||
@[simp] theorem length_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} :
|
||||
@[simp] theorem length_mapFinIdx {as : List α} {f : Fin as.length → α → β} :
|
||||
(as.mapFinIdx f).length = as.length := by
|
||||
simp [mapFinIdx, length_mapFinIdx_go]
|
||||
|
||||
theorem getElem_mapFinIdx_go {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} {i : Nat} {h} {w} :
|
||||
theorem getElem_mapFinIdx_go {as : List α} {f : Fin as.length → α → β} {i : Nat} {h} {w} :
|
||||
(mapFinIdx.go as f bs acc h)[i] =
|
||||
if w' : i < acc.size then
|
||||
acc[i]
|
||||
else
|
||||
f i (bs[i - acc.size]'(by simp at w; omega)) (by simp at w; omega) := by
|
||||
if w' : i < acc.size then acc[i] else f ⟨i, by simp at w; omega⟩ (bs[i - acc.size]'(by simp at w; omega)) := by
|
||||
induction bs generalizing acc with
|
||||
| nil =>
|
||||
simp only [length_mapFinIdx_go, length_nil, Nat.zero_add] at w h
|
||||
@@ -88,30 +78,29 @@ theorem getElem_mapFinIdx_go {as : List α} {f : (i : Nat) → α → (h : i < a
|
||||
· have h₃ : i - acc.size = (i - (acc.size + 1)) + 1 := by omega
|
||||
simp [h₃]
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} {i : Nat} {h} :
|
||||
(as.mapFinIdx f)[i] = f i (as[i]'(by simp at h; omega)) (by simp at h; omega) := by
|
||||
@[simp] theorem getElem_mapFinIdx {as : List α} {f : Fin as.length → α → β} {i : Nat} {h} :
|
||||
(as.mapFinIdx f)[i] = f ⟨i, by simp at h; omega⟩ (as[i]'(by simp at h; omega)) := by
|
||||
simp [mapFinIdx, getElem_mapFinIdx_go]
|
||||
|
||||
theorem mapFinIdx_eq_ofFn {as : List α} {f : (i : Nat) → α → (h : i < as.length) → β} :
|
||||
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] i.2 := by
|
||||
theorem mapFinIdx_eq_ofFn {as : List α} {f : Fin as.length → α → β} :
|
||||
as.mapFinIdx f = List.ofFn fun i : Fin as.length => f i as[i] := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {i : Nat} :
|
||||
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f i x (by simp [getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
@[simp] theorem getElem?_mapFinIdx {l : List α} {f : Fin l.length → α → β} {i : Nat} :
|
||||
(l.mapFinIdx f)[i]? = l[i]?.pbind fun x m => f ⟨i, by simp [getElem?_eq_some_iff] at m; exact m.1⟩ x := by
|
||||
simp only [getElem?_def, length_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_cons {l : List α} {a : α} {f : (i : Nat) → α → (h : i < l.length + 1) → β} :
|
||||
mapFinIdx (a :: l) f = f 0 a (by omega) :: mapFinIdx l (fun i a h => f (i + 1) a (by omega)) := by
|
||||
theorem mapFinIdx_cons {l : List α} {a : α} {f : Fin (l.length + 1) → α → β} :
|
||||
mapFinIdx (a :: l) f = f 0 a :: mapFinIdx l (fun i => f i.succ) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· rintro (_|i) h₁ h₂ <;> simp
|
||||
|
||||
theorem mapFinIdx_append {K L : List α} {f : (i : Nat) → α → (h : i < (K ++ L).length) → β} :
|
||||
theorem mapFinIdx_append {K L : List α} {f : Fin (K ++ L).length → α → β} :
|
||||
(K ++ L).mapFinIdx f =
|
||||
K.mapFinIdx (fun i a h => f i a (by simp; omega)) ++
|
||||
L.mapFinIdx (fun i a h => f (i + K.length) a (by simp; omega)) := by
|
||||
K.mapFinIdx (fun i => f (i.castLE (by simp))) ++ L.mapFinIdx (fun i => f ((i.natAdd K.length).cast (by simp))) := by
|
||||
apply ext_getElem
|
||||
· simp
|
||||
· intro i h₁ h₂
|
||||
@@ -119,60 +108,60 @@ theorem mapFinIdx_append {K L : List α} {f : (i : Nat) → α → (h : i < (K +
|
||||
simp only [getElem_mapFinIdx, length_mapFinIdx]
|
||||
split <;> rename_i h
|
||||
· rw [getElem_append_left]
|
||||
congr
|
||||
· simp only [Nat.not_lt] at h
|
||||
rw [getElem_append_right h]
|
||||
congr
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : (i : Nat) → α → (h : i < (l ++ [e]).length) → β}:
|
||||
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i a h => f i a (by simp; omega)) ++ [f l.length e (by simp)] := by
|
||||
@[simp] theorem mapFinIdx_concat {l : List α} {e : α} {f : Fin (l ++ [e]).length → α → β}:
|
||||
(l ++ [e]).mapFinIdx f = l.mapFinIdx (fun i => f (i.castLE (by simp))) ++ [f ⟨l.length, by simp⟩ e] := by
|
||||
simp [mapFinIdx_append]
|
||||
congr
|
||||
|
||||
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) → α → (h : i < 1) → β} :
|
||||
[a].mapFinIdx f = [f 0 a (by simp)] := by
|
||||
theorem mapFinIdx_singleton {a : α} {f : Fin 1 → α → β} :
|
||||
[a].mapFinIdx f = [f ⟨0, by simp⟩ a] := by
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_zipIdx_map {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
l.mapFinIdx f = l.zipIdx.attach.map
|
||||
fun ⟨⟨x, i⟩, m⟩ =>
|
||||
f i x (by rw [mk_mem_zipIdx_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
theorem mapFinIdx_eq_enum_map {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l.enum.attach.map
|
||||
fun ⟨⟨i, x⟩, m⟩ =>
|
||||
f ⟨i, by rw [mk_mem_enum_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1⟩ x := by
|
||||
apply ext_getElem <;> simp
|
||||
|
||||
@[deprecated mapFinIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapFinIdx_eq_zipWithIndex_map := @mapFinIdx_eq_zipIdx_map
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_eq_nil_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
theorem mapFinIdx_eq_nil_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = [] ↔ l = [] := by
|
||||
rw [mapFinIdx_eq_zipIdx_map, map_eq_nil_iff, attach_eq_nil_iff, zipIdx_eq_nil_iff]
|
||||
rw [mapFinIdx_eq_enum_map, map_eq_nil_iff, attach_eq_nil_iff, enum_eq_nil_iff]
|
||||
|
||||
theorem mapFinIdx_ne_nil_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
theorem mapFinIdx_ne_nil_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f ≠ [] ↔ l ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β}
|
||||
(h : b ∈ l.mapFinIdx f) : ∃ (i : Nat) (h : i < l.length), f i l[i] h = b := by
|
||||
rw [mapFinIdx_eq_zipIdx_map] at h
|
||||
theorem exists_of_mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length → α → β}
|
||||
(h : b ∈ l.mapFinIdx f) : ∃ (i : Fin l.length), f i l[i] = b := by
|
||||
rw [mapFinIdx_eq_enum_map] at h
|
||||
replace h := exists_of_mem_map h
|
||||
simp only [mem_attach, true_and, Subtype.exists, Prod.exists, mk_mem_zipIdx_iff_getElem?] at h
|
||||
obtain ⟨b, i, h, rfl⟩ := h
|
||||
simp only [mem_attach, true_and, Subtype.exists, Prod.exists, mk_mem_enum_iff_getElem?] at h
|
||||
obtain ⟨i, b, h, rfl⟩ := h
|
||||
rw [getElem?_eq_some_iff] at h
|
||||
obtain ⟨h', rfl⟩ := h
|
||||
exact ⟨i, h', rfl⟩
|
||||
exact ⟨⟨i, h'⟩, rfl⟩
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Nat) (h : i < l.length), f i l[i] h = b := by
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : List α} {f : Fin l.length → α → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Fin l.length), f i l[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
exact exists_of_mem_mapFinIdx h
|
||||
· rintro ⟨i, h, rfl⟩
|
||||
rw [mem_iff_getElem]
|
||||
exact ⟨i, by simpa using h, by simp⟩
|
||||
exact ⟨i, by simp⟩
|
||||
|
||||
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = b :: l₂ ↔
|
||||
∃ (a : α) (l₁ : List α) (w : l = a :: l₁),
|
||||
f 0 a (by simp [w]) = b ∧ l₁.mapFinIdx (fun i a h => f (i + 1) a (by simp [w]; omega)) = l₂ := by
|
||||
∃ (a : α) (l₁ : List α) (h : l = a :: l₁),
|
||||
f ⟨0, by simp [h]⟩ a = b ∧ l₁.mapFinIdx (fun i => f (i.succ.cast (by simp [h]))) = l₂ := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons x l' =>
|
||||
@@ -180,91 +169,39 @@ theorem mapFinIdx_eq_cons_iff {l : List α} {b : β} {f : (i : Nat) → α → (
|
||||
exists_and_left]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
refine ⟨x, l', ⟨rfl, rfl⟩, by simp⟩
|
||||
· rintro ⟨a, l', ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
|
||||
exact ⟨rfl, by simp⟩
|
||||
refine ⟨x, rfl, l', by simp⟩
|
||||
· rintro ⟨a, ⟨rfl, h⟩, ⟨_, ⟨rfl, rfl⟩, h⟩⟩
|
||||
exact ⟨rfl, h⟩
|
||||
|
||||
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
theorem mapFinIdx_eq_cons_iff' {l : List α} {b : β} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = b :: l₂ ↔
|
||||
l.head?.pbind (fun x m => (f 0 x (by cases l <;> simp_all))) = some b ∧
|
||||
l.tail?.attach.map (fun ⟨t, m⟩ => t.mapFinIdx fun i a h => f (i + 1) a (by cases l <;> simp_all)) = some l₂ := by
|
||||
l.head?.pbind (fun x m => (f ⟨0, by cases l <;> simp_all⟩ x)) = some b ∧
|
||||
l.tail?.attach.map (fun ⟨t, m⟩ => t.mapFinIdx fun i => f (i.succ.cast (by cases l <;> simp_all))) = some l₂ := by
|
||||
cases l <;> simp
|
||||
|
||||
theorem mapFinIdx_eq_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
l.mapFinIdx f = l' ↔ ∃ h : l'.length = l.length, ∀ (i : Nat) (h : i < l.length), l'[i] = f i l[i] h := by
|
||||
theorem mapFinIdx_eq_iff {l : List α} {f : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l' ↔ ∃ h : l'.length = l.length, ∀ (i : Nat) (h : i < l.length), l'[i] = f ⟨i, h⟩ l[i] := by
|
||||
constructor
|
||||
· rintro rfl
|
||||
simp
|
||||
· rintro ⟨h, w⟩
|
||||
apply ext_getElem <;> simp_all
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_singleton_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {b : β} :
|
||||
l.mapFinIdx f = [b] ↔ ∃ (a : α) (w : l = [a]), f 0 a (by simp [w]) = b := by
|
||||
simp [mapFinIdx_eq_cons_iff]
|
||||
|
||||
theorem mapFinIdx_eq_append_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
l.mapFinIdx f = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : List α) (l₂' : List α) (w : l = l₁' ++ l₂'),
|
||||
l₁'.mapFinIdx (fun i a h => f i a (by simp [w]; omega)) = l₁ ∧
|
||||
l₂'.mapFinIdx (fun i a h => f (i + l₁'.length) a (by simp [w]; omega)) = l₂ := by
|
||||
rw [mapFinIdx_eq_iff]
|
||||
constructor
|
||||
· intro ⟨h, w⟩
|
||||
simp only [length_append] at h
|
||||
refine ⟨l.take l₁.length, l.drop l₁.length, by simp, ?_⟩
|
||||
constructor
|
||||
· apply ext_getElem
|
||||
· simp
|
||||
omega
|
||||
· intro i hi₁ hi₂
|
||||
simp only [getElem_mapFinIdx, getElem_take]
|
||||
specialize w i (by omega)
|
||||
rw [getElem_append_left hi₂] at w
|
||||
exact w.symm
|
||||
· apply ext_getElem
|
||||
· simp
|
||||
omega
|
||||
· intro i hi₁ hi₂
|
||||
simp only [getElem_mapFinIdx, getElem_take]
|
||||
simp only [length_take, getElem_drop]
|
||||
have : l₁.length ≤ l.length := by omega
|
||||
simp only [Nat.min_eq_left this, Nat.add_comm]
|
||||
specialize w (i + l₁.length) (by omega)
|
||||
rw [getElem_append_right (by omega)] at w
|
||||
simpa using w.symm
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
refine ⟨by simp, fun i h => ?_⟩
|
||||
rw [getElem_append]
|
||||
split <;> rename_i h'
|
||||
· simp [getElem_append_left (by simpa using h')]
|
||||
· simp only [length_mapFinIdx, Nat.not_lt] at h'
|
||||
have : i - l₁'.length + l₁'.length = i := by omega
|
||||
simp [getElem_append_right h', this]
|
||||
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : (i : Nat) → α → (h : i < l.length) → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Nat) (h : i < l.length), f i l[i] h = g i l[i] h := by
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : List α} {f g : Fin l.length → α → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Fin l.length), f i l[i] = g i l[i] := by
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp [Fin.forall_iff]
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : List α}
|
||||
{f : (i : Nat) → α → (h : i < l.length) → β}
|
||||
{g : (i : Nat) → β → (h : i < (l.mapFinIdx f).length) → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) (by simpa)) := by
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : List α} {f : Fin l.length → α → β} {g : Fin _ → β → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i => g (i.cast (by simp)) ∘ f i) := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {b : β} :
|
||||
l.mapFinIdx f = replicate l.length b ↔ ∀ (i : Nat) (h : i < l.length), f i l[i] h = b := by
|
||||
rw [eq_replicate_iff, length_mapFinIdx]
|
||||
simp only [mem_mapFinIdx, forall_exists_index, true_and]
|
||||
constructor
|
||||
· intro w i h
|
||||
exact w (f i l[i] h) i h rfl
|
||||
· rintro w b i h rfl
|
||||
exact w i h
|
||||
theorem mapFinIdx_eq_replicate_iff {l : List α} {f : Fin l.length → α → β} {b : β} :
|
||||
l.mapFinIdx f = replicate l.length b ↔ ∀ (i : Fin l.length), f i l[i] = b := by
|
||||
simp [eq_replicate_iff, length_mapFinIdx, mem_mapFinIdx, forall_exists_index, true_and]
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {l : List α} {f : (i : Nat) → α → (h : i < l.reverse.length) → β} :
|
||||
l.reverse.mapFinIdx f =
|
||||
(l.mapFinIdx (fun i a h => f (l.length - 1 - i) a (by simp; omega))).reverse := by
|
||||
@[simp] theorem mapFinIdx_reverse {l : List α} {f : Fin l.reverse.length → α → β} :
|
||||
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i => f ⟨l.length - 1 - i, by simp; omega⟩)).reverse := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
intro i h
|
||||
congr
|
||||
@@ -325,28 +262,26 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {arr : Array β} {i : Nat},
|
||||
rw [← getElem?_eq_getElem, getElem?_mapIdx, getElem?_eq_getElem (by simpa using h)]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : (i : Nat) → α → (h : i < l.length) → β} {g : Nat → α → β}
|
||||
(h : ∀ (i : Nat) (h : i < l.length), f i l[i] h = g i l[i]) :
|
||||
@[simp] theorem mapFinIdx_eq_mapIdx {l : List α} {f : Fin l.length → α → β} {g : Nat → α → β}
|
||||
(h : ∀ (i : Fin l.length), f i l[i] = g i l[i]) :
|
||||
l.mapFinIdx f = l.mapIdx g := by
|
||||
simp_all [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mapFinIdx {l : List α} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
|
||||
l.mapIdx f = l.mapFinIdx (fun i => f i) := by
|
||||
simp [mapFinIdx_eq_mapIdx]
|
||||
|
||||
theorem mapIdx_eq_zipIdx_map {l : List α} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.zipIdx.map (fun ⟨a, i⟩ => f i a) := by
|
||||
theorem mapIdx_eq_enum_map {l : List α} :
|
||||
l.mapIdx f = l.enum.map (Function.uncurry f) := by
|
||||
ext1 i
|
||||
simp only [getElem?_mapIdx, Option.map, getElem?_map, getElem?_zipIdx]
|
||||
simp only [getElem?_mapIdx, Option.map, getElem?_map, getElem?_enum]
|
||||
split <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-21")]
|
||||
abbrev mapIdx_eq_enum_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_cons {l : List α} {a : α} :
|
||||
mapIdx f (a :: l) = f 0 a :: mapIdx (fun i => f (i + 1)) l := by
|
||||
simp [mapIdx_eq_zipIdx_map, List.zipIdx_succ]
|
||||
simp [mapIdx_eq_enum_map, enum_eq_zip_range, map_uncurry_zip_eq_zipWith,
|
||||
range_succ_eq_map, zipWith_map_left]
|
||||
|
||||
theorem mapIdx_append {K L : List α} :
|
||||
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.length) := by
|
||||
@@ -363,7 +298,7 @@ theorem mapIdx_singleton {a : α} : mapIdx f [a] = [f 0 a] := by
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_eq_nil_iff {l : List α} : List.mapIdx f l = [] ↔ l = [] := by
|
||||
rw [List.mapIdx_eq_zipIdx_map, List.map_eq_nil_iff, List.zipIdx_eq_nil_iff]
|
||||
rw [List.mapIdx_eq_enum_map, List.map_eq_nil_iff, List.enum_eq_nil_iff]
|
||||
|
||||
theorem mapIdx_ne_nil_iff {l : List α} :
|
||||
List.mapIdx f l ≠ [] ↔ l ≠ [] := by
|
||||
@@ -393,10 +328,6 @@ theorem mapIdx_eq_cons_iff' {l : List α} {b : β} :
|
||||
l.head?.map (f 0) = some b ∧ l.tail?.map (mapIdx fun i => f (i + 1)) = some l₂ := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_eq_singleton_iff {l : List α} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f l = [b] ↔ ∃ (a : α), l = [a] ∧ f 0 a = b := by
|
||||
simp [mapIdx_eq_cons_iff]
|
||||
|
||||
theorem mapIdx_eq_iff {l : List α} : mapIdx f l = l' ↔ ∀ i : Nat, l'[i]? = l[i]?.map (f i) := by
|
||||
constructor
|
||||
· intro w i
|
||||
@@ -405,19 +336,6 @@ theorem mapIdx_eq_iff {l : List α} : mapIdx f l = l' ↔ ∀ i : Nat, l'[i]? =
|
||||
ext1 i
|
||||
simp [w]
|
||||
|
||||
theorem mapIdx_eq_append_iff {l : List α} :
|
||||
mapIdx f l = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : List α) (l₂' : List α), l = l₁' ++ l₂' ∧
|
||||
mapIdx f l₁' = l₁ ∧
|
||||
mapIdx (fun i => f (i + l₁'.length)) l₂' = l₂ := by
|
||||
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_append_iff]
|
||||
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
|
||||
constructor
|
||||
· rintro ⟨l₁, rfl, l₂, rfl, h⟩
|
||||
refine ⟨l₁, l₂, by simp_all⟩
|
||||
· rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
|
||||
refine ⟨l₁, rfl, l₂, by simp_all⟩
|
||||
|
||||
theorem mapIdx_eq_mapIdx_iff {l : List α} :
|
||||
mapIdx f l = mapIdx g l ↔ ∀ i : Nat, (h : i < l.length) → f i l[i] = g i l[i] := by
|
||||
constructor
|
||||
|
||||
@@ -65,11 +65,6 @@ theorem getElem_eraseIdx_of_ge (l : List α) (i : Nat) (j : Nat) (h : j < (l.era
|
||||
rw [getElem_eraseIdx, dif_neg]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_eq_dropLast (l : List α) (i : Nat) (h : i + 1 = l.length) :
|
||||
l.eraseIdx i = l.dropLast := by
|
||||
simp [eraseIdx_eq_take_drop_succ, h]
|
||||
rw [take_eq_dropLast h]
|
||||
|
||||
theorem eraseIdx_set_eq {l : List α} {i : Nat} {a : α} :
|
||||
(l.set i a).eraseIdx i = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
|
||||
@@ -37,14 +37,14 @@ theorem find?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {b : α} :
|
||||
|
||||
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {p q : α → Bool} (w : ∀ x ∈ xs, p x → q x) {i : Nat}
|
||||
(h : xs.findIdx? p = some i) : ∃ j, j ≤ i ∧ xs.findIdx? q = some j := by
|
||||
simp only [findIdx?_eq_findSome?_zipIdx] at h
|
||||
simp only [findIdx?_eq_findSome?_enum] at h
|
||||
rw [findSome?_eq_some_iff] at h
|
||||
simp only [Option.ite_none_right_eq_some, Option.some.injEq, ite_eq_right_iff, reduceCtorEq,
|
||||
imp_false, Bool.not_eq_true, Prod.forall, exists_and_right, Prod.exists] at h
|
||||
obtain ⟨h, h₁, b, ⟨es, h₂⟩, ⟨hb, rfl⟩, h₃⟩ := h
|
||||
rw [zipIdx_eq_append_iff] at h₂
|
||||
rw [enum_eq_enumFrom, enumFrom_eq_append_iff] at h₂
|
||||
obtain ⟨l₁', l₂', rfl, rfl, h₂⟩ := h₂
|
||||
rw [eq_comm, zipIdx_eq_cons_iff] at h₂
|
||||
rw [eq_comm, enumFrom_eq_cons_iff] at h₂
|
||||
obtain ⟨a, as, rfl, h₂, rfl⟩ := h₂
|
||||
simp only [Nat.zero_add, Prod.mk.injEq] at h₂
|
||||
obtain ⟨rfl, rfl⟩ := h₂
|
||||
|
||||
@@ -76,12 +76,6 @@ theorem eraseIdx_modifyHead_zero {f : α → α} {l : List α} :
|
||||
|
||||
@[simp] theorem modifyHead_id : modifyHead (id : α → α) = id := by funext l; cases l <;> simp
|
||||
|
||||
@[simp] theorem modifyHead_dropLast {l : List α} {f : α → α} :
|
||||
l.dropLast.modifyHead f = (l.modifyHead f).dropLast := by
|
||||
rcases l with _|⟨a, l⟩
|
||||
· simp
|
||||
· rcases l with _|⟨b, l⟩ <;> simp
|
||||
|
||||
/-! ### modifyTailIdx -/
|
||||
|
||||
@[simp] theorem modifyTailIdx_id : ∀ n (l : List α), l.modifyTailIdx id n = l
|
||||
|
||||
@@ -195,32 +195,24 @@ theorem erase_range : (range n).erase i = range (min n i) ++ range' (i + 1) (n -
|
||||
|
||||
/-! ### iota -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_reverse_range' : ∀ n : Nat, iota n = reverse (range' 1 n)
|
||||
| 0 => rfl
|
||||
| n + 1 => by simp [iota, range'_concat, iota_eq_reverse_range' n, reverse_append, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
|
||||
@[simp] theorem length_iota (n : Nat) : length (iota n) = n := by simp [iota_eq_reverse_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
|
||||
@[simp] theorem iota_eq_nil {n : Nat} : iota n = [] ↔ n = 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_ne_nil {n : Nat} : iota n ≠ [] ↔ n ≠ 0 := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
@[simp]
|
||||
theorem mem_iota {m n : Nat} : m ∈ iota n ↔ 0 < m ∧ m ≤ n := by
|
||||
simp [iota_eq_reverse_range', Nat.add_comm, Nat.lt_succ]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem iota_inj : iota n = iota n' ↔ n = n' := by
|
||||
@[simp] theorem iota_inj : iota n = iota n' ↔ n = n' := by
|
||||
constructor
|
||||
· intro h
|
||||
have h' := congrArg List.length h
|
||||
@@ -229,7 +221,6 @@ theorem iota_inj : iota n = iota n' ↔ n = n' := by
|
||||
· rintro rfl
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n - 1) := by
|
||||
simp [iota_eq_reverse_range']
|
||||
simp [range'_eq_append_iff, reverse_eq_iff]
|
||||
@@ -243,7 +234,6 @@ theorem iota_eq_cons_iff : iota n = a :: xs ↔ n = a ∧ 0 < n ∧ xs = iota (n
|
||||
rw [eq_comm, range'_eq_singleton]
|
||||
omega
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (range' (k + 1) (n - k)).reverse ∧ ys = iota k := by
|
||||
simp only [iota_eq_reverse_range']
|
||||
rw [reverse_eq_append_iff]
|
||||
@@ -255,52 +245,42 @@ theorem iota_eq_append_iff : iota n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs = (rang
|
||||
· rintro ⟨k, h, rfl, rfl⟩
|
||||
exact ⟨k, by simp; omega⟩
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem pairwise_gt_iota (n : Nat) : Pairwise (· > ·) (iota n) := by
|
||||
simpa only [iota_eq_reverse_range', pairwise_reverse] using pairwise_lt_range' 1 n
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem nodup_iota (n : Nat) : Nodup (iota n) :=
|
||||
(pairwise_gt_iota n).imp Nat.ne_of_gt
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
|
||||
@[simp] theorem head?_iota (n : Nat) : (iota n).head? = if n = 0 then none else some n := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
|
||||
@[simp] theorem head_iota (n : Nat) (h) : (iota n).head h = n := by
|
||||
cases n with
|
||||
| zero => simp at h
|
||||
| succ n => simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
|
||||
@[simp] theorem tail_iota (n : Nat) : (iota n).tail = iota (n - 1) := by
|
||||
cases n <;> simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem reverse_iota : reverse (iota n) = range' 1 n := by
|
||||
@[simp] theorem reverse_iota : reverse (iota n) = range' 1 n := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
| succ n ih =>
|
||||
rw [iota_succ, reverse_cons, ih, range'_1_concat, Nat.add_comm]
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
|
||||
@[simp] theorem getLast?_iota (n : Nat) : (iota n).getLast? = if n = 0 then none else some 1 := by
|
||||
rw [getLast?_eq_head?_reverse]
|
||||
simp [head?_range']
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
|
||||
@[simp] theorem getLast_iota (n : Nat) (h) : (iota n).getLast h = 1 := by
|
||||
rw [getLast_eq_head_reverse]
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20")]
|
||||
theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = none ↔ ∀ i, 0 < i → i ≤ n → !p i := by
|
||||
simp
|
||||
|
||||
@[deprecated "Use `(List.range' 1 n).reverse` instead of `iota n`." (since := "2025-01-20"), simp]
|
||||
theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
@@ -337,168 +317,25 @@ theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
· omega
|
||||
· omega
|
||||
|
||||
end
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem zipIdx_singleton (x : α) (k : Nat) : zipIdx [x] k = [(x, k)] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem head?_zipIdx (l : List α) (k : Nat) :
|
||||
(zipIdx l k).head? = l.head?.map fun a => (a, k) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[simp] theorem getLast?_zipIdx (l : List α) (k : Nat) :
|
||||
(zipIdx l k).getLast? = l.getLast?.map fun a => (a, k + l.length - 1) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp; omega
|
||||
|
||||
theorem mk_add_mem_zipIdx_iff_getElem? {k i : Nat} {x : α} {l : List α} :
|
||||
(x, k + i) ∈ zipIdx l k ↔ l[i]? = some x := by
|
||||
simp [mem_iff_getElem?, and_left_comm]
|
||||
|
||||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {k i : Nat} {x : α} {l : List α} :
|
||||
(x, i) ∈ zipIdx l k ↔ k ≤ i ∧ l[i - k]? = some x := by
|
||||
if h : k ≤ i then
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨i, rfl⟩
|
||||
simp [mk_add_mem_zipIdx_iff_getElem?, Nat.add_sub_cancel_left]
|
||||
else
|
||||
have : ∀ m, k + m ≠ i := by rintro _ rfl; simp at h
|
||||
simp [h, mem_iff_get?, this]
|
||||
|
||||
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mk_mem_zipIdx_iff_getElem? {i : Nat} {x : α} {l : List α} : (x, i) ∈ zipIdx l ↔ l[i]? = x := by
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : List α} {k : Nat} :
|
||||
x ∈ zipIdx l k ↔ k ≤ x.2 ∧ l[x.2 - k]? = some x.1 := by
|
||||
cases x
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {l : List α} : x ∈ zipIdx l ↔ l[x.2]? = some x.1 := by
|
||||
cases x
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
theorem le_snd_of_mem_zipIdx {x : α × Nat} {k : Nat} {l : List α} (h : x ∈ zipIdx l k) :
|
||||
k ≤ x.2 :=
|
||||
(mk_mem_zipIdx_iff_le_and_getElem?_sub.1 h).1
|
||||
|
||||
theorem snd_lt_add_of_mem_zipIdx {x : α × Nat} {l : List α} {k : Nat} (h : x ∈ zipIdx l k) :
|
||||
x.2 < k + length l := by
|
||||
rcases mem_iff_get.1 h with ⟨i, rfl⟩
|
||||
simpa using i.isLt
|
||||
|
||||
theorem snd_lt_of_mem_zipIdx {x : α × Nat} {l : List α} {k : Nat} (h : x ∈ l.zipIdx k) : x.2 < l.length + k := by
|
||||
simpa [Nat.add_comm] using snd_lt_add_of_mem_zipIdx h
|
||||
|
||||
theorem map_zipIdx (f : α → β) (l : List α) (k : Nat) :
|
||||
map (Prod.map f id) (zipIdx l k) = zipIdx (l.map f) k := by
|
||||
induction l generalizing k <;> simp_all
|
||||
|
||||
theorem fst_mem_of_mem_zipIdx {x : α × Nat} {l : List α} {k : Nat} (h : x ∈ zipIdx l k) : x.1 ∈ l :=
|
||||
zipIdx_map_fst k l ▸ mem_map_of_mem _ h
|
||||
|
||||
theorem fst_eq_of_mem_zipIdx {x : α × Nat} {l : List α} {k : Nat} (h : x ∈ zipIdx l k) :
|
||||
x.1 = l[x.2 - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) := by
|
||||
induction l generalizing k with
|
||||
| nil => cases h
|
||||
| cons hd tl ih =>
|
||||
cases h with
|
||||
| head h => simp
|
||||
| tail h m =>
|
||||
specialize ih m
|
||||
have : x.2 - k = x.2 - (k + 1) + 1 := by
|
||||
have := le_snd_of_mem_zipIdx m
|
||||
omega
|
||||
simp [this, ih]
|
||||
|
||||
theorem mem_zipIdx {x : α} {i : Nat} {xs : List α} {k : Nat} (h : (x, i) ∈ xs.zipIdx k) :
|
||||
k ≤ i ∧ i < k + xs.length ∧
|
||||
x = xs[i - k]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
|
||||
⟨le_snd_of_mem_zipIdx h, snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h⟩
|
||||
|
||||
/-- Variant of `mem_zipIdx` specialized at `k = 0`. -/
|
||||
theorem mem_zipIdx' {x : α} {i : Nat} {xs : List α} (h : (x, i) ∈ xs.zipIdx) :
|
||||
i < xs.length ∧ x = xs[i]'(by have := le_snd_of_mem_zipIdx h; have := snd_lt_add_of_mem_zipIdx h; omega) :=
|
||||
⟨by simpa using snd_lt_add_of_mem_zipIdx h, fst_eq_of_mem_zipIdx h⟩
|
||||
|
||||
theorem zipIdx_map (l : List α) (k : Nat) (f : α → β) :
|
||||
zipIdx (l.map f) k = (zipIdx l k).map (Prod.map f id) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons hd tl IH =>
|
||||
rw [map_cons, zipIdx_cons', zipIdx_cons', map_cons, map_map, IH, map_map]
|
||||
rfl
|
||||
|
||||
theorem zipIdx_append (xs ys : List α) (k : Nat) :
|
||||
zipIdx (xs ++ ys) k = zipIdx xs k ++ zipIdx ys (k + xs.length) := by
|
||||
induction xs generalizing ys k with
|
||||
| nil => simp
|
||||
| cons x xs IH =>
|
||||
rw [cons_append, zipIdx_cons, IH, ← cons_append, ← zipIdx_cons, length, Nat.add_right_comm,
|
||||
Nat.add_assoc]
|
||||
|
||||
theorem zipIdx_eq_cons_iff {l : List α} {k : Nat} :
|
||||
zipIdx l k = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (a, k) ∧ l' = zipIdx as (k + 1) := by
|
||||
rw [zipIdx_eq_zip_range', zip_eq_cons_iff]
|
||||
constructor
|
||||
· rintro ⟨l₁, l₂, rfl, h, rfl⟩
|
||||
rw [range'_eq_cons_iff] at h
|
||||
obtain ⟨rfl, -, rfl⟩ := h
|
||||
exact ⟨x.1, l₁, by simp [zipIdx_eq_zip_range']⟩
|
||||
· rintro ⟨a, as, rfl, rfl, rfl⟩
|
||||
refine ⟨as, range' (k+1) as.length, ?_⟩
|
||||
simp [zipIdx_eq_zip_range', range'_succ]
|
||||
|
||||
theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
|
||||
zipIdx l k = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = zipIdx l₁' k ∧ l₂ = zipIdx l₂' (k + l₁'.length) := by
|
||||
rw [zipIdx_eq_zip_range', zip_eq_append_iff]
|
||||
constructor
|
||||
· rintro ⟨w, x, y, z, h, rfl, h', rfl, rfl⟩
|
||||
rw [range'_eq_append_iff] at h'
|
||||
obtain ⟨k, -, rfl, rfl⟩ := h'
|
||||
simp only [length_range'] at h
|
||||
obtain rfl := h
|
||||
refine ⟨w, x, rfl, ?_⟩
|
||||
simp only [zipIdx_eq_zip_range', length_append, true_and]
|
||||
congr
|
||||
omega
|
||||
· rintro ⟨l₁', l₂', rfl, rfl, rfl⟩
|
||||
simp only [zipIdx_eq_zip_range']
|
||||
refine ⟨l₁', l₂', range' k l₁'.length, range' (k + l₁'.length) l₂'.length, ?_⟩
|
||||
simp [Nat.add_comm]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enumFrom_singleton (x : α) (n : Nat) : enumFrom n [x] = [(n, x)] :=
|
||||
rfl
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem head?_enumFrom (n : Nat) (l : List α) :
|
||||
@[simp] theorem head?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).head? = l.head?.map fun a => (n, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enumFrom (n : Nat) (l : List α) :
|
||||
@[simp] theorem getLast?_enumFrom (n : Nat) (l : List α) :
|
||||
(enumFrom n l).getLast? = l.getLast?.map fun a => (n + l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
cases l <;> simp; omega
|
||||
|
||||
@[deprecated mk_add_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_add_mem_enumFrom_iff_getElem? {n i : Nat} {x : α} {l : List α} :
|
||||
(n + i, x) ∈ enumFrom n l ↔ l[i]? = some x := by
|
||||
simp [mem_iff_get?]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_le_and_getElem?_sub (since := "2025-01-21")]
|
||||
theorem mk_mem_enumFrom_iff_le_and_getElem?_sub {n i : Nat} {x : α} {l : List α} :
|
||||
(i, x) ∈ enumFrom n l ↔ n ≤ i ∧ l[i - n]? = x := by
|
||||
if h : n ≤ i then
|
||||
@@ -508,27 +345,22 @@ theorem mk_mem_enumFrom_iff_le_and_getElem?_sub {n i : Nat} {x : α} {l : List
|
||||
have : ∀ k, n + k ≠ i := by rintro k rfl; simp at h
|
||||
simp [h, mem_iff_get?, this]
|
||||
|
||||
@[deprecated le_snd_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem le_fst_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
n ≤ x.1 :=
|
||||
(mk_mem_enumFrom_iff_le_and_getElem?_sub.1 h).1
|
||||
|
||||
@[deprecated snd_lt_add_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_add_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.1 < n + length l := by
|
||||
rcases mem_iff_get.1 h with ⟨i, rfl⟩
|
||||
simpa using i.isLt
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enumFrom (f : α → β) (n : Nat) (l : List α) :
|
||||
map (Prod.map id f) (enumFrom n l) = enumFrom n (map f l) := by
|
||||
induction l generalizing n <;> simp_all
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) : x.2 ∈ l :=
|
||||
enumFrom_map_snd n l ▸ mem_map_of_mem _ h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x ∈ enumFrom n l) :
|
||||
x.2 = l[x.1 - n]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) := by
|
||||
induction l generalizing n with
|
||||
@@ -543,13 +375,11 @@ theorem snd_eq_of_mem_enumFrom {x : Nat × α} {n : Nat} {l : List α} (h : x
|
||||
omega
|
||||
simp [this, ih]
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enumFrom {x : α} {i j : Nat} {xs : List α} (h : (i, x) ∈ xs.enumFrom j) :
|
||||
j ≤ i ∧ i < j + xs.length ∧
|
||||
x = xs[i - j]'(by have := le_fst_of_mem_enumFrom h; have := fst_lt_add_of_mem_enumFrom h; omega) :=
|
||||
⟨le_fst_of_mem_enumFrom h, fst_lt_add_of_mem_enumFrom h, snd_eq_of_mem_enumFrom h⟩
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enumFrom_map (n : Nat) (l : List α) (f : α → β) :
|
||||
enumFrom n (l.map f) = (enumFrom n l).map (Prod.map id f) := by
|
||||
induction l with
|
||||
@@ -558,7 +388,6 @@ theorem enumFrom_map (n : Nat) (l : List α) (f : α → β) :
|
||||
rw [map_cons, enumFrom_cons', enumFrom_cons', map_cons, map_map, IH, map_map]
|
||||
rfl
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enumFrom_append (xs ys : List α) (n : Nat) :
|
||||
enumFrom n (xs ++ ys) = enumFrom n xs ++ enumFrom (n + xs.length) ys := by
|
||||
induction xs generalizing ys n with
|
||||
@@ -567,7 +396,6 @@ theorem enumFrom_append (xs ys : List α) (n : Nat) :
|
||||
rw [cons_append, enumFrom_cons, IH, ← cons_append, ← enumFrom_cons, length, Nat.add_right_comm,
|
||||
Nat.add_assoc]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_cons_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (n, a) ∧ l' = enumFrom (n + 1) as := by
|
||||
rw [enumFrom_eq_zip_range', zip_eq_cons_iff]
|
||||
@@ -580,7 +408,6 @@ theorem enumFrom_eq_cons_iff {l : List α} {n : Nat} :
|
||||
refine ⟨range' (n+1) as.length, as, ?_⟩
|
||||
simp [enumFrom_eq_zip_range', range'_succ]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
l.enumFrom n = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enumFrom n ∧ l₂ = l₂'.enumFrom (n + l₁'.length) := by
|
||||
@@ -600,113 +427,89 @@ theorem enumFrom_eq_append_iff {l : List α} {n : Nat} :
|
||||
refine ⟨range' n l₁'.length, range' (n + l₁'.length) l₂'.length, l₁', l₂', ?_⟩
|
||||
simp [Nat.add_comm]
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enum_eq_nil_iff {l : List α} : List.enum l = [] ↔ l = [] := enumFrom_eq_nil
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2024-11-04")]
|
||||
@[deprecated enum_eq_nil_iff (since := "2024-11-04")]
|
||||
theorem enum_eq_nil {l : List α} : List.enum l = [] ↔ l = [] := enum_eq_nil_iff
|
||||
|
||||
@[deprecated zipIdx_singleton (since := "2025-01-21"), simp]
|
||||
theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl
|
||||
@[simp] theorem enum_singleton (x : α) : enum [x] = [(0, x)] := rfl
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enum_length : (enum l).length = l.length :=
|
||||
@[simp] theorem enum_length : (enum l).length = l.length :=
|
||||
enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem getElem?_enum (l : List α) (n : Nat) : (enum l)[n]? = l[n]?.map fun a => (n, a) := by
|
||||
rw [enum, getElem?_enumFrom, Nat.zero_add]
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem getElem_enum (l : List α) (i : Nat) (h : i < l.enum.length) :
|
||||
l.enum[i] = (i, l[i]'(by simpa [enum_length] using h)) := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated head?_zipIdx (since := "2025-01-21"), simp] theorem head?_enum (l : List α) :
|
||||
@[simp] theorem head?_enum (l : List α) :
|
||||
l.enum.head? = l.head?.map fun a => (0, a) := by
|
||||
simp [head?_eq_getElem?]
|
||||
|
||||
@[deprecated getLast?_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem getLast?_enum (l : List α) :
|
||||
@[simp] theorem getLast?_enum (l : List α) :
|
||||
l.enum.getLast? = l.getLast?.map fun a => (l.length - 1, a) := by
|
||||
simp [getLast?_eq_getElem?]
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem tail_enum (l : List α) : (enum l).tail = enumFrom 1 l.tail := by
|
||||
@[simp] theorem tail_enum (l : List α) : (enum l).tail = enumFrom 1 l.tail := by
|
||||
simp [enum]
|
||||
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mk_mem_enum_iff_getElem? {i : Nat} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l[i]? = x := by
|
||||
simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub]
|
||||
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-21")]
|
||||
theorem mem_enum_iff_getElem? {x : Nat × α} {l : List α} : x ∈ enum l ↔ l[x.1]? = some x.2 :=
|
||||
mk_mem_enum_iff_getElem?
|
||||
|
||||
@[deprecated snd_lt_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem fst_lt_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.1 < length l := by
|
||||
simpa using fst_lt_add_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_mem_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_mem_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) : x.2 ∈ l :=
|
||||
snd_mem_of_mem_enumFrom h
|
||||
|
||||
@[deprecated fst_eq_of_mem_zipIdx (since := "2025-01-21")]
|
||||
theorem snd_eq_of_mem_enum {x : Nat × α} {l : List α} (h : x ∈ enum l) :
|
||||
x.2 = l[x.1]'(fst_lt_of_mem_enum h) :=
|
||||
snd_eq_of_mem_enumFrom h
|
||||
|
||||
@[deprecated mem_zipIdx (since := "2025-01-21")]
|
||||
theorem mem_enum {x : α} {i : Nat} {xs : List α} (h : (i, x) ∈ xs.enum) :
|
||||
i < xs.length ∧ x = xs[i]'(fst_lt_of_mem_enum h) :=
|
||||
by simpa using mem_enumFrom h
|
||||
|
||||
@[deprecated map_zipIdx (since := "2025-01-21")]
|
||||
theorem map_enum (f : α → β) (l : List α) : map (Prod.map id f) (enum l) = enum (map f l) :=
|
||||
map_enumFrom f 0 l
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by
|
||||
@[simp] theorem enum_map_fst (l : List α) : map Prod.fst (enum l) = range l.length := by
|
||||
simp only [enum, enumFrom_map_fst, range_eq_range']
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enum_map_snd (l : List α) : map Prod.snd (enum l) = l :=
|
||||
enumFrom_map_snd _ _
|
||||
|
||||
@[deprecated zipIdx_map (since := "2025-01-21")]
|
||||
theorem enum_map (l : List α) (f : α → β) : (l.map f).enum = l.enum.map (Prod.map id f) :=
|
||||
enumFrom_map _ _ _
|
||||
|
||||
@[deprecated zipIdx_append (since := "2025-01-21")]
|
||||
theorem enum_append (xs ys : List α) : enum (xs ++ ys) = enum xs ++ enumFrom xs.length ys := by
|
||||
simp [enum, enumFrom_append]
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enum_eq_zip_range (l : List α) : l.enum = (range l.length).zip l :=
|
||||
zip_of_prod (enum_map_fst _) (enum_map_snd _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem unzip_enum_eq_prod (l : List α) : l.enum.unzip = (range l.length, l) := by
|
||||
simp only [enum_eq_zip_range, unzip_zip, length_range]
|
||||
|
||||
@[deprecated zipIdx_eq_cons_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_cons_iff {l : List α} :
|
||||
l.enum = x :: l' ↔ ∃ a as, l = a :: as ∧ x = (0, a) ∧ l' = enumFrom 1 as := by
|
||||
rw [enum, enumFrom_eq_cons_iff]
|
||||
|
||||
@[deprecated zipIdx_eq_append_iff (since := "2025-01-21")]
|
||||
theorem enum_eq_append_iff {l : List α} :
|
||||
l.enum = l₁ ++ l₂ ↔
|
||||
∃ l₁' l₂', l = l₁' ++ l₂' ∧ l₁ = l₁'.enum ∧ l₂ = l₂'.enumFrom l₁'.length := by
|
||||
simp [enum, enumFrom_eq_append_iff]
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -47,16 +47,41 @@ length `> i`. Version designed to rewrite from the small list to the big list. -
|
||||
L[i]'(Nat.lt_of_lt_of_le h (length_take_le' _ _)) := by
|
||||
rw [length_take, Nat.lt_min] at h; rw [getElem_take' L _ h.1]
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the big list to the small list. -/
|
||||
@[deprecated getElem_take' (since := "2024-06-12")]
|
||||
theorem get_take (L : List α) {i j : Nat} (hi : i < L.length) (hj : i < j) :
|
||||
get L ⟨i, hi⟩ = get (L.take j) ⟨i, length_take .. ▸ Nat.lt_min.mpr ⟨hj, hi⟩⟩ := by
|
||||
simp
|
||||
|
||||
/-- The `i`-th element of a list coincides with the `i`-th element of any of its prefixes of
|
||||
length `> i`. Version designed to rewrite from the small list to the big list. -/
|
||||
@[deprecated getElem_take (since := "2024-06-12")]
|
||||
theorem get_take' (L : List α) {j i} :
|
||||
get (L.take j) i =
|
||||
get L ⟨i.1, Nat.lt_of_lt_of_le i.2 (length_take_le' _ _)⟩ := by
|
||||
simp [getElem_take]
|
||||
|
||||
theorem getElem?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||||
(l.take n)[m]? = none :=
|
||||
getElem?_eq_none <| Nat.le_trans (length_take_le _ _) h
|
||||
|
||||
@[deprecated getElem?_take_eq_none (since := "2024-06-12")]
|
||||
theorem get?_take_eq_none {l : List α} {n m : Nat} (h : n ≤ m) :
|
||||
(l.take n).get? m = none := by
|
||||
simp [getElem?_take_eq_none h]
|
||||
|
||||
theorem getElem?_take {l : List α} {n m : Nat} :
|
||||
(l.take n)[m]? = if m < n then l[m]? else none := by
|
||||
split
|
||||
· next h => exact getElem?_take_of_lt h
|
||||
· next h => exact getElem?_take_eq_none (Nat.le_of_not_lt h)
|
||||
|
||||
@[deprecated getElem?_take (since := "2024-06-12")]
|
||||
theorem get?_take_eq_if {l : List α} {n m : Nat} :
|
||||
(l.take n).get? m = if m < n then l.get? m else none := by
|
||||
simp [getElem?_take]
|
||||
|
||||
theorem head?_take {l : List α} {n : Nat} :
|
||||
(l.take n).head? = if n = 0 then none else l.head? := by
|
||||
simp [head?_eq_getElem?, getElem?_take]
|
||||
@@ -171,20 +196,6 @@ theorem dropLast_take {n : Nat} {l : List α} (h : n < l.length) :
|
||||
|
||||
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append_split := @map_eq_append_iff
|
||||
|
||||
theorem take_eq_dropLast {l : List α} {i : Nat} (h : i + 1 = l.length) :
|
||||
l.take i = l.dropLast := by
|
||||
induction l generalizing i with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
cases i
|
||||
· simp_all
|
||||
· cases as with
|
||||
| nil => simp_all
|
||||
| cons b bs =>
|
||||
simp only [take_succ_cons, dropLast_cons₂]
|
||||
rw [ih]
|
||||
simpa using h
|
||||
|
||||
theorem take_prefix_take_left (l : List α) {m n : Nat} (h : m ≤ n) : take m l <+: take n l := by
|
||||
rw [isPrefix_iff]
|
||||
intro i w
|
||||
@@ -215,6 +226,13 @@ theorem getElem_drop' (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
· simp [Nat.min_eq_left this, Nat.add_sub_cancel_left]
|
||||
· simp [Nat.min_eq_left this, Nat.le_add_right]
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the big list to the small list. -/
|
||||
@[deprecated getElem_drop' (since := "2024-06-12")]
|
||||
theorem get_drop (L : List α) {i j : Nat} (h : i + j < L.length) :
|
||||
get L ⟨i + j, h⟩ = get (L.drop i) ⟨j, lt_length_drop L h⟩ := by
|
||||
simp [getElem_drop']
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||||
@[simp] theorem getElem_drop (L : List α) {i : Nat} {j : Nat} {h : j < (L.drop i).length} :
|
||||
@@ -223,6 +241,15 @@ dropping the first `i` elements. Version designed to rewrite from the small list
|
||||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ h)) := by
|
||||
rw [getElem_drop']
|
||||
|
||||
/-- The `i + j`-th element of a list coincides with the `j`-th element of the list obtained by
|
||||
dropping the first `i` elements. Version designed to rewrite from the small list to the big list. -/
|
||||
@[deprecated getElem_drop' (since := "2024-06-12")]
|
||||
theorem get_drop' (L : List α) {i j} :
|
||||
get (L.drop i) j = get L ⟨i + j, by
|
||||
rw [Nat.add_comm]
|
||||
exact Nat.add_lt_of_lt_sub (length_drop i L ▸ j.2)⟩ := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? := by
|
||||
ext
|
||||
@@ -234,6 +261,10 @@ theorem getElem?_drop (L : List α) (i j : Nat) : (L.drop i)[j]? = L[i + j]? :=
|
||||
rw [Nat.add_comm] at h
|
||||
apply Nat.lt_sub_of_add_lt h
|
||||
|
||||
@[deprecated getElem?_drop (since := "2024-06-12")]
|
||||
theorem get?_drop (L : List α) (i j : Nat) : get? (L.drop i) j = get? L (i + j) := by
|
||||
simp
|
||||
|
||||
theorem mem_take_iff_getElem {l : List α} {a : α} :
|
||||
a ∈ l.take n ↔ ∃ (i : Nat) (hm : i < min n l.length), l[i] = a := by
|
||||
rw [mem_iff_getElem]
|
||||
|
||||
@@ -68,15 +68,6 @@ theorem ofFn_succ {n} (f : Fin (n + 1) → α) : ofFn f = f 0 :: ofFn fun i => f
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
@[simp 500]
|
||||
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
obtain ⟨i, h, rfl⟩ := getElem_of_mem w
|
||||
exact ⟨⟨i, by simpa using h⟩, by simp⟩
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
theorem head_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn _ ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
|
||||
@@ -204,97 +204,17 @@ theorem getLast?_range (n : Nat) : (range n).getLast? = if n = 0 then none else
|
||||
| zero => simp at h
|
||||
| succ n => simp [getLast?_range, getLast_eq_iff_getLast_eq_some]
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem zipIdx_eq_nil_iff {l : List α} {n : Nat} : List.zipIdx l n = [] ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem length_zipIdx : ∀ {l : List α} {n}, (zipIdx l n).length = l.length
|
||||
| [], _ => rfl
|
||||
| _ :: _, _ => congrArg Nat.succ length_zipIdx
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_zipIdx :
|
||||
∀ (l : List α) n m, (zipIdx l n)[m]? = l[m]?.map fun a => (a, n + m)
|
||||
| [], _, _ => rfl
|
||||
| _ :: _, _, 0 => by simp
|
||||
| _ :: l, n, m + 1 => by
|
||||
simp only [zipIdx_cons, getElem?_cons_succ]
|
||||
exact (getElem?_zipIdx l (n + 1) m).trans <| by rw [Nat.add_right_comm]; rfl
|
||||
|
||||
@[simp]
|
||||
theorem getElem_zipIdx (l : List α) (n) (i : Nat) (h : i < (l.zipIdx n).length) :
|
||||
(l.zipIdx n)[i] = (l[i]'(by simpa [length_zipIdx] using h), n + i) := by
|
||||
simp only [length_zipIdx] at h
|
||||
rw [getElem_eq_getElem?_get]
|
||||
simp only [getElem?_zipIdx, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem tail_zipIdx (l : List α) (n : Nat) : (zipIdx l n).tail = zipIdx l.tail (n + 1) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [ih, zipIdx_cons]
|
||||
|
||||
theorem map_snd_add_zipIdx_eq_zipIdx (l : List α) (n k : Nat) :
|
||||
map (Prod.map id (· + n)) (zipIdx l k) = zipIdx l (n + k) :=
|
||||
ext_getElem? fun i ↦ by simp [(· ∘ ·), Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
theorem zipIdx_cons' (n : Nat) (x : α) (xs : List α) :
|
||||
zipIdx (x :: xs) n = (x, n) :: (zipIdx xs n).map (Prod.map id (· + 1)) := by
|
||||
rw [zipIdx_cons, Nat.add_comm, ← map_snd_add_zipIdx_eq_zipIdx]
|
||||
|
||||
@[simp]
|
||||
theorem zipIdx_map_snd (n) :
|
||||
∀ (l : List α), map Prod.snd (zipIdx l n) = range' n l.length
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg (cons _) (zipIdx_map_snd _ _)
|
||||
|
||||
@[simp]
|
||||
theorem zipIdx_map_fst : ∀ (n) (l : List α), map Prod.fst (zipIdx l n) = l
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg (cons _) (zipIdx_map_fst _ _)
|
||||
|
||||
theorem zipIdx_eq_zip_range' (l : List α) {n : Nat} : l.zipIdx n = l.zip (range' n l.length) :=
|
||||
zip_of_prod (zipIdx_map_fst _ _) (zipIdx_map_snd _ _)
|
||||
|
||||
@[simp]
|
||||
theorem unzip_zipIdx_eq_prod (l : List α) {n : Nat} :
|
||||
(l.zipIdx n).unzip = (l, range' n l.length) := by
|
||||
simp only [zipIdx_eq_zip_range', unzip_zip, length_range']
|
||||
|
||||
/-- Replace `zipIdx` with a starting index `n+1` with `zipIdx` starting from `n`,
|
||||
followed by a `map` increasing the indices by one. -/
|
||||
theorem zipIdx_succ (l : List α) (n : Nat) :
|
||||
l.zipIdx (n + 1) = (l.zipIdx n).map (fun ⟨a, i⟩ => (a, i + 1)) := by
|
||||
induction l generalizing n with
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp only [zipIdx_cons, ih (n + 1), map_cons]
|
||||
|
||||
/-- Replace `zipIdx` with a starting index with `zipIdx` starting from 0,
|
||||
followed by a `map` increasing the indices. -/
|
||||
theorem zipIdx_eq_map_add (l : List α) (n : Nat) :
|
||||
l.zipIdx n = l.zipIdx.map (fun ⟨a, i⟩ => (a, n + i)) := by
|
||||
induction l generalizing n with
|
||||
| nil => rfl
|
||||
| cons _ _ ih => simp [ih (n+1), zipIdx_succ, Nat.add_assoc, Nat.add_comm 1]
|
||||
|
||||
/-! ### enumFrom -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_eq_nil_iff (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enumFrom_eq_nil {n : Nat} {l : List α} : List.enumFrom n l = [] ↔ l = [] := by
|
||||
cases l <;> simp
|
||||
|
||||
@[deprecated length_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_length : ∀ {n} {l : List α}, (enumFrom n l).length = l.length
|
||||
@[simp] theorem enumFrom_length : ∀ {n} {l : List α}, (enumFrom n l).length = l.length
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg Nat.succ enumFrom_length
|
||||
|
||||
@[deprecated getElem?_zipIdx (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem getElem?_enumFrom :
|
||||
∀ n (l : List α) m, (enumFrom n l)[m]? = l[m]?.map fun a => (n + m, a)
|
||||
| _, [], _ => rfl
|
||||
@@ -303,7 +223,7 @@ theorem getElem?_enumFrom :
|
||||
simp only [enumFrom_cons, getElem?_cons_succ]
|
||||
exact (getElem?_enumFrom (n + 1) l m).trans <| by rw [Nat.add_right_comm]; rfl
|
||||
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem getElem_enumFrom (l : List α) (n) (i : Nat) (h : i < (l.enumFrom n).length) :
|
||||
(l.enumFrom n)[i] = (n + i, l[i]'(by simpa [enumFrom_length] using h)) := by
|
||||
simp only [enumFrom_length] at h
|
||||
@@ -311,66 +231,53 @@ theorem getElem_enumFrom (l : List α) (n) (i : Nat) (h : i < (l.enumFrom n).len
|
||||
simp only [getElem?_enumFrom, getElem?_eq_getElem h]
|
||||
simp
|
||||
|
||||
@[deprecated tail_zipIdx (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem tail_enumFrom (l : List α) (n : Nat) : (enumFrom n l).tail = enumFrom (n + 1) l.tail := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons _ l ih => simp [ih, enumFrom_cons]
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enumFrom_eq_enumFrom (l : List α) (n k : Nat) :
|
||||
map (Prod.map (· + n) id) (enumFrom k l) = enumFrom (n + k) l :=
|
||||
ext_getElem? fun i ↦ by simp [(· ∘ ·), Nat.add_comm, Nat.add_left_comm]; rfl
|
||||
|
||||
@[deprecated map_snd_add_zipIdx_eq_zipIdx (since := "2025-01-21"), simp]
|
||||
theorem map_fst_add_enum_eq_enumFrom (l : List α) (n : Nat) :
|
||||
map (Prod.map (· + n) id) (enum l) = enumFrom n l :=
|
||||
map_fst_add_enumFrom_eq_enumFrom l _ _
|
||||
|
||||
@[deprecated zipIdx_cons' (since := "2025-01-21"), simp]
|
||||
theorem enumFrom_cons' (n : Nat) (x : α) (xs : List α) :
|
||||
enumFrom n (x :: xs) = (n, x) :: (enumFrom n xs).map (Prod.map (· + 1) id) := by
|
||||
rw [enumFrom_cons, Nat.add_comm, ← map_fst_add_enumFrom_eq_enumFrom]
|
||||
|
||||
@[deprecated zipIdx_map_snd (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enumFrom_map_fst (n) :
|
||||
∀ (l : List α), map Prod.fst (enumFrom n l) = range' n l.length
|
||||
| [] => rfl
|
||||
| _ :: _ => congrArg (cons _) (enumFrom_map_fst _ _)
|
||||
|
||||
@[deprecated zipIdx_map_fst (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem enumFrom_map_snd : ∀ (n) (l : List α), map Prod.snd (enumFrom n l) = l
|
||||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg (cons _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated zipIdx_eq_zip_range' (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_zip_range' (l : List α) {n : Nat} : l.enumFrom n = (range' n l.length).zip l :=
|
||||
zip_of_prod (enumFrom_map_fst _ _) (enumFrom_map_snd _ _)
|
||||
|
||||
@[deprecated unzip_zipIdx_eq_prod (since := "2025-01-21"), simp]
|
||||
@[simp]
|
||||
theorem unzip_enumFrom_eq_prod (l : List α) {n : Nat} :
|
||||
(l.enumFrom n).unzip = (range' n l.length, l) := by
|
||||
simp only [enumFrom_eq_zip_range', unzip_zip, length_range']
|
||||
|
||||
end
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
section
|
||||
set_option linter.deprecated false
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons : (a::as).enum = (0, a) :: as.enumFrom 1 := rfl
|
||||
|
||||
@[deprecated zipIdx_cons (since := "2025-01-21")]
|
||||
theorem enum_cons' (x : α) (xs : List α) :
|
||||
enum (x :: xs) = (0, x) :: (enum xs).map (Prod.map (· + 1) id) :=
|
||||
enumFrom_cons' _ _ _
|
||||
|
||||
@[deprecated "These are now both `l.zipIdx 0`" (since := "2025-01-21")]
|
||||
theorem enum_eq_enumFrom {l : List α} : l.enum = l.enumFrom 0 := rfl
|
||||
|
||||
@[deprecated "Use the reverse direction of `map_snd_add_zipIdx_eq_zipIdx` instead" (since := "2025-01-21")]
|
||||
theorem enumFrom_eq_map_enum (l : List α) (n : Nat) :
|
||||
enumFrom n l = (enum l).map (Prod.map (· + n) id) := by
|
||||
induction l generalizing n with
|
||||
@@ -381,6 +288,4 @@ theorem enumFrom_eq_map_enum (l : List α) (n : Nat) :
|
||||
intro a b _
|
||||
exact (succ_add a n).symm
|
||||
|
||||
end
|
||||
|
||||
end List
|
||||
|
||||
@@ -73,14 +73,14 @@ termination_by xs => xs.length
|
||||
|
||||
/--
|
||||
Given an ordering relation `le : α → α → Bool`,
|
||||
construct the lexicographic ordering on `α × Nat`.
|
||||
which first compares the first components using `le`,
|
||||
construct the reverse lexicographic ordering on `Nat × α`.
|
||||
which first compares the second components using `le`,
|
||||
but if these are equivalent (in the sense `le a.2 b.2 && le b.2 a.2`)
|
||||
then compares the second components using `≤`.
|
||||
then compares the first components using `≤`.
|
||||
|
||||
This function is only used in stating the stability properties of `mergeSort`.
|
||||
-/
|
||||
def zipIdxLE (le : α → α → Bool) (a b : α × Nat) : Bool :=
|
||||
if le a.1 b.1 then if le b.1 a.1 then a.2 ≤ b.2 else true else false
|
||||
def enumLE (le : α → α → Bool) (a b : Nat × α) : Bool :=
|
||||
if le a.2 b.2 then if le b.2 a.2 then a.1 ≤ b.1 else true else false
|
||||
|
||||
end List
|
||||
|
||||
@@ -38,35 +38,35 @@ namespace MergeSort.Internal
|
||||
theorem splitInTwo_fst_append_splitInTwo_snd (l : { l : List α // l.length = n }) : (splitInTwo l).1.1 ++ (splitInTwo l).2.1 = l.1 := by
|
||||
simp
|
||||
|
||||
theorem splitInTwo_cons_cons_zipIdx_fst (i : Nat) (l : List α) :
|
||||
(splitInTwo ⟨(a, i) :: (b, i+1) :: l.zipIdx (i+2), rfl⟩).1.1 =
|
||||
(splitInTwo ⟨a :: b :: l, rfl⟩).1.1.zipIdx i := by
|
||||
simp only [length_cons, splitInTwo_fst, length_zipIdx]
|
||||
theorem splitInTwo_cons_cons_enumFrom_fst (i : Nat) (l : List α) :
|
||||
(splitInTwo ⟨(i, a) :: (i+1, b) :: l.enumFrom (i+2), rfl⟩).1.1 =
|
||||
(splitInTwo ⟨a :: b :: l, rfl⟩).1.1.enumFrom i := by
|
||||
simp only [length_cons, splitInTwo_fst, enumFrom_length]
|
||||
ext1 j
|
||||
rw [getElem?_take, getElem?_zipIdx, getElem?_take]
|
||||
rw [getElem?_take, getElem?_enumFrom, getElem?_take]
|
||||
split
|
||||
· rw [getElem?_cons, getElem?_cons, getElem?_cons, getElem?_cons]
|
||||
split
|
||||
· simp; omega
|
||||
· split
|
||||
· simp; omega
|
||||
· simp only [getElem?_zipIdx]
|
||||
· simp only [getElem?_enumFrom]
|
||||
congr
|
||||
ext <;> simp; omega
|
||||
· simp
|
||||
|
||||
theorem splitInTwo_cons_cons_zipIdx_snd (i : Nat) (l : List α) :
|
||||
(splitInTwo ⟨(a, i) :: (b, i+1) :: l.zipIdx (i+2), rfl⟩).2.1 =
|
||||
(splitInTwo ⟨a :: b :: l, rfl⟩).2.1.zipIdx (i+(l.length+3)/2) := by
|
||||
simp only [length_cons, splitInTwo_snd, length_zipIdx]
|
||||
theorem splitInTwo_cons_cons_enumFrom_snd (i : Nat) (l : List α) :
|
||||
(splitInTwo ⟨(i, a) :: (i+1, b) :: l.enumFrom (i+2), rfl⟩).2.1 =
|
||||
(splitInTwo ⟨a :: b :: l, rfl⟩).2.1.enumFrom (i+(l.length+3)/2) := by
|
||||
simp only [length_cons, splitInTwo_snd, enumFrom_length]
|
||||
ext1 j
|
||||
rw [getElem?_drop, getElem?_zipIdx, getElem?_drop]
|
||||
rw [getElem?_drop, getElem?_enumFrom, getElem?_drop]
|
||||
rw [getElem?_cons, getElem?_cons, getElem?_cons, getElem?_cons]
|
||||
split
|
||||
· simp; omega
|
||||
· split
|
||||
· simp; omega
|
||||
· simp only [getElem?_zipIdx]
|
||||
· simp only [getElem?_enumFrom]
|
||||
congr
|
||||
ext <;> simp; omega
|
||||
|
||||
@@ -88,13 +88,13 @@ end MergeSort.Internal
|
||||
|
||||
open MergeSort.Internal
|
||||
|
||||
/-! ### zipIdxLE -/
|
||||
/-! ### enumLE -/
|
||||
|
||||
variable {le : α → α → Bool}
|
||||
|
||||
theorem zipIdxLE_trans (trans : ∀ a b c, le a b → le b c → le a c)
|
||||
(a b c : α × Nat) : zipIdxLE le a b → zipIdxLE le b c → zipIdxLE le a c := by
|
||||
simp only [zipIdxLE]
|
||||
theorem enumLE_trans (trans : ∀ a b c, le a b → le b c → le a c)
|
||||
(a b c : Nat × α) : enumLE le a b → enumLE le b c → enumLE le a c := by
|
||||
simp only [enumLE]
|
||||
split <;> split <;> split <;> rename_i ab₂ ba₂ bc₂
|
||||
· simp_all
|
||||
intro ab₁
|
||||
@@ -120,14 +120,14 @@ theorem zipIdxLE_trans (trans : ∀ a b c, le a b → le b c → le a c)
|
||||
· simp_all
|
||||
· simp_all
|
||||
|
||||
theorem zipIdxLE_total (total : ∀ a b, le a b || le b a)
|
||||
(a b : α × Nat) : zipIdxLE le a b || zipIdxLE le b a := by
|
||||
simp only [zipIdxLE]
|
||||
theorem enumLE_total (total : ∀ a b, le a b || le b a)
|
||||
(a b : Nat × α) : enumLE le a b || enumLE le b a := by
|
||||
simp only [enumLE]
|
||||
split <;> split
|
||||
· simpa using Nat.le_total a.2 b.2
|
||||
· simpa using Nat.le_total a.fst b.fst
|
||||
· simp
|
||||
· simp
|
||||
· have := total a.1 b.1
|
||||
· have := total a.2 b.2
|
||||
simp_all
|
||||
|
||||
/-! ### merge -/
|
||||
@@ -179,12 +179,12 @@ theorem mem_merge_left (s : α → α → Bool) (h : x ∈ l) : x ∈ merge l r
|
||||
theorem mem_merge_right (s : α → α → Bool) (h : x ∈ r) : x ∈ merge l r s :=
|
||||
mem_merge.2 <| .inr h
|
||||
|
||||
theorem merge_stable : ∀ (xs ys) (_ : ∀ x y, x ∈ xs → y ∈ ys → x.2 ≤ y.2),
|
||||
(merge xs ys (zipIdxLE le)).map (·.1) = merge (xs.map (·.1)) (ys.map (·.1)) le
|
||||
theorem merge_stable : ∀ (xs ys) (_ : ∀ x y, x ∈ xs → y ∈ ys → x.1 ≤ y.1),
|
||||
(merge xs ys (enumLE le)).map (·.2) = merge (xs.map (·.2)) (ys.map (·.2)) le
|
||||
| [], ys, _ => by simp [merge]
|
||||
| xs, [], _ => by simp [merge]
|
||||
| (i, x) :: xs, (j, y) :: ys, h => by
|
||||
simp only [merge, zipIdxLE, map_cons]
|
||||
simp only [merge, enumLE, map_cons]
|
||||
split <;> rename_i w
|
||||
· rw [if_pos (by simp [h _ _ (mem_cons_self ..) (mem_cons_self ..)])]
|
||||
simp only [map_cons, cons.injEq, true_and]
|
||||
@@ -331,59 +331,57 @@ See also:
|
||||
* `sublist_mergeSort`: if `c <+ l` and `c.Pairwise le`, then `c <+ mergeSort le l`.
|
||||
* `pair_sublist_mergeSort`: if `[a, b] <+ l` and `le a b`, then `[a, b] <+ mergeSort le l`)
|
||||
-/
|
||||
theorem mergeSort_zipIdx {l : List α} :
|
||||
(mergeSort (l.zipIdx) (zipIdxLE le)).map (·.1) = mergeSort l le :=
|
||||
theorem mergeSort_enum {l : List α} :
|
||||
(mergeSort (l.enum) (enumLE le)).map (·.2) = mergeSort l le :=
|
||||
go 0 l
|
||||
where go : ∀ (i : Nat) (l : List α),
|
||||
(mergeSort (l.zipIdx i) (zipIdxLE le)).map (·.1) = mergeSort l le
|
||||
(mergeSort (l.enumFrom i) (enumLE le)).map (·.2) = mergeSort l le
|
||||
| _, []
|
||||
| _, [a] => by simp [mergeSort]
|
||||
| _, a :: b :: xs => by
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).1.1.length < xs.length + 1 + 1 := by simp [splitInTwo_fst]; omega
|
||||
have : (splitInTwo ⟨a :: b :: xs, rfl⟩).2.1.length < xs.length + 1 + 1 := by simp [splitInTwo_snd]; omega
|
||||
simp only [mergeSort, zipIdx]
|
||||
rw [splitInTwo_cons_cons_zipIdx_fst]
|
||||
rw [splitInTwo_cons_cons_zipIdx_snd]
|
||||
simp only [mergeSort, enumFrom]
|
||||
rw [splitInTwo_cons_cons_enumFrom_fst]
|
||||
rw [splitInTwo_cons_cons_enumFrom_snd]
|
||||
rw [merge_stable]
|
||||
· rw [go, go]
|
||||
· simp only [mem_mergeSort, Prod.forall]
|
||||
intros j x k y mx my
|
||||
have := mem_zipIdx mx
|
||||
have := mem_zipIdx my
|
||||
have := mem_enumFrom mx
|
||||
have := mem_enumFrom my
|
||||
simp_all
|
||||
omega
|
||||
termination_by _ l => l.length
|
||||
|
||||
@[deprecated mergeSort_zipIdx (since := "2025-01-21")] abbrev mergeSort_enum := @mergeSort_zipIdx
|
||||
|
||||
theorem mergeSort_cons {le : α → α → Bool}
|
||||
(trans : ∀ (a b c : α), le a b → le b c → le a c)
|
||||
(total : ∀ (a b : α), le a b || le b a)
|
||||
(a : α) (l : List α) :
|
||||
∃ l₁ l₂, mergeSort (a :: l) le = l₁ ++ a :: l₂ ∧ mergeSort l le = l₁ ++ l₂ ∧
|
||||
∀ b, b ∈ l₁ → !le a b := by
|
||||
rw [← mergeSort_zipIdx]
|
||||
rw [zipIdx_cons]
|
||||
have nd : Nodup ((a :: l).zipIdx.map (·.2)) := by rw [zipIdx_map_snd]; exact nodup_range' _ _
|
||||
have m₁ : (a, 0) ∈ mergeSort ((a :: l).zipIdx) (zipIdxLE le) :=
|
||||
rw [← mergeSort_enum]
|
||||
rw [enum_cons]
|
||||
have nd : Nodup ((a :: l).enum.map (·.1)) := by rw [enum_map_fst]; exact nodup_range _
|
||||
have m₁ : (0, a) ∈ mergeSort ((a :: l).enum) (enumLE le) :=
|
||||
mem_mergeSort.mpr (mem_cons_self _ _)
|
||||
obtain ⟨l₁, l₂, h⟩ := append_of_mem m₁
|
||||
have s := sorted_mergeSort (zipIdxLE_trans trans) (zipIdxLE_total total) ((a :: l).zipIdx)
|
||||
have s := sorted_mergeSort (enumLE_trans trans) (enumLE_total total) ((a :: l).enum)
|
||||
rw [h] at s
|
||||
have p := mergeSort_perm ((a :: l).zipIdx) (zipIdxLE le)
|
||||
have p := mergeSort_perm ((a :: l).enum) (enumLE le)
|
||||
rw [h] at p
|
||||
refine ⟨l₁.map (·.1), l₂.map (·.1), ?_, ?_, ?_⟩
|
||||
· simpa using congrArg (·.map (·.1)) h
|
||||
· rw [← mergeSort_zipIdx.go 1, ← map_append]
|
||||
refine ⟨l₁.map (·.2), l₂.map (·.2), ?_, ?_, ?_⟩
|
||||
· simpa using congrArg (·.map (·.2)) h
|
||||
· rw [← mergeSort_enum.go 1, ← map_append]
|
||||
congr 1
|
||||
have q : mergeSort (l.zipIdx 1) (zipIdxLE le) ~ l₁ ++ l₂ :=
|
||||
(mergeSort_perm (l.zipIdx 1) (zipIdxLE le)).trans
|
||||
have q : mergeSort (enumFrom 1 l) (enumLE le) ~ l₁ ++ l₂ :=
|
||||
(mergeSort_perm (enumFrom 1 l) (enumLE le)).trans
|
||||
(p.symm.trans perm_middle).cons_inv
|
||||
apply Perm.eq_of_sorted (le := zipIdxLE le)
|
||||
· rintro ⟨a, i⟩ ⟨b, j⟩ ha hb
|
||||
apply Perm.eq_of_sorted (le := enumLE le)
|
||||
· rintro ⟨i, a⟩ ⟨j, b⟩ ha hb
|
||||
simp only [mem_mergeSort] at ha
|
||||
simp only [← q.mem_iff, mem_mergeSort] at hb
|
||||
simp only [zipIdxLE]
|
||||
simp only [enumLE]
|
||||
simp only [Bool.if_false_right, Bool.and_eq_true, Prod.mk.injEq, and_imp]
|
||||
intro ab h ba h'
|
||||
simp only [Bool.decide_eq_true] at ba
|
||||
@@ -391,24 +389,24 @@ theorem mergeSort_cons {le : α → α → Bool}
|
||||
replace h' : j ≤ i := by simpa [ab, ba] using h'
|
||||
cases Nat.le_antisymm h h'
|
||||
constructor
|
||||
· have := mem_zipIdx ha
|
||||
have := mem_zipIdx hb
|
||||
simp_all
|
||||
· rfl
|
||||
· exact sorted_mergeSort (zipIdxLE_trans trans) (zipIdxLE_total total) ..
|
||||
· exact s.sublist ((sublist_cons_self (a, 0) l₂).append_left l₁)
|
||||
· have := mem_enumFrom ha
|
||||
have := mem_enumFrom hb
|
||||
simp_all
|
||||
· exact sorted_mergeSort (enumLE_trans trans) (enumLE_total total) ..
|
||||
· exact s.sublist ((sublist_cons_self (0, a) l₂).append_left l₁)
|
||||
· exact q
|
||||
· intro b m
|
||||
simp only [mem_map, Prod.exists] at m
|
||||
obtain ⟨j, _, m, rfl⟩ := m
|
||||
replace p := p.map (·.2)
|
||||
simp only [mem_map, Prod.exists, exists_eq_right] at m
|
||||
obtain ⟨j, m⟩ := m
|
||||
replace p := p.map (·.1)
|
||||
have nd' := nd.perm p.symm
|
||||
rw [map_append] at nd'
|
||||
have j0 := nd'.rel_of_mem_append
|
||||
(mem_map_of_mem (·.2) m) (mem_map_of_mem _ (mem_cons_self _ _))
|
||||
(mem_map_of_mem (·.1) m) (mem_map_of_mem _ (mem_cons_self _ _))
|
||||
simp only [ne_eq] at j0
|
||||
have r := s.rel_of_mem_append m (mem_cons_self _ _)
|
||||
simp_all [zipIdxLE]
|
||||
simp_all [enumLE]
|
||||
|
||||
/--
|
||||
Another statement of stability of merge sort.
|
||||
|
||||
@@ -67,9 +67,17 @@ theorem getElem_cons_drop : ∀ (l : List α) (i : Nat) (h : i < l.length),
|
||||
| _::_, 0, _ => rfl
|
||||
| _::_, i+1, h => getElem_cons_drop _ i (Nat.add_one_lt_add_one_iff.mp h)
|
||||
|
||||
@[deprecated getElem_cons_drop (since := "2024-06-12")]
|
||||
theorem get_cons_drop (l : List α) (i) : get l i :: drop (i + 1) l = drop i l := by
|
||||
simp
|
||||
|
||||
theorem drop_eq_getElem_cons {n} {l : List α} (h : n < l.length) : drop n l = l[n] :: drop (n + 1) l :=
|
||||
(getElem_cons_drop _ n h).symm
|
||||
|
||||
@[deprecated drop_eq_getElem_cons (since := "2024-06-12")]
|
||||
theorem drop_eq_get_cons {n} {l : List α} (h) : drop n l = get l ⟨n, h⟩ :: drop (n + 1) l := by
|
||||
simp [drop_eq_getElem_cons]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_take_of_lt {l : List α} {n m : Nat} (h : m < n) : (l.take n)[m]? = l[m]? := by
|
||||
induction n generalizing l m with
|
||||
@@ -83,6 +91,10 @@ theorem getElem?_take_of_lt {l : List α} {n m : Nat} (h : m < n) : (l.take n)[m
|
||||
· simp
|
||||
· simpa using hn (Nat.lt_of_succ_lt_succ h)
|
||||
|
||||
@[deprecated getElem?_take_of_lt (since := "2024-06-12")]
|
||||
theorem get?_take {l : List α} {n m : Nat} (h : m < n) : (l.take n).get? m = l.get? m := by
|
||||
simp [getElem?_take_of_lt, h]
|
||||
|
||||
theorem getElem?_take_of_succ {l : List α} {n : Nat} : (l.take (n + 1))[n]? = l[n]? := by simp
|
||||
|
||||
@[simp] theorem drop_drop (n : Nat) : ∀ (m) (l : List α), drop n (drop m l) = drop (m + n) l
|
||||
@@ -99,6 +111,10 @@ theorem take_drop : ∀ (m n : Nat) (l : List α), take n (drop m l) = drop m (t
|
||||
| _, _, [] => by simp
|
||||
| _+1, _, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop ..
|
||||
|
||||
@[deprecated drop_drop (since := "2024-06-15")]
|
||||
theorem drop_add (m n) (l : List α) : drop (m + n) l = drop n (drop m l) := by
|
||||
simp [drop_drop]
|
||||
|
||||
@[simp]
|
||||
theorem tail_drop (l : List α) (n : Nat) : (l.drop n).tail = l.drop (n + 1) := by
|
||||
induction l generalizing n with
|
||||
|
||||
@@ -13,21 +13,6 @@ import Init.Data.Array.Lex.Basic
|
||||
|
||||
We prefer to pull `List.toArray` outwards past `Array` operations.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem toList_set (a : Array α) (i x h) :
|
||||
(a.set i x).toList = a.toList.set i x := rfl
|
||||
|
||||
theorem swap_def (a : Array α) (i j : Nat) (hi hj) :
|
||||
a.swap i j hi hj = (a.set i a[j]).set j a[i] (by simpa using hj) := by
|
||||
simp [swap]
|
||||
|
||||
@[simp] theorem toList_swap (a : Array α) (i j : Nat) (hi hj) :
|
||||
(a.swap i j hi hj).toList = (a.toList.set i a[j]).set j a[i] := by simp [swap_def]
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
|
||||
open Array
|
||||
@@ -158,9 +143,6 @@ theorem forM_toArray [Monad m] (l : List α) (f : α → m PUnit) :
|
||||
subst h
|
||||
rw [foldl_toList]
|
||||
|
||||
@[simp] theorem sum_toArray [Add α] [Zero α] (l : List α) : l.toArray.sum = l.sum := by
|
||||
simp [Array.sum, List.sum]
|
||||
|
||||
@[simp] theorem append_toArray (l₁ l₂ : List α) :
|
||||
l₁.toArray ++ l₂.toArray = (l₁ ++ l₂).toArray := by
|
||||
apply ext'
|
||||
@@ -312,7 +294,7 @@ theorem zipWithAux_toArray_zero (f : α → β → γ) (as : List α) (bs : List
|
||||
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
|
||||
|
||||
@[simp] theorem zipWith_toArray (as : List α) (bs : List β) (f : α → β → γ) :
|
||||
Array.zipWith f as.toArray bs.toArray = (List.zipWith f as bs).toArray := by
|
||||
Array.zipWith as.toArray bs.toArray f = (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWith]
|
||||
simp [zipWithAux_toArray_zero]
|
||||
|
||||
@@ -355,7 +337,7 @@ theorem zipWithAll_go_toArray (as : List α) (bs : List β) (f : Option α → O
|
||||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||||
|
||||
@[simp] theorem zipWithAll_toArray (f : Option α → Option β → γ) (as : List α) (bs : List β) :
|
||||
Array.zipWithAll f as.toArray bs.toArray = (List.zipWithAll f as bs).toArray := by
|
||||
Array.zipWithAll as.toArray bs.toArray f = (List.zipWithAll f as bs).toArray := by
|
||||
simp [Array.zipWithAll, zipWithAll_go_toArray]
|
||||
|
||||
@[simp] theorem toArray_appendList (l₁ l₂ : List α) :
|
||||
@@ -412,54 +394,4 @@ theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
@[deprecated toArray_replicate (since := "2024-12-13")]
|
||||
abbrev _root_.Array.mkArray_eq_toArray_replicate := @toArray_replicate
|
||||
|
||||
@[simp] theorem flatMap_empty {β} (f : α → Array β) : (#[] : Array α).flatMap f = #[] := rfl
|
||||
|
||||
theorem flatMap_toArray_cons {β} (f : α → Array β) (a : α) (as : List α) :
|
||||
(a :: as).toArray.flatMap f = f a ++ as.toArray.flatMap f := by
|
||||
simp [Array.flatMap]
|
||||
suffices ∀ cs, List.foldl (fun bs a => bs ++ f a) (f a ++ cs) as =
|
||||
f a ++ List.foldl (fun bs a => bs ++ f a) cs as by
|
||||
erw [empty_append] -- Why doesn't this work via `simp`?
|
||||
simpa using this #[]
|
||||
intro cs
|
||||
induction as generalizing cs <;> simp_all
|
||||
|
||||
@[simp] theorem flatMap_toArray {β} (f : α → Array β) (as : List α) :
|
||||
as.toArray.flatMap f = (as.flatMap (fun a => (f a).toList)).toArray := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as ih =>
|
||||
apply ext'
|
||||
simp [ih, flatMap_toArray_cons]
|
||||
|
||||
@[simp] theorem swap_toArray (l : List α) (i j : Nat) {hi hj}:
|
||||
l.toArray.swap i j hi hj = ((l.set i l[j]).set j l[i]).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem eraseIdx_toArray (l : List α) (i : Nat) (h : i < l.toArray.size) :
|
||||
l.toArray.eraseIdx i h = (l.eraseIdx i).toArray := by
|
||||
rw [Array.eraseIdx]
|
||||
split <;> rename_i h'
|
||||
· rw [eraseIdx_toArray]
|
||||
simp only [swap_toArray, Fin.getElem_fin, toList_toArray, mk.injEq]
|
||||
rw [eraseIdx_set_gt (by simp), eraseIdx_set_eq]
|
||||
simp
|
||||
· simp at h h'
|
||||
have t : i = l.length - 1 := by omega
|
||||
simp [t]
|
||||
termination_by l.length - i
|
||||
decreasing_by
|
||||
rename_i h
|
||||
simp at h
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem eraseIdxIfInBounds_toArray (l : List α) (i : Nat) :
|
||||
l.toArray.eraseIdxIfInBounds i = (l.eraseIdx i).toArray := by
|
||||
rw [Array.eraseIdxIfInBounds]
|
||||
split
|
||||
· simp
|
||||
· simp_all [eraseIdx_eq_self.2]
|
||||
|
||||
end List
|
||||
|
||||
@@ -31,18 +31,16 @@ theorem zipWith_comm_of_comm (f : α → α → β) (comm : ∀ x y : α, f x y
|
||||
simp only [comm]
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_self (f : α → α → δ) : ∀ l : List α, zipWith f l l = l.map fun a => f a a
|
||||
theorem zipWith_same (f : α → α → δ) : ∀ l : List α, zipWith f l l = l.map fun a => f a a
|
||||
| [] => rfl
|
||||
| _ :: xs => congrArg _ (zipWith_self f xs)
|
||||
|
||||
@[deprecated zipWith_self (since := "2025-01-29")] abbrev zipWith_same := @zipWith_self
|
||||
| _ :: xs => congrArg _ (zipWith_same f xs)
|
||||
|
||||
/--
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
using `Option.map` and `Option.bind` rather than a `match`.
|
||||
-/
|
||||
theorem getElem?_zipWith {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
(List.zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
induction as generalizing bs i with
|
||||
| nil => cases bs with
|
||||
@@ -78,6 +76,15 @@ theorem getElem?_zip_eq_some {l₁ : List α} {l₂ : List β} {z : α × β} {i
|
||||
· rintro ⟨h₀, h₁⟩
|
||||
exact ⟨_, _, h₀, h₁, rfl⟩
|
||||
|
||||
@[deprecated getElem?_zipWith (since := "2024-06-12")]
|
||||
theorem get?_zipWith {f : α → β → γ} :
|
||||
(List.zipWith f as bs).get? i = match as.get? i, bs.get? i with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
simp [getElem?_zipWith]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem?_zipWith (since := "2024-06-07")] abbrev zipWith_get? := @get?_zipWith
|
||||
|
||||
theorem head?_zipWith {f : α → β → γ} :
|
||||
(List.zipWith f as bs).head? = match as.head?, bs.head? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
@@ -196,11 +203,11 @@ theorem zipWith_eq_append_iff {f : α → β → γ} {l₁ : List α} {l₂ : Li
|
||||
cases l₂ with
|
||||
| nil =>
|
||||
constructor
|
||||
· simp only [zipWith_nil_right, nil_eq, append_eq_nil_iff, exists_and_left, and_imp]
|
||||
· simp only [zipWith_nil_right, nil_eq, append_eq_nil, exists_and_left, and_imp]
|
||||
rintro rfl rfl
|
||||
exact ⟨[], x₁ :: l₁, [], by simp⟩
|
||||
· rintro ⟨w, x, y, z, h₁, _, h₃, rfl, rfl⟩
|
||||
simp only [nil_eq, append_eq_nil_iff] at h₃
|
||||
simp only [nil_eq, append_eq_nil] at h₃
|
||||
obtain ⟨rfl, rfl⟩ := h₃
|
||||
simp
|
||||
| cons x₂ l₂ =>
|
||||
@@ -240,14 +247,6 @@ theorem map_uncurry_zip_eq_zipWith (f : α → β → γ) (l : List α) (l' : Li
|
||||
| cons hl tl ih =>
|
||||
cases l' <;> simp [ih]
|
||||
|
||||
theorem map_zip_eq_zipWith (f : α × β → γ) (l : List α) (l' : List β) :
|
||||
map f (l.zip l') = zipWith (Function.curry f) l l' := by
|
||||
rw [zip]
|
||||
induction l generalizing l' with
|
||||
| nil => simp
|
||||
| cons hl tl ih =>
|
||||
cases l' <;> simp [ih]
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
theorem zip_eq_zipWith : ∀ (l₁ : List α) (l₂ : List β), zip l₁ l₂ = zipWith Prod.mk l₁ l₂
|
||||
@@ -259,7 +258,8 @@ theorem zip_map (f : α → γ) (g : β → δ) :
|
||||
∀ (l₁ : List α) (l₂ : List β), zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g)
|
||||
| [], _ => rfl
|
||||
| _, [] => by simp only [map, zip_nil_right]
|
||||
| _ :: _, _ :: _ => by simp only [map, zip_cons_cons, zip_map, Prod.map]
|
||||
| _ :: _, _ :: _ => by
|
||||
simp only [map, zip_cons_cons, zip_map, Prod.map]; try constructor -- TODO: remove try constructor after update stage0
|
||||
|
||||
theorem zip_map_left (f : α → γ) (l₁ : List α) (l₂ : List β) :
|
||||
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
@@ -369,6 +369,15 @@ theorem getElem?_zipWithAll {f : Option α → Option β → γ} {i : Nat} :
|
||||
cases i <;> simp_all
|
||||
| cons b bs => cases i <;> simp_all
|
||||
|
||||
@[deprecated getElem?_zipWithAll (since := "2024-06-12")]
|
||||
theorem get?_zipWithAll {f : Option α → Option β → γ} :
|
||||
(zipWithAll f as bs).get? i = match as.get? i, bs.get? i with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
simp [getElem?_zipWithAll]
|
||||
|
||||
set_option linter.deprecated false in
|
||||
@[deprecated getElem?_zipWithAll (since := "2024-06-07")] abbrev zipWithAll_get? := @get?_zipWithAll
|
||||
|
||||
theorem head?_zipWithAll {f : Option α → Option β → γ} :
|
||||
(zipWithAll f as bs).head? = match as.head?, bs.head? with
|
||||
| none, none => .none | a?, b? => some (f a? b?) := by
|
||||
|
||||
@@ -788,6 +788,9 @@ theorem not_eq_zero_of_lt (h : b < a) : a ≠ 0 := by
|
||||
theorem pred_lt_of_lt {n m : Nat} (h : m < n) : pred n < n :=
|
||||
pred_lt (not_eq_zero_of_lt h)
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated pred_lt_of_lt (since := "2024-06-01")] abbrev pred_lt' := @pred_lt_of_lt
|
||||
|
||||
theorem sub_one_lt_of_lt {n m : Nat} (h : m < n) : n - 1 < n :=
|
||||
sub_one_lt (not_eq_zero_of_lt h)
|
||||
|
||||
@@ -1071,6 +1074,9 @@ theorem pred_mul (n m : Nat) : pred n * m = n * m - m := by
|
||||
| zero => simp
|
||||
| succ n => rw [Nat.pred_succ, succ_mul, Nat.add_sub_cancel]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated pred_mul (since := "2024-06-01")] abbrev mul_pred_left := @pred_mul
|
||||
|
||||
protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
|
||||
cases n with
|
||||
| zero => simp
|
||||
@@ -1080,6 +1086,9 @@ protected theorem sub_one_mul (n m : Nat) : (n - 1) * m = n * m - m := by
|
||||
theorem mul_pred (n m : Nat) : n * pred m = n * m - n := by
|
||||
rw [Nat.mul_comm, pred_mul, Nat.mul_comm]
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated mul_pred (since := "2024-06-01")] abbrev mul_pred_right := @mul_pred
|
||||
|
||||
theorem mul_sub_one (n m : Nat) : n * (m - 1) = n * m - n := by
|
||||
rw [Nat.mul_comm, Nat.sub_one_mul , Nat.mul_comm]
|
||||
|
||||
|
||||
@@ -711,32 +711,6 @@ theorem mul_add_lt_is_or {b : Nat} (b_lt : b < 2^i) (a : Nat) : 2^i * a + b = 2^
|
||||
rw [mod_two_eq_one_iff_testBit_zero, testBit_shiftLeft]
|
||||
simp
|
||||
|
||||
theorem testBit_mul_two_pow (x i n : Nat) :
|
||||
(x * 2 ^ n).testBit i = (decide (n ≤ i) && x.testBit (i - n)) := by
|
||||
rw [← testBit_shiftLeft, shiftLeft_eq]
|
||||
|
||||
theorem bitwise_mul_two_pow (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f x y) * 2 ^ n = bitwise f (x * 2 ^ n) (y * 2 ^ n) := by
|
||||
apply Nat.eq_of_testBit_eq
|
||||
simp only [testBit_mul_two_pow, testBit_bitwise of_false_false, Bool.if_false_right]
|
||||
intro i
|
||||
by_cases hn : n ≤ i
|
||||
· simp [hn]
|
||||
· simp [hn, of_false_false]
|
||||
|
||||
theorem shiftLeft_bitwise_distrib {a b : Nat} (of_false_false : f false false = false := by rfl) :
|
||||
(bitwise f a b) <<< i = bitwise f (a <<< i) (b <<< i) := by
|
||||
simp [shiftLeft_eq, bitwise_mul_two_pow of_false_false]
|
||||
|
||||
theorem shiftLeft_and_distrib {a b : Nat} : (a &&& b) <<< i = a <<< i &&& b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
theorem shiftLeft_or_distrib {a b : Nat} : (a ||| b) <<< i = a <<< i ||| b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
theorem shiftLeft_xor_distrib {a b : Nat} : (a ^^^ b) <<< i = a <<< i ^^^ b <<< i :=
|
||||
shiftLeft_bitwise_distrib
|
||||
|
||||
@[simp] theorem decide_shiftRight_mod_two_eq_one :
|
||||
decide (x >>> i % 2 = 1) = x.testBit i := by
|
||||
simp only [testBit, one_and_eq_mod_two, mod_two_bne_zero]
|
||||
|
||||
@@ -622,14 +622,6 @@ protected theorem pos_of_mul_pos_right {a b : Nat} (h : 0 < a * b) : 0 < a := by
|
||||
0 < a * b ↔ 0 < a :=
|
||||
⟨Nat.pos_of_mul_pos_right, fun w => Nat.mul_pos w h⟩
|
||||
|
||||
protected theorem pos_of_lt_mul_left {a b c : Nat} (h : a < b * c) : 0 < c := by
|
||||
replace h : 0 < b * c := by omega
|
||||
exact Nat.pos_of_mul_pos_left h
|
||||
|
||||
protected theorem pos_of_lt_mul_right {a b c : Nat} (h : a < b * c) : 0 < b := by
|
||||
replace h : 0 < b * c := by omega
|
||||
exact Nat.pos_of_mul_pos_right h
|
||||
|
||||
/-! ### div/mod -/
|
||||
|
||||
theorem mod_two_eq_zero_or_one (n : Nat) : n % 2 = 0 ∨ n % 2 = 1 :=
|
||||
@@ -1003,6 +995,11 @@ theorem shiftLeft_add (m n : Nat) : ∀ k, m <<< (n + k) = (m <<< n) <<< k
|
||||
| 0 => rfl
|
||||
| k + 1 => by simp [← Nat.add_assoc, shiftLeft_add _ _ k, shiftLeft_succ]
|
||||
|
||||
@[deprecated shiftLeft_add (since := "2024-06-02")]
|
||||
theorem shiftLeft_shiftLeft (m n : Nat) : ∀ k, (m <<< n) <<< k = m <<< (n + k)
|
||||
| 0 => rfl
|
||||
| k + 1 => by simp [← Nat.add_assoc, shiftLeft_shiftLeft _ _ k, shiftLeft_succ]
|
||||
|
||||
@[simp] theorem shiftLeft_shiftRight (x n : Nat) : x <<< n >>> n = x := by
|
||||
rw [Nat.shiftLeft_eq, Nat.shiftRight_eq_div_pow, Nat.mul_div_cancel _ (Nat.two_pow_pos _)]
|
||||
|
||||
|
||||
@@ -718,7 +718,8 @@ theorem Expr.eq_of_toNormPoly_eq (ctx : Context) (e e' : Expr) (h : e.toNormPoly
|
||||
|
||||
end Linear
|
||||
|
||||
def elimOffset {α : Sort u} (a b k : Nat) (h₁ : a + k = b + k) (h₂ : a = b → α) : α :=
|
||||
h₂ (Nat.add_right_cancel h₁)
|
||||
def elimOffset {α : Sort u} (a b k : Nat) (h₁ : a + k = b + k) (h₂ : a = b → α) : α := by
|
||||
simp_arith at h₁
|
||||
exact h₂ h₁
|
||||
|
||||
end Nat
|
||||
|
||||
@@ -57,11 +57,11 @@ theorem mod_mul_right_div_self (m n k : Nat) : m % (n * k) / n = m / n % k := by
|
||||
theorem mod_mul_left_div_self (m n k : Nat) : m % (k * n) / n = m / n % k := by
|
||||
rw [Nat.mul_comm k n, mod_mul_right_div_self]
|
||||
|
||||
@[simp]
|
||||
@[simp 1100]
|
||||
theorem mod_mul_right_mod (a b c : Nat) : a % (b * c) % b = a % b :=
|
||||
Nat.mod_mod_of_dvd a (Nat.dvd_mul_right b c)
|
||||
|
||||
@[simp]
|
||||
@[simp 1100]
|
||||
theorem mod_mul_left_mod (a b c : Nat) : a % (b * c) % c = a % c :=
|
||||
Nat.mod_mod_of_dvd a (Nat.mul_comm _ _ ▸ Nat.dvd_mul_left c b)
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ theorem get_mem : ∀ {o : Option α} (h : isSome o), o.get h ∈ o
|
||||
theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
|
||||
| _, _, rfl => rfl
|
||||
|
||||
@[simp] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
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]
|
||||
@@ -208,15 +208,6 @@ theorem comp_map (h : β → γ) (g : α → β) (x : Option α) : x.map (h ∘
|
||||
|
||||
theorem mem_map_of_mem (g : α → β) (h : a ∈ x) : g a ∈ Option.map g x := h.symm ▸ map_some' ..
|
||||
|
||||
theorem map_inj_right {f : α → β} {o o' : Option α} (w : ∀ x y, f x = f y → x = y) :
|
||||
o.map f = o'.map f ↔ o = o' := by
|
||||
cases o with
|
||||
| none => cases o' <;> simp
|
||||
| some a =>
|
||||
cases o' with
|
||||
| none => simp
|
||||
| some a' => simpa using ⟨fun h => w _ _ h, fun h => congrArg f h⟩
|
||||
|
||||
@[simp] theorem map_if {f : α → β} [Decidable c] :
|
||||
(if c then some a else none).map f = if c then some (f a) else none := by
|
||||
split <;> rfl
|
||||
@@ -638,15 +629,6 @@ theorem pbind_eq_some_iff {o : Option α} {f : (a : α) → a ∈ o → Option
|
||||
· rintro ⟨h, rfl⟩
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (o : Option α) (H) :
|
||||
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H) :
|
||||
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
|
||||
cases o <;> simp
|
||||
|
||||
/-! ### pelim -/
|
||||
|
||||
@[simp] theorem pelim_none : pelim none b f = b := rfl
|
||||
@@ -655,10 +637,4 @@ theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (o H)
|
||||
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp] theorem elim_pmap {p : α → Prop} (f : (a : α) → p a → β) (o : Option α)
|
||||
(H : ∀ (a : α), a ∈ o → p a) (g : γ) (g' : β → γ) :
|
||||
(o.pmap f H).elim g g' =
|
||||
o.pelim g (fun a h => g' (f a (H a h))) := by
|
||||
cases o <;> simp
|
||||
|
||||
end Option
|
||||
|
||||
@@ -5,7 +5,6 @@ Authors: Johannes Hölzl
|
||||
-/
|
||||
prelude
|
||||
import Init.Ext
|
||||
import Init.Core
|
||||
|
||||
namespace Subtype
|
||||
|
||||
|
||||
@@ -13,17 +13,11 @@ macro "declare_bitwise_uint_theorems" typeName:ident bits:term:arg : command =>
|
||||
`(
|
||||
namespace $typeName
|
||||
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_add {a b : $typeName} : (a + b).toBitVec = a.toBitVec + b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_sub {a b : $typeName} : (a - b).toBitVec = a.toBitVec - b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_mul {a b : $typeName} : (a * b).toBitVec = a.toBitVec * b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_div {a b : $typeName} : (a / b).toBitVec = a.toBitVec / b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_mod {a b : $typeName} : (a % b).toBitVec = a.toBitVec % b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_not {a : $typeName} : (~~~a).toBitVec = ~~~a.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_and (a b : $typeName) : (a &&& b).toBitVec = a.toBitVec &&& b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_or (a b : $typeName) : (a ||| b).toBitVec = a.toBitVec ||| b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_xor (a b : $typeName) : (a ^^^ b).toBitVec = a.toBitVec ^^^ b.toBitVec := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
|
||||
@[simp, int_toBitVec] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
|
||||
@[simp] protected theorem toBitVec_and (a b : $typeName) : (a &&& b).toBitVec = a.toBitVec &&& b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_or (a b : $typeName) : (a ||| b).toBitVec = a.toBitVec ||| b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_xor (a b : $typeName) : (a ^^^ b).toBitVec = a.toBitVec ^^^ b.toBitVec := rfl
|
||||
@[simp] protected theorem toBitVec_shiftLeft (a b : $typeName) : (a <<< b).toBitVec = a.toBitVec <<< (b.toBitVec % $bits) := rfl
|
||||
@[simp] protected theorem toBitVec_shiftRight (a b : $typeName) : (a >>> b).toBitVec = a.toBitVec >>> (b.toBitVec % $bits) := rfl
|
||||
|
||||
@[simp] protected theorem toNat_and (a b : $typeName) : (a &&& b).toNat = a.toNat &&& b.toNat := by simp [toNat]
|
||||
@[simp] protected theorem toNat_or (a b : $typeName) : (a ||| b).toNat = a.toNat ||| b.toNat := by simp [toNat]
|
||||
@@ -43,31 +37,3 @@ declare_bitwise_uint_theorems UInt16 16
|
||||
declare_bitwise_uint_theorems UInt32 32
|
||||
declare_bitwise_uint_theorems UInt64 64
|
||||
declare_bitwise_uint_theorems USize System.Platform.numBits
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem Bool.toBitVec_toUInt8 {b : Bool} :
|
||||
b.toUInt8.toBitVec = (BitVec.ofBool b).setWidth 8 := by
|
||||
cases b <;> simp [toUInt8]
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem Bool.toBitVec_toUInt16 {b : Bool} :
|
||||
b.toUInt16.toBitVec = (BitVec.ofBool b).setWidth 16 := by
|
||||
cases b <;> simp [toUInt16]
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem Bool.toBitVec_toUInt32 {b : Bool} :
|
||||
b.toUInt32.toBitVec = (BitVec.ofBool b).setWidth 32 := by
|
||||
cases b <;> simp [toUInt32]
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem Bool.toBitVec_toUInt64 {b : Bool} :
|
||||
b.toUInt64.toBitVec = (BitVec.ofBool b).setWidth 64 := by
|
||||
cases b <;> simp [toUInt64]
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
theorem Bool.toBitVec_toUSize {b : Bool} :
|
||||
b.toUSize.toBitVec = (BitVec.ofBool b).setWidth System.Platform.numBits := by
|
||||
cases b
|
||||
· simp [toUSize]
|
||||
· apply BitVec.eq_of_toNat_eq
|
||||
simp [toUSize]
|
||||
|
||||
@@ -41,9 +41,9 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
theorem toNat_ofNat_of_lt {n : Nat} (h : n < size) : (ofNat n).toNat = n := by
|
||||
rw [toNat, toBitVec_eq_of_lt h]
|
||||
|
||||
@[int_toBitVec] theorem le_def {a b : $typeName} : a ≤ b ↔ a.toBitVec ≤ b.toBitVec := .rfl
|
||||
theorem le_def {a b : $typeName} : a ≤ b ↔ a.toBitVec ≤ b.toBitVec := .rfl
|
||||
|
||||
@[int_toBitVec] theorem lt_def {a b : $typeName} : a < b ↔ a.toBitVec < b.toBitVec := .rfl
|
||||
theorem lt_def {a b : $typeName} : a < b ↔ a.toBitVec < b.toBitVec := .rfl
|
||||
|
||||
theorem le_iff_toNat_le {a b : $typeName} : a ≤ b ↔ a.toNat ≤ b.toNat := .rfl
|
||||
|
||||
@@ -74,11 +74,6 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
protected theorem toBitVec_inj {a b : $typeName} : a.toBitVec = b.toBitVec ↔ a = b :=
|
||||
Iff.intro eq_of_toBitVec_eq toBitVec_eq_of_eq
|
||||
|
||||
open $typeName (eq_of_toBitVec_eq toBitVec_eq_of_eq) in
|
||||
@[int_toBitVec]
|
||||
protected theorem eq_iff_toBitVec_eq {a b : $typeName} : a = b ↔ a.toBitVec = b.toBitVec :=
|
||||
Iff.intro toBitVec_eq_of_eq eq_of_toBitVec_eq
|
||||
|
||||
open $typeName (eq_of_toBitVec_eq) in
|
||||
protected theorem eq_of_val_eq {a b : $typeName} (h : a.val = b.val) : a = b := by
|
||||
rcases a with ⟨⟨_⟩⟩; rcases b with ⟨⟨_⟩⟩; simp_all [val]
|
||||
@@ -87,19 +82,10 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
protected theorem val_inj {a b : $typeName} : a.val = b.val ↔ a = b :=
|
||||
Iff.intro eq_of_val_eq (congrArg val)
|
||||
|
||||
open $typeName (eq_of_toBitVec_eq) in
|
||||
protected theorem toBitVec_ne_of_ne {a b : $typeName} (h : a ≠ b) : a.toBitVec ≠ b.toBitVec :=
|
||||
fun h' => h (eq_of_toBitVec_eq h')
|
||||
|
||||
open $typeName (toBitVec_eq_of_eq) in
|
||||
protected theorem ne_of_toBitVec_ne {a b : $typeName} (h : a.toBitVec ≠ b.toBitVec) : a ≠ b :=
|
||||
fun h' => absurd (toBitVec_eq_of_eq h') h
|
||||
|
||||
open $typeName (ne_of_toBitVec_ne toBitVec_ne_of_ne) in
|
||||
@[int_toBitVec]
|
||||
protected theorem ne_iff_toBitVec_ne {a b : $typeName} : a ≠ b ↔ a.toBitVec ≠ b.toBitVec :=
|
||||
Iff.intro toBitVec_ne_of_ne ne_of_toBitVec_ne
|
||||
|
||||
open $typeName (ne_of_toBitVec_ne) in
|
||||
protected theorem ne_of_lt {a b : $typeName} (h : a < b) : a ≠ b := by
|
||||
apply ne_of_toBitVec_ne
|
||||
@@ -173,7 +159,7 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
|
||||
@[simp]
|
||||
theorem val_ofNat (n : Nat) : val (no_index (OfNat.ofNat n)) = OfNat.ofNat n := rfl
|
||||
|
||||
@[simp, int_toBitVec]
|
||||
@[simp]
|
||||
theorem toBitVec_ofNat (n : Nat) : toBitVec (no_index (OfNat.ofNat n)) = BitVec.ofNat _ n := rfl
|
||||
|
||||
@[simp]
|
||||
@@ -234,3 +220,23 @@ theorem UInt32.toNat_le_of_le {n : UInt32} {m : Nat} (h : m < size) : n ≤ ofNa
|
||||
|
||||
theorem UInt32.le_toNat_of_le {n : UInt32} {m : Nat} (h : m < size) : ofNat m ≤ n → m ≤ n.toNat := by
|
||||
simp [le_def, BitVec.le_def, UInt32.toNat, toBitVec_eq_of_lt h]
|
||||
|
||||
@[deprecated UInt8.toNat_zero (since := "2024-06-23")] protected abbrev UInt8.zero_toNat := @UInt8.toNat_zero
|
||||
@[deprecated UInt8.toNat_div (since := "2024-06-23")] protected abbrev UInt8.div_toNat := @UInt8.toNat_div
|
||||
@[deprecated UInt8.toNat_mod (since := "2024-06-23")] protected abbrev UInt8.mod_toNat := @UInt8.toNat_mod
|
||||
|
||||
@[deprecated UInt16.toNat_zero (since := "2024-06-23")] protected abbrev UInt16.zero_toNat := @UInt16.toNat_zero
|
||||
@[deprecated UInt16.toNat_div (since := "2024-06-23")] protected abbrev UInt16.div_toNat := @UInt16.toNat_div
|
||||
@[deprecated UInt16.toNat_mod (since := "2024-06-23")] protected abbrev UInt16.mod_toNat := @UInt16.toNat_mod
|
||||
|
||||
@[deprecated UInt32.toNat_zero (since := "2024-06-23")] protected abbrev UInt32.zero_toNat := @UInt32.toNat_zero
|
||||
@[deprecated UInt32.toNat_div (since := "2024-06-23")] protected abbrev UInt32.div_toNat := @UInt32.toNat_div
|
||||
@[deprecated UInt32.toNat_mod (since := "2024-06-23")] protected abbrev UInt32.mod_toNat := @UInt32.toNat_mod
|
||||
|
||||
@[deprecated UInt64.toNat_zero (since := "2024-06-23")] protected abbrev UInt64.zero_toNat := @UInt64.toNat_zero
|
||||
@[deprecated UInt64.toNat_div (since := "2024-06-23")] protected abbrev UInt64.div_toNat := @UInt64.toNat_div
|
||||
@[deprecated UInt64.toNat_mod (since := "2024-06-23")] protected abbrev UInt64.mod_toNat := @UInt64.toNat_mod
|
||||
|
||||
@[deprecated USize.toNat_zero (since := "2024-06-23")] protected abbrev USize.zero_toNat := @USize.toNat_zero
|
||||
@[deprecated USize.toNat_div (since := "2024-06-23")] protected abbrev USize.div_toNat := @USize.toNat_div
|
||||
@[deprecated USize.toNat_mod (since := "2024-06-23")] protected abbrev USize.mod_toNat := @USize.toNat_mod
|
||||
|
||||
@@ -5,10 +5,3 @@ Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Basic
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Vector.Lex
|
||||
import Init.Data.Vector.MapIdx
|
||||
import Init.Data.Vector.Count
|
||||
import Init.Data.Vector.DecidableEq
|
||||
import Init.Data.Vector.Zip
|
||||
import Init.Data.Vector.OfFn
|
||||
|
||||
@@ -1,551 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Array.Attach
|
||||
|
||||
namespace Vector
|
||||
|
||||
/--
|
||||
`O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
|
||||
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||
to apply `f`.
|
||||
|
||||
We replace this at runtime with a more efficient version via the `csimp` lemma `pmap_eq_pmapImpl`.
|
||||
-/
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) (l : Vector α n) (H : ∀ a ∈ l, P a) : Vector β n :=
|
||||
Vector.mk (l.toArray.pmap f (fun a m => H a (by simpa using m))) (by simp)
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
`Vector {x // P x} n` is the same as the input `Vector α n`.
|
||||
-/
|
||||
@[inline] private unsafe def attachWithImpl
|
||||
(xs : Vector α n) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Vector {x // P x} n := unsafeCast xs
|
||||
|
||||
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array
|
||||
with the same elements but in the type `{x // P x}`. -/
|
||||
@[implemented_by attachWithImpl] def attachWith
|
||||
(xs : Vector α n) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Vector {x // P x} n :=
|
||||
Vector.mk (xs.toArray.attachWith P fun x h => H x (by simpa using h)) (by simp)
|
||||
|
||||
/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new vector
|
||||
with the same elements but in the type `{x // x ∈ xs}`. -/
|
||||
@[inline] def attach (xs : Vector α n) : Vector {x // x ∈ xs} n := xs.attachWith _ fun _ => id
|
||||
|
||||
@[simp] theorem attachWith_mk {xs : Array α} {h : xs.size = n} {P : α → Prop} {H : ∀ x ∈ mk xs h, P x} :
|
||||
(mk xs h).attachWith P H = mk (xs.attachWith P (by simpa using H)) (by simpa using h) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem attach_mk {xs : Array α} {h : xs.size = n} :
|
||||
(mk xs h).attach = mk (xs.attachWith (· ∈ mk xs h) (by simp)) (by simpa using h):= by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem pmap_mk {xs : Array α} {h : xs.size = n} {P : α → Prop} {f : ∀ a, P a → β}
|
||||
{H : ∀ a ∈ mk xs h, P a} :
|
||||
(mk xs h).pmap f H = mk (xs.pmap f (by simpa using H)) (by simpa using h) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toArray_attachWith {l : Vector α n} {P : α → Prop} {H : ∀ x ∈ l, P x} :
|
||||
(l.attachWith P H).toArray = l.toArray.attachWith P (by simpa using H) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem toArray_attach {α : Type _} {l : Vector α n} :
|
||||
l.attach.toArray = l.toArray.attachWith (· ∈ l) (by simp) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toArray_pmap {l : Vector α n} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l, P a} :
|
||||
(l.pmap f H).toArray = l.toArray.pmap f (fun a m => H a (by simpa using m)) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem toList_attachWith {l : Vector α n} {P : α → Prop} {H : ∀ x ∈ l, P x} :
|
||||
(l.attachWith P H).toList = l.toList.attachWith P (by simpa using H) := by
|
||||
simp [attachWith]
|
||||
|
||||
@[simp] theorem toList_attach {α : Type _} {l : Vector α n} :
|
||||
l.attach.toList = l.toList.attachWith (· ∈ l) (by simp) := by
|
||||
simp [attach]
|
||||
|
||||
@[simp] theorem toList_pmap {l : Vector α n} {P : α → Prop} {f : ∀ a, P a → β} {H : ∀ a ∈ l, P a} :
|
||||
(l.pmap f H).toList = l.toList.pmap f (fun a m => H a (by simpa using m)) := by
|
||||
simp [pmap]
|
||||
|
||||
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||
@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : Vector α n) (H : ∀ a ∈ l, P a) :
|
||||
Vector β n := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h'
|
||||
|
||||
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
|
||||
funext α β n p f L h'
|
||||
rcases L with ⟨L, rfl⟩
|
||||
simp only [pmap, pmapImpl, attachWith_mk, map_mk, Array.map_attachWith, eq_mk]
|
||||
apply Array.pmap_congr_left
|
||||
intro a m h₁ h₂
|
||||
congr
|
||||
|
||||
@[simp] theorem pmap_empty {P : α → Prop} (f : ∀ a, P a → β) : pmap f #v[] (by simp) = #v[] := rfl
|
||||
|
||||
@[simp] theorem pmap_push {P : α → Prop} (f : ∀ a, P a → β) (a : α) (l : Vector α n) (h : ∀ b ∈ l.push a, P b) :
|
||||
pmap f (l.push a) h =
|
||||
(pmap f l (fun a m => by simp at h; exact h a (.inl m))).push (f a (h a (by simp))) := by
|
||||
simp [pmap]
|
||||
|
||||
@[simp] theorem attach_empty : (#v[] : Vector α 0).attach = #v[] := rfl
|
||||
|
||||
@[simp] theorem attachWith_empty {P : α → Prop} (H : ∀ x ∈ #v[], P x) : (#v[] : Vector α 0).attachWith P H = #v[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_map (p : α → Prop) (f : α → β) (l : Vector α n) (H) :
|
||||
@pmap _ _ _ p (fun a _ => f a) l H = map f l := by
|
||||
cases l; simp
|
||||
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (l : Vector α n) {H₁ H₂}
|
||||
(h : ∀ a ∈ l, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp only [pmap_mk, eq_mk]
|
||||
apply Array.pmap_congr_left
|
||||
simpa using h
|
||||
|
||||
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (l : Vector α n) (H) :
|
||||
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.map_pmap]
|
||||
|
||||
theorem pmap_map {p : β → Prop} (g : ∀ b, p b → γ) (f : α → β) (l : Vector α n) (H) :
|
||||
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun _ h => H _ (mem_map_of_mem _ h) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.pmap_map]
|
||||
|
||||
theorem attach_congr {l₁ l₂ : Vector α n} (h : l₁ = l₂) :
|
||||
l₁.attach = l₂.attach.map (fun x => ⟨x.1, h ▸ x.2⟩) := by
|
||||
subst h
|
||||
simp
|
||||
|
||||
theorem attachWith_congr {l₁ l₂ : Vector α n} (w : l₁ = l₂) {P : α → Prop} {H : ∀ x ∈ l₁, P x} :
|
||||
l₁.attachWith P H = l₂.attachWith P fun _ h => H _ (w ▸ h) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_push {a : α} {l : Vector α n} :
|
||||
(l.push a).attach =
|
||||
(l.attach.map (fun ⟨x, h⟩ => ⟨x, mem_push_of_mem a h⟩)).push ⟨a, by simp⟩ := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.map_attachWith]
|
||||
|
||||
@[simp] theorem attachWith_push {a : α} {l : Vector α n} {P : α → Prop} {H : ∀ x ∈ l.push a, P x} :
|
||||
(l.push a).attachWith P H =
|
||||
(l.attachWith P (fun x h => by simp at H; exact H x (.inl h))).push ⟨a, H a (by simp)⟩ := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l : Vector α n) (H) :
|
||||
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp only [pmap_mk, Array.pmap_eq_map_attach, attach_mk, map_mk, eq_mk]
|
||||
rw [Array.map_attach, Array.map_attachWith]
|
||||
ext i hi₁ hi₂ <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem pmap_eq_attachWith {p q : α → Prop} (f : ∀ a, p a → q a) (l : Vector α n) (H) :
|
||||
pmap (fun a h => ⟨a, f a h⟩) l H = l.attachWith q (fun x h => f x (H x h)) := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem attach_map_coe (l : Vector α n) (f : α → β) :
|
||||
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
theorem attach_map_val (l : Vector α n) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||
attach_map_coe _ _
|
||||
|
||||
theorem attach_map_subtype_val (l : Vector α n) : l.attach.map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_coe {p : α → Prop} (f : α → β) (l : Vector α n) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun (i : { i // p i}) => f i) = l.map f := by
|
||||
cases l; simp
|
||||
|
||||
theorem attachWith_map_val {p : α → Prop} (f : α → β) (l : Vector α n) (H : ∀ a ∈ l, p a) :
|
||||
((l.attachWith p H).map fun i => f i.val) = l.map f :=
|
||||
attachWith_map_coe _ _ _
|
||||
|
||||
theorem attachWith_map_subtype_val {p : α → Prop} (l : Vector α n) (H : ∀ a ∈ l, p a) :
|
||||
(l.attachWith p H).map Subtype.val = l := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem mem_attach (l : Vector α n) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||
exact m
|
||||
|
||||
@[simp]
|
||||
theorem mem_attachWith (l : Vector α n) {q : α → Prop} (H) (x : {x // q x}) :
|
||||
x ∈ l.attachWith q H ↔ x.1 ∈ l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l : Vector α n} {H b} :
|
||||
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {l : Vector α n} {H} {a} (h : a ∈ l) :
|
||||
f a (H a h) ∈ pmap f l H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
theorem pmap_eq_self {l : Vector α n} {p : α → Prop} {hp : ∀ (a : α), a ∈ l → p a}
|
||||
{f : (a : α) → p a → α} : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
cases l; simp [Array.pmap_eq_self]
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Vector α n} (h : ∀ a ∈ l, p a) (i : Nat) :
|
||||
(pmap f l h)[i]? = Option.pmap f l[i]? fun x H => h x (mem_of_getElem? H) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : Vector α n} (h : ∀ a ∈ l, p a) {i : Nat}
|
||||
(hn : i < n) :
|
||||
(pmap f l h)[i] = f (l[i]) (h _ (by simp)) := by
|
||||
cases l; simp
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attachWith {xs : Vector α n} {i : Nat} {P : α → Prop} {H : ∀ a ∈ xs, P a} :
|
||||
(xs.attachWith P H)[i]? = xs[i]?.pmap Subtype.mk (fun _ a => H _ (mem_of_getElem? a)) :=
|
||||
getElem?_pmap ..
|
||||
|
||||
@[simp]
|
||||
theorem getElem?_attach {xs : Vector α n} {i : Nat} :
|
||||
xs.attach[i]? = xs[i]?.pmap Subtype.mk (fun _ a => mem_of_getElem? a) :=
|
||||
getElem?_attachWith
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attachWith {xs : Vector α n} {P : α → Prop} {H : ∀ a ∈ xs, P a}
|
||||
{i : Nat} (h : i < n) :
|
||||
(xs.attachWith P H)[i] = ⟨xs[i]'(by simpa using h), H _ (getElem_mem (by simpa using h))⟩ :=
|
||||
getElem_pmap _ _ h
|
||||
|
||||
@[simp]
|
||||
theorem getElem_attach {xs : Vector α n} {i : Nat} (h : i < n) :
|
||||
xs.attach[i] = ⟨xs[i]'(by simpa using h), getElem_mem (by simpa using h)⟩ :=
|
||||
getElem_attachWith h
|
||||
|
||||
@[simp] theorem pmap_attach (l : Vector α n) {p : {x // x ∈ l} → Prop} (f : ∀ a, p a → β) (H) :
|
||||
pmap f l.attach H =
|
||||
l.pmap (P := fun a => ∃ h : a ∈ l, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨h, H ⟨a, h⟩ (by simp)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem pmap_attachWith (l : Vector α n) {p : {x // q x} → Prop} (f : ∀ a, p a → β) (H₁ H₂) :
|
||||
pmap f (l.attachWith q H₁) H₂ =
|
||||
l.pmap (P := fun a => ∃ h : q a, p ⟨a, h⟩)
|
||||
(fun a h => f ⟨a, h.1⟩ h.2) (fun a h => ⟨H₁ _ h, H₂ ⟨a, H₁ _ h⟩ (by simpa)⟩) := by
|
||||
ext <;> simp
|
||||
|
||||
theorem foldl_pmap (l : Vector α n) {P : α → Prop} (f : (a : α) → P a → β)
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : γ → β → γ) (x : γ) :
|
||||
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
|
||||
rw [pmap_eq_map_attach, foldl_map]
|
||||
|
||||
theorem foldr_pmap (l : Vector α n) {P : α → Prop} (f : (a : α) → P a → β)
|
||||
(H : ∀ (a : α), a ∈ l → P a) (g : β → γ → γ) (x : γ) :
|
||||
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by
|
||||
rw [pmap_eq_map_attach, foldr_map]
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldl_subtype` below.
|
||||
-/
|
||||
theorem foldl_attach (l : Vector α n) (f : β → α → β) (b : β) :
|
||||
l.attach.foldl (fun acc t => f acc t.1) b = l.foldl f b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.foldl_attach]
|
||||
|
||||
/--
|
||||
If we fold over `l.attach` with a function that ignores the membership predicate,
|
||||
we get the same results as folding over `l` directly.
|
||||
|
||||
This is useful when we need to use `attach` to show termination.
|
||||
|
||||
Unfortunately this can't be applied by `simp` because of the higher order unification problem,
|
||||
and even when rewriting we need to specify the function explicitly.
|
||||
See however `foldr_subtype` below.
|
||||
-/
|
||||
theorem foldr_attach (l : Vector α n) (f : α → β → β) (b : β) :
|
||||
l.attach.foldr (fun t acc => f t.1 acc) b = l.foldr f b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.foldr_attach]
|
||||
|
||||
theorem attach_map {l : Vector α n} (f : α → β) :
|
||||
(l.map f).attach = l.attach.map (fun ⟨x, h⟩ => ⟨f x, mem_map_of_mem f h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem attachWith_map {l : Vector α n} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ l.map f → P b} :
|
||||
(l.map f).attachWith P H = (l.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.attachWith_map]
|
||||
|
||||
theorem map_attachWith {l : Vector α n} {P : α → Prop} {H : ∀ (a : α), a ∈ l → P a}
|
||||
(f : { x // P x } → β) :
|
||||
(l.attachWith P H).map f =
|
||||
l.pmap (fun a (h : a ∈ l ∧ P a) => f ⟨a, H _ h.1⟩) (fun a h => ⟨h, H a h⟩) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
/-- See also `pmap_eq_map_attach` for writing `pmap` in terms of `map` and `attach`. -/
|
||||
theorem map_attach {l : Vector α n} (f : { x // x ∈ l } → β) :
|
||||
l.attach.map f = l.pmap (fun a h => f ⟨a, h⟩) (fun _ => id) := by
|
||||
cases l
|
||||
ext <;> simp
|
||||
|
||||
theorem pmap_pmap {p : α → Prop} {q : β → Prop} (g : ∀ a, p a → β) (f : ∀ b, q b → γ) (l : Vector α n) (H₁ H₂) :
|
||||
pmap f (pmap g l H₁) H₂ =
|
||||
pmap (α := { x // x ∈ l }) (fun a h => f (g a h) (H₂ (g a h) (mem_pmap_of_mem a.2))) l.attach
|
||||
(fun a _ => H₁ a a.2) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem pmap_append {p : ι → Prop} (f : ∀ a : ι, p a → α) (l₁ : Vector ι n) (l₂ : Vector ι m)
|
||||
(h : ∀ a ∈ l₁ ++ l₂, p a) :
|
||||
(l₁ ++ l₂).pmap f h =
|
||||
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
|
||||
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ : Vector α n) (l₂ : Vector α m)
|
||||
(h₁ : ∀ a ∈ l₁, p a) (h₂ : ∀ a ∈ l₂, p a) :
|
||||
((l₁ ++ l₂).pmap f fun a ha => (mem_append.1 ha).elim (h₁ a) (h₂ a)) =
|
||||
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
|
||||
pmap_append f l₁ l₂ _
|
||||
|
||||
@[simp] theorem attach_append (xs : Vector α n) (ys : Vector α m) :
|
||||
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => (⟨x, mem_append_left ys h⟩ : { x // x ∈ xs ++ ys })) ++
|
||||
ys.attach.map (fun ⟨y, h⟩ => (⟨y, mem_append_right xs h⟩ : { y // y ∈ xs ++ ys })) := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
rcases ys with ⟨ys, rfl⟩
|
||||
simp [Array.map_attachWith]
|
||||
|
||||
@[simp] theorem attachWith_append {P : α → Prop} {xs : Vector α n} {ys : Vector α m}
|
||||
{H : ∀ (a : α), a ∈ xs ++ ys → P a} :
|
||||
(xs ++ ys).attachWith P H = xs.attachWith P (fun a h => H a (mem_append_left ys h)) ++
|
||||
ys.attachWith P (fun a h => H a (mem_append_right xs h)) := by
|
||||
simp [attachWith, attach_append, map_pmap, pmap_append]
|
||||
|
||||
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : Vector α n)
|
||||
(H : ∀ (a : α), a ∈ xs.reverse → P a) :
|
||||
xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||
induction xs <;> simp_all
|
||||
|
||||
theorem reverse_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Vector α n)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||
rw [pmap_reverse]
|
||||
|
||||
@[simp] theorem attachWith_reverse {P : α → Prop} {xs : Vector α n}
|
||||
{H : ∀ (a : α), a ∈ xs.reverse → P a} :
|
||||
xs.reverse.attachWith P H =
|
||||
(xs.attachWith P (fun a h => H a (by simpa using h))).reverse := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
theorem reverse_attachWith {P : α → Prop} {xs : Vector α n}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).reverse = (xs.reverse.attachWith P (fun a h => H a (by simpa using h))) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem attach_reverse (xs : Vector α n) :
|
||||
xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
rw [attach_congr (reverse_mk ..)]
|
||||
simp [Array.map_attachWith]
|
||||
|
||||
theorem reverse_attach (xs : Vector α n) :
|
||||
xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||
cases xs
|
||||
simp [Array.map_attachWith]
|
||||
|
||||
@[simp] theorem back?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : Vector α n)
|
||||
(H : ∀ (a : α), a ∈ xs → P a) :
|
||||
(xs.pmap f H).back? = xs.attach.back?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_attachWith {P : α → Prop} {xs : Vector α n}
|
||||
{H : ∀ (a : α), a ∈ xs → P a} :
|
||||
(xs.attachWith P H).back? = xs.back?.pbind (fun a h => some ⟨a, H _ (mem_of_back? h)⟩) := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem back?_attach {xs : Vector α n} :
|
||||
xs.attach.back? = xs.back?.pbind fun a h => some ⟨a, mem_of_back? h⟩ := by
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem countP_attach (l : Vector α n) (p : α → Bool) :
|
||||
l.attach.countP (fun a : {x // x ∈ l} => p a) = l.countP p := by
|
||||
cases l
|
||||
simp [Function.comp_def]
|
||||
|
||||
@[simp]
|
||||
theorem countP_attachWith {p : α → Prop} (l : Vector α n) (H : ∀ a ∈ l, p a) (q : α → Bool) :
|
||||
(l.attachWith p H).countP (fun a : {x // p x} => q a) = l.countP q := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attach [DecidableEq α] (l : Vector α n) (a : {x // x ∈ l}) :
|
||||
l.attach.count a = l.count ↑a := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem count_attachWith [DecidableEq α] {p : α → Prop} (l : Vector α n) (H : ∀ a ∈ l, p a) (a : {x // p x}) :
|
||||
(l.attachWith p H).count a = l.count ↑a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_pmap {p : α → Prop} (g : ∀ a, p a → β) (f : β → Bool) (l : Vector α n) (H₁) :
|
||||
(l.pmap g H₁).countP f =
|
||||
l.attach.countP (fun ⟨a, m⟩ => f (g a (H₁ a m))) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp only [pmap_mk, countP_mk, Array.countP_pmap]
|
||||
simp [Array.countP_eq_size_filter]
|
||||
|
||||
/-! ## unattach
|
||||
|
||||
`Vector.unattach` is the (one-sided) inverse of `Vector.attach`. It is a synonym for `Vector.map Subtype.val`.
|
||||
|
||||
We use it by providing a simp lemma `l.attach.unattach = l`, and simp lemmas which recognize higher order
|
||||
functions applied to `l : Vector { x // p x }` which only depend on the value, not the predicate, and rewrite these
|
||||
in terms of a simpler function applied to `l.unattach`.
|
||||
|
||||
Further, we provide simp lemmas that push `unattach` inwards.
|
||||
-/
|
||||
|
||||
/--
|
||||
A synonym for `l.map (·.val)`. Mostly this should not be needed by users.
|
||||
It is introduced as in intermediate step by lemmas such as `map_subtype`,
|
||||
and is ideally subsequently simplified away by `unattach_attach`.
|
||||
|
||||
If not, usually the right approach is `simp [Vector.unattach, -Vector.map_subtype]` to unfold.
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (l : Vector { x // p x } n) : Vector α n := l.map (·.val)
|
||||
|
||||
@[simp] theorem unattach_nil {p : α → Prop} : (#v[] : Vector { x // p x } 0).unattach = #v[] := rfl
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {l : Vector { x // p x } n} :
|
||||
(l.push a).unattach = l.unattach.push a.1 := by
|
||||
simp only [unattach, Vector.map_push]
|
||||
|
||||
@[simp] theorem unattach_mk {p : α → Prop} {l : Array { x // p x }} {h : l.size = n} :
|
||||
(mk l h).unattach = mk l.unattach (by simpa using h) := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem toArray_unattach {p : α → Prop} {l : Vector { x // p x } n} :
|
||||
l.unattach.toArray = l.toArray.unattach := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem toList_unattach {p : α → Prop} {l : Array { x // p x }} :
|
||||
l.unattach.toList = l.toList.unattach := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem unattach_attach {l : Vector α n} : l.attach.unattach = l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem unattach_attachWith {p : α → Prop} {l : Vector α n}
|
||||
{H : ∀ a ∈ l, p a} :
|
||||
(l.attachWith p H).unattach = l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_unattach {p : α → Prop} {l : Vector { x // p x } n} (i : Nat) :
|
||||
l.unattach[i]? = l[i]?.map Subtype.val := by
|
||||
simp [unattach]
|
||||
|
||||
@[simp] theorem getElem_unattach
|
||||
{p : α → Prop} {l : Vector { x // p x } n} (i : Nat) (h : i < n) :
|
||||
l.unattach[i] = (l[i]'(by simpa using h)).1 := by
|
||||
simp [unattach]
|
||||
|
||||
/-! ### Recognizing higher order functions using a function that only depends on the value. -/
|
||||
|
||||
/--
|
||||
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
|
||||
and simplifies these to the function directly taking the value.
|
||||
-/
|
||||
@[simp] theorem foldl_subtype {p : α → Prop} {l : Vector { x // p x } n}
|
||||
{f : β → { x // p x } → β} {g : β → α → β} {x : β}
|
||||
{hf : ∀ b x h, f b ⟨x, h⟩ = g b x} :
|
||||
l.foldl f x = l.unattach.foldl g x := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.foldl_subtype (hf := hf)]
|
||||
|
||||
/--
|
||||
This lemma identifies folds over arrays of subtypes, where the function only depends on the value, not the proposition,
|
||||
and simplifies these to the function directly taking the value.
|
||||
-/
|
||||
@[simp] theorem foldr_subtype {p : α → Prop} {l : Vector { x // p x } n}
|
||||
{f : { x // p x } → β → β} {g : α → β → β} {x : β}
|
||||
{hf : ∀ x h b, f ⟨x, h⟩ b = g x b} :
|
||||
l.foldr f x = l.unattach.foldr g x := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.foldr_subtype (hf := hf)]
|
||||
|
||||
/--
|
||||
This lemma identifies maps over arrays of subtypes, where the function only depends on the value, not the proposition,
|
||||
and simplifies these to the function directly taking the value.
|
||||
-/
|
||||
@[simp] theorem map_subtype {p : α → Prop} {l : Vector { x // p x } n}
|
||||
{f : { x // p x } → β} {g : α → β} {hf : ∀ x h, f ⟨x, h⟩ = g x} :
|
||||
l.map f = l.unattach.map g := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.map_subtype (hf := hf)]
|
||||
|
||||
/-! ### Simp lemmas pushing `unattach` inwards. -/
|
||||
|
||||
@[simp] theorem unattach_reverse {p : α → Prop} {l : Vector { x // p x } n} :
|
||||
l.reverse.unattach = l.unattach.reverse := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.unattach_reverse]
|
||||
|
||||
|
||||
@[simp] theorem unattach_append {p : α → Prop} {l₁ l₂ : Vector { x // p x } n} :
|
||||
(l₁ ++ l₂).unattach = l₁.unattach ++ l₂.unattach := by
|
||||
rcases l₁
|
||||
rcases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem unattach_flatten {p : α → Prop} {l : Vector (Vector { x // p x } n) n} :
|
||||
l.flatten.unattach = (l.map unattach).flatten := by
|
||||
unfold unattach
|
||||
cases l using vector₂_induction
|
||||
simp only [flatten_mk, Array.map_map, Function.comp_apply, Array.map_subtype,
|
||||
Array.unattach_attach, Array.map_id_fun', id_eq, map_mk, Array.map_flatten, map_subtype,
|
||||
map_id_fun', unattach_mk, eq_mk]
|
||||
unfold Array.unattach
|
||||
rfl
|
||||
|
||||
@[simp] theorem unattach_mkVector {p : α → Prop} {n : Nat} {x : { x // p x }} :
|
||||
(mkVector n x).unattach = mkVector n x.1 := by
|
||||
simp [unattach]
|
||||
|
||||
end Vector
|
||||
@@ -6,9 +6,7 @@ Authors: Shreyas Srinivas, François G. Dorais, Kim Morrison
|
||||
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Range
|
||||
import Init.Data.Stream
|
||||
|
||||
/-!
|
||||
# Vectors
|
||||
@@ -92,12 +90,14 @@ of bounds.
|
||||
/-- The last element of a vector. Panics if the vector is empty. -/
|
||||
@[inline] def back! [Inhabited α] (v : Vector α n) : α := v.toArray.back!
|
||||
|
||||
/-- The last element of a vector, or `none` if the vector is empty. -/
|
||||
/-- The last element of a vector, or `none` if the array is empty. -/
|
||||
@[inline] def back? (v : Vector α n) : Option α := v.toArray.back?
|
||||
|
||||
/-- The last element of a non-empty vector. -/
|
||||
@[inline] def back [NeZero n] (v : Vector α n) : α :=
|
||||
v[n - 1]'(Nat.sub_one_lt (NeZero.ne n))
|
||||
-- TODO: change to just `v[n]`
|
||||
have : Inhabited α := ⟨v[0]'(Nat.pos_of_neZero n)⟩
|
||||
v.back!
|
||||
|
||||
/-- The first element of a non-empty vector. -/
|
||||
@[inline] def head [NeZero n] (v : Vector α n) := v[0]'(Nat.pos_of_neZero n)
|
||||
@@ -170,47 +170,9 @@ result is empty. If `stop` is greater than the size of the vector, the size is u
|
||||
@[inline] def map (f : α → β) (v : Vector α n) : Vector β n :=
|
||||
⟨v.toArray.map f, by simp⟩
|
||||
|
||||
/-- Maps elements of a vector using the function `f`, which also receives the index of the element. -/
|
||||
@[inline] def mapIdx (f : Nat → α → β) (v : Vector α n) : Vector β n :=
|
||||
⟨v.toArray.mapIdx f, by simp⟩
|
||||
|
||||
/-- Maps elements of a vector using the function `f`,
|
||||
which also receives the index of the element, and the fact that the index is less than the size of the vector. -/
|
||||
@[inline] def mapFinIdx (v : Vector α n) (f : (i : Nat) → α → (h : i < n) → β) : Vector β n :=
|
||||
⟨v.toArray.mapFinIdx (fun i a h => f i a (by simpa [v.size_toArray] using h)), by simp⟩
|
||||
|
||||
/-- Map a monadic function over a vector. -/
|
||||
def mapM [Monad m] (f : α → m β) (v : Vector α n) : m (Vector β n) := do
|
||||
go 0 (Nat.zero_le n) #v[]
|
||||
where
|
||||
go (i : Nat) (h : i ≤ n) (r : Vector β i) : m (Vector β n) := do
|
||||
if h' : i < n then
|
||||
go (i+1) (by omega) (r.push (← f v[i]))
|
||||
else
|
||||
return r.cast (by omega)
|
||||
|
||||
@[inline] def flatten (v : Vector (Vector α n) m) : Vector α (m * n) :=
|
||||
⟨(v.toArray.map Vector.toArray).flatten,
|
||||
by rcases v; simp_all [Function.comp_def, Array.map_const']⟩
|
||||
|
||||
@[inline] def flatMap (v : Vector α n) (f : α → Vector β m) : Vector β (n * m) :=
|
||||
⟨v.toArray.flatMap fun a => (f a).toArray, by simp [Array.map_const']⟩
|
||||
|
||||
@[inline] def zipIdx (v : Vector α n) (k : Nat := 0) : Vector (α × Nat) n :=
|
||||
⟨v.toArray.zipIdx k, by simp⟩
|
||||
|
||||
@[deprecated zipIdx (since := "2025-01-21")]
|
||||
abbrev zipWithIndex := @zipIdx
|
||||
|
||||
@[inline] def zip (v : Vector α n) (w : Vector β n) : Vector (α × β) n :=
|
||||
⟨v.toArray.zip w.toArray, by simp⟩
|
||||
|
||||
/-- Maps corresponding elements of two vectors of equal size using the function `f`. -/
|
||||
@[inline] def zipWith (f : α → β → φ) (a : Vector α n) (b : Vector β n) : Vector φ n :=
|
||||
⟨Array.zipWith f a.toArray b.toArray, by simp⟩
|
||||
|
||||
@[inline] def unzip (v : Vector (α × β) n) : Vector α n × Vector β n :=
|
||||
⟨⟨v.toArray.unzip.1, by simp⟩, ⟨v.toArray.unzip.2, by simp⟩⟩
|
||||
@[inline] def zipWith (a : Vector α n) (b : Vector β n) (f : α → β → φ) : Vector φ n :=
|
||||
⟨Array.zipWith a.toArray b.toArray f, by simp⟩
|
||||
|
||||
/-- The vector of length `n` whose `i`-th element is `f i`. -/
|
||||
@[inline] def ofFn (f : Fin n → α) : Vector α n :=
|
||||
@@ -332,27 +294,6 @@ no element of the index matches the given value.
|
||||
@[inline] def all (v : Vector α n) (p : α → Bool) : Bool :=
|
||||
v.toArray.all p
|
||||
|
||||
/-- Count the number of elements of a vector that satisfy the predicate `p`. -/
|
||||
@[inline] def countP (p : α → Bool) (v : Vector α n) : Nat :=
|
||||
v.toArray.countP p
|
||||
|
||||
/-- Count the number of elements of a vector that are equal to `a`. -/
|
||||
@[inline] def count [BEq α] (a : α) (v : Vector α n) : Nat :=
|
||||
v.toArray.count a
|
||||
|
||||
/-! ### ForIn instance -/
|
||||
|
||||
@[simp] theorem mem_toArray_iff (a : α) (v : Vector α n) : a ∈ v.toArray ↔ a ∈ v :=
|
||||
⟨fun h => ⟨h⟩, fun ⟨h⟩ => h⟩
|
||||
|
||||
instance : ForIn' m (Vector α n) α inferInstance where
|
||||
forIn' v b f := Array.forIn' v.toArray b (fun a h b => f a (by simpa using h) b)
|
||||
|
||||
/-! ### ToStream instance -/
|
||||
|
||||
instance : ToStream (Vector α n) (Subarray α) where
|
||||
toStream v := v.toArray[:n]
|
||||
|
||||
/-! ### Lexicographic ordering -/
|
||||
|
||||
instance instLT [LT α] : LT (Vector α n) := ⟨fun v w => v.toArray < w.toArray⟩
|
||||
|
||||
@@ -1,233 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Count
|
||||
import Init.Data.Vector.Lemmas
|
||||
|
||||
/-!
|
||||
# Lemmas about `Vector.countP` and `Vector.count`.
|
||||
-/
|
||||
|
||||
namespace Vector
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ### countP -/
|
||||
section countP
|
||||
|
||||
variable (p q : α → Bool)
|
||||
|
||||
@[simp] theorem countP_empty : countP p #v[] = 0 := rfl
|
||||
|
||||
@[simp] theorem countP_push_of_pos (l : Vector α n) (pa : p a) : countP p (l.push a) = countP p l + 1 := by
|
||||
rcases l with ⟨l⟩
|
||||
simp_all
|
||||
|
||||
@[simp] theorem countP_push_of_neg (l : Vector α n) (pa : ¬p a) : countP p (l.push a) = countP p l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp_all
|
||||
|
||||
theorem countP_push (a : α) (l : Vector α n) : countP p (l.push a) = countP p l + if p a then 1 else 0 := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.countP_push]
|
||||
|
||||
@[simp] theorem countP_singleton (a : α) : countP p #v[a] = if p a then 1 else 0 := by
|
||||
simp [countP_push]
|
||||
|
||||
theorem size_eq_countP_add_countP (l : Vector α n) : n = countP p l + countP (fun a => ¬p a) l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [List.length_eq_countP_add_countP (p := p)]
|
||||
|
||||
theorem countP_le_size {l : Vector α n} : countP p l ≤ n := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.countP_le_size (p := p)]
|
||||
|
||||
@[simp] theorem countP_append (l₁ : Vector α n) (l₂ : Vector α m) : countP p (l₁ ++ l₂) = countP p l₁ + countP p l₂ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_pos_iff {p} : 0 < countP p l ↔ ∃ a ∈ l, p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem one_le_countP_iff {p} : 1 ≤ countP p l ↔ ∃ a ∈ l, p a :=
|
||||
countP_pos_iff
|
||||
|
||||
@[simp] theorem countP_eq_zero {p} : countP p l = 0 ↔ ∀ a ∈ l, ¬p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_eq_size {p} : countP p l = l.size ↔ ∀ a ∈ l, p a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_cast (p : α → Bool) (l : Vector α n) : countP p (l.cast h) = countP p l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
theorem countP_mkVector (p : α → Bool) (a : α) (n : Nat) :
|
||||
countP p (mkVector n a) = if p a then n else 0 := by
|
||||
simp only [mkVector_eq_toVector_mkArray, countP_cast, countP_mk]
|
||||
simp [Array.countP_mkArray]
|
||||
|
||||
theorem boole_getElem_le_countP (p : α → Bool) (l : Vector α n) (i : Nat) (h : i < n) :
|
||||
(if p l[i] then 1 else 0) ≤ l.countP p := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.boole_getElem_le_countP]
|
||||
|
||||
theorem countP_set (p : α → Bool) (l : Vector α n) (i : Nat) (a : α) (h : i < n) :
|
||||
(l.set i a).countP p = l.countP p - (if p l[i] then 1 else 0) + (if p a then 1 else 0) := by
|
||||
cases l
|
||||
simp [Array.countP_set, h]
|
||||
|
||||
@[simp] theorem countP_true : (countP fun (_ : α) => true) = (fun (_ : Vector α n) => n) := by
|
||||
funext l
|
||||
rw [countP]
|
||||
simp only [Array.countP_true, l.2]
|
||||
|
||||
@[simp] theorem countP_false : (countP fun (_ : α) => false) = (fun (_ : Vector α n) => 0) := by
|
||||
funext l
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_map (p : β → Bool) (f : α → β) (l : Vector α n) :
|
||||
countP p (map f l) = countP (p ∘ f) l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem countP_flatten (l : Vector (Vector α m) n) :
|
||||
countP p l.flatten = (l.map (countP p)).sum := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Function.comp_def]
|
||||
|
||||
theorem countP_flatMap (p : β → Bool) (l : Vector α n) (f : α → Vector β m) :
|
||||
countP p (l.flatMap f) = (map (countP p ∘ f) l).sum := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.countP_flatMap, Function.comp_def]
|
||||
|
||||
@[simp] theorem countP_reverse (l : Vector α n) : countP p l.reverse = countP p l := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
variable {p q}
|
||||
|
||||
theorem countP_mono_left (h : ∀ x ∈ l, p x → q x) : countP p l ≤ countP q l := by
|
||||
cases l
|
||||
simpa using Array.countP_mono_left (by simpa using h)
|
||||
|
||||
theorem countP_congr (h : ∀ x ∈ l, p x ↔ q x) : countP p l = countP q l :=
|
||||
Nat.le_antisymm
|
||||
(countP_mono_left fun x hx => (h x hx).1)
|
||||
(countP_mono_left fun x hx => (h x hx).2)
|
||||
|
||||
end countP
|
||||
|
||||
/-! ### count -/
|
||||
section count
|
||||
|
||||
variable [BEq α]
|
||||
|
||||
@[simp] theorem count_empty (a : α) : count a #v[] = 0 := rfl
|
||||
|
||||
theorem count_push (a b : α) (l : Vector α n) :
|
||||
count a (l.push b) = count a l + if b == a then 1 else 0 := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_push]
|
||||
|
||||
theorem count_eq_countP (a : α) (l : Vector α n) : count a l = countP (· == a) l := rfl
|
||||
|
||||
theorem count_eq_countP' {a : α} : count (n := n) a = countP (· == a) := by
|
||||
funext l
|
||||
apply count_eq_countP
|
||||
|
||||
theorem count_le_size (a : α) (l : Vector α n) : count a l ≤ n := countP_le_size _
|
||||
|
||||
theorem count_le_count_push (a b : α) (l : Vector α n) : count a l ≤ count a (l.push b) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_push]
|
||||
|
||||
@[simp] theorem count_singleton (a b : α) : count a #v[b] = if b == a then 1 else 0 := by
|
||||
simp [count_eq_countP]
|
||||
|
||||
@[simp] theorem count_append (a : α) (l₁ : Vector α n) (l₂ : Vector α m) :
|
||||
count a (l₁ ++ l₂) = count a l₁ + count a l₂ :=
|
||||
countP_append ..
|
||||
|
||||
@[simp] theorem count_flatten (a : α) (l : Vector (Vector α m) n) :
|
||||
count a l.flatten = (l.map (count a)).sum := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_flatten, Function.comp_def]
|
||||
|
||||
@[simp] theorem count_reverse (a : α) (l : Vector α n) : count a l.reverse = count a l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
theorem boole_getElem_le_count (a : α) (l : Vector α n) (i : Nat) (h : i < n) :
|
||||
(if l[i] == a then 1 else 0) ≤ l.count a := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.boole_getElem_le_count, h]
|
||||
|
||||
theorem count_set (a b : α) (l : Vector α n) (i : Nat) (h : i < n) :
|
||||
(l.set i a).count b = l.count b - (if l[i] == b then 1 else 0) + (if a == b then 1 else 0) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_set, h]
|
||||
|
||||
@[simp] theorem count_cast (l : Vector α n) : (l.cast h).count a = l.count a := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
variable [LawfulBEq α]
|
||||
|
||||
@[simp] theorem count_push_self (a : α) (l : Vector α n) : count a (l.push a) = count a l + 1 := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_push_self]
|
||||
|
||||
@[simp] theorem count_push_of_ne (h : b ≠ a) (l : Vector α n) : count a (l.push b) = count a l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_push_of_ne, h]
|
||||
|
||||
theorem count_singleton_self (a : α) : count a #v[a] = 1 := by simp
|
||||
|
||||
@[simp]
|
||||
theorem count_pos_iff {a : α} {l : Vector α n} : 0 < count a l ↔ a ∈ l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_pos_iff, beq_iff_eq, exists_eq_right]
|
||||
|
||||
@[simp] theorem one_le_count_iff {a : α} {l : Vector α n} : 1 ≤ count a l ↔ a ∈ l :=
|
||||
count_pos_iff
|
||||
|
||||
theorem count_eq_zero_of_not_mem {a : α} {l : Vector α n} (h : a ∉ l) : count a l = 0 :=
|
||||
Decidable.byContradiction fun h' => h <| count_pos_iff.1 (Nat.pos_of_ne_zero h')
|
||||
|
||||
theorem not_mem_of_count_eq_zero {a : α} {l : Vector α n} (h : count a l = 0) : a ∉ l :=
|
||||
fun h' => Nat.ne_of_lt (count_pos_iff.2 h') h.symm
|
||||
|
||||
theorem count_eq_zero {l : Vector α n} : count a l = 0 ↔ a ∉ l :=
|
||||
⟨not_mem_of_count_eq_zero, count_eq_zero_of_not_mem⟩
|
||||
|
||||
theorem count_eq_size {l : Vector α n} : count a l = l.size ↔ ∀ b ∈ l, a = b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_eq_size]
|
||||
|
||||
@[simp] theorem count_mkVector_self (a : α) (n : Nat) : count a (mkVector n a) = n := by
|
||||
simp only [mkVector_eq_toVector_mkArray, count_cast, count_mk]
|
||||
simp
|
||||
|
||||
theorem count_mkVector (a b : α) (n : Nat) : count a (mkVector n b) = if b == a then n else 0 := by
|
||||
simp only [mkVector_eq_toVector_mkArray, count_cast, count_mk]
|
||||
simp [Array.count_mkArray]
|
||||
|
||||
theorem count_le_count_map [DecidableEq β] (l : Vector α n) (f : α → β) (x : α) :
|
||||
count x l ≤ count (f x) (map f l) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_le_count_map]
|
||||
|
||||
theorem count_flatMap {α} [BEq β] (l : Vector α n) (f : α → Vector β m) (x : β) :
|
||||
count x (l.flatMap f) = (map (count x ∘ f) l).sum := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.count_flatMap, Function.comp_def]
|
||||
|
||||
end count
|
||||
@@ -1,58 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.DecidableEq
|
||||
import Init.Data.Vector.Lemmas
|
||||
|
||||
namespace Vector
|
||||
|
||||
theorem isEqv_iff_rel {a b : Vector α n} {r} :
|
||||
Vector.isEqv a b r ↔ ∀ (i : Nat) (h' : i < n), r a[i] b[i] := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
rcases b with ⟨b, h⟩
|
||||
simp [Array.isEqv_iff_rel, h]
|
||||
|
||||
theorem isEqv_eq_decide (a b : Vector α n) (r) :
|
||||
Vector.isEqv a b r = decide (∀ (i : Nat) (h' : i < n), r a[i] b[i]) := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
rcases b with ⟨b, h⟩
|
||||
simp [Array.isEqv_eq_decide, h]
|
||||
|
||||
@[simp] theorem isEqv_toArray [BEq α] (a b : Vector α n) : (a.toArray.isEqv b.toArray r) = (a.isEqv b r) := by
|
||||
simp [isEqv_eq_decide, Array.isEqv_eq_decide]
|
||||
|
||||
theorem eq_of_isEqv [DecidableEq α] (a b : Vector α n) (h : Vector.isEqv a b (fun x y => x = y)) : a = b := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
rcases b with ⟨b, h⟩
|
||||
rw [← Vector.toArray_inj]
|
||||
apply Array.eq_of_isEqv
|
||||
simp_all
|
||||
|
||||
theorem isEqv_self_beq [BEq α] [ReflBEq α] (a : Vector α n) : Vector.isEqv a a (· == ·) = true := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp [Array.isEqv_self_beq]
|
||||
|
||||
theorem isEqv_self [DecidableEq α] (a : Vector α n) : Vector.isEqv a a (· = ·) = true := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp [Array.isEqv_self]
|
||||
|
||||
instance [DecidableEq α] : DecidableEq (Vector α n) :=
|
||||
fun a b =>
|
||||
match h:isEqv a b (fun a b => a = b) with
|
||||
| true => isTrue (eq_of_isEqv a b h)
|
||||
| false => isFalse fun h' => by subst h'; rw [isEqv_self] at h; contradiction
|
||||
|
||||
theorem beq_eq_decide [BEq α] (a b : Vector α n) :
|
||||
(a == b) = decide (∀ (i : Nat) (h' : i < n), a[i] == b[i]) := by
|
||||
simp [BEq.beq, isEqv_eq_decide]
|
||||
|
||||
@[simp] theorem beq_toArray [BEq α] (a b : Vector α n) : (a.toArray == b.toArray) = (a == b) := by
|
||||
simp [beq_eq_decide, Array.beq_eq_decide]
|
||||
|
||||
@[simp] theorem beq_toList [BEq α] (a b : Vector α n) : (a.toList == b.toList) = (a == b) := by
|
||||
simp [beq_eq_decide, List.beq_eq_decide]
|
||||
|
||||
end Vector
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,366 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.MapIdx
|
||||
import Init.Data.Vector.Lemmas
|
||||
|
||||
namespace Vector
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[simp] theorem getElem_mapFinIdx (a : Vector α n) (f : (i : Nat) → α → (h : i < n) → β) (i : Nat)
|
||||
(h : i < n) :
|
||||
(a.mapFinIdx f)[i] = f i a[i] h := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_mapFinIdx (a : Vector α n) (f : (i : Nat) → α → (h : i < n) → β) (i : Nat) :
|
||||
(a.mapFinIdx f)[i]? =
|
||||
a[i]?.pbind fun b h => f i b (getElem?_eq_some_iff.1 h).1 := by
|
||||
simp only [getElem?_def, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp] theorem getElem_mapIdx (f : Nat → α → β) (a : Vector α n) (i : Nat) (h : i < n) :
|
||||
(a.mapIdx f)[i] = f i (a[i]'(by simp_all)) := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (f : Nat → α → β) (a : Vector α n) (i : Nat) :
|
||||
(a.mapIdx f)[i]? = a[i]?.map (f i) := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp
|
||||
|
||||
end Vector
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem mapFinIdx_toVector (l : Array α) (f : (i : Nat) → α → (h : i < l.size) → β) :
|
||||
l.toVector.mapFinIdx f = (l.mapFinIdx f).toVector.cast (by simp) := by
|
||||
ext <;> simp
|
||||
|
||||
@[simp] theorem mapIdx_toVector (f : Nat → α → β) (l : Array α) :
|
||||
l.toVector.mapIdx f = (l.mapIdx f).toVector.cast (by simp) := by
|
||||
ext <;> simp
|
||||
|
||||
end Array
|
||||
|
||||
namespace Vector
|
||||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
@[simp] theorem toList_zipIdx (a : Vector α n) (k : Nat := 0) :
|
||||
(a.zipIdx k).toList = a.toList.zipIdx k := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem getElem_zipIdx (a : Vector α n) (i : Nat) (h : i < n) :
|
||||
(a.zipIdx k)[i] = (a[i]'(by simp_all), i + k) := by
|
||||
rcases a with ⟨a, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem zipIdx_toVector {l : Array α} {k : Nat} :
|
||||
l.toVector.zipIdx k = (l.zipIdx k).toVector.cast (by simp) := by
|
||||
ext <;> simp
|
||||
|
||||
theorem mk_mem_zipIdx_iff_le_and_getElem?_sub {x : α} {i : Nat} {l : Vector α n} {k : Nat} :
|
||||
(x, i) ∈ l.zipIdx k ↔ k ≤ i ∧ l[i - k]? = x := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
/-- Variant of `mk_mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mk_mem_zipIdx_iff_getElem? {x : α} {i : Nat} {l : Vector α n} :
|
||||
(x, i) ∈ l.zipIdx ↔ l[i]? = x := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
theorem mem_zipIdx_iff_le_and_getElem?_sub {x : α × Nat} {l : Vector α n} {k : Nat} :
|
||||
x ∈ zipIdx l k ↔ k ≤ x.2 ∧ l[x.2 - k]? = some x.1 := by
|
||||
cases x
|
||||
simp [mk_mem_zipIdx_iff_le_and_getElem?_sub]
|
||||
|
||||
/-- Variant of `mem_zipIdx_iff_le_and_getElem?_sub` specialized at `k = 0`,
|
||||
to avoid the inequality and the subtraction. -/
|
||||
theorem mem_zipIdx_iff_getElem? {x : α × Nat} {l : Vector α n} :
|
||||
x ∈ l.zipIdx ↔ l[x.2]? = some x.1 := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mem_zipIdx_iff_getElem?]
|
||||
|
||||
@[deprecated toList_zipIdx (since := "2025-01-27")]
|
||||
abbrev toList_zipWithIndex := @toList_zipIdx
|
||||
@[deprecated getElem_zipIdx (since := "2025-01-27")]
|
||||
abbrev getElem_zipWithIndex := @getElem_zipIdx
|
||||
@[deprecated zipIdx_toVector (since := "2025-01-27")]
|
||||
abbrev zipWithIndex_toVector := @zipIdx_toVector
|
||||
@[deprecated mk_mem_zipIdx_iff_le_and_getElem?_sub (since := "2025-01-27")]
|
||||
abbrev mk_mem_zipWithIndex_iff_le_and_getElem?_sub := @mk_mem_zipIdx_iff_le_and_getElem?_sub
|
||||
@[deprecated mk_mem_zipIdx_iff_getElem? (since := "2025-01-27")]
|
||||
abbrev mk_mem_zipWithIndex_iff_getElem? := @mk_mem_zipIdx_iff_getElem?
|
||||
@[deprecated mem_zipIdx_iff_le_and_getElem?_sub (since := "2025-01-27")]
|
||||
abbrev mem_zipWithIndex_iff_le_and_getElem?_sub := @mem_zipIdx_iff_le_and_getElem?_sub
|
||||
@[deprecated mem_zipIdx_iff_getElem? (since := "2025-01-27")]
|
||||
abbrev mem_zipWithIndex_iff_getElem? := @mem_zipIdx_iff_getElem?
|
||||
|
||||
/-! ### mapFinIdx -/
|
||||
|
||||
@[congr] theorem mapFinIdx_congr {xs ys : Vector α n} (w : xs = ys)
|
||||
(f : (i : Nat) → α → (h : i < n) → β) :
|
||||
mapFinIdx xs f = mapFinIdx ys f := by
|
||||
subst w
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_empty {f : (i : Nat) → α → (h : i < 0) → β} : mapFinIdx #v[] f = #v[] :=
|
||||
rfl
|
||||
|
||||
theorem mapFinIdx_eq_ofFn {as : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
as.mapFinIdx f = Vector.ofFn fun i : Fin n => f i as[i] i.2 := by
|
||||
rcases as with ⟨as, rfl⟩
|
||||
simp [Array.mapFinIdx_eq_ofFn]
|
||||
|
||||
theorem mapFinIdx_append {K : Vector α n} {L : Vector α m} {f : (i : Nat) → α → (h : i < n + m) → β} :
|
||||
(K ++ L).mapFinIdx f =
|
||||
K.mapFinIdx (fun i a h => f i a (by omega)) ++
|
||||
L.mapFinIdx (fun i a h => f (i + n) a (by omega)) := by
|
||||
rcases K with ⟨K, rfl⟩
|
||||
rcases L with ⟨L, rfl⟩
|
||||
simp [Array.mapFinIdx_append]
|
||||
|
||||
@[simp]
|
||||
theorem mapFinIdx_push {l : Vector α n} {a : α} {f : (i : Nat) → α → (h : i < n + 1) → β} :
|
||||
mapFinIdx (l.push a) f =
|
||||
(mapFinIdx l (fun i a h => f i a (by omega))).push (f l.size a (by simp)) := by
|
||||
simp [← append_singleton, mapFinIdx_append]
|
||||
|
||||
theorem mapFinIdx_singleton {a : α} {f : (i : Nat) → α → (h : i < 1) → β} :
|
||||
#v[a].mapFinIdx f = #v[f 0 a (by simp)] := by
|
||||
simp
|
||||
|
||||
-- FIXME this lemma can't be stated until we've aligned `List/Array/Vector.attach`:
|
||||
-- theorem mapFinIdx_eq_zipWithIndex_map {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
-- l.mapFinIdx f = l.zipWithIndex.attach.map
|
||||
-- fun ⟨⟨x, i⟩, m⟩ =>
|
||||
-- f i x (by simp [mk_mem_zipWithIndex_iff_getElem?, getElem?_eq_some_iff] at m; exact m.1) := by
|
||||
-- ext <;> simp
|
||||
|
||||
theorem exists_of_mem_mapFinIdx {b : β} {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β}
|
||||
(h : b ∈ l.mapFinIdx f) : ∃ (i : Nat) (h : i < n), f i l[i] h = b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
exact List.exists_of_mem_mapFinIdx (by simpa using h)
|
||||
|
||||
@[simp] theorem mem_mapFinIdx {b : β} {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
b ∈ l.mapFinIdx f ↔ ∃ (i : Nat) (h : i < n), f i l[i] h = b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
theorem mapFinIdx_eq_iff {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
l.mapFinIdx f = l' ↔ ∀ (i : Nat) (h : i < n), l'[i] = f i l[i] h := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [mapFinIdx_mk, eq_mk, getElem_mk, Array.mapFinIdx_eq_iff, h]
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_singleton_iff {l : Vector α 1} {f : (i : Nat) → α → (h : i < 1) → β} {b : β} :
|
||||
l.mapFinIdx f = #v[b] ↔ ∃ (a : α), l = #v[a] ∧ f 0 a (by omega) = b := by
|
||||
rcases l with ⟨l, h⟩
|
||||
simp only [mapFinIdx_mk, eq_mk, Array.mapFinIdx_eq_singleton_iff]
|
||||
constructor
|
||||
· rintro ⟨a, rfl, rfl⟩
|
||||
exact ⟨a, by simp⟩
|
||||
· rintro ⟨a, rfl, rfl⟩
|
||||
exact ⟨a, by simp⟩
|
||||
|
||||
theorem mapFinIdx_eq_append_iff {l : Vector α (n + m)} {f : (i : Nat) → α → (h : i < n + m) → β}
|
||||
{l₁ : Vector β n} {l₂ : Vector β m} :
|
||||
l.mapFinIdx f = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : Vector α n) (l₂' : Vector α m), l = l₁' ++ l₂' ∧
|
||||
l₁'.mapFinIdx (fun i a h => f i a (by omega)) = l₁ ∧
|
||||
l₂'.mapFinIdx (fun i a h => f (i + n) a (by omega)) = l₂ := by
|
||||
rcases l with ⟨l, h⟩
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, rfl⟩
|
||||
simp only [mapFinIdx_mk, mk_append_mk, eq_mk, Array.mapFinIdx_eq_append_iff, toArray_mapFinIdx,
|
||||
mk_eq, toArray_append, exists_and_left, exists_prop]
|
||||
constructor
|
||||
· rintro ⟨l₁', l₂', rfl, h₁, h₂⟩
|
||||
have h₁' := congrArg Array.size h₁
|
||||
have h₂' := congrArg Array.size h₂
|
||||
simp only [Array.size_mapFinIdx] at h₁' h₂'
|
||||
exact ⟨⟨l₁', h₁'⟩, ⟨l₂', h₂'⟩, by simp_all⟩
|
||||
· rintro ⟨⟨l₁, s₁⟩, ⟨l₂, s₂⟩, rfl, h₁, h₂⟩
|
||||
refine ⟨l₁, l₂, by simp_all⟩
|
||||
|
||||
theorem mapFinIdx_eq_push_iff {l : Vector α (n + 1)} {b : β} {f : (i : Nat) → α → (h : i < n + 1) → β} {l₂ : Vector β n} :
|
||||
l.mapFinIdx f = l₂.push b ↔
|
||||
∃ (l₁ : Vector α n) (a : α), l = l₁.push a ∧
|
||||
l₁.mapFinIdx (fun i a h => f i a (by omega)) = l₂ ∧ b = f n a (by omega) := by
|
||||
rcases l with ⟨l, h⟩
|
||||
rcases l₂ with ⟨l₂, rfl⟩
|
||||
simp only [mapFinIdx_mk, push_mk, eq_mk, Array.mapFinIdx_eq_push_iff, mk_eq, toArray_push,
|
||||
toArray_mapFinIdx]
|
||||
constructor
|
||||
· rintro ⟨l₁, a, rfl, h₁, rfl⟩
|
||||
simp only [Array.size_push, Nat.add_right_cancel_iff] at h
|
||||
exact ⟨⟨l₁, h⟩, a, by simp_all⟩
|
||||
· rintro ⟨⟨l₁, h⟩, a, rfl, h₁, rfl⟩
|
||||
exact ⟨l₁, a, by simp_all⟩
|
||||
|
||||
theorem mapFinIdx_eq_mapFinIdx_iff {l : Vector α n} {f g : (i : Nat) → α → (h : i < n) → β} :
|
||||
l.mapFinIdx f = l.mapFinIdx g ↔ ∀ (i : Nat) (h : i < n), f i l[i] h = g i l[i] h := by
|
||||
rw [eq_comm, mapFinIdx_eq_iff]
|
||||
simp
|
||||
|
||||
@[simp] theorem mapFinIdx_mapFinIdx {l : Vector α n}
|
||||
{f : (i : Nat) → α → (h : i < n) → β}
|
||||
{g : (i : Nat) → β → (h : i < n) → γ} :
|
||||
(l.mapFinIdx f).mapFinIdx g = l.mapFinIdx (fun i a h => g i (f i a h) h) := by
|
||||
simp [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapFinIdx_eq_mkVector_iff {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {b : β} :
|
||||
l.mapFinIdx f = mkVector n b ↔ ∀ (i : Nat) (h : i < n), f i l[i] h = b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mapFinIdx_eq_mkArray_iff]
|
||||
|
||||
@[simp] theorem mapFinIdx_reverse {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} :
|
||||
l.reverse.mapFinIdx f = (l.mapFinIdx (fun i a h => f (n - 1 - i) a (by omega))).reverse := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_empty {f : Nat → α → β} : mapIdx f #v[] = #v[] :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem mapFinIdx_eq_mapIdx {l : Vector α n} {f : (i : Nat) → α → (h : i < n) → β} {g : Nat → α → β}
|
||||
(h : ∀ (i : Nat) (h : i < n), f i l[i] h = g i l[i]) :
|
||||
l.mapFinIdx f = l.mapIdx g := by
|
||||
simp_all [mapFinIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mapFinIdx {l : Vector α n} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.mapFinIdx (fun i a _ => f i a) := by
|
||||
simp [mapFinIdx_eq_mapIdx]
|
||||
|
||||
theorem mapIdx_eq_zipIdx_map {l : Vector α n} {f : Nat → α → β} :
|
||||
l.mapIdx f = l.zipIdx.map fun ⟨a, i⟩ => f i a := by
|
||||
ext <;> simp
|
||||
|
||||
@[deprecated mapIdx_eq_zipIdx_map (since := "2025-01-27")]
|
||||
abbrev mapIdx_eq_zipWithIndex_map := @mapIdx_eq_zipIdx_map
|
||||
|
||||
theorem mapIdx_append {K : Vector α n} {L : Vector α m} :
|
||||
(K ++ L).mapIdx f = K.mapIdx f ++ L.mapIdx fun i => f (i + K.size) := by
|
||||
rcases K with ⟨K, rfl⟩
|
||||
rcases L with ⟨L, rfl⟩
|
||||
simp [Array.mapIdx_append]
|
||||
|
||||
@[simp]
|
||||
theorem mapIdx_push {l : Vector α n} {a : α} :
|
||||
mapIdx f (l.push a) = (mapIdx f l).push (f l.size a) := by
|
||||
simp [← append_singleton, mapIdx_append]
|
||||
|
||||
theorem mapIdx_singleton {a : α} : mapIdx f #v[a] = #v[f 0 a] := by
|
||||
simp
|
||||
|
||||
theorem exists_of_mem_mapIdx {b : β} {l : Vector α n}
|
||||
(h : b ∈ l.mapIdx f) : ∃ (i : Nat) (h : i < n), f i l[i] = b := by
|
||||
rw [mapIdx_eq_mapFinIdx] at h
|
||||
simpa [Fin.exists_iff] using exists_of_mem_mapFinIdx h
|
||||
|
||||
@[simp] theorem mem_mapIdx {b : β} {l : Vector α n} :
|
||||
b ∈ l.mapIdx f ↔ ∃ (i : Nat) (h : i < n), f i l[i] = b := by
|
||||
constructor
|
||||
· intro h
|
||||
exact exists_of_mem_mapIdx h
|
||||
· rintro ⟨i, h, rfl⟩
|
||||
rw [mem_iff_getElem]
|
||||
exact ⟨i, by simpa using h, by simp⟩
|
||||
|
||||
theorem mapIdx_eq_push_iff {l : Vector α (n + 1)} {b : β} :
|
||||
mapIdx f l = l₂.push b ↔
|
||||
∃ (a : α) (l₁ : Vector α n), l = l₁.push a ∧ mapIdx f l₁ = l₂ ∧ f l₁.size a = b := by
|
||||
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_push_iff]
|
||||
simp only [mapFinIdx_eq_mapIdx, exists_and_left, exists_prop]
|
||||
constructor
|
||||
· rintro ⟨l₁, a, rfl, rfl, rfl⟩
|
||||
exact ⟨a, l₁, by simp⟩
|
||||
· rintro ⟨a, l₁, rfl, rfl, rfl⟩
|
||||
exact ⟨l₁, a, rfl, by simp⟩
|
||||
|
||||
@[simp] theorem mapIdx_eq_singleton_iff {l : Vector α 1} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f l = #v[b] ↔ ∃ (a : α), l = #v[a] ∧ f 0 a = b := by
|
||||
rcases l with ⟨l⟩
|
||||
simp
|
||||
|
||||
theorem mapIdx_eq_append_iff {l : Vector α (n + m)} {f : Nat → α → β} {l₁ : Vector β n} {l₂ : Vector β m} :
|
||||
mapIdx f l = l₁ ++ l₂ ↔
|
||||
∃ (l₁' : Vector α n) (l₂' : Vector α m), l = l₁' ++ l₂' ∧
|
||||
l₁'.mapIdx f = l₁ ∧
|
||||
l₂'.mapIdx (fun i => f (i + l₁'.size)) = l₂ := by
|
||||
rcases l with ⟨l, h⟩
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, rfl⟩
|
||||
rw [mapIdx_eq_mapFinIdx, mapFinIdx_eq_append_iff]
|
||||
simp
|
||||
|
||||
theorem mapIdx_eq_iff {l : Vector α n} :
|
||||
mapIdx f l = l' ↔ ∀ (i : Nat) (h : i < n), f i l[i] = l'[i] := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp only [mapIdx_mk, eq_mk, Array.mapIdx_eq_iff, getElem_mk]
|
||||
constructor
|
||||
· rintro h' i h
|
||||
specialize h' i
|
||||
simp_all
|
||||
· intro h' i
|
||||
specialize h' i
|
||||
by_cases w : i < l.size
|
||||
· specialize h' w
|
||||
simp_all
|
||||
· simp only [Nat.not_lt] at w
|
||||
simp_all [Array.getElem?_eq_none_iff.mpr w]
|
||||
|
||||
theorem mapIdx_eq_mapIdx_iff {l : Vector α n} :
|
||||
mapIdx f l = mapIdx g l ↔ ∀ (i : Nat) (h : i < n), f i l[i] = g i l[i] := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mapIdx_eq_mapIdx_iff]
|
||||
|
||||
@[simp] theorem mapIdx_set {l : Vector α n} {i : Nat} {h : i < n} {a : α} :
|
||||
(l.set i a).mapIdx f = (l.mapIdx f).set i (f i a) (by simpa) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem mapIdx_setIfInBounds {l : Vector α n} {i : Nat} {a : α} :
|
||||
(l.setIfInBounds i a).mapIdx f = (l.mapIdx f).setIfInBounds i (f i a) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem back?_mapIdx {l : Vector α n} {f : Nat → α → β} :
|
||||
(mapIdx f l).back? = (l.back?).map (f (l.size - 1)) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem back_mapIdx [NeZero n] {l : Vector α n} {f : Nat → α → β} :
|
||||
(mapIdx f l).back = f (l.size - 1) (l.back) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp] theorem mapIdx_mapIdx {l : Vector α n} {f : Nat → α → β} {g : Nat → β → γ} :
|
||||
(l.mapIdx f).mapIdx g = l.mapIdx (fun i => g i ∘ f i) := by
|
||||
simp [mapIdx_eq_iff]
|
||||
|
||||
theorem mapIdx_eq_mkVector_iff {l : Vector α n} {f : Nat → α → β} {b : β} :
|
||||
mapIdx f l = mkVector n b ↔ ∀ (i : Nat) (h : i < n), f i l[i] = b := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mapIdx_eq_mkArray_iff]
|
||||
|
||||
@[simp] theorem mapIdx_reverse {l : Vector α n} {f : Nat → α → β} :
|
||||
l.reverse.mapIdx f = (mapIdx (fun i => f (l.size - 1 - i)) l).reverse := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.mapIdx_reverse]
|
||||
|
||||
end Vector
|
||||
@@ -1,37 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Vector.Lemmas
|
||||
import Init.Data.Array.OfFn
|
||||
|
||||
/-!
|
||||
# Theorems about `Vector.ofFn`
|
||||
-/
|
||||
|
||||
namespace Vector
|
||||
|
||||
@[simp] theorem getElem_ofFn {α n} (f : Fin n → α) (i : Nat) (h : i < n) :
|
||||
(Vector.ofFn f)[i] = f ⟨i, by simpa using h⟩ := by
|
||||
simp [ofFn]
|
||||
|
||||
theorem getElem?_ofFn (f : Fin n → α) (i : Nat) :
|
||||
(ofFn f)[i]? = if h : i < n then some (f ⟨i, h⟩) else none := by
|
||||
simp [getElem?_def]
|
||||
|
||||
@[simp 500]
|
||||
theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ ∃ i, f i = a := by
|
||||
constructor
|
||||
· intro w
|
||||
obtain ⟨i, h, rfl⟩ := getElem_of_mem w
|
||||
exact ⟨⟨i, by simpa using h⟩, by simp⟩
|
||||
· rintro ⟨i, rfl⟩
|
||||
apply mem_of_getElem (i := i) <;> simp
|
||||
|
||||
theorem back_ofFn {n} [NeZero n](f : Fin n → α) :
|
||||
(ofFn f).back = f ⟨n - 1, by have := NeZero.ne n; omega⟩ := by
|
||||
simp [back]
|
||||
|
||||
end Vector
|
||||
@@ -1,287 +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
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Zip
|
||||
import Init.Data.Vector.Lemmas
|
||||
|
||||
/-!
|
||||
# Lemmas about `Vector.zip`, `Vector.zipWith`, `Vector.zipWithAll`, and `Vector.unzip`.
|
||||
-/
|
||||
|
||||
namespace Vector
|
||||
|
||||
open Nat
|
||||
|
||||
/-! ## Zippers -/
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
theorem zipWith_comm (f : α → β → γ) (la : Vector α n) (lb : Vector β n) :
|
||||
zipWith f la lb = zipWith (fun b a => f a b) lb la := by
|
||||
rcases la with ⟨la, rfl⟩
|
||||
rcases lb with ⟨lb, h⟩
|
||||
simpa using Array.zipWith_comm _ _ _
|
||||
|
||||
theorem zipWith_comm_of_comm (f : α → α → β) (comm : ∀ x y : α, f x y = f y x) (l l' : Vector α n) :
|
||||
zipWith f l l' = zipWith f l' l := by
|
||||
rw [zipWith_comm]
|
||||
simp only [comm]
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_self (f : α → α → δ) (l : Vector α n) : zipWith f l l = l.map fun a => f a a := by
|
||||
cases l
|
||||
simp
|
||||
|
||||
/--
|
||||
See also `getElem?_zipWith'` for a variant
|
||||
using `Option.map` and `Option.bind` rather than a `match`.
|
||||
-/
|
||||
theorem getElem?_zipWith {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f as bs)[i]? = match as[i]?, bs[i]? with
|
||||
| some a, some b => some (f a b) | _, _ => none := by
|
||||
cases as
|
||||
cases bs
|
||||
simp [Array.getElem?_zipWith]
|
||||
rfl
|
||||
|
||||
/-- Variant of `getElem?_zipWith` using `Option.map` and `Option.bind` rather than a `match`. -/
|
||||
theorem getElem?_zipWith' {f : α → β → γ} {i : Nat} :
|
||||
(zipWith f l₁ l₂)[i]? = (l₁[i]?.map f).bind fun g => l₂[i]?.map g := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [Array.getElem?_zipWith']
|
||||
|
||||
theorem getElem?_zipWith_eq_some {f : α → β → γ} {l₁ : Vector α n} {l₂ : Vector β n} {z : γ} {i : Nat} :
|
||||
(zipWith f l₁ l₂)[i]? = some z ↔
|
||||
∃ x y, l₁[i]? = some x ∧ l₂[i]? = some y ∧ f x y = z := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp [Array.getElem?_zipWith_eq_some]
|
||||
|
||||
theorem getElem?_zip_eq_some {l₁ : Vector α n} {l₂ : Vector β n} {z : α × β} {i : Nat} :
|
||||
(zip l₁ l₂)[i]? = some z ↔ l₁[i]? = some z.1 ∧ l₂[i]? = some z.2 := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.getElem?_zip_eq_some]
|
||||
|
||||
@[simp]
|
||||
theorem zipWith_map {μ} (f : γ → δ → μ) (g : α → γ) (h : β → δ) (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
zipWith f (l₁.map g) (l₂.map h) = zipWith (fun a b => f (g a) (h b)) l₁ l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.zipWith_map]
|
||||
|
||||
theorem zipWith_map_left (l₁ : Vector α n) (l₂ : Vector β n) (f : α → α') (g : α' → β → γ) :
|
||||
zipWith g (l₁.map f) l₂ = zipWith (fun a b => g (f a) b) l₁ l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.zipWith_map_left]
|
||||
|
||||
theorem zipWith_map_right (l₁ : Vector α n) (l₂ : Vector β n) (f : β → β') (g : α → β' → γ) :
|
||||
zipWith g l₁ (l₂.map f) = zipWith (fun a b => g a (f b)) l₁ l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.zipWith_map_right]
|
||||
|
||||
theorem zipWith_foldr_eq_zip_foldr {f : α → β → γ} (i : δ):
|
||||
(zipWith f l₁ l₂).foldr g i = (zip l₁ l₂).foldr (fun p r => g (f p.1 p.2) r) i := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simpa using Array.zipWith_foldr_eq_zip_foldr _
|
||||
|
||||
theorem zipWith_foldl_eq_zip_foldl {f : α → β → γ} (i : δ):
|
||||
(zipWith f l₁ l₂).foldl g i = (zip l₁ l₂).foldl (fun r p => g r (f p.1 p.2)) i := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simpa using Array.zipWith_foldl_eq_zip_foldl _
|
||||
|
||||
|
||||
theorem map_zipWith {δ : Type _} (f : α → β) (g : γ → δ → α) (l : Vector γ n) (l' : Vector δ n) :
|
||||
map f (zipWith g l l') = zipWith (fun x y => f (g x y)) l l' := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.map_zipWith]
|
||||
|
||||
theorem take_zipWith : (zipWith f l l').take n = zipWith f (l.take n) (l'.take n) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.take_zipWith]
|
||||
|
||||
theorem extract_zipWith : (zipWith f l l').extract m n = zipWith f (l.extract m n) (l'.extract m n) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.extract_zipWith]
|
||||
|
||||
theorem zipWith_append (f : α → β → γ)
|
||||
(l : Vector α n) (la : Vector α m) (l' : Vector β n) (lb : Vector β m) :
|
||||
zipWith f (l ++ la) (l' ++ lb) = zipWith f l l' ++ zipWith f la lb := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
rcases la with ⟨la, rfl⟩
|
||||
rcases lb with ⟨lb, h'⟩
|
||||
simp [Array.zipWith_append, *]
|
||||
|
||||
theorem zipWith_eq_append_iff {f : α → β → γ} {l₁ : Vector α (n + m)} {l₂ : Vector β (n + m)} :
|
||||
zipWith f l₁ l₂ = l₁' ++ l₂' ↔
|
||||
∃ w x y z, l₁ = w ++ x ∧ l₂ = y ++ z ∧ l₁' = zipWith f w y ∧ l₂' = zipWith f x z := by
|
||||
rcases l₁ with ⟨l₁, h₁⟩
|
||||
rcases l₂ with ⟨l₂, h₂⟩
|
||||
rcases l₁' with ⟨l₁', rfl⟩
|
||||
rcases l₂' with ⟨l₂', rfl⟩
|
||||
simp only [mk_zipWith_mk, mk_append_mk, eq_mk, Array.zipWith_eq_append_iff,
|
||||
mk_eq, toArray_append, toArray_zipWith]
|
||||
constructor
|
||||
· rintro ⟨w, x, y, z, h, rfl, rfl, rfl, rfl⟩
|
||||
simp only [Array.size_append, Array.size_zipWith] at h₁ h₂
|
||||
exact ⟨mk w (by simp; omega), mk x (by simp; omega), mk y (by simp; omega), mk z (by simp; omega), by simp⟩
|
||||
· rintro ⟨⟨w, hw⟩, ⟨x, hx⟩, ⟨y, hy⟩, ⟨z, hz⟩, rfl, rfl, w₁, w₂⟩
|
||||
simp only at w₁ w₂
|
||||
exact ⟨w, x, y, z, by simpa [hw, hy] using ⟨w₁, w₂⟩⟩
|
||||
|
||||
@[simp] theorem zipWith_mkVector {a : α} {b : β} {n : Nat} :
|
||||
zipWith f (mkVector n a) (mkVector n b) = mkVector n (f a b) := by
|
||||
ext
|
||||
simp
|
||||
|
||||
theorem map_uncurry_zip_eq_zipWith (f : α → β → γ) (l : Vector α n) (l' : Vector β n) :
|
||||
map (Function.uncurry f) (l.zip l') = zipWith f l l' := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.map_uncurry_zip_eq_zipWith]
|
||||
|
||||
theorem map_zip_eq_zipWith (f : α × β → γ) (l : Vector α n) (l' : Vector β n) :
|
||||
map f (l.zip l') = zipWith (Function.curry f) l l' := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.map_zip_eq_zipWith]
|
||||
|
||||
theorem reverse_zipWith :
|
||||
(zipWith f l l').reverse = zipWith f l.reverse l'.reverse := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rcases l' with ⟨l', h⟩
|
||||
simp [Array.reverse_zipWith, h]
|
||||
|
||||
/-! ### zip -/
|
||||
|
||||
@[simp]
|
||||
theorem getElem_zip {l : Vector α n} {l' : Vector β n} {i : Nat} {h : i < n} :
|
||||
(zip l l')[i] = (l[i], l'[i]) :=
|
||||
getElem_zipWith ..
|
||||
|
||||
theorem zip_eq_zipWith (l₁ : Vector α n) (l₂ : Vector β n) : zip l₁ l₂ = zipWith Prod.mk l₁ l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.zip_eq_zipWith, h]
|
||||
|
||||
theorem zip_map (f : α → γ) (g : β → δ) (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
zip (l₁.map f) (l₂.map g) = (zip l₁ l₂).map (Prod.map f g) := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.zip_map, h]
|
||||
|
||||
theorem zip_map_left (f : α → γ) (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
zip (l₁.map f) l₂ = (zip l₁ l₂).map (Prod.map f id) := by rw [← zip_map, map_id]
|
||||
|
||||
theorem zip_map_right (f : β → γ) (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
zip l₁ (l₂.map f) = (zip l₁ l₂).map (Prod.map id f) := by rw [← zip_map, map_id]
|
||||
|
||||
theorem zip_append {l₁ : Vector α n} {l₂ : Vector β n} {r₁ : Vector α m} {r₂ : Vector β m} :
|
||||
zip (l₁ ++ r₁) (l₂ ++ r₂) = zip l₁ l₂ ++ zip r₁ r₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
rcases r₁ with ⟨r₁, rfl⟩
|
||||
rcases r₂ with ⟨r₂, h'⟩
|
||||
simp [Array.zip_append, h, h']
|
||||
|
||||
theorem zip_map' (f : α → β) (g : α → γ) (l : Vector α n) :
|
||||
zip (l.map f) (l.map g) = l.map fun a => (f a, g a) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp [Array.zip_map']
|
||||
|
||||
theorem of_mem_zip {a b} {l₁ : Vector α n} {l₂ : Vector β n} : (a, b) ∈ zip l₁ l₂ → a ∈ l₁ ∧ b ∈ l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simpa using Array.of_mem_zip
|
||||
|
||||
theorem map_fst_zip (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
map Prod.fst (zip l₁ l₂) = l₁ := by
|
||||
cases l₁
|
||||
cases l₂
|
||||
simp_all [Array.map_fst_zip]
|
||||
|
||||
theorem map_snd_zip (l₁ : Vector α n) (l₂ : Vector β n) :
|
||||
map Prod.snd (zip l₁ l₂) = l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.map_snd_zip, h]
|
||||
|
||||
theorem map_prod_left_eq_zip {l : Vector α n} (f : α → β) :
|
||||
(l.map fun x => (x, f x)) = l.zip (l.map f) := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rw [← zip_map']
|
||||
congr
|
||||
simp
|
||||
|
||||
theorem map_prod_right_eq_zip {l : Vector α n} (f : α → β) :
|
||||
(l.map fun x => (f x, x)) = (l.map f).zip l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
rw [← zip_map']
|
||||
congr
|
||||
simp
|
||||
|
||||
theorem zip_eq_append_iff {l₁ : Vector α (n + m)} {l₂ : Vector β (n + m)} {l₁' : Vector (α × β) n} {l₂' : Vector (α × β) m} :
|
||||
zip l₁ l₂ = l₁' ++ l₂' ↔
|
||||
∃ w x y z, l₁ = w ++ x ∧ l₂ = y ++ z ∧ l₁' = zip w y ∧ l₂' = zip x z := by
|
||||
simp [zip_eq_zipWith, zipWith_eq_append_iff]
|
||||
|
||||
@[simp] theorem zip_mkVector {a : α} {b : β} {n : Nat} :
|
||||
zip (mkVector n a) (mkVector n b) = mkVector n (a, b) := by
|
||||
ext <;> simp
|
||||
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
induction l <;> simp_all
|
||||
|
||||
@[simp] theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem unzip_eq_map (l : Vector (α × β) n) : unzip l = (l.map Prod.fst, l.map Prod.snd) := by
|
||||
cases l
|
||||
simp [List.unzip_eq_map]
|
||||
|
||||
theorem zip_unzip (l : Vector (α × β) n) : zip (unzip l).1 (unzip l).2 = l := by
|
||||
rcases l with ⟨l, rfl⟩
|
||||
simp only [unzip_mk, mk_zip_mk, Array.zip_unzip]
|
||||
|
||||
theorem unzip_zip_left {l₁ : Vector α n} {l₂ : Vector β n} :
|
||||
(unzip (zip l₁ l₂)).1 = l₁ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.unzip_zip_left, h, Array.map_fst_zip]
|
||||
|
||||
theorem unzip_zip_right {l₁ : Vector α n} {l₂ : Vector β n} :
|
||||
(unzip (zip l₁ l₂)).2 = l₂ := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.unzip_zip_right, h, Array.map_snd_zip]
|
||||
|
||||
theorem unzip_zip {l₁ : Vector α n} {l₂ : Vector β n} :
|
||||
unzip (zip l₁ l₂) = (l₁, l₂) := by
|
||||
rcases l₁ with ⟨l₁, rfl⟩
|
||||
rcases l₂ with ⟨l₂, h⟩
|
||||
simp [Array.unzip_zip, h, Array.map_fst_zip, Array.map_snd_zip]
|
||||
|
||||
theorem zip_of_prod {l : Vector α n} {l' : Vector β n} {lp : Vector (α × β) n} (hl : lp.map Prod.fst = l)
|
||||
(hr : lp.map Prod.snd = l') : lp = l.zip l' := by
|
||||
rw [← hl, ← hr, ← zip_unzip lp, ← unzip_fst, ← unzip_snd, zip_unzip, zip_unzip]
|
||||
|
||||
@[simp] theorem unzip_mkVector {n : Nat} {a : α} {b : β} :
|
||||
unzip (mkVector n (a, b)) = (mkVector n a, mkVector n b) := by
|
||||
ext1 <;> simp
|
||||
|
||||
end Vector
|
||||
@@ -11,4 +11,3 @@ import Init.Grind.Cases
|
||||
import Init.Grind.Propagator
|
||||
import Init.Grind.Util
|
||||
import Init.Grind.Offset
|
||||
import Init.Grind.PP
|
||||
|
||||
@@ -5,7 +5,11 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Core
|
||||
import Init.Grind.Tactics
|
||||
|
||||
attribute [grind cases eager] And Prod False Empty True Unit Exists
|
||||
attribute [grind cases] Or
|
||||
attribute [grind_cases] And Prod False Empty True Unit Exists
|
||||
|
||||
namespace Lean.Grind.Eager
|
||||
|
||||
attribute [scoped grind_cases] Or
|
||||
|
||||
end Lean.Grind.Eager
|
||||
|
||||
@@ -12,9 +12,6 @@ import Init.Grind.Util
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
theorem rfl_true : true = true :=
|
||||
rfl
|
||||
|
||||
theorem intro_with_eq (p p' q : Prop) (he : p = p') (h : p' → q) : p → q :=
|
||||
fun hp => h (he.mp hp)
|
||||
|
||||
@@ -69,12 +66,6 @@ theorem eq_eq_of_eq_true_right {a b : Prop} (h : b = True) : (a = b) = a := by s
|
||||
theorem eq_congr {α : Sort u} {a₁ b₁ a₂ b₂ : α} (h₁ : a₁ = a₂) (h₂ : b₁ = b₂) : (a₁ = b₁) = (a₂ = b₂) := by simp [*]
|
||||
theorem eq_congr' {α : Sort u} {a₁ b₁ a₂ b₂ : α} (h₁ : a₁ = b₂) (h₂ : b₁ = a₂) : (a₁ = b₁) = (a₂ = b₂) := by rw [h₁, h₂, Eq.comm (a := a₂)]
|
||||
|
||||
/- The following two helper theorems are used to case-split `a = b` representing `iff`. -/
|
||||
theorem of_eq_eq_true {a b : Prop} (h : (a = b) = True) : (¬a ∨ b) ∧ (¬b ∨ a) := by
|
||||
by_cases a <;> by_cases b <;> simp_all
|
||||
theorem of_eq_eq_false {a b : Prop} (h : (a = b) = False) : (¬a ∨ ¬b) ∧ (b ∨ a) := by
|
||||
by_cases a <;> by_cases b <;> simp_all
|
||||
|
||||
/-! Forall -/
|
||||
|
||||
theorem forall_propagator (p : Prop) (q : p → Prop) (q' : Prop) (h₁ : p = True) (h₂ : q (of_eq_true h₁) = q') : (∀ hp : p, q hp) = q' := by
|
||||
|
||||
@@ -12,105 +12,110 @@ import Init.ByCases
|
||||
namespace Lean.Grind
|
||||
/-!
|
||||
Normalization theorems for the `grind` tactic.
|
||||
|
||||
We are also going to use simproc's in the future.
|
||||
-/
|
||||
|
||||
theorem iff_eq (p q : Prop) : (p ↔ q) = (p = q) := by
|
||||
-- Not
|
||||
attribute [grind_norm] Classical.not_not
|
||||
|
||||
-- Ne
|
||||
attribute [grind_norm] ne_eq
|
||||
|
||||
-- Iff
|
||||
@[grind_norm] theorem iff_eq (p q : Prop) : (p ↔ q) = (p = q) := by
|
||||
by_cases p <;> by_cases q <;> simp [*]
|
||||
|
||||
theorem eq_true_eq (p : Prop) : (p = True) = p := by simp
|
||||
theorem eq_false_eq (p : Prop) : (p = False) = ¬p := by simp
|
||||
theorem not_eq_prop (p q : Prop) : (¬(p = q)) = (p = ¬q) := by
|
||||
-- Eq
|
||||
attribute [grind_norm] eq_self heq_eq_eq
|
||||
|
||||
-- Prop equality
|
||||
@[grind_norm] theorem eq_true_eq (p : Prop) : (p = True) = p := by simp
|
||||
@[grind_norm] theorem eq_false_eq (p : Prop) : (p = False) = ¬p := by simp
|
||||
@[grind_norm] theorem not_eq_prop (p q : Prop) : (¬(p = q)) = (p = ¬q) := by
|
||||
by_cases p <;> by_cases q <;> simp [*]
|
||||
|
||||
-- True
|
||||
attribute [grind_norm] not_true
|
||||
|
||||
-- False
|
||||
attribute [grind_norm] not_false_eq_true
|
||||
|
||||
-- Remark: we disabled the following normalization rule because we want this information when implementing splitting heuristics
|
||||
-- Implication as a clause
|
||||
theorem imp_eq (p q : Prop) : (p → q) = (¬ p ∨ q) := by
|
||||
by_cases p <;> by_cases q <;> simp [*]
|
||||
|
||||
theorem true_imp_eq (p : Prop) : (True → p) = p := by simp
|
||||
theorem false_imp_eq (p : Prop) : (False → p) = True := by simp
|
||||
theorem imp_true_eq (p : Prop) : (p → True) = True := by simp
|
||||
theorem imp_false_eq (p : Prop) : (p → False) = ¬p := by simp
|
||||
theorem imp_self_eq (p : Prop) : (p → p) = True := by simp
|
||||
|
||||
theorem not_and (p q : Prop) : (¬(p ∧ q)) = (¬p ∨ ¬q) := by
|
||||
-- And
|
||||
@[grind_norm↓] theorem not_and (p q : Prop) : (¬(p ∧ q)) = (¬p ∨ ¬q) := by
|
||||
by_cases p <;> by_cases q <;> simp [*]
|
||||
attribute [grind_norm] and_true true_and and_false false_and and_assoc
|
||||
|
||||
theorem not_ite {_ : Decidable p} (q r : Prop) : (¬ite p q r) = ite p (¬q) (¬r) := by
|
||||
-- Or
|
||||
attribute [grind_norm↓] not_or
|
||||
attribute [grind_norm] or_true true_or or_false false_or or_assoc
|
||||
|
||||
-- ite
|
||||
attribute [grind_norm] ite_true ite_false
|
||||
@[grind_norm↓] theorem not_ite {_ : Decidable p} (q r : Prop) : (¬ite p q r) = ite p (¬q) (¬r) := by
|
||||
by_cases p <;> simp [*]
|
||||
|
||||
theorem ite_true_false {_ : Decidable p} : (ite p True False) = p := by
|
||||
@[grind_norm] theorem ite_true_false {_ : Decidable p} : (ite p True False) = p := by
|
||||
by_cases p <;> simp
|
||||
|
||||
theorem ite_false_true {_ : Decidable p} : (ite p False True) = ¬p := by
|
||||
@[grind_norm] theorem ite_false_true {_ : Decidable p} : (ite p False True) = ¬p := by
|
||||
by_cases p <;> simp
|
||||
|
||||
theorem not_forall (p : α → Prop) : (¬∀ x, p x) = ∃ x, ¬p x := by simp
|
||||
-- Forall
|
||||
@[grind_norm↓] theorem not_forall (p : α → Prop) : (¬∀ x, p x) = ∃ x, ¬p x := by simp
|
||||
attribute [grind_norm] forall_and
|
||||
|
||||
theorem not_exists (p : α → Prop) : (¬∃ x, p x) = ∀ x, ¬p x := by simp
|
||||
-- Exists
|
||||
@[grind_norm↓] theorem not_exists (p : α → Prop) : (¬∃ x, p x) = ∀ x, ¬p x := by simp
|
||||
attribute [grind_norm] exists_const exists_or exists_prop exists_and_left exists_and_right
|
||||
|
||||
theorem cond_eq_ite (c : Bool) (a b : α) : cond c a b = ite c a b := by
|
||||
-- Bool cond
|
||||
@[grind_norm] theorem cond_eq_ite (c : Bool) (a b : α) : cond c a b = ite c a b := by
|
||||
cases c <;> simp [*]
|
||||
|
||||
theorem Nat.lt_eq (a b : Nat) : (a < b) = (a + 1 ≤ b) := by
|
||||
-- Bool or
|
||||
attribute [grind_norm]
|
||||
Bool.or_false Bool.or_true Bool.false_or Bool.true_or Bool.or_eq_true Bool.or_assoc
|
||||
|
||||
-- Bool and
|
||||
attribute [grind_norm]
|
||||
Bool.and_false Bool.and_true Bool.false_and Bool.true_and Bool.and_eq_true Bool.and_assoc
|
||||
|
||||
-- Bool not
|
||||
attribute [grind_norm]
|
||||
Bool.not_not
|
||||
|
||||
-- beq
|
||||
attribute [grind_norm] beq_iff_eq
|
||||
|
||||
-- bne
|
||||
attribute [grind_norm] bne_iff_ne
|
||||
|
||||
-- Bool not eq true/false
|
||||
attribute [grind_norm] Bool.not_eq_true Bool.not_eq_false
|
||||
|
||||
-- decide
|
||||
attribute [grind_norm] decide_eq_true_eq decide_not not_decide_eq_true
|
||||
|
||||
-- Nat LE
|
||||
attribute [grind_norm] Nat.le_zero_eq
|
||||
|
||||
-- Nat/Int LT
|
||||
@[grind_norm] theorem Nat.lt_eq (a b : Nat) : (a < b) = (a + 1 ≤ b) := by
|
||||
simp [Nat.lt, LT.lt]
|
||||
|
||||
theorem Int.lt_eq (a b : Int) : (a < b) = (a + 1 ≤ b) := by
|
||||
@[grind_norm] theorem Int.lt_eq (a b : Int) : (a < b) = (a + 1 ≤ b) := by
|
||||
simp [Int.lt, LT.lt]
|
||||
|
||||
theorem ge_eq [LE α] (a b : α) : (a ≥ b) = (b ≤ a) := rfl
|
||||
theorem gt_eq [LT α] (a b : α) : (a > b) = (b < a) := rfl
|
||||
-- GT GE
|
||||
attribute [grind_norm] GT.gt GE.ge
|
||||
|
||||
init_grind_norm
|
||||
/- Pre theorems -/
|
||||
not_and not_or not_ite not_forall not_exists
|
||||
|
|
||||
/- Post theorems -/
|
||||
Classical.not_not
|
||||
ne_eq iff_eq eq_self heq_eq_eq
|
||||
-- Prop equality
|
||||
eq_true_eq eq_false_eq not_eq_prop
|
||||
-- True
|
||||
not_true
|
||||
-- False
|
||||
not_false_eq_true
|
||||
-- Implication
|
||||
true_imp_eq false_imp_eq imp_true_eq imp_false_eq imp_self_eq
|
||||
-- And
|
||||
and_true true_and and_false false_and and_assoc
|
||||
-- Or
|
||||
or_true true_or or_false false_or or_assoc
|
||||
-- ite
|
||||
ite_true ite_false ite_true_false ite_false_true
|
||||
-- Forall
|
||||
forall_and
|
||||
-- Exists
|
||||
exists_const exists_or exists_prop exists_and_left exists_and_right
|
||||
-- Bool cond
|
||||
cond_eq_ite
|
||||
-- Bool or
|
||||
Bool.or_false Bool.or_true Bool.false_or Bool.true_or Bool.or_eq_true Bool.or_assoc
|
||||
-- Bool and
|
||||
Bool.and_false Bool.and_true Bool.false_and Bool.true_and Bool.and_eq_true Bool.and_assoc
|
||||
-- Bool not
|
||||
Bool.not_not
|
||||
-- beq
|
||||
beq_iff_eq
|
||||
-- bne
|
||||
bne_iff_ne
|
||||
-- Bool not eq true/false
|
||||
Bool.not_eq_true Bool.not_eq_false
|
||||
-- decide
|
||||
decide_eq_true_eq decide_not not_decide_eq_true
|
||||
-- Nat LE
|
||||
Nat.le_zero_eq
|
||||
-- Nat/Int LT
|
||||
Nat.lt_eq
|
||||
-- Nat.succ
|
||||
Nat.succ_eq_add_one
|
||||
-- Int
|
||||
Int.lt_eq
|
||||
-- GT GE
|
||||
ge_eq gt_eq
|
||||
-- Succ
|
||||
attribute [grind_norm] Nat.succ_eq_add_one
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -7,86 +7,159 @@ prelude
|
||||
import Init.Core
|
||||
import Init.Omega
|
||||
|
||||
namespace Lean.Grind
|
||||
abbrev isLt (x y : Nat) : Bool := x < y
|
||||
abbrev isLE (x y : Nat) : Bool := x ≤ y
|
||||
namespace Lean.Grind.Offset
|
||||
|
||||
/-! Theorems for transitivity. -/
|
||||
theorem Nat.le_ro (u w v k : Nat) : u ≤ w → w ≤ v + k → u ≤ v + k := by
|
||||
omega
|
||||
theorem Nat.le_lo (u w v k : Nat) : u ≤ w → w + k ≤ v → u + k ≤ v := by
|
||||
omega
|
||||
theorem Nat.lo_le (u w v k : Nat) : u + k ≤ w → w ≤ v → u + k ≤ v := by
|
||||
omega
|
||||
theorem Nat.lo_lo (u w v k₁ k₂ : Nat) : u + k₁ ≤ w → w + k₂ ≤ v → u + (k₁ + k₂) ≤ v := by
|
||||
omega
|
||||
theorem Nat.lo_ro_1 (u w v k₁ k₂ : Nat) : isLt k₂ k₁ = true → u + k₁ ≤ w → w ≤ v + k₂ → u + (k₁ - k₂) ≤ v := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.lo_ro_2 (u w v k₁ k₂ : Nat) : u + k₁ ≤ w → w ≤ v + k₂ → u ≤ v + (k₂ - k₁) := by
|
||||
omega
|
||||
theorem Nat.ro_le (u w v k : Nat) : u ≤ w + k → w ≤ v → u ≤ v + k := by
|
||||
omega
|
||||
theorem Nat.ro_lo_1 (u w v k₁ k₂ : Nat) : u ≤ w + k₁ → w + k₂ ≤ v → u ≤ v + (k₁ - k₂) := by
|
||||
omega
|
||||
theorem Nat.ro_lo_2 (u w v k₁ k₂ : Nat) : isLt k₁ k₂ = true → u ≤ w + k₁ → w + k₂ ≤ v → u + (k₂ - k₁) ≤ v := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.ro_ro (u w v k₁ k₂ : Nat) : u ≤ w + k₁ → w ≤ v + k₂ → u ≤ v + (k₁ + k₂) := by
|
||||
omega
|
||||
abbrev Var := Nat
|
||||
abbrev Context := Lean.RArray Nat
|
||||
|
||||
/-! Theorems for negating constraints. -/
|
||||
theorem Nat.of_le_eq_false (u v : Nat) : ((u ≤ v) = False) → v + 1 ≤ u := by
|
||||
simp; omega
|
||||
theorem Nat.of_lo_eq_false_1 (u v : Nat) : ((u + 1 ≤ v) = False) → v ≤ u := by
|
||||
simp; omega
|
||||
theorem Nat.of_lo_eq_false (u v k : Nat) : ((u + k ≤ v) = False) → v ≤ u + (k-1) := by
|
||||
simp; omega
|
||||
theorem Nat.of_ro_eq_false (u v k : Nat) : ((u ≤ v + k) = False) → v + (k+1) ≤ u := by
|
||||
simp; omega
|
||||
def fixedVar := 100000000 -- Any big number should work here
|
||||
|
||||
/-! Theorems for closing a goal. -/
|
||||
theorem Nat.unsat_le_lo (u v k : Nat) : isLt 0 k = true → u ≤ v → v + k ≤ u → False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.unsat_lo_lo (u v k₁ k₂ : Nat) : isLt 0 (k₁+k₂) = true → u + k₁ ≤ v → v + k₂ ≤ u → False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.unsat_lo_ro (u v k₁ k₂ : Nat) : isLt k₂ k₁ = true → u + k₁ ≤ v → v ≤ u + k₂ → False := by
|
||||
simp [isLt]; omega
|
||||
def Var.denote (ctx : Context) (v : Var) : Nat :=
|
||||
bif v == fixedVar then 1 else ctx.get v
|
||||
|
||||
/-! Theorems for propagating constraints to `True` -/
|
||||
theorem Nat.lo_eq_true_of_lo (u v k₁ k₂ : Nat) : isLE k₂ k₁ = true → u + k₁ ≤ v → (u + k₂ ≤ v) = True :=
|
||||
by simp [isLt]; omega
|
||||
theorem Nat.le_eq_true_of_lo (u v k : Nat) : u + k ≤ v → (u ≤ v) = True :=
|
||||
by simp; omega
|
||||
theorem Nat.le_eq_true_of_le (u v : Nat) : u ≤ v → (u ≤ v) = True :=
|
||||
by simp
|
||||
theorem Nat.ro_eq_true_of_lo (u v k₁ k₂ : Nat) : u + k₁ ≤ v → (u ≤ v + k₂) = True :=
|
||||
by simp; omega
|
||||
theorem Nat.ro_eq_true_of_le (u v k : Nat) : u ≤ v → (u ≤ v + k) = True :=
|
||||
by simp; omega
|
||||
theorem Nat.ro_eq_true_of_ro (u v k₁ k₂ : Nat) : isLE k₁ k₂ = true → u ≤ v + k₁ → (u ≤ v + k₂) = True :=
|
||||
by simp [isLE]; omega
|
||||
structure Cnstr where
|
||||
x : Var
|
||||
y : Var
|
||||
k : Nat := 0
|
||||
l : Bool := true
|
||||
deriving Repr, DecidableEq, Inhabited
|
||||
|
||||
/-!
|
||||
Theorems for propagating constraints to `False`.
|
||||
They are variants of the theorems for closing a goal.
|
||||
-/
|
||||
theorem Nat.lo_eq_false_of_le (u v k : Nat) : isLt 0 k = true → u ≤ v → (v + k ≤ u) = False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.le_eq_false_of_lo (u v k : Nat) : isLt 0 k = true → u + k ≤ v → (v ≤ u) = False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.lo_eq_false_of_lo (u v k₁ k₂ : Nat) : isLt 0 (k₁+k₂) = true → u + k₁ ≤ v → (v + k₂ ≤ u) = False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.ro_eq_false_of_lo (u v k₁ k₂ : Nat) : isLt k₂ k₁ = true → u + k₁ ≤ v → (v ≤ u + k₂) = False := by
|
||||
simp [isLt]; omega
|
||||
theorem Nat.lo_eq_false_of_ro (u v k₁ k₂ : Nat) : isLt k₁ k₂ = true → u ≤ v + k₁ → (v + k₂ ≤ u) = False := by
|
||||
simp [isLt]; omega
|
||||
def Cnstr.denote (c : Cnstr) (ctx : Context) : Prop :=
|
||||
if c.l then
|
||||
c.x.denote ctx + c.k ≤ c.y.denote ctx
|
||||
else
|
||||
c.x.denote ctx ≤ c.y.denote ctx + c.k
|
||||
|
||||
/-!
|
||||
Helper theorems for equality propagation
|
||||
-/
|
||||
def trivialCnstr : Cnstr := { x := 0, y := 0, k := 0, l := true }
|
||||
|
||||
theorem Nat.le_of_eq_1 (u v : Nat) : u = v → u ≤ v := by omega
|
||||
theorem Nat.le_of_eq_2 (u v : Nat) : u = v → v ≤ u := by omega
|
||||
theorem Nat.eq_of_le_of_le (u v : Nat) : u ≤ v → v ≤ u → u = v := by omega
|
||||
theorem Nat.le_offset (a k : Nat) : k ≤ a + k := by omega
|
||||
@[simp] theorem denote_trivial (ctx : Context) : trivialCnstr.denote ctx := by
|
||||
simp [Cnstr.denote, trivialCnstr]
|
||||
|
||||
end Lean.Grind
|
||||
def Cnstr.trans (c₁ c₂ : Cnstr) : Cnstr :=
|
||||
if c₁.y = c₂.x then
|
||||
let { x, k := k₁, l := l₁, .. } := c₁
|
||||
let { y, k := k₂, l := l₂, .. } := c₂
|
||||
match l₁, l₂ with
|
||||
| false, false =>
|
||||
{ x, y, k := k₁ + k₂, l := false }
|
||||
| false, true =>
|
||||
if k₁ < k₂ then
|
||||
{ x, y, k := k₂ - k₁, l := true }
|
||||
else
|
||||
{ x, y, k := k₁ - k₂, l := false }
|
||||
| true, false =>
|
||||
if k₁ < k₂ then
|
||||
{ x, y, k := k₂ - k₁, l := false }
|
||||
else
|
||||
{ x, y, k := k₁ - k₂, l := true }
|
||||
| true, true =>
|
||||
{ x, y, k := k₁ + k₂, l := true }
|
||||
else
|
||||
trivialCnstr
|
||||
|
||||
@[simp] theorem Cnstr.denote_trans_easy (ctx : Context) (c₁ c₂ : Cnstr) (h : c₁.y ≠ c₂.x) : (c₁.trans c₂).denote ctx := by
|
||||
simp [*, Cnstr.trans]
|
||||
|
||||
@[simp] theorem Cnstr.denote_trans (ctx : Context) (c₁ c₂ : Cnstr) : c₁.denote ctx → c₂.denote ctx → (c₁.trans c₂).denote ctx := by
|
||||
by_cases c₁.y = c₂.x
|
||||
case neg => simp [*]
|
||||
simp [trans, *]
|
||||
let { x, k := k₁, l := l₁, .. } := c₁
|
||||
let { y, k := k₂, l := l₂, .. } := c₂
|
||||
simp_all; split
|
||||
· simp [denote]; omega
|
||||
· split <;> simp [denote] <;> omega
|
||||
· split <;> simp [denote] <;> omega
|
||||
· simp [denote]; omega
|
||||
|
||||
def Cnstr.isTrivial (c : Cnstr) : Bool := c.x == c.y && c.k == 0
|
||||
|
||||
theorem Cnstr.of_isTrivial (ctx : Context) (c : Cnstr) : c.isTrivial = true → c.denote ctx := by
|
||||
cases c; simp [isTrivial]; intros; simp [*, denote]
|
||||
|
||||
def Cnstr.isFalse (c : Cnstr) : Bool := c.x == c.y && c.k != 0 && c.l == true
|
||||
|
||||
theorem Cnstr.of_isFalse (ctx : Context) {c : Cnstr} : c.isFalse = true → ¬c.denote ctx := by
|
||||
cases c; simp [isFalse]; intros; simp [*, denote]; omega
|
||||
|
||||
def Cnstrs := List Cnstr
|
||||
|
||||
def Cnstrs.denoteAnd' (ctx : Context) (c₁ : Cnstr) (c₂ : Cnstrs) : Prop :=
|
||||
match c₂ with
|
||||
| [] => c₁.denote ctx
|
||||
| c::cs => c₁.denote ctx ∧ Cnstrs.denoteAnd' ctx c cs
|
||||
|
||||
theorem Cnstrs.denote'_trans (ctx : Context) (c₁ c : Cnstr) (cs : Cnstrs) : c₁.denote ctx → denoteAnd' ctx c cs → denoteAnd' ctx (c₁.trans c) cs := by
|
||||
induction cs
|
||||
next => simp [denoteAnd', *]; apply Cnstr.denote_trans
|
||||
next c cs ih => simp [denoteAnd']; intros; simp [*]
|
||||
|
||||
def Cnstrs.trans' (c₁ : Cnstr) (c₂ : Cnstrs) : Cnstr :=
|
||||
match c₂ with
|
||||
| [] => c₁
|
||||
| c::c₂ => trans' (c₁.trans c) c₂
|
||||
|
||||
@[simp] theorem Cnstrs.denote'_trans' (ctx : Context) (c₁ : Cnstr) (c₂ : Cnstrs) : denoteAnd' ctx c₁ c₂ → (trans' c₁ c₂).denote ctx := by
|
||||
induction c₂ generalizing c₁
|
||||
next => intros; simp_all [trans', denoteAnd']
|
||||
next c cs ih => simp [denoteAnd']; intros; simp [trans']; apply ih; apply denote'_trans <;> assumption
|
||||
|
||||
def Cnstrs.denoteAnd (ctx : Context) (c : Cnstrs) : Prop :=
|
||||
match c with
|
||||
| [] => True
|
||||
| c::cs => denoteAnd' ctx c cs
|
||||
|
||||
def Cnstrs.trans (c : Cnstrs) : Cnstr :=
|
||||
match c with
|
||||
| [] => trivialCnstr
|
||||
| c::cs => trans' c cs
|
||||
|
||||
theorem Cnstrs.of_denoteAnd_trans {ctx : Context} {c : Cnstrs} : c.denoteAnd ctx → c.trans.denote ctx := by
|
||||
cases c <;> simp [*, trans, denoteAnd] <;> intros <;> simp [*]
|
||||
|
||||
def Cnstrs.isFalse (c : Cnstrs) : Bool :=
|
||||
c.trans.isFalse
|
||||
|
||||
theorem Cnstrs.unsat' (ctx : Context) (c : Cnstrs) : c.isFalse = true → ¬ c.denoteAnd ctx := by
|
||||
simp [isFalse]; intro h₁ h₂
|
||||
have := of_denoteAnd_trans h₂
|
||||
have := Cnstr.of_isFalse ctx h₁
|
||||
contradiction
|
||||
|
||||
/-- `denote ctx [c_1, ..., c_n] C` is `c_1.denote ctx → ... → c_n.denote ctx → C` -/
|
||||
def Cnstrs.denote (ctx : Context) (cs : Cnstrs) (C : Prop) : Prop :=
|
||||
match cs with
|
||||
| [] => C
|
||||
| c::cs => c.denote ctx → denote ctx cs C
|
||||
|
||||
theorem Cnstrs.not_denoteAnd'_eq (ctx : Context) (c : Cnstr) (cs : Cnstrs) (C : Prop) : (denoteAnd' ctx c cs → C) = denote ctx (c::cs) C := by
|
||||
simp [denote]
|
||||
induction cs generalizing c
|
||||
next => simp [denoteAnd', denote]
|
||||
next c' cs ih =>
|
||||
simp [denoteAnd', denote, *]
|
||||
|
||||
theorem Cnstrs.not_denoteAnd_eq (ctx : Context) (cs : Cnstrs) (C : Prop) : (denoteAnd ctx cs → C) = denote ctx cs C := by
|
||||
cases cs
|
||||
next => simp [denoteAnd, denote]
|
||||
next c cs => apply not_denoteAnd'_eq
|
||||
|
||||
def Cnstr.isImpliedBy (cs : Cnstrs) (c : Cnstr) : Bool :=
|
||||
cs.trans == c
|
||||
|
||||
/-! Main theorems used by `grind`. -/
|
||||
|
||||
/-- Auxiliary theorem used by `grind` to prove that a system of offset inequalities is unsatisfiable. -/
|
||||
theorem Cnstrs.unsat (ctx : Context) (cs : Cnstrs) : cs.isFalse = true → cs.denote ctx False := by
|
||||
intro h
|
||||
rw [← not_denoteAnd_eq]
|
||||
apply unsat'
|
||||
assumption
|
||||
|
||||
/-- Auxiliary theorem used by `grind` to prove an implied offset inequality. -/
|
||||
theorem Cnstrs.imp (ctx : Context) (cs : Cnstrs) (c : Cnstr) (h : c.isImpliedBy cs = true) : cs.denote ctx (c.denote ctx) := by
|
||||
rw [← eq_of_beq h]
|
||||
rw [← not_denoteAnd_eq]
|
||||
apply of_denoteAnd_trans
|
||||
|
||||
end Lean.Grind.Offset
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.NotationExtra
|
||||
|
||||
namespace Lean.Grind
|
||||
/-!
|
||||
This is a hackish module for hovering node information in the `grind` tactic state.
|
||||
-/
|
||||
|
||||
inductive NodeDef where
|
||||
| unit
|
||||
|
||||
set_option linter.unusedVariables false in
|
||||
def node_def (_ : Nat) {α : Sort u} {a : α} : NodeDef := .unit
|
||||
|
||||
@[app_unexpander node_def]
|
||||
def nodeDefUnexpander : PrettyPrinter.Unexpander := fun stx => do
|
||||
match stx with
|
||||
| `($_ $id:num) => return mkIdent <| Name.mkSimple $ "#" ++ toString id.getNat
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander NodeDef]
|
||||
def NodeDefUnexpander : PrettyPrinter.Unexpander := fun _ => do
|
||||
return mkIdent <| Name.mkSimple "NodeDef"
|
||||
|
||||
end Lean.Grind
|
||||
@@ -6,26 +6,17 @@ Authors: Leonardo de Moura
|
||||
prelude
|
||||
import Init.Tactics
|
||||
|
||||
namespace Lean.Parser
|
||||
/--
|
||||
Reset all `grind` attributes. This command is intended for testing purposes only and should not be used in applications.
|
||||
-/
|
||||
syntax (name := resetGrindAttrs) "%reset_grind_attrs" : command
|
||||
namespace Lean.Parser.Attr
|
||||
|
||||
namespace Attr
|
||||
syntax grindEq := "= "
|
||||
syntax grindEqBoth := atomic("_" "=" "_ ")
|
||||
syntax grindEqRhs := atomic("=" "_ ")
|
||||
syntax grindEqBwd := atomic("←" "= ")
|
||||
syntax grindBwd := "← "
|
||||
syntax grindFwd := "→ "
|
||||
syntax grindUsr := &"usr "
|
||||
syntax grindCases := &"cases "
|
||||
syntax grindCasesEager := atomic(&"cases" &"eager ")
|
||||
syntax grindMod := grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd <|> grindFwd <|> grindUsr <|> grindCasesEager <|> grindCases
|
||||
syntax (name := grind) "grind" (grindMod)? : attr
|
||||
end Attr
|
||||
end Lean.Parser
|
||||
syntax grindEq := "="
|
||||
syntax grindEqBoth := atomic("_" "=" "_")
|
||||
syntax grindEqRhs := atomic("=" "_")
|
||||
syntax grindBwd := "←"
|
||||
syntax grindFwd := "→"
|
||||
|
||||
syntax (name := grind) "grind" (grindEqBoth <|> grindEqRhs <|> grindEq <|> grindBwd <|> grindFwd)? : attr
|
||||
|
||||
end Lean.Parser.Attr
|
||||
|
||||
namespace Lean.Grind
|
||||
/--
|
||||
@@ -33,10 +24,8 @@ The configuration for `grind`.
|
||||
Passed to `grind` using, for example, the `grind (config := { matchEqs := true })` syntax.
|
||||
-/
|
||||
structure Config where
|
||||
/-- If `trace` is `true`, `grind` records used E-matching theorems and case-splits. -/
|
||||
trace : Bool := false
|
||||
/-- Maximum number of case-splits in a proof search branch. It does not include splits performed during normalization. -/
|
||||
splits : Nat := 8
|
||||
splits : Nat := 5
|
||||
/-- Maximum number of E-matching (aka heuristic theorem instantiation) rounds before each case split. -/
|
||||
ematch : Nat := 5
|
||||
/--
|
||||
@@ -54,14 +43,8 @@ structure Config where
|
||||
splitIte : Bool := true
|
||||
/--
|
||||
If `splitIndPred` is `true`, `grind` performs case-splitting on inductive predicates.
|
||||
Otherwise, it performs case-splitting only on types marked with `[grind cases]` attribute. -/
|
||||
splitIndPred : Bool := false
|
||||
/-- By default, `grind` halts as soon as it encounters a sub-goal where no further progress can be made. -/
|
||||
failures : Nat := 1
|
||||
/-- Maximum number of heartbeats (in thousands) the canonicalizer can spend per definitional equality test. -/
|
||||
canonHeartbeats : Nat := 1000
|
||||
/-- If `ext` is `true`, `grind` uses extensionality theorems available in the environment. -/
|
||||
ext : Bool := true
|
||||
Otherwise, it performs case-splitting only on types marked with `[grind_split]` attribute. -/
|
||||
splitIndPred : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
end Lean.Grind
|
||||
@@ -72,19 +55,7 @@ namespace Lean.Parser.Tactic
|
||||
`grind` tactic and related tactics.
|
||||
-/
|
||||
|
||||
syntax grindErase := "-" ident
|
||||
syntax grindLemma := (Attr.grindMod)? ident
|
||||
syntax grindParam := grindErase <|> grindLemma
|
||||
|
||||
syntax (name := grind)
|
||||
"grind" optConfig (&" only")?
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
("on_failure " term)? : tactic
|
||||
|
||||
|
||||
syntax (name := grindTrace)
|
||||
"grind?" optConfig (&" only")?
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
("on_failure " term)? : tactic
|
||||
-- TODO: parameters
|
||||
syntax (name := grind) "grind" optConfig ("on_failure " term)? : tactic
|
||||
|
||||
end Lean.Parser.Tactic
|
||||
|
||||
@@ -9,20 +9,18 @@ import Init.Core
|
||||
namespace Lean.Grind
|
||||
|
||||
/-- A helper gadget for annotating nested proofs in goals. -/
|
||||
def nestedProof (p : Prop) {h : p} : p := h
|
||||
def nestedProof (p : Prop) (h : p) : p := h
|
||||
|
||||
/--
|
||||
Gadget for marking `match`-expressions that should not be reduced by the `grind` simplifier, but the discriminants should be normalized.
|
||||
Gadget for marking terms that should not be normalized by `grind`s simplifier.
|
||||
`grind` uses a simproc to implement this feature.
|
||||
We use it when adding instances of `match`-equations to prevent them from being simplified to true.
|
||||
-/
|
||||
def simpMatchDiscrsOnly {α : Sort u} (a : α) : α := a
|
||||
def doNotSimp {α : Sort u} (a : α) : α := a
|
||||
|
||||
/-- Gadget for representing offsets `t+k` in patterns. -/
|
||||
def offset (a b : Nat) : Nat := a + b
|
||||
|
||||
/-- Gadget for representing `a = b` in patterns for backward propagation. -/
|
||||
def eqBwdPattern (a b : α) : Prop := a = b
|
||||
|
||||
/--
|
||||
Gadget for annotating the equalities in `match`-equations conclusions.
|
||||
`_origin` is the term used to instantiate the `match`-equation using E-matching.
|
||||
@@ -30,15 +28,7 @@ When `EqMatch a b origin` is `True`, we mark `origin` as a resolved case-split.
|
||||
-/
|
||||
def EqMatch (a b : α) {_origin : α} : Prop := a = b
|
||||
|
||||
/--
|
||||
Gadget for annotating conditions of `match` equational lemmas.
|
||||
We use this annotation for two different reasons:
|
||||
- We don't want to normalize them.
|
||||
- We have a propagator for them.
|
||||
-/
|
||||
def MatchCond (p : Prop) : Prop := p
|
||||
|
||||
theorem nestedProof_congr (p q : Prop) (h : p = q) (hp : p) (hq : q) : HEq (@nestedProof p hp) (@nestedProof q hq) := by
|
||||
theorem nestedProof_congr (p q : Prop) (h : p = q) (hp : p) (hq : q) : HEq (nestedProof p hp) (nestedProof q hq) := by
|
||||
subst h; apply HEq.refl
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -5,5 +5,4 @@ Authors: Joachim Breitner
|
||||
-/
|
||||
prelude
|
||||
import Init.Internal.Order.Basic
|
||||
import Init.Internal.Order.Lemmas
|
||||
import Init.Internal.Order.Tactic
|
||||
|
||||
@@ -59,7 +59,7 @@ end PartialOrder
|
||||
section CCPO
|
||||
|
||||
/--
|
||||
A chain-complete partial order (CCPO) is a partial order where every chain has a least upper bound.
|
||||
A chain-complete partial order (CCPO) is a partial order where every chain a least upper bound.
|
||||
|
||||
This is intended to be used in the construction of `partial_fixpoint`, and not meant to be used otherwise.
|
||||
-/
|
||||
@@ -104,7 +104,7 @@ variable {α : Sort u} [PartialOrder α]
|
||||
variable {β : Sort v} [PartialOrder β]
|
||||
|
||||
/--
|
||||
A function is monotone if it maps related elements to related elements.
|
||||
A function is monotone if if it maps related elements to releated elements.
|
||||
|
||||
This is intended to be used in the construction of `partial_fixpoint`, and not meant to be used otherwise.
|
||||
-/
|
||||
@@ -401,7 +401,6 @@ theorem monotone_letFun
|
||||
(hmono : ∀ y, monotone (fun x => k x y)) :
|
||||
monotone fun (x : α) => letFun v (k x) := hmono v
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_ite
|
||||
{α : Sort u} {β : Sort v} [PartialOrder α] [PartialOrder β]
|
||||
(c : Prop) [Decidable c]
|
||||
@@ -412,7 +411,6 @@ theorem monotone_ite
|
||||
· apply hmono₁
|
||||
· apply hmono₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_dite
|
||||
{α : Sort u} {β : Sort v} [PartialOrder α] [PartialOrder β]
|
||||
(c : Prop) [Decidable c]
|
||||
@@ -442,41 +440,38 @@ instance [PartialOrder α] [PartialOrder β] : PartialOrder (α ×' β) where
|
||||
dsimp at *
|
||||
rw [rel_antisymm ha.1 hb.1, rel_antisymm ha.2 hb.2]
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem PProd.monotone_mk [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
theorem monotone_pprod [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
{f : γ → α} {g : γ → β} (hf : monotone f) (hg : monotone g) :
|
||||
monotone (fun x => PProd.mk (f x) (g x)) :=
|
||||
fun _ _ h12 => ⟨hf _ _ h12, hg _ _ h12⟩
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem PProd.monotone_fst [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
theorem monotone_pprod_fst [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
{f : γ → α ×' β} (hf : monotone f) : monotone (fun x => (f x).1) :=
|
||||
fun _ _ h12 => (hf _ _ h12).1
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem PProd.monotone_snd [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
theorem monotone_pprod_snd [PartialOrder α] [PartialOrder β] [PartialOrder γ]
|
||||
{f : γ → α ×' β} (hf : monotone f) : monotone (fun x => (f x).2) :=
|
||||
fun _ _ h12 => (hf _ _ h12).2
|
||||
|
||||
def PProd.chain.fst [CCPO α] [CCPO β] (c : α ×' β → Prop) : α → Prop := fun a => ∃ b, c ⟨a, b⟩
|
||||
def PProd.chain.snd [CCPO α] [CCPO β] (c : α ×' β → Prop) : β → Prop := fun b => ∃ a, c ⟨a, b⟩
|
||||
def chain_pprod_fst [CCPO α] [CCPO β] (c : α ×' β → Prop) : α → Prop := fun a => ∃ b, c ⟨a, b⟩
|
||||
def chain_pprod_snd [CCPO α] [CCPO β] (c : α ×' β → Prop) : β → Prop := fun b => ∃ a, c ⟨a, b⟩
|
||||
|
||||
theorem PProd.chain.chain_fst [CCPO α] [CCPO β] {c : α ×' β → Prop} (hchain : chain c) :
|
||||
chain (chain.fst c) := by
|
||||
theorem chain.pprod_fst [CCPO α] [CCPO β] (c : α ×' β → Prop) (hchain : chain c) :
|
||||
chain (chain_pprod_fst c) := by
|
||||
intro a₁ a₂ ⟨b₁, h₁⟩ ⟨b₂, h₂⟩
|
||||
cases hchain ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ h₁ h₂
|
||||
case inl h => left; exact h.1
|
||||
case inr h => right; exact h.1
|
||||
|
||||
theorem PProd.chain.chain_snd [CCPO α] [CCPO β] {c : α ×' β → Prop} (hchain : chain c) :
|
||||
chain (chain.snd c) := by
|
||||
theorem chain.pprod_snd [CCPO α] [CCPO β] (c : α ×' β → Prop) (hchain : chain c) :
|
||||
chain (chain_pprod_snd c) := by
|
||||
intro b₁ b₂ ⟨a₁, h₁⟩ ⟨a₂, h₂⟩
|
||||
cases hchain ⟨a₁, b₁⟩ ⟨a₂, b₂⟩ h₁ h₂
|
||||
case inl h => left; exact h.2
|
||||
case inr h => right; exact h.2
|
||||
|
||||
instance instCCPOPProd [CCPO α] [CCPO β] : CCPO (α ×' β) where
|
||||
csup c := ⟨CCPO.csup (PProd.chain.fst c), CCPO.csup (PProd.chain.snd c)⟩
|
||||
instance [CCPO α] [CCPO β] : CCPO (α ×' β) where
|
||||
csup c := ⟨CCPO.csup (chain_pprod_fst c), CCPO.csup (chain_pprod_snd c)⟩
|
||||
csup_spec := by
|
||||
intro ⟨a, b⟩ c hchain
|
||||
dsimp
|
||||
@@ -485,32 +480,32 @@ instance instCCPOPProd [CCPO α] [CCPO β] : CCPO (α ×' β) where
|
||||
intro ⟨h₁, h₂⟩ ⟨a', b'⟩ cab
|
||||
constructor <;> dsimp at *
|
||||
· apply rel_trans ?_ h₁
|
||||
apply le_csup (PProd.chain.chain_fst hchain)
|
||||
apply le_csup hchain.pprod_fst
|
||||
exact ⟨b', cab⟩
|
||||
· apply rel_trans ?_ h₂
|
||||
apply le_csup (PProd.chain.chain_snd hchain)
|
||||
apply le_csup hchain.pprod_snd
|
||||
exact ⟨a', cab⟩
|
||||
next =>
|
||||
intro h
|
||||
constructor <;> dsimp
|
||||
· apply csup_le (PProd.chain.chain_fst hchain)
|
||||
· apply csup_le hchain.pprod_fst
|
||||
intro a' ⟨b', hcab⟩
|
||||
apply (h _ hcab).1
|
||||
· apply csup_le (PProd.chain.chain_snd hchain)
|
||||
· apply csup_le hchain.pprod_snd
|
||||
intro b' ⟨a', hcab⟩
|
||||
apply (h _ hcab).2
|
||||
|
||||
theorem admissible_pprod_fst {α : Sort u} {β : Sort v} [CCPO α] [CCPO β] (P : α → Prop)
|
||||
(hadm : admissible P) : admissible (fun (x : α ×' β) => P x.1) := by
|
||||
intro c hchain h
|
||||
apply hadm _ (PProd.chain.chain_fst hchain)
|
||||
apply hadm _ hchain.pprod_fst
|
||||
intro x ⟨y, hxy⟩
|
||||
apply h ⟨x,y⟩ hxy
|
||||
|
||||
theorem admissible_pprod_snd {α : Sort u} {β : Sort v} [CCPO α] [CCPO β] (P : β → Prop)
|
||||
(hadm : admissible P) : admissible (fun (x : α ×' β) => P x.2) := by
|
||||
intro c hchain h
|
||||
apply hadm _ (PProd.chain.chain_snd hchain)
|
||||
apply hadm _ hchain.pprod_snd
|
||||
intro y ⟨x, hxy⟩
|
||||
apply h ⟨x,y⟩ hxy
|
||||
|
||||
@@ -614,7 +609,6 @@ class MonoBind (m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] wh
|
||||
bind_mono_left {a₁ a₂ : m α} {f : α → m b} (h : a₁ ⊑ a₂) : a₁ >>= f ⊑ a₂ >>= f
|
||||
bind_mono_right {a : m α} {f₁ f₂ : α → m b} (h : ∀ x, f₁ x ⊑ f₂ x) : a >>= f₁ ⊑ a >>= f₂
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_bind
|
||||
(m : Type u → Type v) [Bind m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
{α β : Type u}
|
||||
@@ -640,7 +634,7 @@ noncomputable instance : MonoBind Option where
|
||||
· exact FlatOrder.rel.refl
|
||||
· exact h _
|
||||
|
||||
theorem Option.admissible_eq_some (P : Prop) (y : α) :
|
||||
theorem admissible_eq_some (P : Prop) (y : α) :
|
||||
admissible (fun (x : Option α) => x = some y → P) := by
|
||||
apply admissible_flatOrder; simp
|
||||
|
||||
@@ -683,7 +677,7 @@ theorem find_spec : ∀ n m, find P n = some m → n ≤ m ∧ P m := by
|
||||
refine fix_induct (motive := fun (f : Nat → Option Nat) => ∀ n m, f n = some m → n ≤ m ∧ P m) _ ?hadm ?hstep
|
||||
case hadm =>
|
||||
-- apply admissible_pi_apply does not work well, hard to infer everything
|
||||
exact admissible_pi_apply _ (fun n => admissible_pi _ (fun m => Option.admissible_eq_some _ m))
|
||||
exact admissible_pi_apply _ (fun n => admissible_pi _ (fun m => admissible_eq_some _ m))
|
||||
case hstep =>
|
||||
intro f ih n m heq
|
||||
simp only [findF] at heq
|
||||
|
||||
@@ -1,685 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner
|
||||
-/
|
||||
|
||||
prelude
|
||||
|
||||
import Init.Data.List.Control
|
||||
import Init.Data.Array.Basic
|
||||
import Init.Internal.Order.Basic
|
||||
|
||||
/-!
|
||||
|
||||
This file contains monotonicity lemmas for higher-order monadic operations (e.g. `mapM`) in the
|
||||
standard library. This allows recursive definitions using `partial_fixpoint` to use nested
|
||||
recursion.
|
||||
|
||||
Ideally, every higher-order monadic funciton in the standard library has a lemma here. At the time
|
||||
of writing, this file covers functions from
|
||||
|
||||
* Init/Data/Option/Basic.lean
|
||||
* Init/Data/List/Control.lean
|
||||
* Init/Data/Array/Basic.lean
|
||||
|
||||
in the order of their apperance there. No automation to check the exhaustiveness exists yet.
|
||||
|
||||
The lemma statements are written manually, but follow a predictable scheme, and could be automated.
|
||||
Likewise, the proofs are written very naively. Most of them could be handled by a tactic like
|
||||
`monotonicity` (extended to make use of local hypotheses).
|
||||
-/
|
||||
|
||||
namespace Lean.Order
|
||||
|
||||
open Lean.Order
|
||||
|
||||
variable {m : Type u → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m]
|
||||
variable {α β : Type u}
|
||||
variable {γ : Type w} [PartialOrder γ]
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem Functor.monotone_map [LawfulMonad m] (f : γ → m α) (g : α → β) (hmono : monotone f) :
|
||||
monotone (fun x => g <$> f x) := by
|
||||
simp only [← LawfulMonad.bind_pure_comp ]
|
||||
apply monotone_bind _ _ _ hmono
|
||||
apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem Seq.monotone_seq [LawfulMonad m] (f : γ → m α) (g : γ → m (α → β))
|
||||
(hmono₁ : monotone g) (hmono₂ : monotone f) :
|
||||
monotone (fun x => g x <*> f x) := by
|
||||
simp only [← LawfulMonad.bind_map ]
|
||||
apply monotone_bind
|
||||
· assumption
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply Functor.monotone_map
|
||||
assumption
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem SeqLeft.monotone_seqLeft [LawfulMonad m] (f : γ → m α) (g : γ → m β)
|
||||
(hmono₁ : monotone g) (hmono₂ : monotone f) :
|
||||
monotone (fun x => g x <* f x) := by
|
||||
simp only [seqLeft_eq]
|
||||
apply Seq.monotone_seq
|
||||
· apply Functor.monotone_map
|
||||
assumption
|
||||
· assumption
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem SeqRight.monotone_seqRight [LawfulMonad m] (f : γ → m α) (g : γ → m β)
|
||||
(hmono₁ : monotone g) (hmono₂ : monotone f) :
|
||||
monotone (fun x => g x *> f x) := by
|
||||
simp only [seqRight_eq]
|
||||
apply Seq.monotone_seq
|
||||
· apply Functor.monotone_map
|
||||
assumption
|
||||
· assumption
|
||||
|
||||
namespace Option
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_bindM (f : γ → α → m (Option β)) (xs : Option α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.bindM (f x)) := by
|
||||
cases xs with
|
||||
| none => apply monotone_const
|
||||
| some x =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_mapM (f : γ → α → m β) (xs : Option α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.mapM (f x)) := by
|
||||
cases xs with
|
||||
| none => apply monotone_const
|
||||
| some x =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_elimM (a : γ → m (Option α)) (n : γ → m β) (s : γ → α → m β)
|
||||
(hmono₁ : monotone a) (hmono₂ : monotone n) (hmono₃ : monotone s) :
|
||||
monotone (fun x => Option.elimM (a x) (n x) (s x)) := by
|
||||
apply monotone_bind
|
||||
· apply hmono₁
|
||||
· apply monotone_of_monotone_apply
|
||||
intro o
|
||||
cases o
|
||||
case none => apply hmono₂
|
||||
case some y =>
|
||||
dsimp only [Option.elim]
|
||||
apply monotone_apply
|
||||
apply hmono₃
|
||||
|
||||
omit [MonoBind m] in
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_getDM (o : Option α) (y : γ → m α) (hmono : monotone y) :
|
||||
monotone (fun x => o.getDM (y x)) := by
|
||||
cases o
|
||||
· apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
end Option
|
||||
|
||||
|
||||
namespace List
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_mapM (f : γ → α → m β) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.mapM (f x)) := by
|
||||
cases xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ xs =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
dsimp
|
||||
generalize [y] = ys
|
||||
induction xs generalizing ys with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forM (f : γ → α → m PUnit) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.forM (f x)) := by
|
||||
induction xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_filterAuxM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs acc : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.filterAuxM (f x) acc) := by
|
||||
induction xs generalizing acc with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_filterM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.filterM (f x)) := by
|
||||
apply monotone_bind
|
||||
· exact monotone_filterAuxM f xs [] hmono
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_filterRevM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.filterRevM (f x)) := by
|
||||
exact monotone_filterAuxM f xs.reverse [] hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldlM
|
||||
(f : γ → β → α → m β) (init : β) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.foldlM (f x) (init := init)) := by
|
||||
induction xs generalizing init with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldrM
|
||||
(f : γ → α → β → m β) (init : β) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.foldrM (f x) (init := init)) := by
|
||||
apply monotone_foldlM
|
||||
apply monotone_of_monotone_apply
|
||||
intro s
|
||||
apply monotone_of_monotone_apply
|
||||
intro a
|
||||
apply monotone_apply (a := s)
|
||||
apply monotone_apply (a := a)
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_anyM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.anyM (f x)) := by
|
||||
induction xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y
|
||||
· apply ih
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_allM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.allM (f x)) := by
|
||||
induction xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y
|
||||
· apply monotone_const
|
||||
· apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findM?
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findM? (f x)) := by
|
||||
induction xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y
|
||||
· apply ih
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findSomeM?
|
||||
(f : γ → α → m (Option β)) (xs : List α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findSomeM? (f x)) := by
|
||||
induction xs with
|
||||
| nil => apply monotone_const
|
||||
| cons _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y
|
||||
· apply ih
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn'_loop {α : Type uu}
|
||||
(as : List α) (f : γ → (a : α) → a ∈ as → β → m (ForInStep β)) (as' : List α) (b : β)
|
||||
(p : Exists (fun bs => bs ++ as' = as)) (hmono : monotone f) :
|
||||
monotone (fun x => List.forIn'.loop as (f x) as' b p) := by
|
||||
induction as' generalizing b with
|
||||
| nil => apply monotone_const
|
||||
| cons a as' ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y with
|
||||
| done => apply monotone_const
|
||||
| yield => apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn' {α : Type uu}
|
||||
(as : List α) (init : β) (f : γ → (a : α) → a ∈ as → β → m (ForInStep β)) (hmono : monotone f) :
|
||||
monotone (fun x => forIn' as init (f x)) := by
|
||||
apply monotone_forIn'_loop
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn {α : Type uu}
|
||||
(as : List α) (init : β) (f : γ → (a : α) → β → m (ForInStep β)) (hmono : monotone f) :
|
||||
monotone (fun x => forIn as init (f x)) := by
|
||||
apply monotone_forIn' as init _
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro p
|
||||
apply monotone_apply (a := y)
|
||||
apply hmono
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_modifyM (a : Array α) (i : Nat) (f : γ → α → m α) (hmono : monotone f) :
|
||||
monotone (fun x => a.modifyM i (f x)) := by
|
||||
unfold Array.modifyM
|
||||
split
|
||||
· apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn'_loop {α : Type uu}
|
||||
(as : Array α) (f : γ → (a : α) → a ∈ as → β → m (ForInStep β)) (i : Nat) (h : i ≤ as.size)
|
||||
(b : β) (hmono : monotone f) :
|
||||
monotone (fun x => Array.forIn'.loop as (f x) i h b) := by
|
||||
induction i, h, b using Array.forIn'.loop.induct with
|
||||
| case1 => apply monotone_const
|
||||
| case2 _ _ _ _ _ _ _ ih =>
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y with
|
||||
| done => apply monotone_const
|
||||
| yield => apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn' {α : Type uu}
|
||||
(as : Array α) (init : β) (f : γ → (a : α) → a ∈ as → β → m (ForInStep β)) (hmono : monotone f) :
|
||||
monotone (fun x => forIn' as init (f x)) := by
|
||||
apply monotone_forIn'_loop
|
||||
apply hmono
|
||||
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_forIn {α : Type uu}
|
||||
(as : Array α) (init : β) (f : γ → (a : α) → β → m (ForInStep β)) (hmono : monotone f) :
|
||||
monotone (fun x => forIn as init (f x)) := by
|
||||
apply monotone_forIn' as init _
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro p
|
||||
apply monotone_apply (a := y)
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldlM_loop
|
||||
(f : γ → β → α → m β) (xs : Array α) (stop : Nat) (h : stop ≤ xs.size) (i j : Nat) (b : β)
|
||||
(hmono : monotone f) : monotone (fun x => Array.foldlM.loop (f x) xs stop h i j b) := by
|
||||
induction i, j, b using Array.foldlM.loop.induct (h := h) with
|
||||
| case1 =>
|
||||
simp only [Array.foldlM.loop, ↓reduceDIte, *]
|
||||
apply monotone_const
|
||||
| case2 _ _ _ _ _ ih =>
|
||||
unfold Array.foldlM.loop
|
||||
simp only [↓reduceDIte, *]
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
apply ih
|
||||
| case3 =>
|
||||
simp only [Array.foldlM.loop, ↓reduceDIte, *]
|
||||
apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldlM
|
||||
(f : γ → β → α → m β) (init : β) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.foldlM (f x) init start stop) := by
|
||||
unfold Array.foldlM
|
||||
split <;> apply monotone_foldlM_loop (hmono := hmono)
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldrM_fold
|
||||
(f : γ → α → β → m β) (xs : Array α) (stop i : Nat) (h : i ≤ xs.size) (b : β)
|
||||
(hmono : monotone f) : monotone (fun x => Array.foldrM.fold (f x) xs stop i h b) := by
|
||||
induction i, h, b using Array.foldrM.fold.induct (stop := stop) with
|
||||
| case1 =>
|
||||
unfold Array.foldrM.fold
|
||||
simp only [↓reduceIte, *]
|
||||
apply monotone_const
|
||||
| case2 =>
|
||||
unfold Array.foldrM.fold
|
||||
simp only [↓reduceIte, *]
|
||||
apply monotone_const
|
||||
| case3 _ _ _ _ _ _ ih =>
|
||||
unfold Array.foldrM.fold
|
||||
simp only [reduceCtorEq, ↓reduceIte, *]
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_foldrM
|
||||
(f : γ → α → β → m β) (init : β) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.foldrM (f x) init start stop) := by
|
||||
unfold Array.foldrM
|
||||
split
|
||||
· split
|
||||
· apply monotone_foldrM_fold (hmono := hmono)
|
||||
· apply monotone_const
|
||||
· split
|
||||
· apply monotone_foldrM_fold (hmono := hmono)
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_mapM (xs : Array α) (f : γ → α → m β) (hmono : monotone f) :
|
||||
monotone (fun x => xs.mapM (f x)) := by
|
||||
suffices ∀ i r, monotone (fun x => Array.mapM.map (f x) xs i r) by apply this
|
||||
intros i r
|
||||
induction i, r using Array.mapM.map.induct xs
|
||||
case case1 ih =>
|
||||
unfold Array.mapM.map
|
||||
simp only [↓reduceDIte, *]
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· intro y
|
||||
apply monotone_of_monotone_apply
|
||||
apply ih
|
||||
case case2 =>
|
||||
unfold Array.mapM.map
|
||||
simp only [↓reduceDIte, *]
|
||||
apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_mapFinIdxM (xs : Array α) (f : γ → (i : Nat) → α → i < xs.size → m β)
|
||||
(hmono : monotone f) : monotone (fun x => xs.mapFinIdxM (f x)) := by
|
||||
suffices ∀ i j (h : i + j = xs.size) r, monotone (fun x => Array.mapFinIdxM.map xs (f x) i j h r) by apply this
|
||||
intros i j h r
|
||||
induction i, j, h, r using Array.mapFinIdxM.map.induct xs
|
||||
case case1 =>
|
||||
apply monotone_const
|
||||
case case2 ih =>
|
||||
apply monotone_bind
|
||||
· dsimp
|
||||
apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
· intro y
|
||||
apply monotone_of_monotone_apply
|
||||
apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findSomeM?
|
||||
(f : γ → α → m (Option β)) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findSomeM? (f x)) := by
|
||||
unfold Array.findSomeM?
|
||||
apply monotone_bind
|
||||
· apply monotone_forIn
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro r
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findM?
|
||||
{m : Type → Type} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findM? (f x)) := by
|
||||
unfold Array.findM?
|
||||
apply monotone_bind
|
||||
· apply monotone_forIn
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro r
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findIdxM?
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type u}
|
||||
(f : γ → α → m Bool) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findIdxM? (f x)) := by
|
||||
unfold Array.findIdxM?
|
||||
apply monotone_bind
|
||||
· apply monotone_forIn
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro r
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_anyM_loop
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type u}
|
||||
(f : γ → α → m Bool) (xs : Array α) (stop : Nat) (h : stop ≤ xs.size) (j : Nat)
|
||||
(hmono : monotone f) : monotone (fun x => Array.anyM.loop (f x) xs stop h j) := by
|
||||
induction j using Array.anyM.loop.induct (h := h) with
|
||||
| case2 =>
|
||||
unfold Array.anyM.loop
|
||||
simp only [↓reduceDIte, *]
|
||||
apply monotone_const
|
||||
| case1 _ _ _ ih =>
|
||||
unfold Array.anyM.loop
|
||||
simp only [↓reduceDIte, *]
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
split
|
||||
· apply monotone_const
|
||||
· apply ih
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_anyM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type u}
|
||||
(f : γ → α → m Bool) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.anyM (f x) start stop) := by
|
||||
unfold Array.anyM
|
||||
split
|
||||
· apply monotone_anyM_loop
|
||||
apply hmono
|
||||
· apply monotone_anyM_loop
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_allM
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type u}
|
||||
(f : γ → α → m Bool) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.allM (f x) start stop) := by
|
||||
unfold Array.allM
|
||||
apply monotone_bind
|
||||
· apply monotone_anyM
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findSomeRevM?
|
||||
(f : γ → α → m (Option β)) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findSomeRevM? (f x)) := by
|
||||
unfold Array.findSomeRevM?
|
||||
suffices ∀ i (h : i ≤ xs.size), monotone (fun x => Array.findSomeRevM?.find (f x) xs i h) by apply this
|
||||
intros i h
|
||||
induction i, h using Array.findSomeRevM?.find.induct with
|
||||
| case1 =>
|
||||
unfold Array.findSomeRevM?.find
|
||||
apply monotone_const
|
||||
| case2 _ _ _ _ ih =>
|
||||
unfold Array.findSomeRevM?.find
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_of_monotone_apply
|
||||
intro y
|
||||
cases y with
|
||||
| none => apply ih
|
||||
| some y => apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_findRevM?
|
||||
{m : Type → Type v} [Monad m] [∀ α, PartialOrder (m α)] [MonoBind m] {α : Type}
|
||||
(f : γ → α → m Bool) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.findRevM? (f x)) := by
|
||||
unfold Array.findRevM?
|
||||
apply monotone_findSomeRevM?
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_array_forM
|
||||
(f : γ → α → m PUnit) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.forM (f x) start stop) := by
|
||||
unfold Array.forM
|
||||
apply monotone_foldlM
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_array_forRevM
|
||||
(f : γ → α → m PUnit) (xs : Array α) (start stop : Nat) (hmono : monotone f) :
|
||||
monotone (fun x => xs.forRevM (f x) start stop) := by
|
||||
unfold Array.forRevM
|
||||
apply monotone_foldrM
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro z
|
||||
apply monotone_apply
|
||||
apply hmono
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_flatMapM
|
||||
(f : γ → α → m (Array β)) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.flatMapM (f x)) := by
|
||||
unfold Array.flatMapM
|
||||
apply monotone_foldlM
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro z
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_array_filterMapM
|
||||
(f : γ → α → m (Option β)) (xs : Array α) (hmono : monotone f) :
|
||||
monotone (fun x => xs.filterMapM (f x)) := by
|
||||
unfold Array.filterMapM
|
||||
apply monotone_foldlM
|
||||
apply monotone_of_monotone_apply
|
||||
intro y
|
||||
apply monotone_of_monotone_apply
|
||||
intro z
|
||||
apply monotone_bind
|
||||
· apply monotone_apply
|
||||
apply hmono
|
||||
· apply monotone_const
|
||||
|
||||
end Array
|
||||
|
||||
end Lean.Order
|
||||
@@ -93,8 +93,7 @@ def isLetterLike (c : Char) : Bool :=
|
||||
def isSubScriptAlnum (c : Char) : Bool :=
|
||||
isNumericSubscript c ||
|
||||
(0x2090 ≤ c.val && c.val ≤ 0x209c) ||
|
||||
(0x1d62 ≤ c.val && c.val ≤ 0x1d6a) ||
|
||||
c.val == 0x2c7c
|
||||
(0x1d62 ≤ c.val && c.val ≤ 0x1d6a)
|
||||
|
||||
@[inline] def isIdFirst (c : Char) : Bool :=
|
||||
c.isAlpha || c = '_' || isLetterLike c
|
||||
|
||||
@@ -109,11 +109,6 @@ structure Config where
|
||||
to find candidate `simp` theorems. It approximates Lean 3 `simp` behavior.
|
||||
-/
|
||||
index : Bool := true
|
||||
/--
|
||||
When `true` (default : `true`), then simps will remove unused let-declarations:
|
||||
`let x := v; e` simplifies to `e` when `x` does not occur in `e`.
|
||||
-/
|
||||
zetaUnused : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
end DSimp
|
||||
@@ -233,11 +228,6 @@ structure Config where
|
||||
input and output terms are definitionally equal.
|
||||
-/
|
||||
implicitDefEqProofs : Bool := true
|
||||
/--
|
||||
When `true` (default : `true`), then simps will remove unused let-declarations:
|
||||
`let x := v; e` simplifies to `e` when `x` does not occur in `e`.
|
||||
-/
|
||||
zetaUnused : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
-- Configuration object for `simp_all`
|
||||
@@ -258,7 +248,6 @@ def neutralConfig : Simp.Config := {
|
||||
autoUnfold := false
|
||||
ground := false
|
||||
zetaDelta := false
|
||||
zetaUnused := false
|
||||
}
|
||||
|
||||
structure NormCastConfig extends Simp.Config where
|
||||
|
||||
@@ -67,7 +67,9 @@ abbrev leading (xs : Coeffs) : Int := IntList.leading xs
|
||||
abbrev map (f : Int → Int) (xs : Coeffs) : Coeffs := List.map f xs
|
||||
/-- Shim for `.enum.find?`. -/
|
||||
abbrev findIdx? (f : Int → Bool) (xs : Coeffs) : Option Nat :=
|
||||
List.findIdx? f xs
|
||||
-- List.findIdx? f xs
|
||||
-- We could avoid `Batteries.Data.List.Basic` by using the less efficient:
|
||||
xs.enum.find? (f ·.2) |>.map (·.1)
|
||||
/-- Shim for `IntList.bmod`. -/
|
||||
abbrev bmod (x : Coeffs) (m : Nat) : Coeffs := IntList.bmod x m
|
||||
/-- Shim for `IntList.bmod_dot_sub_dot_bmod`. -/
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace LinearCombo
|
||||
|
||||
instance : ToString LinearCombo where
|
||||
toString lc :=
|
||||
s!"{lc.const}{String.join <| lc.coeffs.toList.zipIdx.map fun ⟨c, i⟩ => s!" + {c} * x{i+1}"}"
|
||||
s!"{lc.const}{String.join <| lc.coeffs.toList.enum.map fun ⟨i, c⟩ => s!" + {c} * x{i+1}"}"
|
||||
|
||||
instance : Inhabited LinearCombo := ⟨{const := 1}⟩
|
||||
|
||||
|
||||
@@ -150,9 +150,6 @@ It can also be written as `()`.
|
||||
/-- Marker for information that has been erased by the code generator. -/
|
||||
unsafe axiom lcErased : Type
|
||||
|
||||
/-- Marker for type dependency that has been erased by the code generator. -/
|
||||
unsafe axiom lcAny : Type
|
||||
|
||||
/--
|
||||
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.
|
||||
|
||||
@@ -3705,7 +3702,8 @@ inductive Syntax where
|
||||
/-- Node in the syntax tree.
|
||||
|
||||
The `info` field is used by the delaborator to store the position of the
|
||||
subexpression corresponding to this node.
|
||||
subexpression corresponding to this node. The parser sets the `info` field
|
||||
to `none`.
|
||||
The parser sets the `info` field to `none`, with position retrieval continuing recursively.
|
||||
Nodes created by quotations use the result from `SourceInfo.fromRef` so that they are marked
|
||||
as synthetic even when the leading/trailing token is not.
|
||||
|
||||
@@ -1648,6 +1648,17 @@ If there are several with the same priority, it is uses the "most recent one". E
|
||||
-/
|
||||
syntax (name := simp) "simp" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
/--
|
||||
Theorems tagged with the `grind_norm` attribute are used by the `grind` tactic normalizer/pre-processor.
|
||||
-/
|
||||
syntax (name := grind_norm) "grind_norm" (Tactic.simpPre <|> Tactic.simpPost)? (ppSpace prio)? : attr
|
||||
|
||||
/--
|
||||
Simplification procedures tagged with the `grind_norm_proc` attribute are used by the `grind` tactic normalizer/pre-processor.
|
||||
-/
|
||||
syntax (name := grind_norm_proc) "grind_norm_proc" (Tactic.simpPre <|> Tactic.simpPost)? : attr
|
||||
|
||||
|
||||
/-- The possible `norm_cast` kinds: `elim`, `move`, or `squash`. -/
|
||||
syntax normCastLabel := &"elim" <|> &"move" <|> &"squash"
|
||||
|
||||
|
||||
@@ -14,85 +14,26 @@ register_builtin_option debug.skipKernelTC : Bool := {
|
||||
descr := "skip kernel type checker. WARNING: setting this option to true may compromise soundness because your proofs will not be checked by the Lean kernel"
|
||||
}
|
||||
|
||||
/-- Adds given declaration to the environment, respecting `debug.skipKernelTC`. -/
|
||||
def Kernel.Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except Exception Environment :=
|
||||
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except KernelException Environment :=
|
||||
if debug.skipKernelTC.get opts then
|
||||
addDeclWithoutChecking env decl
|
||||
else
|
||||
addDeclCore env (Core.getMaxHeartbeats opts).toUSize decl cancelTk?
|
||||
|
||||
private def Environment.addDeclAux (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
|
||||
env.addDeclCore (Core.getMaxHeartbeats opts).toUSize decl cancelTk? (!debug.skipKernelTC.get opts)
|
||||
|
||||
@[deprecated "use `Lean.addDecl` instead to ensure new namespaces are registered" (since := "2024-12-03")]
|
||||
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
|
||||
Environment.addDeclAux env opts decl cancelTk?
|
||||
|
||||
private def isNamespaceName : Name → Bool
|
||||
| .str .anonymous _ => true
|
||||
| .str p _ => isNamespaceName p
|
||||
| _ => false
|
||||
|
||||
private def registerNamePrefixes (env : Environment) (name : Name) : Environment :=
|
||||
match name with
|
||||
| .str _ s =>
|
||||
if s.get 0 == '_' then
|
||||
-- Do not register namespaces that only contain internal declarations.
|
||||
env
|
||||
else
|
||||
go env name
|
||||
| _ => env
|
||||
where go env
|
||||
| .str p _ => if isNamespaceName p then go (env.registerNamespace p) p else env
|
||||
| _ => env
|
||||
def Environment.addAndCompile (env : Environment) (opts : Options) (decl : Declaration)
|
||||
(cancelTk? : Option IO.CancelToken := none) : Except KernelException Environment := do
|
||||
let env ← addDecl env opts decl cancelTk?
|
||||
compileDecl env opts decl
|
||||
|
||||
def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
let mut env ← getEnv
|
||||
-- register namespaces for newly added constants; this used to be done by the kernel itself
|
||||
-- but that is incompatible with moving it to a separate task
|
||||
env := decl.getNames.foldl registerNamePrefixes env
|
||||
if let .inductDecl _ _ types _ := decl then
|
||||
env := types.foldl (registerNamePrefixes · <| ·.name ++ `rec) env
|
||||
|
||||
if !Elab.async.get (← getOptions) then
|
||||
setEnv env
|
||||
return (← doAdd)
|
||||
|
||||
-- convert `Declaration` to `ConstantInfo` to use as a preliminary value in the environment until
|
||||
-- kernel checking has finished; not all cases are supported yet
|
||||
let (name, info, kind) ← match decl with
|
||||
| .thmDecl thm => pure (thm.name, .thmInfo thm, .thm)
|
||||
| .defnDecl defn => pure (defn.name, .defnInfo defn, .defn)
|
||||
| .mutualDefnDecl [defn] => pure (defn.name, .defnInfo defn, .defn)
|
||||
| _ => return (← doAdd)
|
||||
|
||||
-- no environment extension changes to report after kernel checking; ensures we do not
|
||||
-- accidentally wait for this snapshot when querying extension states
|
||||
let async ← env.addConstAsync (reportExts := false) name kind
|
||||
-- report preliminary constant info immediately
|
||||
async.commitConst async.asyncEnv (some info)
|
||||
setEnv async.mainEnv
|
||||
let checkAct ← Core.wrapAsyncAsSnapshot fun _ => do
|
||||
try
|
||||
setEnv async.asyncEnv
|
||||
doAdd
|
||||
async.commitCheckEnv (← getEnv)
|
||||
finally
|
||||
async.commitFailure
|
||||
let t ← BaseIO.mapTask (fun _ => checkAct) env.checked
|
||||
let endRange? := (← getRef).getTailPos?.map fun pos => ⟨pos, pos⟩
|
||||
Core.logSnapshotTask { range? := endRange?, task := t }
|
||||
where doAdd := do
|
||||
profileitM Exception "type checking" (← getOptions) do
|
||||
withTraceNode `Kernel (fun _ => return m!"typechecking declarations {decl.getNames}") do
|
||||
withTraceNode `Kernel (fun _ => return m!"typechecking declaration") do
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
logWarning m!"declaration uses 'sorry'"
|
||||
let env ← (← getEnv).addDeclAux (← getOptions) decl (← read).cancelTk?
|
||||
|> ofExceptKernelException
|
||||
setEnv env
|
||||
logWarning "declaration uses 'sorry'"
|
||||
match (← getEnv).addDecl (← getOptions) decl (← read).cancelTk? with
|
||||
| .ok env => setEnv env
|
||||
| .error ex => throwKernelException ex
|
||||
|
||||
def addAndCompile (decl : Declaration) : CoreM Unit := do
|
||||
addDecl decl
|
||||
|
||||
@@ -144,7 +144,11 @@ def declareBuiltin (forDecl : Name) (value : Expr) : CoreM Unit := do
|
||||
let type := mkApp (mkConst `IO) (mkConst `Unit)
|
||||
let decl := Declaration.defnDecl { name, levelParams := [], type, value, hints := ReducibilityHints.opaque,
|
||||
safety := DefinitionSafety.safe }
|
||||
addAndCompile decl
|
||||
IO.ofExcept (setBuiltinInitAttr (← getEnv) name) >>= setEnv
|
||||
match (← getEnv).addAndCompile {} decl with
|
||||
-- TODO: pretty print error
|
||||
| Except.error e => do
|
||||
let msg ← (e.toMessageData {}).toString
|
||||
throwError "failed to emit registration code for builtin '{forDecl}': {msg}"
|
||||
| Except.ok env => IO.ofExcept (setBuiltinInitAttr env name) >>= setEnv
|
||||
|
||||
end Lean
|
||||
|
||||
@@ -80,7 +80,7 @@ partial def merge (v1 v2 : Value) : Value :=
|
||||
| top, _ | _, top => top
|
||||
| ctor i1 vs1, ctor i2 vs2 =>
|
||||
if i1 == i2 then
|
||||
ctor i1 (Array.zipWith merge vs1 vs2)
|
||||
ctor i1 (vs1.zipWith vs2 merge)
|
||||
else
|
||||
choice [v1, v2]
|
||||
| choice vs1, choice vs2 =>
|
||||
|
||||
@@ -33,7 +33,6 @@ def shouldGenerateCode (declName : Name) : CoreM Bool := do
|
||||
let some info ← getDeclInfo? declName | return false
|
||||
unless info.hasValue (allowOpaque := true) do return false
|
||||
if hasMacroInlineAttribute env declName then return false
|
||||
if (getImplementedBy? env declName).isSome then return false
|
||||
if (← Meta.isMatcher declName) then return false
|
||||
if isCasesOnRecursor env declName then return false
|
||||
-- TODO: check if type class instance
|
||||
|
||||
@@ -72,23 +72,23 @@ The type contains only `→` and constants.
|
||||
-/
|
||||
partial def toMonoType (type : Expr) : CoreM Expr := do
|
||||
let type := type.headBeta
|
||||
match type with
|
||||
| .const .. => visitApp type #[]
|
||||
| .app .. => type.withApp visitApp
|
||||
| .forallE _ d b _ =>
|
||||
let monoB ← toMonoType (b.instantiate1 anyExpr)
|
||||
match monoB with
|
||||
| .const ``lcErased _ => return erasedExpr
|
||||
| _ => mkArrow (← toMonoType d) monoB
|
||||
| .sort _ => return erasedExpr
|
||||
| _ => return anyExpr
|
||||
if type.isErased then
|
||||
return erasedExpr
|
||||
else if type.isErased then
|
||||
return erasedExpr
|
||||
else if isTypeFormerType type then
|
||||
return erasedExpr
|
||||
else match type with
|
||||
| .const .. => visitApp type #[]
|
||||
| .app .. => type.withApp visitApp
|
||||
| .forallE _ d b _ => mkArrow (← toMonoType d) (← toMonoType (b.instantiate1 erasedExpr))
|
||||
| _ => return erasedExpr
|
||||
where
|
||||
visitApp (f : Expr) (args : Array Expr) : CoreM Expr := do
|
||||
match f with
|
||||
| .const ``lcErased _ => return erasedExpr
|
||||
| .const ``lcAny _ => return anyExpr
|
||||
| .const ``Decidable _ => return mkConst ``Bool
|
||||
| .const declName us =>
|
||||
if declName == ``Decidable then
|
||||
return mkConst ``Bool
|
||||
if let some info ← hasTrivialStructure? declName then
|
||||
let ctorType ← getOtherDeclBaseType info.ctorName []
|
||||
toMonoType (getParamTypes (← instantiateForall ctorType args[:info.numParams]))[info.fieldIdx]!
|
||||
@@ -98,13 +98,15 @@ where
|
||||
for arg in args do
|
||||
let .forallE _ d b _ := type.headBeta | unreachable!
|
||||
let arg := arg.headBeta
|
||||
if d matches .const ``lcErased _ | .sort _ then
|
||||
if arg.isErased then
|
||||
result := mkApp result arg
|
||||
else if d.isErased || d matches .sort _ then
|
||||
result := mkApp result (← toMonoType arg)
|
||||
else
|
||||
result := mkApp result erasedExpr
|
||||
type := b.instantiate1 arg
|
||||
return result
|
||||
| _ => return anyExpr
|
||||
| _ => return erasedExpr
|
||||
|
||||
/--
|
||||
State for the environment extension used to save the LCNF mono phase type for declarations
|
||||
|
||||
@@ -81,10 +81,7 @@ def ppLetDecl (letDecl : LetDecl) : M Format := do
|
||||
return f!"let {letDecl.binderName} := {← ppLetValue letDecl.value}"
|
||||
|
||||
def getFunType (ps : Array Param) (type : Expr) : CoreM Expr :=
|
||||
if type.isErased then
|
||||
pure type
|
||||
else
|
||||
instantiateForall type (ps.map (mkFVar ·.fvarId))
|
||||
instantiateForall type (ps.map (mkFVar ·.fvarId))
|
||||
|
||||
mutual
|
||||
partial def ppFunDecl (funDecl : FunDecl) : M Format := do
|
||||
|
||||
@@ -186,7 +186,7 @@ def saveSpecParamInfo (decls : Array Decl) : CompilerM Unit := do
|
||||
let mut paramsInfo := declsInfo[i]!
|
||||
let some mask := m.find? decl.name | unreachable!
|
||||
trace[Compiler.specialize.info] "{decl.name} {mask}"
|
||||
paramsInfo := Array.zipWith (fun info fixed => if fixed || info matches .user then info else .other) paramsInfo mask
|
||||
paramsInfo := paramsInfo.zipWith mask fun info fixed => if fixed || info matches .user then info else .other
|
||||
for j in [:paramsInfo.size] do
|
||||
let mut info := paramsInfo[j]!
|
||||
if info matches .fixedNeutral && !hasFwdDeps decl paramsInfo j then
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user