mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-29 00:04:11 +00:00
Compare commits
123 Commits
injective_
...
grind_proc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c35ec8668d | ||
|
|
ec7add0b48 | ||
|
|
9b842b7554 | ||
|
|
fc718eac88 | ||
|
|
8b3c82cce2 | ||
|
|
0d1b7e6c88 | ||
|
|
d898c9ed17 | ||
|
|
c6abc3c036 | ||
|
|
d07862db2a | ||
|
|
8a79ef3633 | ||
|
|
b1c82f776b | ||
|
|
f278f31469 | ||
|
|
38b4062edb | ||
|
|
ae8dc414c3 | ||
|
|
7822ee4500 | ||
|
|
8f22c56420 | ||
|
|
0e122870be | ||
|
|
13c23877d4 | ||
|
|
7fba12f8f7 | ||
|
|
abb487a0c0 | ||
|
|
1091053824 | ||
|
|
545bd8a96c | ||
|
|
2f9618f76b | ||
|
|
fa36fcd448 | ||
|
|
9a3b4b2716 | ||
|
|
9fb5ab8450 | ||
|
|
a62c0bce77 | ||
|
|
3ce554abd7 | ||
|
|
257c347f9f | ||
|
|
ca1315e3ba | ||
|
|
197bc6cb66 | ||
|
|
02ca710872 | ||
|
|
3fbf080d72 | ||
|
|
4379002d05 | ||
|
|
5d50ec90f9 | ||
|
|
6ca699b1ff | ||
|
|
c2d56fa031 | ||
|
|
b6d590ccc3 | ||
|
|
719765ec5c | ||
|
|
11b0e7d89c | ||
|
|
37f3f0e1e2 | ||
|
|
85645958f9 | ||
|
|
a80169165e | ||
|
|
8dca311ba5 | ||
|
|
e6dfde1ad6 | ||
|
|
e532ce95ce | ||
|
|
e74b81169d | ||
|
|
cf8ffc28d3 | ||
|
|
d625aaa96f | ||
|
|
89e4f9815f | ||
|
|
9002cc8761 | ||
|
|
5a7d663624 | ||
|
|
efb398b040 | ||
|
|
4cbd1a439a | ||
|
|
20873d5d72 | ||
|
|
4c1830e5ae | ||
|
|
7b75db7c6e | ||
|
|
8d418201a6 | ||
|
|
850a4c897f | ||
|
|
186f5a6960 | ||
|
|
917715c862 | ||
|
|
50435417ac | ||
|
|
9deff2751f | ||
|
|
f3d93970dc | ||
|
|
d1577fda7a | ||
|
|
ca10fd7c4f | ||
|
|
a1cd945e82 | ||
|
|
9c372b9bc2 | ||
|
|
38214ac121 | ||
|
|
6d30aeefe5 | ||
|
|
112fa51e08 | ||
|
|
9b53e39804 | ||
|
|
ede1acfb44 | ||
|
|
0799e5c4e9 | ||
|
|
32a4c88986 | ||
|
|
4cf3c0ae67 | ||
|
|
06ba748221 | ||
|
|
d2d32f13c0 | ||
|
|
9aa6448fa9 | ||
|
|
3bea7e209e | ||
|
|
88fa4212d7 | ||
|
|
97464c9d7f | ||
|
|
8df968de01 | ||
|
|
d869c38e7b | ||
|
|
4d8d502754 | ||
|
|
8e1df86939 | ||
|
|
4ff33eaef5 | ||
|
|
22a4cab8c7 | ||
|
|
1e12cdddc0 | ||
|
|
cab33ac1da | ||
|
|
6b97e41650 | ||
|
|
c2521e94e1 | ||
|
|
f771dea78b | ||
|
|
02a4713875 | ||
|
|
7407534eb8 | ||
|
|
3f80e530d3 | ||
|
|
3146f6c651 | ||
|
|
22aab5c3bb | ||
|
|
7e9ea00ac0 | ||
|
|
409cbe1da9 | ||
|
|
3e4fa12c72 | ||
|
|
ed5dc328d9 | ||
|
|
2bbf5db04f | ||
|
|
116b708269 | ||
|
|
4b6eab762f | ||
|
|
9d6f391414 | ||
|
|
245ede65b5 | ||
|
|
2422b9db87 | ||
|
|
3f9f8f094d | ||
|
|
cf18337157 | ||
|
|
3cf7fdcbe0 | ||
|
|
caa0eacea8 | ||
|
|
b8e584a054 | ||
|
|
ae682ed225 | ||
|
|
b64111d5a8 | ||
|
|
72cc6c85eb | ||
|
|
a966ce64ca | ||
|
|
5c88a2bf56 | ||
|
|
73c85b177e | ||
|
|
5c06c79c15 | ||
|
|
c8117a34c1 | ||
|
|
a5f5d793d7 | ||
|
|
61c46fd5f8 |
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -4,3 +4,9 @@ RELEASES.md merge=union
|
||||
stage0/** binary linguist-generated
|
||||
# The following file is often manually edited, so do show it in diffs
|
||||
stage0/src/stdlib_flags.h -binary -linguist-generated
|
||||
# These files should not have line endings translated on Windows, because
|
||||
# it throws off parser tests. Later lines override earlier ones, so the
|
||||
# runner code is still treated as ordinary text.
|
||||
tests/lean/docparse/* eol=lf
|
||||
tests/lean/docparse/*.lean eol=auto
|
||||
tests/lean/docparse/*.sh eol=auto
|
||||
|
||||
10
.github/workflows/update-stage0.yml
vendored
10
.github/workflows/update-stage0.yml
vendored
@@ -21,6 +21,8 @@ jobs:
|
||||
runs-on: nscloud-ubuntu-22.04-amd64-8x16
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPRESS: true
|
||||
CCACHE_MAXSIZE: 400M
|
||||
steps:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
@@ -72,10 +74,14 @@ jobs:
|
||||
restore-keys: |
|
||||
Linux Lake-build-v3
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: cmake --preset release
|
||||
# sync options with `Linux Lake` to ensure cache reuse
|
||||
run: |
|
||||
mkdir -p build
|
||||
cmake --preset release -B build -DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: make -j$NPROC -C build/release update-stage0-commit
|
||||
run: |
|
||||
make -j$NPROC -C build update-stage0-commit
|
||||
shell: 'nix develop -c bash -euxo pipefail {0}'
|
||||
- if: env.should_update_stage0 == 'yes'
|
||||
run: git show --stat
|
||||
|
||||
@@ -2,19 +2,19 @@ This is the repository for **Lean 4**.
|
||||
|
||||
# About
|
||||
|
||||
- [Quickstart](https://lean-lang.org/documentation/setup/)
|
||||
- [Quickstart](https://lean-lang.org/install/)
|
||||
- [Homepage](https://lean-lang.org)
|
||||
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
|
||||
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
|
||||
- [Documentation Overview](https://lean-lang.org/documentation/)
|
||||
- [Documentation Overview](https://lean-lang.org/learn/)
|
||||
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
|
||||
- [Release notes](RELEASES.md) starting at v4.0.0-m3
|
||||
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
|
||||
- [Examples](https://lean-lang.org/examples/)
|
||||
- [External Contribution Guidelines](CONTRIBUTING.md)
|
||||
|
||||
# Installation
|
||||
|
||||
See [Setting Up Lean](https://lean-lang.org/documentation/setup/).
|
||||
See [Install Lean](https://lean-lang.org/install/).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build-old",
|
||||
"type": "shell",
|
||||
"command": "make -C build/release -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) LAKE_EXTRA_ARGS=--old",
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "build"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "test",
|
||||
"type": "shell",
|
||||
|
||||
@@ -5,6 +5,7 @@ Merge a tag into a branch on a GitHub repository.
|
||||
|
||||
This script checks if a specified tag can be merged cleanly into a branch and performs
|
||||
the merge if possible. If the merge cannot be done cleanly, it prints a helpful message.
|
||||
Merge conflicts in the lean-toolchain file are automatically resolved by accepting the incoming changes.
|
||||
|
||||
Usage:
|
||||
python3 merge_remote.py <org/repo> <branch> <tag>
|
||||
@@ -58,6 +59,32 @@ def clone_repo(repo, temp_dir):
|
||||
return True
|
||||
|
||||
|
||||
def get_conflicted_files():
|
||||
"""Get list of files with merge conflicts."""
|
||||
result = run_command("git diff --name-only --diff-filter=U", check=False)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip().split('\n') if result.stdout.strip() else []
|
||||
return []
|
||||
|
||||
|
||||
def resolve_lean_toolchain_conflict(tag):
|
||||
"""Resolve lean-toolchain conflict by accepting incoming (tag) changes."""
|
||||
print("Resolving lean-toolchain conflict by accepting incoming changes...")
|
||||
# Accept theirs (incoming) version for lean-toolchain
|
||||
result = run_command(f"git checkout --theirs lean-toolchain", check=False)
|
||||
if result.returncode != 0:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
return False
|
||||
|
||||
# Add the resolved file
|
||||
add_result = run_command("git add lean-toolchain", check=False)
|
||||
if add_result.returncode != 0:
|
||||
print("Failed to stage resolved lean-toolchain")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_and_merge(repo, branch, tag, temp_dir):
|
||||
"""Check if tag can be merged into branch and perform the merge if possible."""
|
||||
# Change to the temporary directory
|
||||
@@ -98,12 +125,37 @@ def check_and_merge(repo, branch, tag, temp_dir):
|
||||
# Try merging the tag directly
|
||||
print(f"Merging {tag} into {branch}...")
|
||||
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
|
||||
|
||||
|
||||
if merge_result.returncode != 0:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur. Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
# Check which files have conflicts
|
||||
conflicted_files = get_conflicted_files()
|
||||
|
||||
if conflicted_files == ['lean-toolchain']:
|
||||
# Only lean-toolchain has conflicts, resolve it
|
||||
print("Merge conflict detected only in lean-toolchain.")
|
||||
if resolve_lean_toolchain_conflict(tag):
|
||||
# Continue the merge with the resolved conflict
|
||||
print("Continuing merge with resolved lean-toolchain...")
|
||||
continue_result = run_command(f"git commit --no-edit", check=False)
|
||||
if continue_result.returncode != 0:
|
||||
print("Failed to complete merge after resolving lean-toolchain")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
print("Failed to resolve lean-toolchain conflict")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
else:
|
||||
# Other files have conflicts, or unable to determine
|
||||
if conflicted_files:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print(f"Merge conflicts in: {', '.join(conflicted_files)}")
|
||||
else:
|
||||
print(f"Cannot merge {tag} cleanly into {branch}.")
|
||||
print("Merge conflicts would occur.")
|
||||
print("Aborting merge.")
|
||||
run_command("git merge --abort")
|
||||
return False
|
||||
|
||||
print(f"Pushing changes to remote...")
|
||||
push_result = run_command(f"git push origin {branch}")
|
||||
|
||||
@@ -52,6 +52,7 @@ def sort_sections_order():
|
||||
return [
|
||||
"Language",
|
||||
"Library",
|
||||
"Tactics",
|
||||
"Compiler",
|
||||
"Pretty Printing",
|
||||
"Documentation",
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
repositories:
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: batteries
|
||||
url: https://github.com/leanprover-community/batteries
|
||||
toolchain-tag: true
|
||||
@@ -7,6 +14,13 @@ repositories:
|
||||
bump-branch: true
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: lean4checker
|
||||
url: https://github.com/leanprover/lean4checker
|
||||
toolchain-tag: true
|
||||
@@ -21,20 +35,6 @@ repositories:
|
||||
branch: master
|
||||
dependencies: []
|
||||
|
||||
- name: lean4-cli
|
||||
url: https://github.com/leanprover/lean4-cli
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: verso
|
||||
url: https://github.com/leanprover/verso
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: plausible
|
||||
url: https://github.com/leanprover-community/plausible
|
||||
toolchain-tag: true
|
||||
@@ -96,6 +96,15 @@ repositories:
|
||||
- import-graph
|
||||
- plausible
|
||||
|
||||
- name: cslib
|
||||
url: https://github.com/leanprover/cslib
|
||||
toolchain-tag: true
|
||||
stable-branch: true
|
||||
branch: main
|
||||
bump-branch: true
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: repl
|
||||
url: https://github.com/leanprover-community/repl
|
||||
toolchain-tag: true
|
||||
@@ -103,3 +112,11 @@ repositories:
|
||||
branch: master
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: lean-fro.org
|
||||
url: https://github.com/leanprover/lean-fro.org
|
||||
toolchain-tag: false
|
||||
stable-branch: false
|
||||
branch: master
|
||||
dependencies:
|
||||
- verso
|
||||
|
||||
@@ -377,6 +377,33 @@ def execute_release_steps(repo, version, config):
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
elif repo_name == "lean-fro.org":
|
||||
# Update lean-toolchain in examples/hero
|
||||
print(blue("Updating examples/hero/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "examples" / "hero" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated examples/hero/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
print(blue("Running `lake update`..."))
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
print(blue("Running `lake update` in examples/hero..."))
|
||||
run_command("lake update", cwd=repo_path / "examples" / "hero", stream_output=True)
|
||||
elif repo_name == "cslib":
|
||||
print(blue("Updating lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
print(blue("Updating docs/lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path / "docs")
|
||||
|
||||
# Update lean-toolchain in docs
|
||||
print(blue("Updating docs/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "docs" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated docs/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 24)
|
||||
set(LEAN_VERSION_MINOR 25)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
|
||||
@@ -42,5 +42,8 @@ public import Init.While
|
||||
public import Init.Syntax
|
||||
public import Init.Internal
|
||||
public import Init.Try
|
||||
public meta import Init.Try -- make sure `Try.Config` can be evaluated anywhere
|
||||
public import Init.BinderNameHint
|
||||
public import Init.Task
|
||||
public import Init.MethodSpecsSimp
|
||||
public import Init.LawfulBEqTactics
|
||||
|
||||
@@ -147,7 +147,7 @@ class LawfulMonad (m : Type u → Type v) [Monad m] : Prop extends LawfulApplica
|
||||
|
||||
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
|
||||
attribute [simp] pure_bind bind_assoc bind_pure_comp
|
||||
attribute [grind] pure_bind
|
||||
attribute [grind <=] pure_bind
|
||||
|
||||
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
|
||||
change x >>= (fun a => pure (id a)) = x
|
||||
|
||||
@@ -1580,6 +1580,7 @@ instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) :=
|
||||
|
||||
gen_injective_theorems% Array
|
||||
gen_injective_theorems% BitVec
|
||||
gen_injective_theorems% ByteArray
|
||||
gen_injective_theorems% Char
|
||||
gen_injective_theorems% DoResultBC
|
||||
gen_injective_theorems% DoResultPR
|
||||
@@ -2546,7 +2547,3 @@ class Irrefl (r : α → α → Prop) : Prop where
|
||||
irrefl : ∀ a, ¬r a a
|
||||
|
||||
end Std
|
||||
|
||||
/-- Deprecated alias for `XorOp`. -/
|
||||
@[deprecated XorOp (since := "2025-07-30")]
|
||||
abbrev Xor := XorOp
|
||||
|
||||
@@ -121,7 +121,7 @@ theorem pmap_eq_map {p : α → Prop} {f : α → β} {xs : Array α} (H) :
|
||||
theorem pmap_congr_left {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (xs : Array α) {H₁ H₂}
|
||||
(h : ∀ a ∈ xs, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
|
||||
cases xs
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.mem_toArray] at h
|
||||
simp only [List.pmap_toArray, mk.injEq]
|
||||
rw [List.pmap_congr_left _ h]
|
||||
|
||||
@@ -194,7 +194,7 @@ theorem attachWith_map_subtype_val {p : α → Prop} {xs : Array α} (H : ∀ a
|
||||
(xs.attachWith p H).map Subtype.val = xs := by
|
||||
cases xs; simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (xs : Array α) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
@@ -212,12 +212,13 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
|
||||
b ∈ pmap f xs H ↔ ∃ (a : _) (h : a ∈ xs), f a (H a h) = b := by
|
||||
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||
|
||||
@[grind]
|
||||
theorem mem_pmap_of_mem {p : α → Prop} {f : ∀ a, p a → β} {xs H} {a} (h : a ∈ xs) :
|
||||
f a (H a h) ∈ pmap f xs H := by
|
||||
rw [mem_pmap]
|
||||
exact ⟨a, h, rfl⟩
|
||||
|
||||
grind_pattern mem_pmap_of_mem => _ ∈ pmap f xs H, a ∈ xs
|
||||
|
||||
@[simp, grind =]
|
||||
theorem size_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H} : (pmap f xs H).size = xs.size := by
|
||||
cases xs; simp
|
||||
@@ -345,7 +346,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
|
||||
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldl_toArray', mem_toArray, List.foldl_subtype]
|
||||
List.foldl_toArray', List.mem_toArray, List.foldl_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
@@ -364,7 +365,7 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
|
||||
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
|
||||
List.foldr_toArray', mem_toArray, List.foldr_subtype]
|
||||
List.foldr_toArray', List.mem_toArray, List.foldr_subtype]
|
||||
congr
|
||||
ext
|
||||
simpa using fun a => List.mem_of_getElem? a
|
||||
|
||||
@@ -108,13 +108,19 @@ instance : Membership α (Array α) where
|
||||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||||
|
||||
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
@[simp, grind =] theorem _root_.List.mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||||
simp [mem_def]
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
@[deprecated List.mem_toArray (since := "2025-09-04")]
|
||||
theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l :=
|
||||
List.mem_toArray
|
||||
|
||||
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] ∈ xs := by
|
||||
rw [Array.mem_def, ← getElem_toList]
|
||||
apply List.getElem_mem
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
|
||||
|
||||
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
|
||||
|
||||
@@ -271,7 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
|
||||
(xs ++ ys).erase a = if a ∈ xs then xs.erase a ++ ys else xs ++ ys.erase a := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
|
||||
simp only [List.append_toArray, List.erase_toArray, List.erase_append, List.mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =]
|
||||
|
||||
@@ -396,7 +396,6 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
#[a].findIdx p = if p a then 0 else 1 := by
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
rcases xs with ⟨xs⟩
|
||||
exact List.findIdx_of_getElem?_eq_some (by simpa using w)
|
||||
|
||||
@@ -88,7 +88,7 @@ theorem eq_empty_iff_size_eq_zero : xs = #[] ↔ xs.size = 0 :=
|
||||
|
||||
theorem size_pos_of_mem {a : α} {xs : Array α} (h : a ∈ xs) : 0 < xs.size := by
|
||||
cases xs
|
||||
simp only [mem_toArray] at h
|
||||
simp only [List.mem_toArray] at h
|
||||
simpa using List.length_pos_of_mem h
|
||||
|
||||
grind_pattern size_pos_of_mem => a ∈ xs, xs.size
|
||||
@@ -465,7 +465,7 @@ theorem mem_singleton_self (a : α) : a ∈ #[a] := by simp
|
||||
|
||||
theorem mem_of_mem_push_of_mem {a b : α} {xs : Array α} : a ∈ xs.push b → b ∈ xs → a ∈ xs := by
|
||||
cases xs
|
||||
simp only [List.push_toArray, mem_toArray, List.mem_append, List.mem_singleton]
|
||||
simp only [List.push_toArray, List.mem_toArray, List.mem_append, List.mem_singleton]
|
||||
rintro (h | rfl)
|
||||
· intro _
|
||||
exact h
|
||||
@@ -1277,7 +1277,9 @@ theorem forall_mem_map {f : α → β} {xs : Array α} {P : β → Prop} :
|
||||
cases xs
|
||||
simp
|
||||
|
||||
@[grind →]
|
||||
-- This would be helpful as a `grind` lemma if
|
||||
-- we could have it fire only once `map f l` and `#[]` are the same equivalence class.
|
||||
-- Otherwise it is too aggressive.
|
||||
theorem eq_empty_of_map_eq_empty {f : α → β} {xs : Array α} (h : map f xs = #[]) : xs = #[] :=
|
||||
map_eq_empty_iff.mp h
|
||||
|
||||
@@ -1472,13 +1474,13 @@ theorem forall_mem_filter {p : α → Bool} {xs : Array α} {P : α → Prop} :
|
||||
(∀ (i) (_ : i ∈ xs.filter p), P i) ↔ ∀ (j) (_ : j ∈ xs), p j → P j := by
|
||||
simp
|
||||
|
||||
@[grind] theorem getElem_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size) :
|
||||
@[grind ←] theorem getElem_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size) :
|
||||
p (xs.filter p)[i] :=
|
||||
(mem_filter.mp (getElem_mem h)).2
|
||||
|
||||
theorem getElem?_filter {xs : Array α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).size)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
rw [getElem?_eq_getElem h] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
@@ -2423,7 +2425,7 @@ abbrev mkArray_succ' := @replicate_succ'
|
||||
|
||||
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b ∈ replicate n a ↔ n ≠ 0 ∧ b = a := by
|
||||
unfold replicate
|
||||
simp only [mem_toArray, List.mem_replicate]
|
||||
simp only [List.mem_toArray, List.mem_replicate]
|
||||
|
||||
@[deprecated mem_replicate (since := "2025-03-18")]
|
||||
abbrev mem_mkArray := @mem_replicate
|
||||
@@ -3249,7 +3251,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp [← foldrM_push, h]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
@[simp, grind! ←] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ (← l.reverse.mapM f).toArray := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
@@ -3262,7 +3264,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
@[simp, grind! ←] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
|
||||
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ (← l.mapM f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
@@ -3336,7 +3338,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
foldrM_push' h
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) :
|
||||
@[simp, grind! ←] theorem foldl_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => acc.push (f a)) bs 0 stop = bs ++ as.map f := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
@@ -3345,14 +3347,14 @@ rather than `(arr.push a).size` as the argument.
|
||||
induction as generalizing bs <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) :
|
||||
@[simp, grind! ←] theorem foldl_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : stop = as.size) :
|
||||
as.foldl (fun acc a => (f a) :: acc) bs 0 stop = (as.map f).reverse.toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : start = as.size) :
|
||||
@[simp, grind! ←] theorem foldr_cons_eq_append {as : Array α} {bs : List β} {f : α → β} (w : start = as.size) :
|
||||
as.foldr (fun a acc => (f a) :: acc) bs start 0 = (as.map f).toList ++ bs := by
|
||||
subst w
|
||||
rcases as with ⟨as⟩
|
||||
@@ -3366,7 +3368,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
simp
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
@[simp, grind! ←] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@@ -3376,7 +3378,7 @@ rather than `(arr.push a).size` as the argument.
|
||||
induction l <;> simp [*]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
@[simp, grind! ←] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
|
||||
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
|
||||
induction l generalizing xs <;> simp [*]
|
||||
|
||||
@@ -3394,28 +3396,28 @@ theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs
|
||||
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
@[simp, grind! ←] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
@[simp, grind! ←] theorem foldl_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (· ++ f ·) ys = ys ++ (xs.map f).flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldr_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
@[simp, grind! ←] theorem foldr_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (fun x acc => acc ++ f x) ys = ys ++ (xs.map f).reverse.flatten := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
induction xs generalizing ys <;> simp_all [Function.comp_def, flatten_toArray]
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind] theorem foldl_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
@[simp, grind! ←] theorem foldl_flip_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldl (fun acc y => f y ++ acc) ys = (xs.map f).reverse.flatten ++ ys:= by
|
||||
rcases xs with ⟨l⟩
|
||||
rcases ys with ⟨l'⟩
|
||||
@@ -4214,7 +4216,7 @@ variable [LawfulBEq α]
|
||||
(xs.replace a b)[i]? = if xs[i]? == some a then if a ∈ xs.take i then some a else some b else xs[i]? := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp only [List.replace_toArray, List.getElem?_toArray, List.getElem?_replace, take_eq_extract,
|
||||
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, mem_toArray]
|
||||
List.extract_toArray, List.extract_eq_drop_take, Nat.sub_zero, List.drop_zero, List.mem_toArray]
|
||||
|
||||
theorem getElem?_replace_of_ne {xs : Array α} {i : Nat} (h : xs[i]? ≠ some a) :
|
||||
(xs.replace a b)[i]? = xs[i]? := by
|
||||
@@ -4235,7 +4237,7 @@ theorem getElem_replace_of_ne {xs : Array α} {i : Nat} {h : i < xs.size} (h' :
|
||||
(xs ++ ys).replace a b = if a ∈ xs then xs.replace a b ++ ys else xs ++ ys.replace a b := by
|
||||
rcases xs with ⟨xs⟩
|
||||
rcases ys with ⟨ys⟩
|
||||
simp only [List.append_toArray, List.replace_toArray, List.replace_append, mem_toArray]
|
||||
simp only [List.append_toArray, List.replace_toArray, List.replace_append, List.mem_toArray]
|
||||
split <;> simp
|
||||
|
||||
@[grind =] theorem replace_push {xs : Array α} {a b c : α} :
|
||||
@@ -4470,10 +4472,10 @@ theorem back!_eq_back? [Inhabited α] {xs : Array α} : xs.back! = xs.back?.getD
|
||||
|
||||
theorem getElem?_push_lt {xs : Array α} {x : α} {i : Nat} (h : i < xs.size) :
|
||||
(xs.push x)[i]? = some xs[i] := by
|
||||
rw [getElem?_pos, getElem_push_lt]
|
||||
rw [getElem?_pos (xs.push x) i (size_push _ ▸ Nat.lt_succ_of_lt h), getElem_push_lt]
|
||||
|
||||
theorem getElem?_push_eq {xs : Array α} {x : α} : (xs.push x)[xs.size]? = some x := by
|
||||
rw [getElem?_pos, getElem_push_eq]
|
||||
rw [getElem?_pos (xs.push x) xs.size (size_push _ ▸ Nat.lt_succ_self xs.size), getElem_push_eq]
|
||||
|
||||
@[simp] theorem getElem?_size {xs : Array α} : xs[xs.size]? = none := by
|
||||
simp only [getElem?_def, Nat.lt_irrefl, dite_false]
|
||||
|
||||
@@ -167,7 +167,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
forIn' as b f = forIn' bs b' g := by
|
||||
cases as <;> cases bs
|
||||
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
simp only [mk.injEq, List.mem_toArray, List.forIn'_toArray] at w h ⊢
|
||||
exact List.forIn'_congr w hb h
|
||||
|
||||
/--
|
||||
|
||||
@@ -116,7 +116,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
rw [← List.toArray_range']
|
||||
simp only [List.find?_toArray, mem_toArray]
|
||||
simp only [List.find?_toArray, List.mem_toArray]
|
||||
simp [List.find?_range'_eq_some]
|
||||
|
||||
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@@ -874,4 +874,7 @@ def clzAuxRec {w : Nat} (x : BitVec w) (n : Nat) : BitVec w :=
|
||||
/-- Count the number of leading zeros. -/
|
||||
def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
|
||||
/-- Count the number of trailing zeros. -/
|
||||
def ctz (x : BitVec w) : BitVec w := (x.reverse).clz
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -1100,6 +1100,10 @@ theorem toInt_setWidth' {m n : Nat} (p : m ≤ n) {x : BitVec m} :
|
||||
rw [setWidth'_eq, toFin_setWidth, Fin.val_ofNat, Fin.coe_castLE, val_toFin,
|
||||
Nat.mod_eq_of_lt (by apply BitVec.toNat_lt_twoPow_of_le p)]
|
||||
|
||||
theorem toNat_setWidth_of_le {w w' : Nat} {b : BitVec w} (h : w ≤ w') : (b.setWidth w').toNat = b.toNat := by
|
||||
rw [BitVec.toNat_setWidth, Nat.mod_eq_of_lt]
|
||||
exact BitVec.toNat_lt_twoPow_of_le h
|
||||
|
||||
/-! ## extractLsb -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -1287,6 +1291,17 @@ theorem extractLsb'_eq_zero {x : BitVec w} {start : Nat} :
|
||||
ext i hi
|
||||
omega
|
||||
|
||||
theorem extractLsb'_setWidth_of_le {b : BitVec w} {start len w' : Nat} (h : start + len ≤ w') :
|
||||
(b.setWidth w').extractLsb' start len = b.extractLsb' start len := by
|
||||
ext i h_i
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem setWidth_extractLsb'_of_le {c : BitVec w} (h : len₁ ≤ len₂) :
|
||||
(c.extractLsb' start len₂).setWidth len₁ = c.extractLsb' start len₁ := by
|
||||
ext i hi
|
||||
simp [show i < len₂ by omega]
|
||||
|
||||
/-! ### allOnes -/
|
||||
|
||||
@[simp, grind =] theorem toNat_allOnes : (allOnes v).toNat = 2^v - 1 := by
|
||||
@@ -1530,6 +1545,12 @@ theorem extractLsb_and {x : BitVec w} {hi lo : Nat} :
|
||||
@[simp, grind =] theorem ofNat_and {x y : Nat} : BitVec.ofNat w (x &&& y) = BitVec.ofNat w x &&& BitVec.ofNat w y :=
|
||||
eq_of_toNat_eq (by simp [Nat.and_mod_two_pow])
|
||||
|
||||
theorem and_or_distrib_left {x y z : BitVec w} : x &&& (y ||| z) = (x &&& y) ||| (x &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_left])
|
||||
|
||||
theorem and_or_distrib_right {x y z : BitVec w} : (x ||| y) &&& z = (x &&& z) ||| (y &&& z) :=
|
||||
BitVec.eq_of_getElem_eq (by simp [Bool.and_or_distrib_right])
|
||||
|
||||
/-! ### xor -/
|
||||
|
||||
@[simp, grind =] theorem toNat_xor (x y : BitVec v) :
|
||||
@@ -2180,6 +2201,10 @@ theorem msb_ushiftRight {x : BitVec w} {n : Nat} :
|
||||
have := lt_of_getLsbD ha
|
||||
omega
|
||||
|
||||
theorem setWidth_ushiftRight_eq_extractLsb {b : BitVec w} : (b >>> w').setWidth w'' = b.extractLsb' w' w'' := by
|
||||
ext i hi
|
||||
simp
|
||||
|
||||
/-! ### ushiftRight reductions from BitVec to Nat -/
|
||||
|
||||
@[simp, grind =]
|
||||
@@ -2970,10 +2995,9 @@ theorem shiftLeft_eq_concat_of_lt {x : BitVec w} {n : Nat} (hn : n < w) :
|
||||
/-- Combine adjacent `extractLsb'` operations into a single `extractLsb'`. -/
|
||||
theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start₂ = start₁ + len₁) :
|
||||
((x.extractLsb' start₂ len₂) ++ (x.extractLsb' start₁ len₁)) =
|
||||
(x.extractLsb' start₁ (len₁ + len₂)).cast (by omega) := by
|
||||
x.extractLsb' start₁ (len₂ + len₁) := by
|
||||
ext i h
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, getElem_cast, ite_eq_left_iff,
|
||||
Nat.not_lt]
|
||||
simp only [getElem_append, getElem_extractLsb', dite_eq_ite, ite_eq_left_iff, Nat.not_lt]
|
||||
intro hi
|
||||
congr 1
|
||||
omega
|
||||
@@ -3085,6 +3109,51 @@ theorem extractLsb'_append_eq_of_le {v w} {xhi : BitVec v} {xlo : BitVec w}
|
||||
extractLsb' start len (xhi ++ xlo) = extractLsb' (start - w) len xhi := by
|
||||
simp [extractLsb'_append_eq_ite, show ¬ start < w by omega]
|
||||
|
||||
theorem extractLsb'_append_eq_left {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' w' w = a := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_le]
|
||||
|
||||
theorem extractLsb'_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).extractLsb' 0 w' = b := by
|
||||
simp [BitVec.extractLsb'_append_eq_of_add_le]
|
||||
|
||||
theorem setWidth_append_eq_right {a : BitVec w} {b : BitVec w'} : (a ++ b).setWidth w' = b := by
|
||||
ext i hi
|
||||
simp [getLsbD_append, hi]
|
||||
|
||||
theorem append_left_inj {s₁ s₂ : BitVec w} (t : BitVec w') : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, dif_neg] using congrArg (·[i + w']'(by omega)) h
|
||||
|
||||
theorem append_right_inj (s : BitVec w) {t₁ t₂ : BitVec w'} : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂ := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ rfl⟩
|
||||
ext i hi
|
||||
simpa [getElem_append, hi] using congrArg (·[i]) h
|
||||
|
||||
theorem setWidth_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} :
|
||||
(b ++ b').setWidth w'' = (b.setWidth w'' <<< w') ||| b'.setWidth w'' := by
|
||||
ext i hi
|
||||
simp only [getElem_setWidth, getElem_or, getElem_shiftLeft]
|
||||
rw [getLsbD_append]
|
||||
split <;> simp_all
|
||||
|
||||
theorem setWidth_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} :
|
||||
(b ++ b' ++ b'').setWidth w''' = (b.setWidth w''' <<< (w' + w'')) ||| (b'.setWidth w''' <<< w'') ||| b''.setWidth w''' := by
|
||||
rw [BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.setWidth_append_eq_shiftLeft_setWidth_or,
|
||||
BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem setWidth_append_append_append_eq_shiftLeft_setWidth_or {b : BitVec w} {b' : BitVec w'} {b'' : BitVec w''} {b''' : BitVec w'''} :
|
||||
(b ++ b' ++ b'' ++ b''').setWidth w'''' = (b.setWidth w'''' <<< (w' + w'' + w''')) ||| (b'.setWidth w'''' <<< (w'' + w''')) |||
|
||||
(b''.setWidth w'''' <<< w''') ||| b'''.setWidth w'''' := by
|
||||
simp only [BitVec.setWidth_append_eq_shiftLeft_setWidth_or, BitVec.shiftLeft_or_distrib, BitVec.shiftLeft_add]
|
||||
|
||||
theorem and_setWidth_allOnes (w' w : Nat) (b : BitVec (w' + w)) :
|
||||
b &&& (BitVec.allOnes w).setWidth (w' + w) = 0#w' ++ b.setWidth w := by
|
||||
ext i hi
|
||||
simp only [getElem_and, getElem_setWidth, getLsbD_allOnes]
|
||||
rw [BitVec.getElem_append]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### rev -/
|
||||
|
||||
@[grind =]
|
||||
@@ -4041,6 +4110,9 @@ instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
|
||||
apply LawfulOrderLT.of_le
|
||||
simpa using fun _ _ => BitVec.lt_asymm
|
||||
|
||||
theorem length_pos_of_lt {b b' : BitVec w} (h : b < b') : 0 < w :=
|
||||
length_pos_of_ne (BitVec.ne_of_lt h)
|
||||
|
||||
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y → x % y < y := by
|
||||
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
|
||||
apply Nat.mod_lt
|
||||
@@ -4112,6 +4184,14 @@ theorem lt_of_msb_false_of_msb_true {x y : BitVec w} (hx : x.msb = false) (hy :
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem lt_add_one {b : BitVec w} (h : b ≠ allOnes w) : b < b + 1 := by
|
||||
simp only [ne_eq, ← toNat_inj, toNat_allOnes] at h
|
||||
simp only [BitVec.lt_def, ofNat_eq_ofNat, toNat_add, toNat_ofNat, Nat.add_mod_mod]
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
· exact Nat.lt_add_one _
|
||||
· have := b.toNat_lt_twoPow_of_le (Nat.le_refl _)
|
||||
omega
|
||||
|
||||
/-! ### udiv -/
|
||||
|
||||
theorem udiv_def {x y : BitVec n} : x / y = BitVec.ofNat n (x.toNat / y.toNat) := by
|
||||
@@ -5257,7 +5337,7 @@ theorem replicate_succ' {x : BitVec w} :
|
||||
(replicate n x ++ x).cast (by rw [Nat.mul_succ]) := by
|
||||
simp [replicate_append_self]
|
||||
|
||||
theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
theorem setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y) = (BitVec.setWidth i x + BitVec.setWidth i y) % (BitVec.twoPow i w) := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
rw [toNat_setWidth]
|
||||
simp only [toNat_setWidth, toNat_add, toNat_umod, Nat.add_mod_mod, Nat.mod_add_mod, toNat_twoPow]
|
||||
@@ -5266,6 +5346,14 @@ theorem BitVec.setWidth_add_eq_mod {x y : BitVec w} : BitVec.setWidth i (x + y)
|
||||
· have hk : 2 ^ w < 2 ^ i := Nat.pow_lt_pow_of_lt (by decide) (Nat.lt_of_not_le h)
|
||||
rw [Nat.mod_eq_of_lt hk, Nat.mod_mod_eq_mod_mod_of_dvd (Nat.pow_dvd_pow _ (Nat.le_of_not_le h))]
|
||||
|
||||
theorem setWidth_setWidth_eq_self {a : BitVec w} {w' : Nat} (h : a < BitVec.twoPow w w') : (a.setWidth w').setWidth w = a := by
|
||||
by_cases hw : w' < w
|
||||
· simp only [toNat_eq, toNat_setWidth]
|
||||
rw [Nat.mod_mod_of_dvd' (Nat.pow_dvd_pow _ (Nat.le_of_lt hw)), Nat.mod_eq_of_lt]
|
||||
rwa [BitVec.lt_def, BitVec.toNat_twoPow_of_lt hw] at h
|
||||
· rw [BitVec.lt_def, BitVec.toNat_twoPow_of_le (by omega)] at h
|
||||
simp at h
|
||||
|
||||
/-! ### intMin -/
|
||||
|
||||
@[grind =]
|
||||
@@ -5779,6 +5867,25 @@ theorem msb_replicate {n w : Nat} {x : BitVec w} :
|
||||
simp only [BitVec.msb, getMsbD_replicate, Nat.zero_mod]
|
||||
cases n <;> cases w <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem reverse_eq_zero_iff {x : BitVec w} :
|
||||
x.reverse = 0#w ↔ x = 0#w := by
|
||||
constructor
|
||||
· intro hrev
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
simp [hrev]
|
||||
· intro hzero
|
||||
ext i hi
|
||||
rw [← getLsbD_eq_getElem, getLsbD_eq_getMsbD, getMsbD_reverse]
|
||||
simp [hi, hzero]
|
||||
|
||||
@[simp]
|
||||
theorem reverse_reverse_eq {x : BitVec w} :
|
||||
x.reverse.reverse = x := by
|
||||
ext k hk
|
||||
rw [getElem_reverse, getMsbD_reverse, getLsbD_eq_getElem]
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
@@ -5909,6 +6016,12 @@ theorem getElem_eq_true_of_lt_of_le {x : BitVec w} (hk' : k < w) (hlt: x.toNat <
|
||||
omega
|
||||
· simp [show w ≤ k + k' by omega] at hk'
|
||||
|
||||
theorem not_lt_iff {b : BitVec w} : ~~~b < b ↔ 0 < w ∧ b.msb = true := by
|
||||
refine ⟨fun h => ?_, fun ⟨hw, hb⟩ => ?_⟩
|
||||
· have := length_pos_of_lt h
|
||||
exact ⟨this, by rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)] at h⟩
|
||||
· rwa [← ult_iff_lt, ult_eq_msb_of_msb_neq (by simp_all)]
|
||||
|
||||
/-! ### Count leading zeros -/
|
||||
|
||||
theorem clzAuxRec_zero (x : BitVec w) :
|
||||
@@ -6182,6 +6295,71 @@ theorem toNat_lt_two_pow_sub_clz {x : BitVec w} :
|
||||
· simp [show w + 1 ≤ i by omega]
|
||||
· simp; omega
|
||||
|
||||
theorem clz_eq_reverse_ctz {x : BitVec w} :
|
||||
x.clz = (x.reverse).ctz := by
|
||||
simp [ctz]
|
||||
|
||||
/-! ### Count trailing zeros -/
|
||||
|
||||
theorem ctz_eq_reverse_clz {x : BitVec w} :
|
||||
x.ctz = (x.reverse).clz := by
|
||||
simp [ctz]
|
||||
|
||||
/-- The number of trailing zeroes is strictly less than the bitwidth iff the bitvector is nonzero. -/
|
||||
@[simp]
|
||||
theorem ctz_lt_iff_ne_zero {x : BitVec w} :
|
||||
ctz x < w ↔ x ≠ 0#w := by
|
||||
simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq]
|
||||
rw [show BitVec.ofNat w w = w by simp, ← reverse_eq_zero_iff (x := x)]
|
||||
apply clz_lt_iff_ne_zero (x := x.reverse)
|
||||
|
||||
/-- If a bitvec is different than zero the bits at indexes lower than `ctz x` are false. -/
|
||||
theorem getLsbD_false_of_lt_ctz {x : BitVec w} (hi : i < x.ctz.toNat) :
|
||||
x.getLsbD i = false := by
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have hiff := ctz_lt_iff_ne_zero (x := x)
|
||||
by_cases hzero : x = 0#w
|
||||
· simp [hzero, getLsbD_reverse]
|
||||
· simp only [ctz_eq_reverse_clz, natCast_eq_ofNat, ne_eq, hzero, not_false_eq_true,
|
||||
iff_true] at hiff
|
||||
simp only [ctz] at hi
|
||||
have hi' : i < w := by simp [BitVec.lt_def] at hiff; omega
|
||||
simp only [hi', decide_true, Bool.true_and]
|
||||
have : (x.reverse.clzAuxRec (w - 1)).toNat ≤ w := by
|
||||
rw [show ((x.reverse.clzAuxRec (w - 1)).toNat ≤ w) =
|
||||
((x.reverse.clzAuxRec (w - 1)).toNat ≤ (BitVec.ofNat w w).toNat) by simp, ← le_def]
|
||||
apply clzAuxRec_le (x := x.reverse) (n := w - 1)
|
||||
let j := (x.reverse.clzAuxRec (w - 1)).toNat - 1 - i
|
||||
rw [show w - 1 - i = w - (x.reverse.clzAuxRec (w - 1)).toNat + j by
|
||||
subst j
|
||||
rw [Nat.sub_sub (n := (x.reverse.clzAuxRec (w - 1)).toNat),
|
||||
← Nat.add_sub_assoc (by exact Nat.one_add_le_iff.mpr hi)]
|
||||
omega]
|
||||
have hfalse : ∀ (i : Nat), w - 1 < i → x.reverse.getLsbD i = false := by
|
||||
intros i hj
|
||||
simp [show w ≤ i by omega]
|
||||
exact getLsbD_false_of_clzAuxRec (x := x.reverse) (n := w - 1) hfalse (j := j)
|
||||
|
||||
/-- If a bitvec is different than zero, the bit at index `ctz x`, i.e., the first bit after the
|
||||
trailing zeros, is true. -/
|
||||
theorem getLsbD_true_ctz_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
x.getLsbD (ctz x).toNat = true := by
|
||||
simp only [ctz_eq_reverse_clz, clz]
|
||||
rw [getLsbD_eq_getMsbD, ← getLsbD_reverse]
|
||||
have := ctz_lt_iff_ne_zero (x := x)
|
||||
simp only [ctz_eq_reverse_clz, clz, natCast_eq_ofNat, lt_def, toNat_ofNat, Nat.mod_two_pow_self,
|
||||
ne_eq] at this
|
||||
simp only [this, hx, not_false_eq_true, decide_true, Bool.true_and]
|
||||
have hnotrev : ¬x.reverse = 0#w := by simp [reverse_eq_zero_iff, hx]
|
||||
apply getLsbD_true_of_eq_clzAuxRec_of_ne_zero (x := x.reverse) (n := w - 1) hnotrev
|
||||
intro i hi
|
||||
simp [show w ≤ i by omega]
|
||||
|
||||
/-- A nonzero bitvector is lower-bounded by its trailing zeroes. -/
|
||||
theorem two_pow_ctz_le_toNat_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
2 ^ (ctz x).toNat ≤ x.toNat := by
|
||||
have hclz := getLsbD_true_ctz_of_ne_zero (x := x) hx
|
||||
exact Nat.ge_two_pow_of_testBit hclz
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.ByteArray.Bootstrap
|
||||
public import Init.Data.ByteArray.Extra
|
||||
public import Init.Data.ByteArray.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
@@ -11,16 +11,11 @@ public import Init.Data.UInt.Basic
|
||||
public import Init.Data.UInt.BasicAux
|
||||
import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Option.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
@[expose] public section
|
||||
universe u
|
||||
|
||||
structure ByteArray where
|
||||
data : Array UInt8
|
||||
|
||||
attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
deriving instance BEq for ByteArray
|
||||
@@ -30,29 +25,15 @@ attribute [ext] ByteArray
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[extern "lean_mk_empty_byte_array"]
|
||||
def emptyWithCapacity (c : @& Nat) : ByteArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@[deprecated emptyWithCapacity (since := "2025-03-12")]
|
||||
abbrev mkEmpty := emptyWithCapacity
|
||||
|
||||
def empty : ByteArray := emptyWithCapacity 0
|
||||
|
||||
instance : Inhabited ByteArray where
|
||||
default := empty
|
||||
|
||||
instance : EmptyCollection ByteArray where
|
||||
emptyCollection := ByteArray.empty
|
||||
|
||||
@[extern "lean_byte_array_push"]
|
||||
def push : ByteArray → UInt8 → ByteArray
|
||||
| ⟨bs⟩, b => ⟨bs.push b⟩
|
||||
|
||||
@[extern "lean_byte_array_size"]
|
||||
def size : (@& ByteArray) → Nat
|
||||
| ⟨bs⟩ => bs.size
|
||||
|
||||
@[extern "lean_sarray_size", simp]
|
||||
def usize (a : @& ByteArray) : USize :=
|
||||
a.size.toUSize
|
||||
@@ -106,11 +87,31 @@ def copySlice (src : @& ByteArray) (srcOff : Nat) (dest : ByteArray) (destOff le
|
||||
def extract (a : ByteArray) (b e : Nat) : ByteArray :=
|
||||
a.copySlice b empty 0 (e - b)
|
||||
|
||||
protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
protected def fastAppend (a : ByteArray) (b : ByteArray) : ByteArray :=
|
||||
-- we assume that `append`s may be repeated, so use asymptotic growing; use `copySlice` directly to customize
|
||||
b.copySlice 0 a a.size b.size false
|
||||
|
||||
instance : Append ByteArray := ⟨ByteArray.append⟩
|
||||
@[simp]
|
||||
theorem size_data {a : ByteArray} :
|
||||
a.data.size = a.size := rfl
|
||||
|
||||
@[csimp]
|
||||
theorem append_eq_fastAppend : @ByteArray.append = @ByteArray.fastAppend := by
|
||||
funext a b
|
||||
ext1
|
||||
apply Array.ext'
|
||||
simp [ByteArray.fastAppend, copySlice, ← size_data, - Array.append_assoc]
|
||||
|
||||
-- Needs to come after the `csimp` lemma
|
||||
instance : Append ByteArray where
|
||||
append := ByteArray.append
|
||||
|
||||
@[simp]
|
||||
theorem append_eq {a b : ByteArray} : a.append b = a ++ b := rfl
|
||||
|
||||
@[simp]
|
||||
theorem fastAppend_eq {a b : ByteArray} : a.fastAppend b = a ++ b := by
|
||||
simp [← append_eq_fastAppend]
|
||||
|
||||
def toList (bs : ByteArray) : List UInt8 :=
|
||||
let rec loop (i : Nat) (r : List UInt8) :=
|
||||
@@ -350,13 +351,4 @@ def prevn : Iterator → Nat → Iterator
|
||||
end Iterator
|
||||
end ByteArray
|
||||
|
||||
/--
|
||||
Converts a list of bytes into a `ByteArray`.
|
||||
-/
|
||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
let rec loop
|
||||
| [], r => r
|
||||
| b::bs, r => loop bs (r.push b)
|
||||
loop bs ByteArray.empty
|
||||
|
||||
instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
|
||||
|
||||
53
src/Init/Data/ByteArray/Bootstrap.lean
Normal file
53
src/Init/Data/ByteArray/Bootstrap.lean
Normal file
@@ -0,0 +1,53 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Data.List.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem data_push {a : ByteArray} {b : UInt8} : (a.push b).data = a.data.push b := rfl
|
||||
|
||||
@[expose]
|
||||
protected def append (a b : ByteArray) : ByteArray :=
|
||||
⟨⟨a.data.toList ++ b.data.toList⟩⟩
|
||||
|
||||
@[simp]
|
||||
theorem toList_data_append' {a b : ByteArray} :
|
||||
(a.append b).data.toList = a.data.toList ++ b.data.toList := by
|
||||
have ⟨⟨a⟩⟩ := a
|
||||
have ⟨⟨b⟩⟩ := b
|
||||
rfl
|
||||
|
||||
theorem ext : {x y : ByteArray} → x.data = y.data → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
|
||||
end ByteArray
|
||||
|
||||
@[simp]
|
||||
theorem List.toList_data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data.toList = l := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data.toList = b.data.toList ++ a by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all [toList_push]
|
||||
where
|
||||
toList_push {xs : Array UInt8} {x : UInt8} : (xs.push x).toList = xs.toList ++ [x] := by
|
||||
have ⟨xs⟩ := xs
|
||||
simp [Array.push, List.concat_eq_append]
|
||||
|
||||
theorem List.toByteArray_append' {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray.append l'.toByteArray :=
|
||||
ByteArray.ext (ext (by simp))
|
||||
where
|
||||
ext : {x y : Array UInt8} → x.toList = y.toList → x = y
|
||||
| ⟨_⟩, ⟨_⟩, rfl => rfl
|
||||
252
src/Init/Data/ByteArray/Lemmas.lean
Normal file
252
src/Init/Data/ByteArray/Lemmas.lean
Normal file
@@ -0,0 +1,252 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.Array.Extract
|
||||
|
||||
public section
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_empty : ByteArray.empty.data = #[] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).data = a.data.extract b e := by
|
||||
simp [extract, copySlice]
|
||||
by_cases b ≤ e
|
||||
· rw [(by omega : b + (e - b) = e)]
|
||||
· rw [Array.extract_eq_empty_of_le (by omega), Array.extract_eq_empty_of_le (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_zero_size {b : ByteArray} : b.extract 0 b.size = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_same {b : ByteArray} {i : Nat} : b.extract i i = ByteArray.empty := by
|
||||
ext1
|
||||
simp [Nat.min_le_left]
|
||||
|
||||
theorem ByteArray.fastAppend_eq_copySlice {a b : ByteArray} :
|
||||
a.fastAppend b = b.copySlice 0 a a.size b.size false := rfl
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_append {l l' : List UInt8} :
|
||||
(l ++ l').toByteArray = l.toByteArray ++ l'.toByteArray := by
|
||||
simp [List.toByteArray_append']
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_data_append {l l' : ByteArray} :
|
||||
(l ++ l').data.toList = l.data.toList ++ l'.data.toList := by
|
||||
simp [← append_eq]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.data_append {l l' : ByteArray} :
|
||||
(l ++ l').data = l.data ++ l'.data := by
|
||||
simp [← Array.toList_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_empty : ByteArray.empty.size = 0 := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.data_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.data = l.toArray := by
|
||||
rw [List.toByteArray]
|
||||
suffices ∀ a b, (List.toByteArray.loop a b).data = b.data ++ a.toArray by
|
||||
simpa using this l ByteArray.empty
|
||||
intro a b
|
||||
fun_induction List.toByteArray.loop a b with simp_all
|
||||
|
||||
@[simp]
|
||||
theorem List.size_toByteArray {l : List UInt8} :
|
||||
l.toByteArray.size = l.length := by
|
||||
simp [← ByteArray.size_data]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_nil : List.toByteArray [] = ByteArray.empty := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.empty_append {b : ByteArray} : ByteArray.empty ++ b = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_empty {b : ByteArray} : b ++ ByteArray.empty = b := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp, grind =]
|
||||
theorem ByteArray.size_append {a b : ByteArray} : (a ++ b).size = a.size + b.size := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_eq_zero_iff {a : ByteArray} : a.size = 0 ↔ a = ByteArray.empty := by
|
||||
refine ⟨fun h => ?_, fun h => h ▸ ByteArray.size_empty⟩
|
||||
ext1
|
||||
simp [← Array.size_eq_zero_iff, h]
|
||||
|
||||
theorem ByteArray.getElem_eq_getElem_data {a : ByteArray} {i : Nat} {h : i < a.size} :
|
||||
a[i] = a.data[i]'(by simpa [← size_data]) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.getElem_append_left {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hlt : i < a.size) : (a ++ b)[i] = a[i] := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_left (by simpa)]
|
||||
|
||||
theorem ByteArray.getElem_append_right {i : Nat} {a b : ByteArray} {h : i < (a ++ b).size}
|
||||
(hle : a.size ≤ i) : (a ++ b)[i] = b[i - a.size]'(by simp_all; omega) := by
|
||||
simp only [getElem_eq_getElem_data, data_append]
|
||||
rw [Array.getElem_append_right (by simpa)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.toByteArray.size} :
|
||||
l.toByteArray[i]'h = l[i]'(by simp_all) := by
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem List.getElem_eq_getElem_toByteArray {l : List UInt8} {i : Nat} {h : i < l.length} :
|
||||
l[i]'h = l.toByteArray[i]'(by simp_all) := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.size_extract {a : ByteArray} {b e : Nat} :
|
||||
(a.extract b e).size = min e a.size - b := by
|
||||
simp [← size_data]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_eq_empty_iff {b : ByteArray} {i j : Nat} : b.extract i j = ByteArray.empty ↔ min j b.size ≤ i := by
|
||||
rw [← size_eq_zero_iff, size_extract]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_add_left {b : ByteArray} {i j : Nat} : b.extract (i + j) i = ByteArray.empty := by
|
||||
simp only [extract_eq_empty_iff]
|
||||
exact Nat.le_trans (Nat.min_le_left _ _) (by simp)
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.append_eq_empty_iff {a b : ByteArray} :
|
||||
a ++ b = ByteArray.empty ↔ a = ByteArray.empty ∧ b = ByteArray.empty := by
|
||||
simp [← size_eq_zero_iff, size_append]
|
||||
|
||||
@[simp]
|
||||
theorem List.toByteArray_eq_empty {l : List UInt8} :
|
||||
l.toByteArray = ByteArray.empty ↔ l = [] := by
|
||||
simp [← ByteArray.size_eq_zero_iff]
|
||||
|
||||
theorem ByteArray.append_right_inj {ys₁ ys₂ : ByteArray} (xs : ByteArray) :
|
||||
xs ++ ys₁ = xs ++ ys₂ ↔ ys₁ = ys₂ := by
|
||||
simp [ByteArray.ext_iff, Array.append_right_inj]
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.extract_append_extract {a : ByteArray} {i j k : Nat} :
|
||||
a.extract i j ++ a.extract j k = a.extract (min i j) (max j k) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_eq_extract_append_extract {a : ByteArray} {i k : Nat} (j : Nat)
|
||||
(hi : i ≤ j) (hk : j ≤ k) :
|
||||
a.extract i k = a.extract i j ++ a.extract j k := by
|
||||
simp
|
||||
rw [Nat.min_eq_left hi, Nat.max_eq_right hk]
|
||||
|
||||
theorem ByteArray.append_inj_left {xs₁ xs₂ ys₁ ys₂ : ByteArray} (h : xs₁ ++ ys₁ = xs₂ ++ ys₂) (hl : xs₁.size = xs₂.size) : xs₁ = xs₂ := by
|
||||
simp only [ByteArray.ext_iff, ← ByteArray.size_data, ByteArray.data_append] at *
|
||||
exact Array.append_inj_left h hl
|
||||
|
||||
theorem ByteArray.extract_append_eq_right {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract i (a ++ b).size = b := by
|
||||
subst hi
|
||||
ext1
|
||||
simp [← size_data]
|
||||
|
||||
theorem ByteArray.extract_append_eq_left {a b : ByteArray} {i : Nat} (hi : i = a.size) :
|
||||
(a ++ b).extract 0 i = a := by
|
||||
subst hi
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_left {a b : ByteArray} {i : Nat} :
|
||||
(a ++ b).extract i a.size = a.extract i a.size := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add {a b : ByteArray} {i j : Nat} :
|
||||
(a ++ b).extract (a.size + i) (a.size + j) = b.extract i j := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append {as bs : ByteArray} {i j : Nat} :
|
||||
(as ++ bs).extract i j = as.extract i j ++ bs.extract (i - as.size) (j - as.size) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.extract_append_size_add' {a b : ByteArray} {i j k : Nat} (h : k = a.size) :
|
||||
(a ++ b).extract (k + i) (k + j) = b.extract i j := by
|
||||
cases h
|
||||
rw [extract_append_size_add]
|
||||
|
||||
theorem ByteArray.extract_extract {a : ByteArray} {i j k l : Nat} :
|
||||
(a.extract i j).extract k l = a.extract (i + k) (min (i + l) j) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
theorem ByteArray.getElem_extract_aux {xs : ByteArray} {start stop : Nat} (h : i < (xs.extract start stop).size) :
|
||||
start + i < xs.size := by
|
||||
rw [size_extract] at h; apply Nat.add_lt_of_lt_sub'; apply Nat.lt_of_lt_of_le h
|
||||
apply Nat.sub_le_sub_right; apply Nat.min_le_right
|
||||
|
||||
theorem ByteArray.getElem_extract {i : Nat} {b : ByteArray} {start stop : Nat}
|
||||
(h) : (b.extract start stop)[i]'h = b[start + i]'(getElem_extract_aux h) := by
|
||||
simp [getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_eq_extract_left {a : ByteArray} {i i' j : Nat} :
|
||||
a.extract i j = a.extract i' j ↔ min j a.size - i = min j a.size - i' := by
|
||||
simp [ByteArray.ext_iff, Array.extract_eq_extract_left]
|
||||
|
||||
theorem ByteArray.extract_add_one {a : ByteArray} {i : Nat} (ha : i + 1 ≤ a.size) :
|
||||
a.extract i (i + 1) = [a[i]].toByteArray := by
|
||||
ext
|
||||
· simp
|
||||
omega
|
||||
· rename_i j hj hj'
|
||||
obtain rfl : j = 0 := by simpa using hj'
|
||||
simp [ByteArray.getElem_eq_getElem_data]
|
||||
|
||||
theorem ByteArray.extract_add_two {a : ByteArray} {i : Nat} (ha : i + 2 ≤ a.size) :
|
||||
a.extract i (i + 2) = [a[i], a[i + 1]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_one (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_three {a : ByteArray} {i : Nat} (ha : i + 3 ≤ a.size) :
|
||||
a.extract i (i + 3) = [a[i], a[i + 1], a[i + 2]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_two (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.extract_add_four {a : ByteArray} {i : Nat} (ha : i + 4 ≤ a.size) :
|
||||
a.extract i (i + 4) = [a[i], a[i + 1], a[i + 2], a[i + 3]].toByteArray := by
|
||||
rw [extract_eq_extract_append_extract (i + 1) (by simp) (by omega),
|
||||
extract_add_one (by omega), extract_add_three (by omega)]
|
||||
simp [← List.toByteArray_append]
|
||||
|
||||
theorem ByteArray.append_assoc {a b c : ByteArray} : a ++ b ++ c = a ++ (b ++ c) := by
|
||||
ext1
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.toList_empty : ByteArray.empty.toList = [] := by
|
||||
simp [ByteArray.toList, ByteArray.toList.loop]
|
||||
|
||||
theorem ByteArray.copySlice_eq_append {src : ByteArray} {srcOff : Nat} {dest : ByteArray} {destOff len : Nat} {exact : Bool} :
|
||||
ByteArray.copySlice src srcOff dest destOff len exact =
|
||||
dest.extract 0 destOff ++ src.extract srcOff (srcOff +len) ++ dest.extract (destOff + min len (src.data.size - srcOff)) dest.data.size := by
|
||||
ext1
|
||||
simp [copySlice]
|
||||
@@ -122,7 +122,7 @@ private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i
|
||||
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
|
||||
else
|
||||
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
|
||||
rw [foldlM_loop_lt]
|
||||
rw [foldlM_loop_lt _ _ h]
|
||||
congr; funext
|
||||
rw [foldlM_loop_eq, foldlM_loop_eq]
|
||||
termination_by n - i
|
||||
|
||||
@@ -3,15 +3,11 @@ Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.Grind.Tactics
|
||||
|
||||
public section
|
||||
|
||||
namespace Function
|
||||
|
||||
/--
|
||||
@@ -51,6 +47,7 @@ theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f
|
||||
rfl
|
||||
|
||||
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
|
||||
@[expose]
|
||||
def Injective (f : α → β) : Prop :=
|
||||
∀ ⦃a₁ a₂⦄, f a₁ = f a₂ → a₁ = a₂
|
||||
|
||||
@@ -59,6 +56,7 @@ theorem Injective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Injectiv
|
||||
|
||||
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
|
||||
for some `a : α`. -/
|
||||
@[expose]
|
||||
def Surjective (f : α → β) : Prop :=
|
||||
∀ b, Exists fun a => f a = b
|
||||
|
||||
@@ -69,20 +67,22 @@ theorem Surjective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Surject
|
||||
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
|
||||
|
||||
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
|
||||
@[grind]
|
||||
@[expose, grind]
|
||||
def LeftInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
∀ x, g (f x) = x
|
||||
|
||||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||||
@[expose]
|
||||
def HasLeftInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => LeftInverse finv f
|
||||
|
||||
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
|
||||
@[grind]
|
||||
@[expose, grind]
|
||||
def RightInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||||
LeftInverse f g
|
||||
|
||||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||||
@[expose]
|
||||
def HasRightInverse {α β} (f : α → β) : Prop :=
|
||||
Exists fun finv : β → α => RightInverse finv f
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import all Init.Data.Int.Gcd
|
||||
public import Init.Data.RArray
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -54,7 +55,7 @@ def Expr.denote (ctx : Context) : Expr → Int
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving @[expose] BEq
|
||||
deriving @[expose] BEq, ReflBEq, LawfulBEq
|
||||
|
||||
@[expose]
|
||||
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
@@ -525,18 +526,6 @@ theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.deno
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go]
|
||||
|
||||
attribute [local simp] Expr.denote_norm
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next ih =>
|
||||
intro _ _ h
|
||||
exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
|
||||
attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm.beq' p) : e.denote ctx = p.denote' ctx := by
|
||||
|
||||
@@ -19,6 +19,7 @@ universe v u v' u'
|
||||
section ULiftT
|
||||
|
||||
/-- `ULiftT.{v, u}` shrinks a monad on `Type max u v` to a monad on `Type u`. -/
|
||||
@[expose] -- for codegen
|
||||
def ULiftT (n : Type max u v → Type v') (α : Type u) := n (ULift.{v} α)
|
||||
|
||||
/-- Returns the underlying `n`-monadic representation of a `ULiftT n α` value. -/
|
||||
|
||||
@@ -139,7 +139,7 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.size]
|
||||
@[always_inline, inline, expose, inherit_doc IterM.size]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
(IteratorSize.size it.toIterM).run.down
|
||||
|
||||
@@ -57,6 +57,6 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
|
||||
rw [← toArray_toList, ← toArray_toList, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith]
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -53,6 +53,6 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
it.uLift.toArray = it.toArray.map ULift.up := by
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp
|
||||
simp [-toArray_toList]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -44,11 +44,13 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
it.toIter.toListRev = it.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray.toList = it.toList := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.toArray = it.toArray := by
|
||||
|
||||
@@ -14,6 +14,7 @@ public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -43,6 +44,20 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
f out acc) := by
|
||||
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
|
||||
|
||||
@[congr] theorem Iter.forIn'_congr {α β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
{ita itb : Iter (α := α) β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → Id (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' Id (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -188,6 +203,13 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
obtain ⟨step, h₁, rfl⟩ := h₁
|
||||
simp [heq, IterStep.successor] at h₁
|
||||
|
||||
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toArray ↔ it.IsPlausibleIndirectOutput out := by
|
||||
rw [← Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
|
||||
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -222,6 +244,17 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [ihs h (f := fun out h acc => f out (this ▸ h) acc)]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
simp only [← Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -234,6 +267,18 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
simp only [forIn'_toList]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toArray]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -260,6 +305,15 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
|
||||
simp only [← Iter.toArray_toList, List.forIn_toArray, forIn_toList]
|
||||
|
||||
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
@@ -301,6 +355,14 @@ theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [F
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toArray]
|
||||
simp only [Array.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
@@ -324,6 +386,12 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
|
||||
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
@@ -344,6 +412,38 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f (it.fold g₁ init) := by
|
||||
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
|
||||
-- w.r.t. the universe of the output.
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
|
||||
|
||||
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom (List.toArray)]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
@@ -352,6 +452,14 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
|
||||
it.toList.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
|
||||
@@ -67,15 +67,17 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.toArray = it.toList := by
|
||||
simp [IterM.toList]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.toList = it.toArray := by
|
||||
simp [IterM.toList]
|
||||
simp [IterM.toList, -toList_toArray]
|
||||
|
||||
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
@@ -153,6 +155,6 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq]
|
||||
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -60,6 +60,20 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
simp only [ForIn.forIn, forIn'_eq]
|
||||
|
||||
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m m]
|
||||
{ita itb : IterM (α := α) m β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
{g : (a' : β) → _ → γ → m (ForInStep γ)}
|
||||
(h : ∀ a m b, f a (by simpa [w] using m) b = g a m b) :
|
||||
letI : ForIn' m (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
|
||||
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
@@ -200,6 +214,23 @@ theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [I
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem IterM.fold_hom {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β}
|
||||
(f : γ₁ → γ₂) {g₁ : γ₁ → β → γ₁} {g₂ : γ₂ → β → γ₂} {init : γ₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) :
|
||||
it.fold g₂ (f init) = f <$> (it.fold g₁ init) := by
|
||||
induction it using IterM.inductSteps generalizing init with | step it ihy ihs =>
|
||||
rw [fold_eq_match_step, fold_eq_match_step, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
rw [bind_pure_comp]
|
||||
split
|
||||
· rw [H, ihy ‹_›]
|
||||
· rw [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
@@ -223,6 +254,15 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
|
||||
simp [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom]
|
||||
simp
|
||||
|
||||
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=
|
||||
|
||||
@@ -167,7 +167,7 @@ theorem attachWith_map_subtype_val {p : α → Prop} {l : List α} (H : ∀ a
|
||||
(l.attachWith p H).map Subtype.val = l :=
|
||||
(attachWith_map_val _).trans (List.map_id _)
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val]; exact h)
|
||||
|
||||
@@ -475,21 +475,6 @@ We define the basic functional programming operations on `List`:
|
||||
|
||||
/-! ### map -/
|
||||
|
||||
/--
|
||||
Applies a function to each element of the list, returning the resulting list of values.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].map f = [f a, f b, f c]`
|
||||
* `[].map Nat.succ = []`
|
||||
* `["one", "two", "three"].map (·.length) = [3, 3, 5]`
|
||||
* `["one", "two", "three"].map (·.reverse) = ["eno", "owt", "eerht"]`
|
||||
-/
|
||||
@[specialize] def map (f : α → β) : (l : List α) → List β
|
||||
| [] => []
|
||||
| a::as => f a :: map f as
|
||||
|
||||
@[simp, grind =] theorem map_nil {f : α → β} : map f [] = [] := rfl
|
||||
@[simp, grind =] theorem map_cons {f : α → β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
|
||||
|
||||
@@ -606,20 +591,6 @@ Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
|
||||
* `[] ++ [4, 5] = [4, 5]`.
|
||||
* `[1, 2, 3] ++ [] = [1, 2, 3]`.
|
||||
-/
|
||||
protected def append : (xs ys : List α) → List α
|
||||
| [], bs => bs
|
||||
| a::as, bs => a :: List.append as bs
|
||||
|
||||
/--
|
||||
Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
This is a tail-recursive version of `List.append`.
|
||||
|
||||
Examples:
|
||||
@@ -691,18 +662,6 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
/--
|
||||
Concatenates a list of lists into a single list, preserving the order of the elements.
|
||||
|
||||
`O(|flatten L|)`.
|
||||
|
||||
Examples:
|
||||
* `[["a"], ["b", "c"]].flatten = ["a", "b", "c"]`
|
||||
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flatten = ["a", "b", "c", "d", "e", "f"]`
|
||||
-/
|
||||
def flatten : List (List α) → List α
|
||||
| [] => []
|
||||
| l :: L => l ++ flatten L
|
||||
|
||||
@[simp, grind =] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
|
||||
@[simp, grind =] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
|
||||
@@ -721,20 +680,14 @@ Examples:
|
||||
|
||||
/-! ### flatMap -/
|
||||
|
||||
/--
|
||||
Applies a function that returns a list to each element of a list, and concatenates the resulting
|
||||
lists.
|
||||
|
||||
Examples:
|
||||
* `[2, 3, 2].flatMap List.range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
* `["red", "blue"].flatMap String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
|
||||
-/
|
||||
@[inline] def flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
@[simp, grind =] theorem flatMap_nil {f : α → List β} : List.flatMap f [] = [] := by simp [List.flatMap]
|
||||
@[simp, grind =] theorem flatMap_cons {x : α} {xs : List α} {f : α → List β} :
|
||||
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
|
||||
|
||||
@[simp, grind _=_] theorem flatMap_append {xs ys : List α} {f : α → List β} :
|
||||
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
|
||||
induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -265,14 +265,18 @@ theorem eraseP_eq_iff {p} {l : List α} :
|
||||
subst p
|
||||
simp_all
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseP (q) : Pairwise p l → Pairwise p (l.eraseP q) :=
|
||||
Pairwise.sublist <| eraseP_sublist
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
|
||||
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
|
||||
|
||||
theorem Nodup.eraseP (p) : Nodup l → Nodup (l.eraseP p) :=
|
||||
Pairwise.eraseP p
|
||||
|
||||
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
|
||||
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
|
||||
|
||||
@[grind =]
|
||||
theorem eraseP_comm {l : List α} (h : ∀ a ∈ l, ¬ p a ∨ ¬ q a) :
|
||||
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
|
||||
@@ -508,10 +512,12 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
|
||||
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
|
||||
grind_pattern List.Nodup.not_mem_erase => a ∈ l.erase a, l.Nodup
|
||||
|
||||
@[grind ←]
|
||||
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l → Nodup (l.erase a) :=
|
||||
Pairwise.erase a
|
||||
|
||||
grind_pattern Nodup.erase => Nodup (l.erase a)
|
||||
grind_pattern Nodup.erase => Nodup l, l.erase a
|
||||
|
||||
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h ∈ xs :=
|
||||
erase_sublist.head_mem h
|
||||
|
||||
@@ -649,15 +655,18 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
|
||||
exact m.2
|
||||
· rw [eraseIdx_of_length_le (by simpa using h)]
|
||||
|
||||
@[grind ←]
|
||||
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l → Pairwise p (l.eraseIdx k) :=
|
||||
Pairwise.sublist <| eraseIdx_sublist _ _
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
|
||||
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
|
||||
|
||||
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l → Nodup (l.eraseIdx k) :=
|
||||
Pairwise.eraseIdx k
|
||||
|
||||
@[grind ←]
|
||||
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
|
||||
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
|
||||
|
||||
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
eraseIdx l k <+: eraseIdx l' k := by
|
||||
rcases h with ⟨t, rfl⟩
|
||||
@@ -667,6 +676,10 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
|
||||
rw [Nat.not_lt] at hkl
|
||||
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
|
||||
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
|
||||
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
|
||||
|
||||
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
|
||||
-- `Init/Data/List/Nat/Basic.lean`.
|
||||
|
||||
@@ -686,6 +699,4 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
|
||||
rw [eq_comm, eraseIdx_eq_self]
|
||||
exact Nat.le_of_eq (idxOf_eq_length h).symm
|
||||
|
||||
|
||||
|
||||
end List
|
||||
|
||||
@@ -559,7 +559,6 @@ where
|
||||
@[simp] theorem findIdx_singleton {a : α} {p : α → Bool} : [a].findIdx p = if p a then 0 else 1 := by
|
||||
simp [findIdx_cons, findIdx_nil]
|
||||
|
||||
@[grind →]
|
||||
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
|
||||
induction xs with
|
||||
| nil => simp_all
|
||||
|
||||
@@ -28,14 +28,14 @@ For each `List` operation, we would like theorems describing the following, when
|
||||
* the length of the result `(f L).length`
|
||||
* the `i`-th element, described via `(f L)[i]` and/or `(f L)[i]?` (these should typically be `@[simp]`)
|
||||
* consequences for `f L` of the fact `x ∈ L` or `x ∉ L`
|
||||
* conditions characterising `x ∈ f L` (often but not always `@[simp]`)
|
||||
* conditions characterizing `x ∈ f L` (often but not always `@[simp]`)
|
||||
* injectivity statements, or congruence statements of the form `p L M → f L = f M`.
|
||||
* conditions characterising the result, i.e. of the form `f L = M ↔ p M` for some predicate `p`,
|
||||
* conditions characterizing the result, i.e. of the form `f L = M ↔ p M` for some predicate `p`,
|
||||
along with special cases of `M` (e.g. `List.append_eq_nil : L ++ M = [] ↔ L = [] ∧ M = []`)
|
||||
* negative characterisations are also useful, e.g. `List.cons_ne_nil`
|
||||
* negative characterizations are also useful, e.g. `List.cons_ne_nil`
|
||||
* interactions with all previously described `List` operations where possible
|
||||
(some of these should be `@[simp]`, particularly if the result can be described by a single operation)
|
||||
* characterising `(∀ (i) (_ : i ∈ f L), P i)`, for some predicate `P`
|
||||
* characterizing `(∀ (i) (_ : i ∈ f L), P i)`, for some predicate `P`
|
||||
|
||||
Of course for any individual operation, not all of these will be relevant or helpful, so some judgement is required.
|
||||
|
||||
@@ -348,6 +348,18 @@ theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
|
||||
theorem getElem?_concat_length {l : List α} {a : α} : (l ++ [a])[l.length]? = some a := by
|
||||
simp
|
||||
|
||||
theorem eq_getElem_of_length_eq_one : (l : List α) → (hl : l.length = 1) → l = [l[0]'(hl ▸ by decide)]
|
||||
| [_], _ => rfl
|
||||
|
||||
theorem eq_getElem_of_length_eq_two : (l : List α) → (hl : l.length = 2) → l = [l[0]'(hl ▸ by decide), l[1]'(hl ▸ by decide)]
|
||||
| [_, _], _ => rfl
|
||||
|
||||
theorem eq_getElem_of_length_eq_three : (l : List α) → (hl : l.length = 3) → l = [l[0]'(hl ▸ by decide), l[1]'(hl ▸ by decide), l[2]'(hl ▸ by decide)]
|
||||
| [_, _, _], _ => rfl
|
||||
|
||||
theorem eq_getElem_of_length_eq_four : (l : List α) → (hl : l.length = 4) → l = [l[0]'(hl ▸ by decide), l[1]'(hl ▸ by decide), l[2]'(hl ▸ by decide), l[3]'(hl ▸ by decide)]
|
||||
| [_, _, _, _], _ => rfl
|
||||
|
||||
/-! ### getD
|
||||
|
||||
We simplify away `getD`, replacing `getD l n a` with `(l[n]?).getD a`.
|
||||
@@ -939,8 +951,8 @@ theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.len
|
||||
| nil => simp
|
||||
| cons _ _ =>
|
||||
apply getLast!_of_getLast?
|
||||
rw [getElem!_pos, getElem_cons_length (h := by simp)]
|
||||
rfl
|
||||
rw [getLast?_eq_getElem?]
|
||||
simp
|
||||
|
||||
/-! ## Head and tail -/
|
||||
|
||||
@@ -1162,7 +1174,9 @@ theorem forall_mem_map {f : α → β} {l : List α} {P : β → Prop} :
|
||||
@[simp] theorem map_eq_nil_iff {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
@[grind →]
|
||||
-- This would be helpful as a `grind` lemma if
|
||||
-- we could have it fire only once `map f l` and `[]` are the same equivalence class.
|
||||
-- Otherwise it is too aggressive.
|
||||
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
|
||||
map_eq_nil_iff.mp h
|
||||
|
||||
@@ -1344,7 +1358,7 @@ grind_pattern getElem_filter => (xs.filter p)[i]
|
||||
|
||||
theorem getElem?_filter {xs : List α} {p : α → Bool} {i : Nat} (h : i < (xs.filter p).length)
|
||||
(w : (xs.filter p)[i]? = some a) : p a := by
|
||||
rw [getElem?_eq_getElem] at w
|
||||
rw [getElem?_eq_getElem h] at w
|
||||
simp only [Option.some.injEq] at w
|
||||
rw [← w]
|
||||
apply getElem_filter h
|
||||
@@ -2134,10 +2148,6 @@ theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
|
||||
simp only [findSome?_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp, grind _=_] theorem flatMap_append {xs ys : List α} {f : α → List β} :
|
||||
(xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
|
||||
induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
|
||||
|
||||
theorem flatMap_assoc {l : List α} {f : α → List β} {g : β → List γ} :
|
||||
(l.flatMap f).flatMap g = l.flatMap fun x => (f x).flatMap g := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@@ -567,9 +567,10 @@ theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
|
||||
f (l[i]'(lt_length_left_of_zipWith h))
|
||||
(l'[i]'(lt_length_right_of_zipWith h)) := by
|
||||
rw [← Option.some_inj, ← getElem?_eq_getElem, getElem?_zipWith_eq_some]
|
||||
have := lt_length_right_of_zipWith h
|
||||
exact
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact ⟨rfl, rfl⟩⟩
|
||||
⟨l[i]'(lt_length_left_of_zipWith h), l'[i],
|
||||
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem this]; exact ⟨rfl, rfl⟩⟩
|
||||
|
||||
theorem zipWith_eq_zipWith_take_min : ∀ {l₁ : List α} {l₂ : List β},
|
||||
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))
|
||||
|
||||
@@ -171,7 +171,7 @@ theorem pairwise_append_comm {R : α → α → Prop} (s : ∀ {x y}, R x y →
|
||||
induction L with
|
||||
| nil => simp
|
||||
| cons l L IH =>
|
||||
simp only [flatten, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
simp only [flatten_cons, pairwise_append, IH, mem_flatten, exists_imp, and_imp, forall_mem_cons,
|
||||
pairwise_cons, and_assoc, and_congr_right_iff]
|
||||
rw [and_comm, and_congr_left_iff]
|
||||
intros; exact ⟨fun h l' b c d e => h c d e l' b, fun h c d e l' b => h l' b c d e⟩
|
||||
@@ -277,10 +277,12 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h :
|
||||
|
||||
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l ↔ List.Pairwise (· ≠ ·) l := Iff.rfl
|
||||
|
||||
@[simp, grind]
|
||||
@[simp]
|
||||
theorem nodup_nil : @Nodup α [] :=
|
||||
Pairwise.nil
|
||||
|
||||
grind_pattern nodup_nil => @Nodup α []
|
||||
|
||||
@[simp, grind =]
|
||||
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) ↔ a ∉ l ∧ Nodup l := by
|
||||
simp only [Nodup, pairwise_cons, forall_mem_ne]
|
||||
|
||||
@@ -151,11 +151,11 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
|
||||
|
||||
/-! ### Sublist and isSublist -/
|
||||
|
||||
@[simp, grind] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
@[simp, grind ←] theorem nil_sublist : ∀ l : List α, [] <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (nil_sublist l).cons a
|
||||
|
||||
@[simp, grind] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
@[simp, grind ←] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (Sublist.refl l).cons₂ a
|
||||
|
||||
@@ -172,7 +172,7 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
|
||||
|
||||
instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩
|
||||
|
||||
attribute [simp, grind] Sublist.cons
|
||||
attribute [simp, grind ←] Sublist.cons
|
||||
|
||||
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
|
||||
|
||||
@@ -638,15 +638,21 @@ protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀
|
||||
|
||||
/-! ### IsPrefix / IsSuffix / IsInfix -/
|
||||
|
||||
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := ⟨l₂, rfl⟩
|
||||
|
||||
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
grind_pattern prefix_append => l₁ <+: l₁ ++ l₂
|
||||
|
||||
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := ⟨l₁, rfl⟩
|
||||
|
||||
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
|
||||
|
||||
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := ⟨l₁, l₃, rfl⟩
|
||||
|
||||
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
|
||||
rw [← List.append_assoc]; apply infix_append
|
||||
|
||||
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
|
||||
|
||||
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := ⟨[], l₂, rfl⟩
|
||||
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := ⟨l₁, [], by simp⟩
|
||||
|
||||
@@ -658,22 +664,24 @@ theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ =>
|
||||
|
||||
grind_pattern IsSuffix.isInfix => l₁ <:+ l₂, IsInfix
|
||||
|
||||
@[simp, grind] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
@[simp, grind ←] theorem nil_prefix {l : List α} : [] <+: l := ⟨l, rfl⟩
|
||||
|
||||
@[simp, grind] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
@[simp, grind ←] theorem nil_suffix {l : List α} : [] <:+ l := ⟨l, append_nil _⟩
|
||||
|
||||
@[simp, grind] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
@[simp, grind ←] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
|
||||
|
||||
theorem prefix_refl (l : List α) : l <+: l := ⟨[], append_nil _⟩
|
||||
@[simp, grind] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
@[simp, grind ←] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
|
||||
|
||||
theorem suffix_refl (l : List α) : l <:+ l := ⟨[], rfl⟩
|
||||
@[simp, grind] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
@[simp, grind ←] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
|
||||
|
||||
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
|
||||
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
@[simp, grind ←] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
|
||||
|
||||
@[simp, grind] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
@[simp] theorem suffix_cons (a : α) : ∀ l, l <:+ a :: l := suffix_append [a]
|
||||
|
||||
grind_pattern suffix_cons => _ <:+ a :: l
|
||||
|
||||
theorem infix_cons : l₁ <:+: l₂ → l₁ <:+: a :: l₂ := fun ⟨l₁', l₂', h⟩ => ⟨a :: l₁', l₂', h ▸ rfl⟩
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ prelude
|
||||
public import Init.ByCases
|
||||
public import Init.Data.Prod
|
||||
public import Init.Data.RArray
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -138,21 +139,7 @@ structure PolyCnstr where
|
||||
eq : Bool
|
||||
lhs : Poly
|
||||
rhs : Poly
|
||||
deriving BEq
|
||||
|
||||
-- TODO: implement LawfulBEq generator companion for BEq
|
||||
instance : LawfulBEq PolyCnstr where
|
||||
eq_of_beq {a b} h := by
|
||||
cases a; rename_i eq₁ lhs₁ rhs₁
|
||||
cases b; rename_i eq₂ lhs₂ rhs₂
|
||||
have h : eq₁ == eq₂ && (lhs₁ == lhs₂ && rhs₁ == rhs₂) := h
|
||||
simp at h
|
||||
have ⟨h₁, h₂, h₃⟩ := h
|
||||
rw [h₁, h₂, h₃]
|
||||
rfl {a} := by
|
||||
cases a; rename_i eq lhs rhs
|
||||
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
|
||||
simp
|
||||
deriving BEq, ReflBEq, LawfulBEq
|
||||
|
||||
structure ExprCnstr where
|
||||
eq : Bool
|
||||
|
||||
@@ -52,7 +52,7 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
|
||||
theorem get_of_eq_some : ∀ {o : Option α} (h : isSome o), o = some a → o.get h = a
|
||||
| _, _, rfl => rfl
|
||||
|
||||
@[simp, grind] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
@[simp, grind ←] theorem not_mem_none (a : α) : a ∉ (none : Option α) := nofun
|
||||
|
||||
theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.getD y) = x := by
|
||||
cases x; {contradiction}; rw [getD_some]
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Option
|
||||
o.toList.foldr f a = o.elim a (fun b => f b a) := by
|
||||
cases o <;> simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem pairwise_toList {P : α → α → Prop} {o : Option α} : o.toList.Pairwise P := by
|
||||
cases o <;> simp
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ public import Init.Data.Range.Polymorphic.Stream
|
||||
public import Init.Data.Range.Polymorphic.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.Nat
|
||||
public import Init.Data.Range.Polymorphic.Int
|
||||
public import Init.Data.Range.Polymorphic.BitVec
|
||||
public import Init.Data.Range.Polymorphic.UInt
|
||||
public import Init.Data.Range.Polymorphic.NatLemmas
|
||||
public import Init.Data.Range.Polymorphic.GetElemTactic
|
||||
|
||||
|
||||
88
src/Init/Data/Range/Polymorphic/BitVec.lean
Normal file
88
src/Init/Data/Range/Polymorphic/BitVec.lean
Normal file
@@ -0,0 +1,88 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.UInt
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
|
||||
open Std Std.PRange
|
||||
|
||||
namespace BitVec
|
||||
|
||||
variable {n : Nat}
|
||||
|
||||
instance : UpwardEnumerable (BitVec n) where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? m i := if h : i.toNat + m < 2 ^ n then some (.ofNatLT _ h) else none
|
||||
|
||||
instance : LawfulUpwardEnumerable (BitVec n) where
|
||||
ne_of_lt := by
|
||||
simp +contextual [UpwardEnumerable.LT, ← BitVec.toNat_inj, succMany?] at ⊢
|
||||
omega
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?, BitVec.toNat_lt_twoPow_of_le]
|
||||
succMany?_succ? a b := by
|
||||
simp +contextual [← BitVec.toNat_inj, succMany?, succ?]
|
||||
split <;> split
|
||||
· rename_i h
|
||||
simp [← BitVec.toNat_inj, Nat.mod_eq_of_lt (a := b.toNat + a + 1) ‹_›]
|
||||
all_goals omega
|
||||
· omega
|
||||
· have : b.toNat + a + 1 = 2 ^ n := by omega
|
||||
simp [this]
|
||||
· simp
|
||||
|
||||
instance : LawfulUpwardEnumerableLE (BitVec n) where
|
||||
le_iff x y := by
|
||||
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, BitVec.le_def]
|
||||
apply Iff.intro
|
||||
· intro hle
|
||||
refine ⟨y.toNat - x.toNat, ?_⟩
|
||||
apply Exists.intro <;> simp [Nat.add_sub_cancel' hle, BitVec.toNat_lt_twoPow_of_le]
|
||||
· rintro ⟨n, hn, rfl⟩
|
||||
simp [BitVec.ofNatLT]
|
||||
|
||||
instance : LawfulOrderLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open (BitVec n) := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open (BitVec n) := inferInstance
|
||||
|
||||
instance : RangeSize .closed (BitVec n) where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
instance : RangeSize .open (BitVec n) := RangeSize.openOfClosed
|
||||
|
||||
instance : LawfulRangeSize .closed (BitVec n) where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simp [SupportsUpperBound.IsSatisfied, BitVec.not_le, RangeSize.size, BitVec.lt_def]
|
||||
omega
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
have := BitVec.toNat_lt_twoPow_of_le (Nat.le_refl _) (x := bound)
|
||||
have (h : (x.toNat + 1) % 2 ^ n = 0) : x.toNat = 2 ^ n - 1 := by
|
||||
apply Classical.not_not.mp
|
||||
intro _
|
||||
simp [Nat.mod_eq_of_lt (a := x.toNat + 1) (b := 2 ^ n) (by omega)] at h
|
||||
simp [RangeSize.size, BitVec.le_def, ← BitVec.toNat_inj, succ?]
|
||||
omega
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
have (h : ¬ (init.toNat + 1) % 2 ^ n = 0) : ¬ (init.toNat + 1 ≥ 2 ^ n) := by
|
||||
intro _
|
||||
have : init.toNat + 1 = 2 ^ n := by omega
|
||||
simp_all
|
||||
simp_all +contextual [RangeSize.size, BitVec.le_def, ← BitVec.toNat_inj,
|
||||
Nat.mod_eq_of_lt (a := init.toNat + 1) (b := 2 ^ n), succ?]
|
||||
omega
|
||||
|
||||
instance : LawfulRangeSize .open (BitVec n) := inferInstance
|
||||
|
||||
end BitVec
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
public import Init.Data.Int.Order
|
||||
import Init.Omega
|
||||
|
||||
public section
|
||||
@@ -23,7 +24,7 @@ instance : LawfulUpwardEnumerable Int where
|
||||
simp only [UpwardEnumerable.LT, UpwardEnumerable.succMany?, Option.some.injEq]
|
||||
omega
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by
|
||||
succMany?_succ? := by
|
||||
simp only [UpwardEnumerable.succMany?, UpwardEnumerable.succ?,
|
||||
Option.bind_some, Option.some.injEq]
|
||||
omega
|
||||
@@ -36,6 +37,14 @@ instance : LawfulUpwardEnumerableLE Int where
|
||||
simp [UpwardEnumerable.LE, UpwardEnumerable.succMany?, Int.le_def, Int.nonneg_def,
|
||||
Int.sub_eq_iff_eq_add', eq_comm (a := y)]
|
||||
|
||||
instance : LawfulOrderLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open Int := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open Int := inferInstance
|
||||
|
||||
instance : RangeSize .closed Int where
|
||||
size bound a := (bound + 1 - a).toNat
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def Internal.iter {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl
|
||||
|
||||
/--
|
||||
Returns the elements of the given range as a list in ascending order, given that ranges of the given
|
||||
type and shape support this function and the range is finite.
|
||||
type and shape are finite and support this function.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
@@ -37,6 +37,18 @@ def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[IteratorCollect (RangeIterator su α) Id Id] : List α :=
|
||||
PRange.Internal.iter r |>.toList
|
||||
|
||||
/--
|
||||
Returns the elements of the given range as an array in ascending order, given that ranges of the
|
||||
given type and shape are finite and support this function.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def toArray {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α]
|
||||
(r : PRange ⟨sl, su⟩ α)
|
||||
[Iterator (RangeIterator su α) Id α] [Finite (RangeIterator su α) Id]
|
||||
[IteratorCollect (RangeIterator su α) Id Id] : Array α :=
|
||||
PRange.Internal.iter r |>.toArray
|
||||
|
||||
/--
|
||||
Iterators for ranges implementing `RangeSize` support the `size` function.
|
||||
-/
|
||||
|
||||
@@ -16,6 +16,7 @@ public import Init.Data.Range.Polymorphic.Iterators
|
||||
import all Init.Data.Range.Polymorphic.Iterators
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
import all Init.Data.Iterators.Consumers.Loop
|
||||
import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
@@ -44,6 +45,12 @@ private theorem Internal.toList_eq_toList_iter {sl su} [UpwardEnumerable α]
|
||||
r.toList = (Internal.iter r).toList := by
|
||||
rfl
|
||||
|
||||
private theorem Internal.toArray_eq_toArray_iter {sl su} [UpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α] {r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = (Internal.iter r).toArray := by
|
||||
rfl
|
||||
|
||||
public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -61,6 +68,35 @@ public theorem RangeIterator.toList_eq_match {su} [UpwardEnumerable α]
|
||||
· simp [*]
|
||||
· split <;> rename_i heq' <;> simp [*]
|
||||
|
||||
public theorem RangeIterator.toArray_eq_match {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{it : Iter (α := RangeIterator su α) α} :
|
||||
it.toArray = match it.internalState.next with
|
||||
| none => #[]
|
||||
| some a => if SupportsUpperBound.IsSatisfied it.internalState.upperBound a then
|
||||
#[a] ++ (⟨⟨UpwardEnumerable.succ? a, it.internalState.upperBound⟩⟩ : Iter (α := RangeIterator su α) α).toArray
|
||||
else
|
||||
#[] := by
|
||||
rw [← Iter.toArray_toList, toList_eq_match]
|
||||
split
|
||||
· rfl
|
||||
· split <;> simp
|
||||
|
||||
@[simp]
|
||||
public theorem toList_toArray {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray.toList = r.toList := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
|
||||
|
||||
@[simp]
|
||||
public theorem toArray_toList {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList.toArray = r.toArray := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.toList_eq_toList_iter]
|
||||
|
||||
public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -73,6 +109,18 @@ public theorem toList_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnume
|
||||
[] := by
|
||||
rw [Internal.toList_eq_toList_iter, RangeIterator.toList_eq_match]; rfl
|
||||
|
||||
public theorem toArray_eq_match {sl su} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = match init? r.lower with
|
||||
| none => #[]
|
||||
| some a => if SupportsUpperBound.IsSatisfied r.upper a then
|
||||
#[a] ++ (PRange.mk (shape := ⟨.open, su⟩) a r.upper).toArray
|
||||
else
|
||||
#[] := by
|
||||
rw [Internal.toArray_eq_toArray_iter, RangeIterator.toArray_eq_match]; rfl
|
||||
|
||||
public theorem toList_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -90,6 +138,14 @@ public theorem toList_open_eq_toList_closed_of_isSome_succ? {su} [UpwardEnumerab
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toList :=
|
||||
toList_Rox_eq_toList_Rcx_of_isSome_succ? h
|
||||
|
||||
public theorem toArray_Rox_eq_toList_Rcx_of_isSome_succ? {su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{lo : Bound .open α} {hi} (h : (UpwardEnumerable.succ? lo).isSome) :
|
||||
(PRange.mk (shape := ⟨.open, su⟩) lo hi).toArray =
|
||||
(PRange.mk (shape := ⟨.closed, su⟩) (UpwardEnumerable.succ? lo |>.get h) hi).toArray := by
|
||||
simp [Internal.toArray_eq_toArray_iter, Internal.iter_Rox_eq_iter_Rcx_of_isSome_succ?, h]
|
||||
|
||||
public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
@@ -101,6 +157,14 @@ public theorem toList_eq_nil_iff {sl su} [UpwardEnumerable α]
|
||||
simp only
|
||||
split <;> rename_i heq <;> simp [heq]
|
||||
|
||||
public theorem toArray_eq_empty_iff {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [BoundedUpwardEnumerable sl α]
|
||||
[LawfulUpwardEnumerable α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray = #[] ↔
|
||||
¬ (∃ a, init? r.lower = some a ∧ SupportsUpperBound.IsSatisfied r.upper a) := by
|
||||
rw [← toArray_toList, List.toArray_eq_iff, Array.toList_empty, toList_eq_nil_iff]
|
||||
|
||||
public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -110,6 +174,15 @@ public theorem mem_toList_iff_mem {sl su} [UpwardEnumerable α]
|
||||
rw [Internal.toList_eq_toList_iter, Iter.mem_toList_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
public theorem mem_toArray_iff_mem {sl su} [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{a : α} : a ∈ r.toArray ↔ a ∈ r := by
|
||||
rw [Internal.toArray_eq_toArray_iter, Iter.mem_toArray_iff_isPlausibleIndirectOutput,
|
||||
Internal.isPlausibleIndirectOutput_iter_iff]
|
||||
|
||||
public theorem BoundedUpwardEnumerable.init?_succ?_closed [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] {lower lower' : Bound .closed α}
|
||||
(h : UpwardEnumerable.succ? lower = some lower') :
|
||||
@@ -301,6 +374,17 @@ public theorem ClosedOpen.toList_succ_succ_eq_map [UpwardEnumerable α] [Support
|
||||
(lower...upper).toList.map succ :=
|
||||
toList_Rco_succ_succ_eq_map
|
||||
|
||||
public theorem toArray_Rco_succ_succ_eq_map [UpwardEnumerable α] [SupportsLowerBound .closed α]
|
||||
[LinearlyUpwardEnumerable α] [InfinitelyUpwardEnumerable α] [SupportsUpperBound .open α]
|
||||
[HasFiniteRanges .open α] [LawfulUpwardEnumerable α] [LawfulOpenUpperBound α]
|
||||
[LawfulUpwardEnumerableLowerBound .closed α] [LawfulUpwardEnumerableUpperBound .open α]
|
||||
{lower : Bound .closed α} {upper : Bound .open α} :
|
||||
((succ lower)...(succ upper)).toArray =
|
||||
(lower...upper).toArray.map succ := by
|
||||
simp only [← toArray_toList]
|
||||
rw [toList_Rco_succ_succ_eq_map]
|
||||
simp only [List.map_toArray]
|
||||
|
||||
private theorem Internal.forIn'_eq_forIn'_iter [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -324,6 +408,18 @@ public theorem forIn'_eq_forIn'_toList [UpwardEnumerable α]
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toList_eq_toList_iter,
|
||||
Iter.forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem forIn'_eq_forIn'_toArray [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → a ∈ r → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r init f =
|
||||
ForIn'.forIn' r.toArray init (fun a ha acc => f a (mem_toArray_iff_mem.mp ha) acc) := by
|
||||
simp [Internal.forIn'_eq_forIn'_iter, Internal.toArray_eq_toArray_iter,
|
||||
Iter.forIn'_eq_forIn'_toArray]
|
||||
|
||||
public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -335,6 +431,17 @@ public theorem forIn'_toList_eq_forIn' [UpwardEnumerable α]
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toList_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toList]
|
||||
|
||||
public theorem forIn'_toArray_eq_forIn' [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨sl, su⟩ α}
|
||||
{γ : Type u} {init : γ} {m : Type u → Type w} [Monad m] [LawfulMonad m]
|
||||
{f : (a : α) → _ → γ → m (ForInStep γ)} :
|
||||
ForIn'.forIn' r.toArray init f =
|
||||
ForIn'.forIn' r init (fun a ha acc => f a (mem_toArray_iff_mem.mpr ha) acc) := by
|
||||
simp [forIn'_eq_forIn'_toArray]
|
||||
|
||||
public theorem mem_of_mem_open [UpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [SupportsLowerBound sl α] [HasFiniteRanges su α]
|
||||
[BoundedUpwardEnumerable sl α] [LawfulUpwardEnumerable α]
|
||||
@@ -431,6 +538,20 @@ public instance {su} [UpwardEnumerable α] [SupportsUpperBound su α] [RangeSize
|
||||
· have := LawfulRangeSize.size_eq_zero_of_not_isSatisfied _ _ h'
|
||||
simp [*] at this
|
||||
|
||||
public theorem length_toList {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[HasFiniteRanges su α] [LawfulRangeSize su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toList.length = r.size := by
|
||||
simp [PRange.toList, PRange.size]
|
||||
|
||||
public theorem size_toArray {sl su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
[RangeSize su α] [LawfulUpwardEnumerable α] [BoundedUpwardEnumerable sl α]
|
||||
[HasFiniteRanges su α] [LawfulRangeSize su α]
|
||||
{r : PRange ⟨sl, su⟩ α} :
|
||||
r.toArray.size = r.size := by
|
||||
simp [PRange.toArray, PRange.size]
|
||||
|
||||
public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[BoundedUpwardEnumerable sl α] [SupportsLowerBound sl α] [SupportsUpperBound su α]
|
||||
[LawfulUpwardEnumerableLowerBound sl α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
@@ -455,4 +576,94 @@ public theorem isEmpty_iff_forall_not_mem {sl su} [UpwardEnumerable α] [LawfulU
|
||||
(Option.some_get hi).symm
|
||||
exact h ((init? r.lower).get hi) ⟨hl, hu⟩
|
||||
|
||||
theorem Std.PRange.getElem?_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} :
|
||||
r.toList[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
|
||||
induction i generalizing r
|
||||
· rw [PRange.toList_eq_match, UpwardEnumerable.succMany?_zero]
|
||||
simp only [Option.filter_some, decide_eq_true_eq]
|
||||
split <;> simp
|
||||
· rename_i n ih
|
||||
rw [PRange.toList_eq_match]
|
||||
simp only
|
||||
split
|
||||
· simp [UpwardEnumerable.succMany?_succ?_eq_succ?_bind_succMany?]
|
||||
cases hs : UpwardEnumerable.succ? r.lower
|
||||
· rw [PRange.toList_eq_match]
|
||||
simp [BoundedUpwardEnumerable.init?, hs]
|
||||
· rw [toList_Rox_eq_toList_Rcx_of_isSome_succ? (by simp [hs])]
|
||||
rw [ih]
|
||||
simp [hs]
|
||||
· simp only [List.length_nil, Nat.not_lt_zero, not_false_eq_true, getElem?_neg]
|
||||
cases hs : UpwardEnumerable.succMany? (n + 1) r.lower
|
||||
· simp
|
||||
· rename_i hl a
|
||||
simp only [Option.filter_some, decide_eq_true_eq, right_eq_ite_iff]
|
||||
have : UpwardEnumerable.LE r.lower a := ⟨n + 1, hs⟩
|
||||
intro ha
|
||||
exact hl.elim <| LawfulUpwardEnumerableUpperBound.isSatisfied_of_le r.upper _ _ ha this (α := α)
|
||||
|
||||
theorem Std.PRange.getElem?_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} :
|
||||
r.toArray[i]? = (UpwardEnumerable.succMany? i r.lower).filter (SupportsUpperBound.IsSatisfied r.upper) := by
|
||||
rw [← toArray_toList, List.getElem?_toArray, getElem?_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.isSome_succMany?_of_lt_length_toList_Rcx [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} (h : i < r.toList.length) :
|
||||
(UpwardEnumerable.succMany? i r.lower).isSome := by
|
||||
have : r.toList[i]?.isSome := by simp [h]
|
||||
simp only [getElem?_toList_Rcx_eq, Option.isSome_filter] at this
|
||||
exact Option.isSome_of_any this
|
||||
|
||||
theorem Std.PRange.isSome_succMany?_of_lt_size_toArray_Rcx [LE α] [UpwardEnumerable α]
|
||||
[LawfulUpwardEnumerable α] [SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i} (h : i < r.toArray.size) :
|
||||
(UpwardEnumerable.succMany? i r.lower).isSome := by
|
||||
have : r.toArray[i]?.isSome := by simp [h]
|
||||
simp only [getElem?_toArray_Rcx_eq, Option.isSome_filter] at this
|
||||
exact Option.isSome_of_any this
|
||||
|
||||
theorem Std.PRange.getElem_toList_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i h} :
|
||||
r.toList[i]'h = (UpwardEnumerable.succMany? i r.lower).get
|
||||
(isSome_succMany?_of_lt_length_toList_Rcx h) := by
|
||||
simp [List.getElem_eq_getElem?_get, getElem?_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.getElem_toArray_Rcx_eq [LE α] [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
[SupportsUpperBound su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
[LawfulUpwardEnumerableLE α] [HasFiniteRanges su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {i h} :
|
||||
r.toArray[i]'h = (UpwardEnumerable.succMany? i r.lower).get
|
||||
(isSome_succMany?_of_lt_size_toArray_Rcx h) := by
|
||||
simp [Array.getElem_eq_getElem?_get, getElem?_toArray_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.eq_succMany?_of_toList_Rcx_eq_append_cons [LE α]
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {pref suff : List α} {cur : α} (h : r.toList = pref ++ cur :: suff) :
|
||||
cur = (UpwardEnumerable.succMany? pref.length r.lower).get
|
||||
(isSome_succMany?_of_lt_length_toList_Rcx (by simp [h])) := by
|
||||
have : cur = (pref ++ cur :: suff)[pref.length] := by simp
|
||||
simp only [← h] at this
|
||||
simp [this, getElem_toList_Rcx_eq]
|
||||
|
||||
theorem Std.PRange.eq_succMany?_of_toArray_Rcx_eq_append_append [LE α]
|
||||
[UpwardEnumerable α] [LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
[SupportsUpperBound su α] [HasFiniteRanges su α] [LawfulUpwardEnumerableUpperBound su α]
|
||||
{r : PRange ⟨.closed, su⟩ α} {pref suff : Array α} {cur : α} (h : r.toArray = pref ++ #[cur] ++ suff) :
|
||||
cur = (UpwardEnumerable.succMany? pref.size r.lower).get
|
||||
(isSome_succMany?_of_lt_size_toArray_Rcx (by simp [h, Nat.add_assoc, Nat.add_comm 1])) := by
|
||||
have : cur = (pref ++ #[cur] ++ suff)[pref.size] := by simp
|
||||
simp only [← h] at this
|
||||
simp [this, getElem_toArray_Rcx_eq]
|
||||
|
||||
end Std.PRange
|
||||
|
||||
@@ -10,10 +10,12 @@ import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Order
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Classes
|
||||
import Init.Data.Order.Lemmas
|
||||
public import Init.Data.Order.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
open Std PRange
|
||||
|
||||
namespace Std.PRange
|
||||
|
||||
instance : UpwardEnumerable Nat where
|
||||
@@ -39,7 +41,7 @@ instance : LawfulUpwardEnumerableLE Nat where
|
||||
|
||||
instance : LawfulUpwardEnumerable Nat where
|
||||
succMany?_zero := by simp [UpwardEnumerable.succMany?]
|
||||
succMany?_succ := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
succMany?_succ? := by simp [UpwardEnumerable.succMany?, UpwardEnumerable.succ?, Nat.add_assoc]
|
||||
ne_of_lt a b hlt := by
|
||||
have hn := hlt.choose_spec
|
||||
simp only [UpwardEnumerable.succMany?, Option.some.injEq] at hn
|
||||
@@ -76,8 +78,7 @@ instance : LawfulRangeSize .closed Nat where
|
||||
instance : LawfulRangeSize .open Nat := inferInstance
|
||||
instance : HasFiniteRanges .closed Nat := inferInstance
|
||||
instance : HasFiniteRanges .open Nat := inferInstance
|
||||
instance : LinearlyUpwardEnumerable Nat := by
|
||||
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
|
||||
instance : LinearlyUpwardEnumerable Nat := inferInstance
|
||||
|
||||
/-!
|
||||
The following instances are used for the implementation of array slices a.k.a. `Subarray`.
|
||||
|
||||
@@ -25,4 +25,17 @@ theorem toList_Rco_succ_succ {m n : Nat} :
|
||||
theorem ClosedOpen.toList_succ_succ {m n : Nat} :
|
||||
((m+1)...(n+1)).toList = (m...n).toList.map (· + 1) := toList_Rco_succ_succ
|
||||
|
||||
@[simp]
|
||||
theorem Nat.size_Rco {a b : Nat} :
|
||||
(a...b).size = b - a := by
|
||||
simp only [size, Iterators.Iter.size, Iterators.IteratorSize.size, Iterators.Iter.toIterM,
|
||||
Internal.iter, init?, RangeSize.size, Id.run_pure]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem Nat.size_Rcc {a b : Nat} :
|
||||
(a...=b).size = b + 1- a := by
|
||||
simp [Std.PRange.size, Std.Iterators.Iter.size, Std.Iterators.IteratorSize.size,
|
||||
Std.PRange.Internal.iter, Std.Iterators.Iter.toIterM, Std.PRange.RangeSize.size]
|
||||
|
||||
end Std.PRange.Nat
|
||||
|
||||
382
src/Init/Data/Range/Polymorphic/UInt.lean
Normal file
382
src/Init/Data/Range/Polymorphic/UInt.lean
Normal file
@@ -0,0 +1,382 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.Order.Lemmas
|
||||
public import Init.Data.UInt
|
||||
import Init.Omega
|
||||
public import Init.Data.Range.Polymorphic.BitVec
|
||||
|
||||
public section
|
||||
|
||||
open Std Std.PRange
|
||||
|
||||
namespace UInt8
|
||||
|
||||
instance : UpwardEnumerable UInt8 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt8.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 8} :
|
||||
UpwardEnumerable.succ? (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt8.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 8} :
|
||||
UpwardEnumerable.succMany? k (UInt8.ofBitVec x) = UInt8.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 8} :
|
||||
UpwardEnumerable.LE (UInt8.ofBitVec x) (UInt8.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 8} :
|
||||
UpwardEnumerable.LT (UInt8.ofBitVec x) (UInt8.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt8 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt8 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt8.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt8 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt8 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt8 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt8} {x : BitVec 8} :
|
||||
RangeSize.size bound (UInt8.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt8 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 8) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 8) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt8.le_iff_toBitVec_le, ← UInt8.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 8) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt8 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt8 := inferInstance
|
||||
|
||||
end UInt8
|
||||
|
||||
namespace UInt16
|
||||
|
||||
instance : UpwardEnumerable UInt16 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt16.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 16} :
|
||||
UpwardEnumerable.succ? (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt16.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 16} :
|
||||
UpwardEnumerable.succMany? k (UInt16.ofBitVec x) = UInt16.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 16} :
|
||||
UpwardEnumerable.LE (UInt16.ofBitVec x) (UInt16.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 16} :
|
||||
UpwardEnumerable.LT (UInt16.ofBitVec x) (UInt16.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt16 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt16 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt16.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt16 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt16 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt16 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt16} {x : BitVec 16} :
|
||||
RangeSize.size bound (UInt16.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt16 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 16) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 16) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt16.le_iff_toBitVec_le, ← UInt16.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 16) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt16 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt16 := inferInstance
|
||||
|
||||
end UInt16
|
||||
|
||||
namespace UInt32
|
||||
|
||||
instance : UpwardEnumerable UInt32 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt32.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 32} :
|
||||
UpwardEnumerable.succ? (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt32.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 32} :
|
||||
UpwardEnumerable.succMany? k (UInt32.ofBitVec x) = UInt32.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 32} :
|
||||
UpwardEnumerable.LE (UInt32.ofBitVec x) (UInt32.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 32} :
|
||||
UpwardEnumerable.LT (UInt32.ofBitVec x) (UInt32.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt32 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt32 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt32.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt32 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt32 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt32 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt32} {x : BitVec 32} :
|
||||
RangeSize.size bound (UInt32.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt32 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 32) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 32) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt32.le_iff_toBitVec_le, ← UInt32.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 32) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt32 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt32 := inferInstance
|
||||
|
||||
end UInt32
|
||||
|
||||
namespace UInt64
|
||||
|
||||
instance : UpwardEnumerable UInt64 where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < UInt64.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec 64} :
|
||||
UpwardEnumerable.succ? (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← UInt64.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec 64} :
|
||||
UpwardEnumerable.succMany? k (UInt64.ofBitVec x) = UInt64.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec 64} :
|
||||
UpwardEnumerable.LE (UInt64.ofBitVec x) (UInt64.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec 64} :
|
||||
UpwardEnumerable.LT (UInt64.ofBitVec x) (UInt64.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable UInt64 where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE UInt64 where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, UInt64.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open UInt64 := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open UInt64 := inferInstance
|
||||
|
||||
instance : RangeSize .closed UInt64 where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed UInt64} {x : BitVec 64} :
|
||||
RangeSize.size bound (UInt64.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed UInt64 where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec 64) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec 64) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, UInt64.le_iff_toBitVec_le, ← UInt64.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec 64) _ _ _
|
||||
|
||||
instance : RangeSize .open UInt64 := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open UInt64 := inferInstance
|
||||
|
||||
end UInt64
|
||||
|
||||
namespace USize
|
||||
|
||||
instance : UpwardEnumerable USize where
|
||||
succ? i := if i + 1 = 0 then none else some (i + 1)
|
||||
succMany? n i := if h : i.toNat + n < USize.size then some (.ofNatLT _ h) else none
|
||||
|
||||
theorem succ?_ofBitVec {x : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.succ? (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succ? x := by
|
||||
simp only [succ?, BitVec.ofNat_eq_ofNat, Option.map_eq_map, ← USize.toBitVec_inj]
|
||||
split <;> simp_all
|
||||
|
||||
theorem succMany?_ofBitVec {k : Nat} {x : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.succMany? k (USize.ofBitVec x) = USize.ofBitVec <$> UpwardEnumerable.succMany? k x := by
|
||||
simp [succMany?]
|
||||
|
||||
theorem upwardEnumerableLE_ofBitVec {x y : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.LE (USize.ofBitVec x) (USize.ofBitVec y) ↔ UpwardEnumerable.LE x y := by
|
||||
simp [UpwardEnumerable.LE, succMany?_ofBitVec]
|
||||
|
||||
theorem upwardEnumerableLT_ofBitVec {x y : BitVec System.Platform.numBits} :
|
||||
UpwardEnumerable.LT (USize.ofBitVec x) (USize.ofBitVec y) ↔ UpwardEnumerable.LT x y := by
|
||||
simp [UpwardEnumerable.LT, succMany?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerable USize where
|
||||
ne_of_lt x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLT_ofBitVec] using LawfulUpwardEnumerable.ne_of_lt _ _
|
||||
succMany?_zero x := by
|
||||
cases x
|
||||
simpa [succMany?_ofBitVec] using succMany?_zero
|
||||
succMany?_succ? n x := by
|
||||
cases x
|
||||
simp [succMany?_ofBitVec, succMany?_succ?, Option.bind_map, Function.comp_def,
|
||||
succ?_ofBitVec]
|
||||
|
||||
instance : LawfulUpwardEnumerableLE USize where
|
||||
le_iff x y := by
|
||||
cases x; cases y
|
||||
simpa [upwardEnumerableLE_ofBitVec, USize.le_iff_toBitVec_le] using
|
||||
LawfulUpwardEnumerableLE.le_iff _ _
|
||||
|
||||
instance : LawfulOrderLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLT USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .closed USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .closed USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableLowerBound .open USize := inferInstance
|
||||
instance : LawfulUpwardEnumerableUpperBound .open USize := inferInstance
|
||||
|
||||
instance : RangeSize .closed USize where
|
||||
size bound a := bound.toNat + 1 - a.toNat
|
||||
|
||||
theorem rangeSizeSize_eq_toBitVec {bound : Bound .closed USize} {x : BitVec System.Platform.numBits} :
|
||||
RangeSize.size bound (USize.ofBitVec x) = RangeSize.size (shape := .closed) bound.toBitVec x := by
|
||||
simp [RangeSize.size]
|
||||
|
||||
instance : LawfulRangeSize .closed USize where
|
||||
size_eq_zero_of_not_isSatisfied bound x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.lt_iff_toBitVec_lt] using
|
||||
LawfulRangeSize.size_eq_zero_of_not_isSatisfied (su := .closed) (α := BitVec System.Platform.numBits) _ _
|
||||
size_eq_one_of_succ?_eq_none bound x := by
|
||||
cases x
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, succ?_ofBitVec] using
|
||||
LawfulRangeSize.size_eq_one_of_succ?_eq_none (su := .closed) (α := BitVec System.Platform.numBits) _ _
|
||||
size_eq_succ_of_succ?_eq_some bound init x := by
|
||||
simpa [rangeSizeSize_eq_toBitVec, USize.le_iff_toBitVec_le, ← USize.toBitVec_inj, succ?] using
|
||||
LawfulRangeSize.size_eq_succ_of_succ?_eq_some (su := .closed) (α := BitVec System.Platform.numBits) _ _ _
|
||||
|
||||
instance : RangeSize .open USize := RangeSize.openOfClosed
|
||||
instance : LawfulRangeSize .open USize := inferInstance
|
||||
|
||||
end USize
|
||||
@@ -40,7 +40,6 @@ class UpwardEnumerable (α : Type u) where
|
||||
-/
|
||||
succMany? (n : Nat) (a : α) : Option α := Nat.repeat (· >>= succ?) n (some a)
|
||||
|
||||
attribute [simp] UpwardEnumerable.succ? UpwardEnumerable.succMany?
|
||||
export UpwardEnumerable (succ? succMany?)
|
||||
|
||||
/--
|
||||
@@ -80,7 +79,6 @@ class Least? (α : Type u) where
|
||||
-/
|
||||
least? : Option α
|
||||
|
||||
attribute [simp] Least?.least?
|
||||
export Least? (least?)
|
||||
|
||||
/--
|
||||
@@ -95,7 +93,7 @@ class LawfulUpwardEnumerable (α : Type u) [UpwardEnumerable α] where
|
||||
The `n + 1`-th successor of `a` is the successor of the `n`-th successor, given that said
|
||||
successors actually exist.
|
||||
-/
|
||||
succMany?_succ (n : Nat) (a : α) :
|
||||
succMany?_succ? (n : Nat) (a : α) :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ?
|
||||
|
||||
theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnumerable α] {a : α} :
|
||||
@@ -105,7 +103,7 @@ theorem UpwardEnumerable.succMany?_zero [UpwardEnumerable α] [LawfulUpwardEnume
|
||||
theorem UpwardEnumerable.succMany?_succ? [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
{n : Nat} {a : α} :
|
||||
succMany? (n + 1) a = (succMany? n a).bind succ? :=
|
||||
LawfulUpwardEnumerable.succMany?_succ n a
|
||||
LawfulUpwardEnumerable.succMany?_succ? n a
|
||||
|
||||
@[deprecated succMany?_succ? (since := "2025-09-03")]
|
||||
theorem UpwardEnumerable.succMany?_succ [UpwardEnumerable α] [LawfulUpwardEnumerable α]
|
||||
|
||||
@@ -10,7 +10,7 @@ public import Init.Core
|
||||
public import Init.Data.Slice.Array.Basic
|
||||
import Init.Data.Iterators.Combinators.Attach
|
||||
import Init.Data.Iterators.Combinators.FilterMap
|
||||
import Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Combinators.ULift
|
||||
public import Init.Data.Iterators.Consumers.Collect
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Range.Polymorphic.Basic
|
||||
@@ -31,7 +31,6 @@ open Std Slice PRange Iterators
|
||||
|
||||
variable {shape : RangeShape} {α : Type u}
|
||||
|
||||
@[no_expose]
|
||||
instance {s : Subarray α} : ToIterator s Id α :=
|
||||
.of _
|
||||
(PRange.Internal.iter (s.internalRepresentation.start...<s.internalRepresentation.stop)
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.String.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.String.Decode
|
||||
public import Init.Data.String.Extra
|
||||
public import Init.Data.String.Lemmas
|
||||
public import Init.Data.String.Repr
|
||||
|
||||
@@ -9,11 +9,370 @@ prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.String.Bootstrap
|
||||
public import Init.Data.ByteArray.Basic
|
||||
public import Init.Data.String.Decode
|
||||
import Init.Data.ByteArray.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
universe u
|
||||
|
||||
section
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_nil : List.utf8Encode [] = ByteArray.empty := by simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_singleton {c : Char} : [c].utf8Encode = (String.utf8EncodeChar c).toByteArray := by
|
||||
simp [utf8Encode]
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_append {l l' : List Char} :
|
||||
(l ++ l').utf8Encode = l.utf8Encode ++ l'.utf8Encode := by
|
||||
simp [utf8Encode]
|
||||
|
||||
theorem List.utf8Encode_cons {c : Char} {l : List Char} : (c :: l).utf8Encode = [c].utf8Encode ++ l.utf8Encode := by
|
||||
rw [← singleton_append, List.utf8Encode_append]
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8EncodeChar_ne_nil {c : Char} : String.utf8EncodeChar c ≠ [] := by
|
||||
fun_cases String.utf8EncodeChar with simp
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Encode_eq_empty {l : List Char} : l.utf8Encode = ByteArray.empty ↔ l = [] := by
|
||||
simp [utf8Encode, ← List.eq_nil_iff_forall_not_mem]
|
||||
|
||||
theorem ByteArray.isValidUtf8_utf8Encode {l : List Char} : IsValidUtf8 l.utf8Encode :=
|
||||
.intro l rfl
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.isValidUtf8_empty : IsValidUtf8 ByteArray.empty :=
|
||||
.intro [] (by simp)
|
||||
|
||||
theorem Char.isValidUtf8_toByteArray_utf8EncodeChar {c : Char} :
|
||||
ByteArray.IsValidUtf8 (String.utf8EncodeChar c).toByteArray :=
|
||||
.intro [c] (by simp [List.utf8Encode_singleton])
|
||||
|
||||
theorem ByteArray.IsValidUtf8.append {b b' : ByteArray} (h : IsValidUtf8 b) (h' : IsValidUtf8 b') :
|
||||
IsValidUtf8 (b ++ b') := by
|
||||
rcases h with ⟨m, rfl⟩
|
||||
rcases h' with ⟨m', rfl⟩
|
||||
exact .intro (m ++ m') (by simp)
|
||||
|
||||
theorem ByteArray.isValidUtf8_utf8Encode_singleton_append_iff {b : ByteArray} {c : Char} :
|
||||
IsValidUtf8 ([c].utf8Encode ++ b) ↔ IsValidUtf8 b := by
|
||||
refine ⟨?_, fun h => IsValidUtf8.append isValidUtf8_utf8Encode h⟩
|
||||
rintro ⟨l, hl⟩
|
||||
match l with
|
||||
| [] => simp at hl
|
||||
| d::l =>
|
||||
obtain rfl : c = d := by
|
||||
replace hl := congrArg (fun l => utf8DecodeChar? l 0) hl
|
||||
simpa [List.utf8DecodeChar?_utf8Encode_singleton_append,
|
||||
List.utf8DecodeChar?_utf8Encode_cons] using hl
|
||||
rw [← List.singleton_append (l := l), List.utf8Encode_append,
|
||||
ByteArray.append_right_inj] at hl
|
||||
exact hl ▸ isValidUtf8_utf8Encode
|
||||
|
||||
@[expose]
|
||||
def ByteArray.utf8Decode? (b : ByteArray) : Option (Array Char) :=
|
||||
go (b.size + 1) 0 #[] (by simp) (by simp)
|
||||
where
|
||||
go (fuel : Nat) (i : Nat) (acc : Array Char) (hi : i ≤ b.size) (hf : b.size - i < fuel) : Option (Array Char) :=
|
||||
match fuel, hf with
|
||||
| fuel + 1, _ =>
|
||||
if i = b.size then
|
||||
some acc
|
||||
else
|
||||
match h : utf8DecodeChar? b i with
|
||||
| none => none
|
||||
| some c => go fuel (i + c.utf8Size) (acc.push c)
|
||||
(le_size_of_utf8DecodeChar?_eq_some h)
|
||||
(have := c.utf8Size_pos; have := le_size_of_utf8DecodeChar?_eq_some h; by omega)
|
||||
termination_by structural fuel
|
||||
|
||||
theorem ByteArray.utf8Decode?.go.congr {b b' : ByteArray} {fuel fuel' i i' : Nat} {acc acc' : Array Char} {hi hi' hf hf'}
|
||||
(hbb' : b = b') (hii' : i = i') (hacc : acc = acc') :
|
||||
ByteArray.utf8Decode?.go b fuel i acc hi hf = ByteArray.utf8Decode?.go b' fuel' i' acc' hi' hf' := by
|
||||
subst hbb' hii' hacc
|
||||
fun_induction ByteArray.utf8Decode?.go b fuel i acc hi hf generalizing fuel' with
|
||||
| case1 =>
|
||||
rw [go.eq_def]
|
||||
split
|
||||
simp
|
||||
| case2 =>
|
||||
rw [go.eq_def]
|
||||
split <;> split
|
||||
· simp_all
|
||||
· split <;> simp_all
|
||||
| case3 =>
|
||||
conv => rhs; rw [go.eq_def]
|
||||
split <;> split
|
||||
· simp_all
|
||||
· split
|
||||
· simp_all
|
||||
· rename_i c₁ hc₁ ih _ _ _ _ _ c₂ hc₂
|
||||
obtain rfl : c₁ = c₂ := by rw [← Option.some_inj, ← hc₁, ← hc₂]
|
||||
apply ih
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.utf8Decode?_empty : ByteArray.empty.utf8Decode? = some #[] := by
|
||||
simp [utf8Decode?, utf8Decode?.go]
|
||||
|
||||
private theorem ByteArray.isSome_utf8Decode?go_iff {b : ByteArray} {fuel i : Nat} {hi : i ≤ b.size} {hf} {acc : Array Char} :
|
||||
(ByteArray.utf8Decode?.go b fuel i acc hi hf).isSome ↔ IsValidUtf8 (b.extract i b.size) := by
|
||||
fun_induction ByteArray.utf8Decode?.go with
|
||||
| case1 => simp
|
||||
| case2 fuel i hi hf acc h₁ h₂ =>
|
||||
simp only [Option.isSome_none, Bool.false_eq_true, false_iff]
|
||||
rintro ⟨l, hl⟩
|
||||
have : l ≠ [] := by
|
||||
rintro rfl
|
||||
simp at hl
|
||||
omega
|
||||
rw [← l.cons_head_tail this] at hl
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract, hl, List.utf8DecodeChar?_utf8Encode_cons] at h₂
|
||||
simp at h₂
|
||||
| case3 i acc hi fuel hf h₁ c h₂ ih =>
|
||||
rw [ih]
|
||||
have h₂' := h₂
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂'
|
||||
obtain ⟨l, hl⟩ := exists_of_utf8DecodeChar?_eq_some h₂'
|
||||
rw [ByteArray.extract_eq_extract_append_extract (i := i) (i + c.utf8Size) (by omega)
|
||||
(le_size_of_utf8DecodeChar?_eq_some h₂)] at hl ⊢
|
||||
rw [ByteArray.append_inj_left hl (by have := le_size_of_utf8DecodeChar?_eq_some h₂; simp; omega),
|
||||
← List.utf8Encode_singleton, isValidUtf8_utf8Encode_singleton_append_iff]
|
||||
|
||||
theorem ByteArray.isSome_utf8Decode?_iff {b : ByteArray} :
|
||||
b.utf8Decode?.isSome ↔ IsValidUtf8 b := by
|
||||
rw [utf8Decode?, isSome_utf8Decode?go_iff, extract_zero_size]
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_empty : "".bytes = ByteArray.empty := (rfl)
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
The internal implementation will perform destructive updates if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".append "def" = "abcdef"`
|
||||
* `"abc" ++ "def" = "abcdef"`
|
||||
* `"" ++ "" = ""`
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def String.append (s t : String) : String where
|
||||
bytes := s.bytes ++ t.bytes
|
||||
isValidUtf8 := s.isValidUtf8.append t.isValidUtf8
|
||||
|
||||
instance : Append String where
|
||||
append s t := s.append t
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_append {s t : String} : (s ++ t).bytes = s.bytes ++ t.bytes := (rfl)
|
||||
|
||||
theorem String.bytes_inj {s t : String} : s.bytes = t.bytes ↔ s = t := by
|
||||
refine ⟨fun h => ?_, (· ▸ rfl)⟩
|
||||
rcases s with ⟨s⟩
|
||||
rcases t with ⟨t⟩
|
||||
subst h
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.empty_append {s : String} : "" ++ s = s := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem String.append_empty {s : String} : s ++ "" = s := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp] theorem List.bytes_asString {l : List Char} : l.asString.bytes = l.utf8Encode := by
|
||||
simp [List.asString, String.mk]
|
||||
|
||||
@[simp]
|
||||
theorem List.asString_nil : List.asString [] = "" := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[simp]
|
||||
theorem List.asString_append {l₁ l₂ : List Char} : (l₁ ++ l₂).asString = l₁.asString ++ l₂.asString := by
|
||||
simp [← String.bytes_inj]
|
||||
|
||||
@[expose]
|
||||
def String.Internal.toArray (b : String) : Array Char :=
|
||||
b.bytes.utf8Decode?.get (b.bytes.isSome_utf8Decode?_iff.2 b.isValidUtf8)
|
||||
|
||||
@[simp]
|
||||
theorem String.Internal.toArray_empty : String.Internal.toArray "" = #[] := by
|
||||
simp [toArray]
|
||||
|
||||
@[extern "lean_string_data", expose]
|
||||
def String.data (b : String) : List Char :=
|
||||
(String.Internal.toArray b).toList
|
||||
|
||||
@[simp]
|
||||
theorem String.data_empty : "".data = [] := by
|
||||
simp [data]
|
||||
|
||||
/--
|
||||
Returns the length of a string in Unicode code points.
|
||||
|
||||
Examples:
|
||||
* `"".length = 0`
|
||||
* `"abc".length = 3`
|
||||
* `"L∃∀N".length = 4`
|
||||
-/
|
||||
@[extern "lean_string_length"]
|
||||
def String.length (b : String) : Nat :=
|
||||
b.data.length
|
||||
|
||||
@[simp]
|
||||
theorem String.Internal.size_toArray {b : String} : (String.Internal.toArray b).size = b.length :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem String.length_data {b : String} : b.data.length = b.length := (rfl)
|
||||
|
||||
theorem String.exists_eq_asString (s : String) :
|
||||
∃ l : List Char, s = l.asString := by
|
||||
rcases s with ⟨_, ⟨l, rfl⟩⟩
|
||||
refine ⟨l, by simp [← String.bytes_inj]⟩
|
||||
|
||||
private theorem ByteArray.utf8Decode?go_eq_utf8Decode?go_extract {b : ByteArray} {fuel i : Nat} {hi : i ≤ b.size} {hf} {acc : Array Char} :
|
||||
utf8Decode?.go b fuel i acc hi hf = (utf8Decode?.go (b.extract i b.size) fuel 0 #[] (by simp) (by simp [hf])).map (acc ++ ·) := by
|
||||
fun_cases utf8Decode?.go b fuel i acc hi hf with
|
||||
| case1 =>
|
||||
rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_pos (by omega)]
|
||||
simp
|
||||
| case2 fuel hf₁ h₁ h₂ hf₂ =>
|
||||
rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_neg (by omega)]
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
|
||||
split <;> simp_all
|
||||
| case3 fuel hf₁ h₁ c h₂ hf₂ =>
|
||||
conv => rhs; rw [utf8Decode?.go]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Nat.zero_add, List.push_toArray,
|
||||
List.nil_append]
|
||||
rw [if_neg (by omega)]
|
||||
rw [utf8DecodeChar?_eq_utf8DecodeChar?_extract] at h₂
|
||||
split
|
||||
· simp_all
|
||||
· rename_i c' hc'
|
||||
obtain rfl : c = c' := by
|
||||
rw [← Option.some_inj, ← h₂, hc']
|
||||
have := c.utf8Size_pos
|
||||
conv => lhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
|
||||
conv => rhs; rw [ByteArray.utf8Decode?go_eq_utf8Decode?go_extract]
|
||||
simp only [size_extract, Nat.le_refl, Nat.min_eq_left, Option.map_map, ByteArray.extract_extract]
|
||||
have : (fun x => acc ++ x) ∘ (fun x => #[c] ++ x) = fun x => acc.push c ++ x := by funext; simp
|
||||
simp [(by omega : i + (b.size - i) = b.size), this]
|
||||
|
||||
theorem ByteArray.utf8Decode?_utf8Encode_singleton_append {l : ByteArray} {c : Char} :
|
||||
([c].utf8Encode ++ l).utf8Decode? = l.utf8Decode?.map (#[c] ++ ·) := by
|
||||
rw [utf8Decode?, utf8Decode?.go,
|
||||
if_neg (by simp [List.utf8Encode_singleton]; have := c.utf8Size_pos; omega)]
|
||||
split
|
||||
· simp_all [List.utf8DecodeChar?_utf8Encode_singleton_append]
|
||||
· rename_i d h
|
||||
obtain rfl : c = d := by simpa [List.utf8DecodeChar?_utf8Encode_singleton_append] using h
|
||||
rw [utf8Decode?go_eq_utf8Decode?go_extract, utf8Decode?]
|
||||
simp only [List.push_toArray, List.nil_append, Nat.zero_add]
|
||||
congr 1
|
||||
apply ByteArray.utf8Decode?.go.congr _ rfl rfl
|
||||
apply extract_append_eq_right
|
||||
simp [List.utf8Encode_singleton]
|
||||
|
||||
@[simp]
|
||||
theorem List.utf8Decode?_utf8Encode {l : List Char} :
|
||||
l.utf8Encode.utf8Decode? = some l.toArray := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons c l ih =>
|
||||
rw [← List.singleton_append, List.utf8Encode_append]
|
||||
simp only [ByteArray.utf8Decode?_utf8Encode_singleton_append, cons_append, nil_append,
|
||||
Option.map_eq_some_iff, Array.append_eq_toArray_iff, cons.injEq, true_and]
|
||||
refine ⟨l.toArray, ih, by simp⟩
|
||||
|
||||
@[simp]
|
||||
theorem ByteArray.utf8Encode_get_utf8Decode? {b : ByteArray} {h} :
|
||||
(b.utf8Decode?.get h).toList.utf8Encode = b := by
|
||||
obtain ⟨l, rfl⟩ := isSome_utf8Decode?_iff.1 h
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem List.data_asString {l : List Char} : l.asString.data = l := by
|
||||
simp [String.data, String.Internal.toArray]
|
||||
|
||||
@[simp]
|
||||
theorem String.asString_data {b : String} : b.data.asString = b := by
|
||||
obtain ⟨l, rfl⟩ := String.exists_eq_asString b
|
||||
rw [List.data_asString]
|
||||
|
||||
theorem List.asString_injective {l₁ l₂ : List Char} (h : l₁.asString = l₂.asString) : l₁ = l₂ := by
|
||||
simpa using congrArg String.data h
|
||||
|
||||
theorem List.asString_inj {l₁ l₂ : List Char} : l₁.asString = l₂.asString ↔ l₁ = l₂ :=
|
||||
⟨asString_injective, (· ▸ rfl)⟩
|
||||
|
||||
theorem String.data_injective {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ := by
|
||||
simpa using congrArg List.asString h
|
||||
|
||||
theorem String.data_inj {s₁ s₂ : String} : s₁.data = s₂.data ↔ s₁ = s₂ :=
|
||||
⟨data_injective, (· ▸ rfl)⟩
|
||||
|
||||
@[simp]
|
||||
theorem String.data_append {l₁ l₂ : String} : (l₁ ++ l₂).data = l₁.data ++ l₂.data := by
|
||||
apply List.asString_injective
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8encode_data {b : String} : b.data.utf8Encode = b.bytes := by
|
||||
have := congrArg String.bytes (String.asString_data (b := b))
|
||||
rwa [← List.bytes_asString]
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_empty : "".utf8ByteSize = 0 := (rfl)
|
||||
|
||||
@[simp]
|
||||
theorem String.utf8ByteSize_append {s t : String} :
|
||||
(s ++ t).utf8ByteSize = s.utf8ByteSize + t.utf8ByteSize := by
|
||||
simp [utf8ByteSize]
|
||||
|
||||
@[simp]
|
||||
theorem String.size_bytes {s : String} : s.bytes.size = s.utf8ByteSize := rfl
|
||||
|
||||
@[simp]
|
||||
theorem String.bytes_push {s : String} {c : Char} : (s.push c).bytes = s.bytes ++ [c].utf8Encode := by
|
||||
simp [push]
|
||||
|
||||
-- This is just to keep the proof of `set_next_add` below from breaking; if that lemma goes away
|
||||
-- or the proof is rewritten, it can be removed.
|
||||
private noncomputable def String.utf8ByteSize' : String → Nat
|
||||
| s => go s.data
|
||||
where
|
||||
go : List Char → Nat
|
||||
| [] => 0
|
||||
| c::cs => go cs + c.utf8Size
|
||||
|
||||
private theorem String.utf8ByteSize'_eq (s : String) : s.utf8ByteSize' = s.utf8ByteSize := by
|
||||
suffices ∀ l, utf8ByteSize'.go l = l.asString.utf8ByteSize by
|
||||
obtain ⟨m, rfl⟩ := s.exists_eq_asString
|
||||
rw [utf8ByteSize', this, asString_data]
|
||||
intro l
|
||||
induction l with
|
||||
| nil => simp [utf8ByteSize'.go]
|
||||
| cons c cs ih =>
|
||||
rw [utf8ByteSize'.go, ih, ← List.singleton_append, List.asString_append,
|
||||
utf8ByteSize_append, Nat.add_comm]
|
||||
congr
|
||||
rw [← size_bytes, List.bytes_asString, List.utf8Encode_singleton,
|
||||
List.size_toByteArray, length_utf8EncodeChar]
|
||||
|
||||
end
|
||||
|
||||
namespace String
|
||||
|
||||
instance : HAdd String.Pos String.Pos String.Pos where
|
||||
@@ -54,8 +413,6 @@ instance : LT String :=
|
||||
instance decidableLT (s₁ s₂ : @& String) : Decidable (s₁ < s₂) :=
|
||||
List.decidableLT s₁.data s₂.data
|
||||
|
||||
|
||||
|
||||
/--
|
||||
Non-strict inequality on strings, typically used via the `≤` operator.
|
||||
|
||||
@@ -69,32 +426,6 @@ instance : LE String :=
|
||||
instance decLE (s₁ s₂ : String) : Decidable (s₁ ≤ s₂) :=
|
||||
inferInstanceAs (Decidable (Not _))
|
||||
|
||||
/--
|
||||
Returns the length of a string in Unicode code points.
|
||||
|
||||
Examples:
|
||||
* `"".length = 0`
|
||||
* `"abc".length = 3`
|
||||
* `"L∃∀N".length = 4`
|
||||
-/
|
||||
@[extern "lean_string_length", expose]
|
||||
def length : (@& String) → Nat
|
||||
| ⟨s⟩ => s.length
|
||||
|
||||
/--
|
||||
Appends two strings. Usually accessed via the `++` operator.
|
||||
|
||||
The internal implementation will perform destructive updates if the string is not shared.
|
||||
|
||||
Examples:
|
||||
* `"abc".append "def" = "abcdef"`
|
||||
* `"abc" ++ "def" = "abcdef"`
|
||||
* `"" ++ "" = ""`
|
||||
-/
|
||||
@[extern "lean_string_append", expose]
|
||||
def append : String → (@& String) → String
|
||||
| ⟨a⟩, ⟨b⟩ => ⟨a ++ b⟩
|
||||
|
||||
/--
|
||||
Converts a string to a list of characters.
|
||||
|
||||
@@ -153,8 +484,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_get", expose]
|
||||
def get (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
utf8GetAux s.data 0 p
|
||||
|
||||
def utf8GetAux? : List Char → Pos → Pos → Option Char
|
||||
| [], _, _ => none
|
||||
@@ -175,7 +505,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_get_opt"]
|
||||
def get? : (@& String) → (@& Pos) → Option Char
|
||||
| ⟨s⟩, p => utf8GetAux? s 0 p
|
||||
| s, p => utf8GetAux? s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the character at position `p` of a string. Panics if `p` is not a valid position.
|
||||
@@ -191,7 +521,7 @@ Examples
|
||||
@[extern "lean_string_utf8_get_bang", expose]
|
||||
def get! (s : @& String) (p : @& Pos) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
| s => utf8GetAux s.data 0 p
|
||||
|
||||
def utf8SetAux (c' : Char) : List Char → Pos → Pos → List Char
|
||||
| [], _, _ => []
|
||||
@@ -214,7 +544,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_set"]
|
||||
def set : String → (@& Pos) → Char → String
|
||||
| ⟨s⟩, i, c => ⟨utf8SetAux c s 0 i⟩
|
||||
| s, i, c => (utf8SetAux c s.data 0 i).asString
|
||||
|
||||
/--
|
||||
Replaces the character at position `p` in the string `s` with the result of applying `f` to that
|
||||
@@ -270,7 +600,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_prev", expose]
|
||||
def prev : (@& String) → (@& Pos) → Pos
|
||||
| ⟨s⟩, p => utf8PrevAux s 0 p
|
||||
| s, p => utf8PrevAux s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the first character in `s`. If `s = ""`, returns `(default : Char)`.
|
||||
@@ -336,7 +666,7 @@ Examples:
|
||||
@[extern "lean_string_utf8_get_fast", expose]
|
||||
def get' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Char :=
|
||||
match s with
|
||||
| ⟨s⟩ => utf8GetAux s 0 p
|
||||
| s => utf8GetAux s.data 0 p
|
||||
|
||||
/--
|
||||
Returns the next position in a string after position `p`. The result is unspecified if `p` is not a
|
||||
@@ -360,16 +690,6 @@ def next' (s : @& String) (p : @& Pos) (h : ¬ s.atEnd p) : Pos :=
|
||||
let c := get s p
|
||||
p + c
|
||||
|
||||
theorem _root_.Char.utf8Size_pos (c : Char) : 0 < c.utf8Size := by
|
||||
repeat first | apply iteInduction (motive := (0 < ·)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_le_four (c : Char) : c.utf8Size ≤ 4 := by
|
||||
repeat first | apply iteInduction (motive := (· ≤ 4)) <;> intros | decide
|
||||
|
||||
theorem _root_.Char.utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||
match c.utf8Size, c.utf8Size_pos, c.utf8Size_le_four with
|
||||
| 1, _, _ | 2, _, _ | 3, _, _ | 4, _, _ => simp
|
||||
|
||||
@[deprecated Char.utf8Size_pos (since := "2026-06-04")] abbrev one_le_csize := Char.utf8Size_pos
|
||||
|
||||
@[simp] theorem pos_lt_eq (p₁ p₂ : Pos) : (p₁ < p₂) = (p₁.1 < p₂.1) := rfl
|
||||
@@ -534,7 +854,7 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_utf8_extract", expose]
|
||||
def extract : (@& String) → (@& Pos) → (@& Pos) → String
|
||||
| ⟨s⟩, b, e => if b.byteIdx ≥ e.byteIdx then "" else ⟨go₁ s 0 b e⟩
|
||||
| s, b, e => if b.byteIdx ≥ e.byteIdx then "" else (go₁ s.data 0 b e).asString
|
||||
where
|
||||
go₁ : List Char → Pos → Pos → Pos → List Char
|
||||
| [], _, _, _ => []
|
||||
@@ -1030,37 +1350,31 @@ theorem utf8SetAux_of_gt (c' : Char) : ∀ (cs : List Char) {i p : Pos}, i > p
|
||||
theorem set_next_add (s : String) (i : Pos) (c : Char) (b₁ b₂)
|
||||
(h : (s.next i).1 + b₁ = s.endPos.1 + b₂) :
|
||||
((s.set i c).next i).1 + b₁ = (s.set i c).endPos.1 + b₂ := by
|
||||
simp [next, get, set, endPos, utf8ByteSize] at h ⊢
|
||||
simp [next, get, set, endPos, ← utf8ByteSize'_eq, utf8ByteSize'] at h ⊢
|
||||
rw [Nat.add_comm i.1, Nat.add_assoc] at h ⊢
|
||||
let rec foo : ∀ cs a b₁ b₂,
|
||||
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize.go cs + b₂ →
|
||||
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize.go (utf8SetAux c cs a i) + b₂
|
||||
(utf8GetAux cs a i).utf8Size + b₁ = utf8ByteSize'.go cs + b₂ →
|
||||
(utf8GetAux (utf8SetAux c cs a i) a i).utf8Size + b₁ = utf8ByteSize'.go (utf8SetAux c cs a i) + b₂
|
||||
| [], _, _, _, h => h
|
||||
| c'::cs, a, b₁, b₂, h => by
|
||||
unfold utf8SetAux
|
||||
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize.go] at h ⊢
|
||||
apply iteInduction (motive := fun p => (utf8GetAux p a i).utf8Size + b₁ = utf8ByteSize'.go p + b₂) <;>
|
||||
intro h' <;> simp [utf8GetAux, h', utf8ByteSize'.go] at h ⊢
|
||||
next =>
|
||||
rw [Nat.add_assoc, Nat.add_left_comm] at h ⊢; rw [Nat.add_left_cancel h]
|
||||
next =>
|
||||
rw [Nat.add_assoc] at h ⊢
|
||||
refine foo cs (a + c') b₁ (c'.utf8Size + b₂) h
|
||||
exact foo s.1 0 _ _ h
|
||||
exact foo s.data 0 _ _ h
|
||||
|
||||
theorem mapAux_lemma (s : String) (i : Pos) (c : Char) (h : ¬s.atEnd i) :
|
||||
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 :=
|
||||
(s.set i c).endPos.1 - ((s.set i c).next i).1 < s.endPos.1 - i.1 := by
|
||||
suffices (s.set i c).endPos.1 - ((s.set i c).next i).1 = s.endPos.1 - (s.next i).1 by
|
||||
rw [this]
|
||||
apply Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next ..)
|
||||
Nat.sub.elim (motive := (_ = ·)) _ _
|
||||
(fun _ k e =>
|
||||
have := set_next_add _ _ _ k 0 e.symm
|
||||
Nat.sub_eq_of_eq_add <| this.symm.trans <| Nat.add_comm ..)
|
||||
(fun h => by
|
||||
have ⟨k, e⟩ := Nat.le.dest h
|
||||
rw [Nat.succ_add] at e
|
||||
have : ((s.set i c).next i).1 = _ := set_next_add _ _ c 0 k.succ e.symm
|
||||
exact Nat.sub_eq_zero_of_le (this ▸ Nat.le_add_right ..))
|
||||
have := set_next_add s i c (s.endPos.byteIdx - (s.next i).byteIdx) 0
|
||||
have := set_next_add s i c 0 ((s.next i).byteIdx - s.endPos.byteIdx)
|
||||
omega
|
||||
|
||||
@[specialize] def mapAux (f : Char → Char) (i : Pos) (s : String) : String :=
|
||||
if h : s.atEnd i then s
|
||||
@@ -2044,40 +2358,51 @@ def stripSuffix (s : String) (suff : String) : String :=
|
||||
|
||||
end String
|
||||
|
||||
namespace Char
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := rfl
|
||||
|
||||
end Char
|
||||
|
||||
namespace String
|
||||
|
||||
@[ext]
|
||||
theorem ext {s₁ s₂ : String} (h : s₁.data = s₂.data) : s₁ = s₂ :=
|
||||
show ⟨s₁.data⟩ = (⟨s₂.data⟩ : String) from h ▸ rfl
|
||||
|
||||
theorem ext_iff {s₁ s₂ : String} : s₁ = s₂ ↔ s₁.data = s₂.data := ⟨fun h => h ▸ rfl, ext⟩
|
||||
data_injective h
|
||||
|
||||
@[simp] theorem default_eq : default = "" := rfl
|
||||
|
||||
@[simp] theorem length_mk (s : List Char) : (String.mk s).length = s.length := rfl
|
||||
@[simp]
|
||||
theorem String.mk_eq_asString (s : List Char) : String.mk s = List.asString s := rfl
|
||||
|
||||
@[simp] theorem length_empty : "".length = 0 := rfl
|
||||
@[simp]
|
||||
theorem _root_.List.length_asString (s : List Char) : (List.asString s).length = s.length := by
|
||||
rw [← length_data, List.data_asString]
|
||||
|
||||
@[simp] theorem length_singleton (c : Char) : (String.singleton c).length = 1 := rfl
|
||||
@[simp] theorem length_empty : "".length = 0 := by simp [← length_data, data_empty]
|
||||
|
||||
@[simp]
|
||||
theorem bytes_singleton {c : Char} : (String.singleton c).bytes = [c].utf8Encode := by
|
||||
simp [singleton]
|
||||
|
||||
theorem singleton_eq {c : Char} : String.singleton c = [c].asString := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp] theorem data_singleton (c : Char) : (String.singleton c).data = [c] := by
|
||||
simp [singleton_eq]
|
||||
|
||||
@[simp]
|
||||
theorem length_singleton {c : Char} : (String.singleton c).length = 1 := by
|
||||
simp [← length_data]
|
||||
|
||||
theorem push_eq_append (c : Char) : String.push s c = s ++ singleton c := by
|
||||
simp [← bytes_inj]
|
||||
|
||||
@[simp] theorem data_push (c : Char) : (String.push s c).data = s.data ++ [c] := by
|
||||
simp [push_eq_append]
|
||||
|
||||
@[simp] theorem length_push (c : Char) : (String.push s c).length = s.length + 1 := by
|
||||
rw [push, length_mk, List.length_append, List.length_singleton, Nat.succ.injEq]
|
||||
rfl
|
||||
simp [← length_data]
|
||||
|
||||
@[simp] theorem length_pushn (c : Char) (n : Nat) : (pushn s c n).length = s.length + n := by
|
||||
unfold pushn; induction n <;> simp [Nat.repeat, Nat.add_assoc, *]
|
||||
|
||||
@[simp] theorem length_append (s t : String) : (s ++ t).length = s.length + t.length := by
|
||||
simp only [length, append, List.length_append]
|
||||
|
||||
@[simp] theorem data_push (s : String) (c : Char) : (s.push c).data = s.data ++ [c] := rfl
|
||||
|
||||
@[simp] theorem data_append (s t : String) : (s ++ t).data = s.data ++ t.data := rfl
|
||||
simp [← length_data]
|
||||
|
||||
attribute [simp] toList -- prefer `String.data` over `String.toList` in lemmas
|
||||
|
||||
@@ -2161,10 +2486,8 @@ end Pos
|
||||
theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
|
||||
|
||||
@[simp] theorem prev_zero (s : String) : prev s 0 = 0 := by
|
||||
cases s with | mk cs
|
||||
cases cs
|
||||
next => rfl
|
||||
next => simp [prev, utf8PrevAux, Pos.le_iff]
|
||||
rw [prev]
|
||||
cases s.data <;> simp [utf8PrevAux, Pos.le_iff]
|
||||
|
||||
@[simp] theorem get'_eq (s : String) (p : Pos) (h) : get' s p h = get s p := rfl
|
||||
|
||||
@@ -2174,19 +2497,20 @@ theorem lt_next' (s : String) (p : Pos) : p < next s p := lt_next ..
|
||||
-- so for proving can be unfolded.
|
||||
attribute [simp] toSubstring'
|
||||
|
||||
theorem singleton_eq (c : Char) : singleton c = ⟨[c]⟩ := rfl
|
||||
|
||||
@[simp] theorem data_singleton (c : Char) : (singleton c).data = [c] := rfl
|
||||
|
||||
@[simp] theorem append_empty (s : String) : s ++ "" = s := ext (List.append_nil _)
|
||||
|
||||
@[simp] theorem empty_append (s : String) : "" ++ s = s := rfl
|
||||
|
||||
theorem append_assoc (s₁ s₂ s₃ : String) : (s₁ ++ s₂) ++ s₃ = s₁ ++ (s₂ ++ s₃) :=
|
||||
ext (List.append_assoc ..)
|
||||
ext (by simp [data_append])
|
||||
|
||||
end String
|
||||
|
||||
namespace Char
|
||||
|
||||
theorem toString_eq_singleton {c : Char} : c.toString = String.singleton c := rfl
|
||||
|
||||
@[simp] theorem length_toString (c : Char) : c.toString.length = 1 := by
|
||||
simp [toString_eq_singleton]
|
||||
|
||||
end Char
|
||||
|
||||
open String
|
||||
|
||||
namespace Substring
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.Data.Char.Basic
|
||||
public import Init.Data.ByteArray.Bootstrap
|
||||
|
||||
public section
|
||||
|
||||
@@ -31,7 +32,11 @@ Examples:
|
||||
-/
|
||||
@[extern "lean_string_push", expose]
|
||||
def push : String → Char → String
|
||||
| ⟨s⟩, c => ⟨s ++ [c]⟩
|
||||
| ⟨b, h⟩, c => ⟨b.append (List.utf8Encode [c]), ?pf⟩
|
||||
where finally
|
||||
have ⟨m, hm⟩ := h
|
||||
cases hm
|
||||
exact .intro (m ++ [c]) (by simp [List.utf8Encode, List.toByteArray_append'])
|
||||
|
||||
/--
|
||||
Returns a new string that contains only the character `c`.
|
||||
@@ -124,8 +129,21 @@ Examples:
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
@[extern "lean_string_mk", expose]
|
||||
def String.mk (data : List Char) : String :=
|
||||
⟨List.utf8Encode data,.intro data rfl⟩
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
@[expose]
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
String.mk s
|
||||
|
||||
namespace Substring.Internal
|
||||
|
||||
|
||||
1238
src/Init/Data/String/Decode.lean
Normal file
1238
src/Init/Data/String/Decode.lean
Normal file
File diff suppressed because it is too large
Load Diff
@@ -133,92 +133,15 @@ the corresponding string, or panics if the array is not a valid UTF-8 encoding o
|
||||
@[inline] def fromUTF8! (a : ByteArray) : String :=
|
||||
if h : validateUTF8 a then fromUTF8 a h else panic! "invalid UTF-8 string"
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def utf8EncodeCharFast (c : Char) : List UInt8 :=
|
||||
let v := c.val
|
||||
if v ≤ 0x7f then
|
||||
[v.toUInt8]
|
||||
else if v ≤ 0x7ff then
|
||||
[(v >>> 6).toUInt8 &&& 0x1f ||| 0xc0,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else if v ≤ 0xffff then
|
||||
[(v >>> 12).toUInt8 &&& 0x0f ||| 0xe0,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
else
|
||||
[(v >>> 18).toUInt8 &&& 0x07 ||| 0xf0,
|
||||
(v >>> 12).toUInt8 &&& 0x3f ||| 0x80,
|
||||
(v >>> 6).toUInt8 &&& 0x3f ||| 0x80,
|
||||
v.toUInt8 &&& 0x3f ||| 0x80]
|
||||
|
||||
private theorem Nat.add_two_pow_eq_or_of_lt {b : Nat} (i : Nat) (b_lt : b < 2 ^ i) (a : Nat) :
|
||||
b + 2 ^ i * a = b ||| 2 ^ i * a := by
|
||||
rw [Nat.add_comm, Nat.or_comm, Nat.two_pow_add_eq_or_of_lt b_lt]
|
||||
|
||||
@[csimp]
|
||||
theorem utf8EncodeChar_eq_utf8EncodeCharFast : @utf8EncodeChar = @utf8EncodeCharFast := by
|
||||
funext c
|
||||
simp only [utf8EncodeChar, utf8EncodeCharFast, UInt8.ofNat_uInt32ToNat, UInt8.ofNat_add,
|
||||
UInt8.reduceOfNat, UInt32.le_iff_toNat_le, UInt32.reduceToNat]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 5 (by omega) 6,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 5, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· split
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 4 (by omega) 14,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 4, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_eq_of_lt (b := 256) (by omega)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
· simp only [List.cons.injEq, ← UInt8.toNat_inj, UInt8.toNat_add, UInt8.toNat_ofNat',
|
||||
Nat.reducePow, UInt8.reduceToNat, Nat.mod_add_mod, UInt8.toNat_or, UInt8.toNat_and,
|
||||
UInt32.toNat_toUInt8, UInt32.toNat_shiftRight, UInt32.reduceToNat, Nat.reduceMod, and_true]
|
||||
refine ⟨?_, ?_, ?_, ?_⟩
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 3 (by omega) 30,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 3, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd _ (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 12) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.shiftRight_eq_div_pow,
|
||||
Nat.mod_mod_of_dvd (c.val.toNat / 2 ^ 6) (by decide)]
|
||||
· rw [Nat.mod_eq_of_lt (by omega), Nat.add_two_pow_eq_or_of_lt 6 (by omega) 2,
|
||||
Nat.and_two_pow_sub_one_eq_mod _ 6, Nat.mod_mod_of_dvd c.val.toNat (by decide)]
|
||||
|
||||
@[simp] theorem length_utf8EncodeChar (c : Char) : (utf8EncodeChar c).length = c.utf8Size := by
|
||||
simp [Char.utf8Size, utf8EncodeChar_eq_utf8EncodeCharFast, utf8EncodeCharFast]
|
||||
cases Decidable.em (c.val ≤ 0x7f) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0x7ff) <;> simp [*]
|
||||
cases Decidable.em (c.val ≤ 0xffff) <;> simp [*]
|
||||
|
||||
/--
|
||||
Encodes a string in UTF-8 as an array of bytes.
|
||||
-/
|
||||
@[extern "lean_string_to_utf8"]
|
||||
def toUTF8 (a : @& String) : ByteArray :=
|
||||
⟨⟨a.data.flatMap utf8EncodeChar⟩⟩
|
||||
a.bytes
|
||||
|
||||
@[simp] theorem size_toUTF8 (s : String) : s.toUTF8.size = s.utf8ByteSize := by
|
||||
simp [toUTF8, ByteArray.size, Array.size, utf8ByteSize, List.flatMap]
|
||||
induction s.data <;> simp [List.map, utf8ByteSize.go, Nat.add_comm, *]
|
||||
rfl
|
||||
|
||||
/--
|
||||
Accesses the indicated byte in the UTF-8 encoding of a string.
|
||||
|
||||
@@ -142,9 +142,9 @@ inductive LiftRel (r : α → γ → Prop) (s : β → δ → Prop) : α ⊕ β
|
||||
@[simp, grind =] theorem liftRel_inl_inl : LiftRel r s (inl a) (inl c) ↔ r a c :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inl⟩
|
||||
|
||||
@[simp, grind] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
|
||||
@[simp, grind ←] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
|
||||
|
||||
@[simp, grind] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
|
||||
@[simp, grind ←] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
|
||||
|
||||
@[simp, grind =] theorem liftRel_inr_inr : LiftRel r s (inr b) (inr d) ↔ s b d :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inr⟩
|
||||
@@ -179,7 +179,7 @@ attribute [simp] Lex.sep
|
||||
@[simp, grind =] theorem lex_inr_inr : Lex r s (inr b₁) (inr b₂) ↔ s b₁ b₂ :=
|
||||
⟨fun h => by cases h; assumption, Lex.inr⟩
|
||||
|
||||
@[simp, grind] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
|
||||
@[simp, grind ←] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
|
||||
|
||||
instance instDecidableRelSumLex [DecidableRel r] [DecidableRel s] : DecidableRel (Lex r s)
|
||||
| inl _, inl _ => decidable_of_iff' _ lex_inl_inl
|
||||
|
||||
@@ -1327,3 +1327,14 @@ theorem UInt64.right_le_or {a b : UInt64} : b ≤ a ||| b := by
|
||||
simpa [UInt64.le_iff_toNat_le] using Nat.right_le_or
|
||||
theorem USize.right_le_or {a b : USize} : b ≤ a ||| b := by
|
||||
simpa [USize.le_iff_toNat_le] using Nat.right_le_or
|
||||
|
||||
theorem UInt8.and_lt_add_one {b c : UInt8} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt8.lt_of_le_of_lt UInt8.and_le_right (UInt8.lt_add_one h)
|
||||
theorem UInt16.and_lt_add_one {b c : UInt16} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt16.lt_of_le_of_lt UInt16.and_le_right (UInt16.lt_add_one h)
|
||||
theorem UInt32.and_lt_add_one {b c : UInt32} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt32.lt_of_le_of_lt UInt32.and_le_right (UInt32.lt_add_one h)
|
||||
theorem UInt64.and_lt_add_one {b c : UInt64} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
UInt64.lt_of_le_of_lt UInt64.and_le_right (UInt64.lt_add_one h)
|
||||
theorem USize.and_lt_add_one {b c : USize} (h : c ≠ -1) : b &&& c < c + 1 :=
|
||||
USize.lt_of_le_of_lt USize.and_le_right (USize.lt_add_one h)
|
||||
|
||||
@@ -311,6 +311,13 @@ theorem UInt64.ofNat_mod_size : ofNat (x % 2 ^ 64) = ofNat x := by
|
||||
theorem USize.ofNat_mod_size : ofNat (x % 2 ^ System.Platform.numBits) = ofNat x := by
|
||||
simp [ofNat, BitVec.ofNat, Fin.ofNat]
|
||||
|
||||
theorem UInt8.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt16.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt32.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem UInt64.ofNat_size : ofNat size = 0 := by decide
|
||||
theorem USize.ofNat_size : ofNat size = 0 := by
|
||||
simp [ofNat, BitVec.ofNat, USize.eq_iff_toBitVec_eq]
|
||||
|
||||
theorem UInt8.lt_ofNat_iff {n : UInt8} {m : Nat} (h : m < size) : n < ofNat m ↔ n.toNat < m := by
|
||||
rw [lt_iff_toNat_lt, toNat_ofNat_of_lt' h]
|
||||
theorem UInt8.ofNat_lt_iff {n : UInt8} {m : Nat} (h : m < size) : ofNat m < n ↔ m < n.toNat := by
|
||||
@@ -3156,3 +3163,15 @@ protected theorem USize.sub_lt {a b : USize} (hb : 0 < b) (hab : b ≤ a) : a -
|
||||
rw [lt_iff_toNat_lt, USize.toNat_sub_of_le _ _ hab]
|
||||
refine Nat.sub_lt ?_ (USize.lt_iff_toNat_lt.1 hb)
|
||||
exact USize.lt_iff_toNat_lt.1 (USize.lt_of_lt_of_le hb hab)
|
||||
|
||||
theorem UInt8.lt_add_one {c : UInt8} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt8.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt8.toBitVec_inj] using h))
|
||||
theorem UInt16.lt_add_one {c : UInt16} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt16.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt16.toBitVec_inj] using h))
|
||||
theorem UInt32.lt_add_one {c : UInt32} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt32.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt32.toBitVec_inj] using h))
|
||||
theorem UInt64.lt_add_one {c : UInt64} (h : c ≠ -1) : c < c + 1 :=
|
||||
UInt64.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one (by simpa [← UInt64.toBitVec_inj] using h))
|
||||
theorem USize.lt_add_one {c : USize} (h : c ≠ -1) : c < c + 1 :=
|
||||
USize.lt_iff_toBitVec_lt.2 (BitVec.lt_add_one
|
||||
(by simpa [← USize.toBitVec_inj, BitVec.neg_one_eq_allOnes] using h))
|
||||
|
||||
@@ -193,7 +193,7 @@ theorem attachWith_map_subtype_val {p : α → Prop} {xs : Vector α n} (H : ∀
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind]
|
||||
@[simp, grind ←]
|
||||
theorem mem_attach (xs : Vector α n) : ∀ x, x ∈ xs.attach
|
||||
| ⟨a, h⟩ => by
|
||||
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||
|
||||
@@ -901,10 +901,12 @@ theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a
|
||||
|
||||
/-! ### mem -/
|
||||
|
||||
@[simp, grind] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
@[simp] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] ∈ xs := by
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
grind_pattern getElem_mem => xs[i] ∈ xs
|
||||
|
||||
theorem not_mem_empty (a : α) : ¬ a ∈ #v[] := nofun
|
||||
|
||||
@[simp, grind =] theorem mem_push {xs : Vector α n} {x y : α} : x ∈ xs.push y ↔ x ∈ xs ∨ x = y := by
|
||||
|
||||
@@ -299,10 +299,12 @@ theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) :
|
||||
theorem getElem_cons_succ (a : α) (as : List α) (i : Nat) (h : i + 1 < (a :: as).length) : getElem (a :: as) (i+1) h = getElem as i (Nat.lt_of_succ_lt_succ h) :=
|
||||
rfl
|
||||
|
||||
@[simp, grind] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
@[simp] theorem getElem_mem : ∀ {l : List α} {n} (h : n < l.length), l[n]'h ∈ l
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
grind_pattern getElem_mem => l[n]'h ∈ l
|
||||
|
||||
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
|
||||
@@ -23,3 +23,4 @@ public import Init.Grind.ToIntLemmas
|
||||
public import Init.Grind.Attr
|
||||
public import Init.Data.Int.OfNat -- This may not have otherwise been imported, breaking `grind` proofs.
|
||||
public import Init.Grind.AC
|
||||
public import Init.Grind.Injective
|
||||
|
||||
@@ -10,6 +10,8 @@ public import Init.Core
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.RArray
|
||||
public import Init.Data.Bool
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Lean.Grind.AC
|
||||
@@ -38,7 +40,7 @@ attribute [local simp] Expr.denote_var Expr.denote_op
|
||||
inductive Seq where
|
||||
| var (x : Var)
|
||||
| cons (x : Var) (s : Seq)
|
||||
deriving Inhabited, Repr, BEq
|
||||
deriving Inhabited, Repr, BEq, ReflBEq, LawfulBEq
|
||||
|
||||
-- Kernel version for Seq.beq
|
||||
noncomputable def Seq.beq' (s₁ : Seq) : Seq → Bool :=
|
||||
@@ -55,12 +57,6 @@ theorem Seq.beq'_eq (s₁ s₂ : Seq) : s₁.beq' s₂ = (s₁ = s₂) := by
|
||||
|
||||
attribute [local simp] Seq.beq'_eq
|
||||
|
||||
instance : LawfulBEq Seq where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp! [BEq.beq]
|
||||
next x₁ s₁ ih x₂ s₂ => intro h₁ h₂; simp [h₁, ih h₂]
|
||||
rfl := by intro a; induction a <;> simp! [BEq.beq]; assumption
|
||||
|
||||
noncomputable def Seq.denote {α} (ctx : Context α) (s : Seq) : α :=
|
||||
Seq.rec (fun x => x.denote ctx) (fun x _ ih => ctx.op (x.denote ctx) ih) s
|
||||
|
||||
|
||||
@@ -98,31 +98,45 @@ syntax grindEqBwd := patternIgnore(atomic("←" "=") <|> atomic("<-" "="))
|
||||
The `←` modifier instructs `grind` to select a multi-pattern from the conclusion of theorem.
|
||||
In other words, `grind` will use the theorem for backwards reasoning.
|
||||
This may fail if not all of the arguments to the theorem appear in the conclusion.
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
-/
|
||||
syntax grindBwd := patternIgnore("←" <|> "<-") (grindGen)?
|
||||
/--
|
||||
The `→` modifier instructs `grind` to select a multi-pattern from the hypotheses of the theorem.
|
||||
In other words, `grind` will use the theorem for forwards reasoning.
|
||||
To generate a pattern, it traverses the hypotheses of the theorem from left to right.
|
||||
Each time it encounters a minimal indexable subexpression which covers an argument which was not
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
-/
|
||||
syntax grindFwd := patternIgnore("→" <|> "->")
|
||||
/--
|
||||
The `⇐` modifier instructs `grind` to select a multi-pattern by traversing the conclusion, and then
|
||||
all the hypotheses from right to left.
|
||||
Each time it encounters a minimal indexable subexpression which covers an argument which was not
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
-/
|
||||
syntax grindRL := patternIgnore("⇐" <|> "<=")
|
||||
/--
|
||||
The `⇒` modifier instructs `grind` to select a multi-pattern by traversing all the hypotheses from
|
||||
left to right, followed by the conclusion.
|
||||
Each time it encounters a minimal indexable subexpression which covers an argument which was not
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
-/
|
||||
syntax grindLR := patternIgnore("⇒" <|> "=>")
|
||||
/--
|
||||
The `.` modifier instructs `grind` to select a multi-pattern by traversing the conclusion of the
|
||||
theorem, and then the hypotheses from eft to right. We say this is the default modifier.
|
||||
Each time it encounters a subexpression which covers an argument which was not
|
||||
previously covered, it adds that subexpression as a pattern, until all arguments have been covered.
|
||||
If `grind!` is used, then only minimal indexable subexpressions are considered.
|
||||
-/
|
||||
syntax grindDef := "." (grindGen)?
|
||||
/--
|
||||
The `usr` modifier indicates that this theorem was applied using a
|
||||
**user-defined instantiation pattern**. Such patterns are declared with
|
||||
the `grind_pattern` command, which lets you specify how `grind` should
|
||||
@@ -168,6 +182,12 @@ available extensionality theorems whose matches the type of `a` and `b`.
|
||||
-/
|
||||
syntax grindExt := &"ext"
|
||||
/--
|
||||
The `inj` modifier marks injectivity theorems for use by `grind`.
|
||||
The conclusion of the theorem must be of the form `Function.Injective f`
|
||||
where the term `f` contains at least one constant symbol.
|
||||
-/
|
||||
syntax grindInj := &"inj"
|
||||
/--
|
||||
`symbol <prio>` sets the priority of a constant for `grind`’s pattern-selection
|
||||
procedure. `grind` prefers patterns that contain higher-priority symbols.
|
||||
Example:
|
||||
@@ -193,8 +213,11 @@ syntax grindSym := &"symbol" ppSpace prio
|
||||
syntax grindMod :=
|
||||
grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd
|
||||
<|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager
|
||||
<|> grindCases <|> grindIntro <|> grindExt <|> grindGen <|> grindSym
|
||||
<|> grindCases <|> grindIntro <|> grindExt <|> grindGen <|> grindSym <|> grindInj
|
||||
<|> grindDef
|
||||
syntax (name := grind) "grind" (ppSpace grindMod)? : attr
|
||||
syntax (name := grind!) "grind!" (ppSpace grindMod)? : attr
|
||||
syntax (name := grind?) "grind?" (ppSpace grindMod)? : attr
|
||||
syntax (name := grind!?) "grind!?" (ppSpace grindMod)? : attr
|
||||
end Attr
|
||||
end Lean.Parser
|
||||
|
||||
34
src/Init/Grind/Injective.lean
Normal file
34
src/Init/Grind/Injective.lean
Normal file
@@ -0,0 +1,34 @@
|
||||
/-
|
||||
Copyright (c) 2025 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
|
||||
-/
|
||||
module
|
||||
prelude
|
||||
public import Init.Data.Function
|
||||
public import Init.Classical
|
||||
|
||||
namespace Lean.Grind
|
||||
open Function
|
||||
|
||||
theorem _root_.Function.Injective.leftInverse
|
||||
{α β} (f : α → β) (hf : Injective f) [hα : Nonempty α] :
|
||||
∃ g : β → α, LeftInverse g f := by
|
||||
classical
|
||||
cases hα; next a0 =>
|
||||
let g : β → α := fun b =>
|
||||
if h : ∃ a, f a = b then Classical.choose h else a0
|
||||
exists g
|
||||
intro a
|
||||
have h : ∃ a', f a' = f a := ⟨a, rfl⟩
|
||||
have hfa : f (Classical.choose h) = f a := Classical.choose_spec h
|
||||
have : Classical.choose h = a := hf hfa
|
||||
simp [g, h, this]
|
||||
|
||||
noncomputable def leftInv {α : Sort u} {β : Sort v} (f : α → β) (hf : Injective f) [Nonempty α] : β → α :=
|
||||
Classical.choose (hf.leftInverse f)
|
||||
|
||||
theorem leftInv_eq {α : Sort u} {β : Sort v} (f : α → β) (hf : Injective f) [Nonempty α] (a : α) : leftInv f hf (f a) = a :=
|
||||
Classical.choose_spec (hf.leftInverse f) a
|
||||
|
||||
end Lean.Grind
|
||||
@@ -182,7 +182,7 @@ init_grind_norm
|
||||
Nat.add_eq Nat.sub_eq Nat.mul_eq Nat.zero_eq Nat.le_eq
|
||||
Nat.div_zero Nat.mod_zero Nat.div_one Nat.mod_one
|
||||
Nat.sub_sub Nat.pow_zero Nat.pow_one Nat.sub_self
|
||||
Nat.one_pow Nat.zero_sub
|
||||
Nat.one_pow Nat.zero_sub Nat.sub_zero
|
||||
-- Int
|
||||
Int.lt_eq
|
||||
Int.emod_neg Int.ediv_neg
|
||||
|
||||
@@ -13,6 +13,7 @@ import all Init.Data.Ord.Basic
|
||||
public import Init.Data.AC
|
||||
import all Init.Data.AC
|
||||
public import Init.Data.RArray
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -55,7 +56,7 @@ def Expr.denote {α} [IntModule α] (ctx : Context α) : Expr → α
|
||||
inductive Poly where
|
||||
| nil
|
||||
| add (k : Int) (v : Var) (p : Poly)
|
||||
deriving BEq, Repr
|
||||
deriving BEq, ReflBEq, LawfulBEq, Repr
|
||||
|
||||
def Poly.denote {α} [IntModule α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
@@ -233,18 +234,6 @@ theorem Expr.denote_norm {α} [IntModule α] (ctx : Context α) (e : Expr) : e.n
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go, Poly.denote]
|
||||
|
||||
attribute [local simp] Expr.denote_norm
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next ih =>
|
||||
intro _ _ h
|
||||
exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
|
||||
attribute [local simp] Poly.denote'_eq_denote
|
||||
|
||||
def Poly.leadCoeff (p : Poly) : Int :=
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
meta import Init.Data.String.Basic
|
||||
public meta import Init.Data.String.Basic
|
||||
|
||||
public section
|
||||
|
||||
|
||||
@@ -4,13 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Kim Morrison
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Poly
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ring.Envelope
|
||||
public import Init.Grind.Ring.OfSemiring
|
||||
public import Init.Grind.Ring.CommSolver
|
||||
public import Init.Grind.Ring.CommSemiringAdapter
|
||||
public import Init.Grind.Ring.ToInt
|
||||
|
||||
public section
|
||||
|
||||
@@ -179,6 +179,20 @@ theorem ofNat_mul (a b : Nat) : OfNat.ofNat (α := α) (a * b) = OfNat.ofNat a *
|
||||
theorem natCast_mul (a b : Nat) : ((a * b : Nat) : α) = ((a : α) * (b : α)) := by
|
||||
rw [← ofNat_eq_natCast, ofNat_mul, ofNat_eq_natCast, ofNat_eq_natCast]
|
||||
|
||||
theorem natCast_mul_comm (a : Nat) (b : α) : a * b = b * a := by
|
||||
induction a
|
||||
next => simp [Semiring.natCast_zero, mul_zero, zero_mul]
|
||||
next ih =>
|
||||
rw [Semiring.natCast_succ, Semiring.left_distrib, Semiring.right_distrib, ih]
|
||||
simp [Semiring.mul_one, Semiring.one_mul]
|
||||
|
||||
theorem natCast_mul_left_comm (a : α) (b : Nat) (c : α) : a * (b * c) = b * (a * c) := by
|
||||
induction b
|
||||
next => simp [Semiring.natCast_zero, mul_zero, zero_mul]
|
||||
next ih =>
|
||||
rw [Semiring.natCast_succ, Semiring.right_distrib, Semiring.left_distrib, ih,
|
||||
Semiring.right_distrib, Semiring.one_mul, Semiring.one_mul]
|
||||
|
||||
theorem pow_one (a : α) : a ^ 1 = a := by
|
||||
rw [pow_succ, pow_zero, one_mul]
|
||||
|
||||
@@ -331,6 +345,18 @@ theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :
|
||||
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_mul_aux,
|
||||
intCast_natCast, intCast_natCast]
|
||||
|
||||
theorem intCast_mul_comm (a : Int) (b : α) : a * b = b * a := by
|
||||
have : a = a.natAbs ∨ a = -a.natAbs := by exact Int.natAbs_eq a
|
||||
cases this
|
||||
next h => rw [h, Ring.intCast_natCast, Semiring.natCast_mul_comm]
|
||||
next h => rw [h, Ring.intCast_neg, Ring.intCast_natCast, Ring.mul_neg, Ring.neg_mul, Semiring.natCast_mul_comm]
|
||||
|
||||
theorem intCast_mul_left_comm (a : α) (b : Int) (c : α) : a * (b * c) = b * (a * c) := by
|
||||
have : b = b.natAbs ∨ b = -b.natAbs := by exact Int.natAbs_eq b
|
||||
cases this
|
||||
next h => rw [h, Ring.intCast_natCast, Semiring.natCast_mul_left_comm]
|
||||
next h => rw [h, Ring.intCast_neg, Ring.intCast_natCast, Ring.neg_mul, Ring.neg_mul, Ring.mul_neg, Semiring.natCast_mul_left_comm]
|
||||
|
||||
theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k := by
|
||||
induction k
|
||||
next => simp [pow_zero, Int.pow_zero, intCast_one]
|
||||
|
||||
@@ -4,79 +4,65 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Grind.Ring.Envelope
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.RArray
|
||||
public import Init.Grind.Ring.Poly
|
||||
|
||||
public import Init.Grind.Ring.CommSolver
|
||||
@[expose] public section
|
||||
namespace Lean.Grind
|
||||
namespace CommRing
|
||||
|
||||
namespace Lean.Grind.Ring.OfSemiring
|
||||
/-!
|
||||
Helper definitions and theorems for converting `Semiring` expressions into `Ring` ones.
|
||||
We use them to implement `grind`
|
||||
-/
|
||||
abbrev Var := Nat
|
||||
inductive Expr where
|
||||
| num (v : Nat)
|
||||
| var (i : Var)
|
||||
| add (a b : Expr)
|
||||
| mul (a b : Expr)
|
||||
| pow (a : Expr) (k : Nat)
|
||||
deriving Inhabited, BEq, Hashable
|
||||
def Expr.denoteS {α} [Semiring α] (ctx : Context α) : Expr → α
|
||||
| .num k => OfNat.ofNat (α := α) k.natAbs
|
||||
| .natCast k => OfNat.ofNat (α := α) k
|
||||
| .var v => v.denote ctx
|
||||
| .add a b => denoteS ctx a + denoteS ctx b
|
||||
| .mul a b => denoteS ctx a * denoteS ctx b
|
||||
| .pow a k => denoteS ctx a ^ k
|
||||
| .sub .. | .neg .. | .intCast .. => 0
|
||||
|
||||
abbrev Context (α : Type u) := RArray α
|
||||
def Expr.denoteSAsRing {α} [Semiring α] (ctx : Context α) : Expr → Ring.OfSemiring.Q α
|
||||
| .num k => OfNat.ofNat (α := Ring.OfSemiring.Q α) k.natAbs
|
||||
| .natCast k => OfNat.ofNat (α := Ring.OfSemiring.Q α) k
|
||||
| .var v => Ring.OfSemiring.toQ (v.denote ctx)
|
||||
| .add a b => denoteSAsRing ctx a + denoteSAsRing ctx b
|
||||
| .mul a b => denoteSAsRing ctx a * denoteSAsRing ctx b
|
||||
| .pow a k => denoteSAsRing ctx a ^ k
|
||||
| .sub .. | .neg .. | .intCast .. => 0
|
||||
|
||||
def Var.denote {α} (ctx : Context α) (v : Var) : α :=
|
||||
ctx.get v
|
||||
attribute [local simp] Ring.OfSemiring.toQ_add Ring.OfSemiring.toQ_mul Ring.OfSemiring.toQ_ofNat
|
||||
Ring.OfSemiring.toQ_pow Ring.OfSemiring.toQ_zero in
|
||||
theorem Expr.denoteAsRing_eq {α} [Semiring α] (ctx : Context α) (e : Expr) : e.denoteSAsRing ctx = Ring.OfSemiring.toQ (e.denoteS ctx) := by
|
||||
induction e <;> simp [denoteS, denoteSAsRing, *]
|
||||
|
||||
def Expr.denote {α} [Semiring α] (ctx : Context α) : Expr → α
|
||||
| .num k => OfNat.ofNat (α := α) k
|
||||
| .var v => v.denote ctx
|
||||
| .add a b => denote ctx a + denote ctx b
|
||||
| .mul a b => denote ctx a * denote ctx b
|
||||
| .pow a k => denote ctx a ^ k
|
||||
|
||||
attribute [local instance] ofSemiring
|
||||
|
||||
def Expr.denoteAsRing {α} [Semiring α] (ctx : Context α) : Expr → Q α
|
||||
| .num k => OfNat.ofNat (α := Q α) k
|
||||
| .var v => toQ (v.denote ctx)
|
||||
| .add a b => denoteAsRing ctx a + denoteAsRing ctx b
|
||||
| .mul a b => denoteAsRing ctx a * denoteAsRing ctx b
|
||||
| .pow a k => denoteAsRing ctx a ^ k
|
||||
|
||||
attribute [local simp] toQ_add toQ_mul toQ_ofNat toQ_pow
|
||||
|
||||
theorem Expr.denoteAsRing_eq {α} [Semiring α] (ctx : Context α) (e : Expr) : e.denoteAsRing ctx = toQ (e.denote ctx) := by
|
||||
induction e <;> simp [denote, denoteAsRing, *]
|
||||
|
||||
theorem of_eq {α} [Semiring α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: lhs.denote ctx = rhs.denote ctx → lhs.denoteAsRing ctx = rhs.denoteAsRing ctx := by
|
||||
intro h; replace h := congrArg toQ h
|
||||
simpa [← Expr.denoteAsRing_eq] using h
|
||||
|
||||
theorem of_diseq {α} [Semiring α] [AddRightCancel α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: lhs.denote ctx ≠ rhs.denote ctx → lhs.denoteAsRing ctx ≠ rhs.denoteAsRing ctx := by
|
||||
intro h₁ h₂
|
||||
simp [Expr.denoteAsRing_eq] at h₂
|
||||
replace h₂ := toQ_inj h₂
|
||||
contradiction
|
||||
|
||||
def Expr.toPoly : Expr → CommRing.Poly
|
||||
| .num n => .num n
|
||||
def Expr.toPolyS : Expr → CommRing.Poly
|
||||
| .num n => .num n.natAbs
|
||||
| .var x => CommRing.Poly.ofVar x
|
||||
| .add a b => a.toPoly.combine b.toPoly
|
||||
| .mul a b => a.toPoly.mul b.toPoly
|
||||
| .add a b => a.toPolyS.combine b.toPolyS
|
||||
| .mul a b => a.toPolyS.mul b.toPolyS
|
||||
| .pow a k =>
|
||||
match a with
|
||||
| .num n => .num (n^k)
|
||||
| .num n => .num (n.natAbs ^ k)
|
||||
| .var x => CommRing.Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly.pow k
|
||||
| _ => a.toPolyS.pow k
|
||||
| .natCast n => .num n
|
||||
| .sub .. | .neg .. | .intCast .. => .num 0
|
||||
|
||||
end Ring.OfSemiring
|
||||
def Expr.toPolyS_nc : Expr → CommRing.Poly
|
||||
| .num n => .num n.natAbs
|
||||
| .var x => CommRing.Poly.ofVar x
|
||||
| .add a b => a.toPolyS_nc.combine b.toPolyS_nc
|
||||
| .mul a b => a.toPolyS_nc.mul_nc b.toPolyS_nc
|
||||
| .pow a k =>
|
||||
match a with
|
||||
| .num n => .num (n.natAbs ^ k)
|
||||
| .var x => CommRing.Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPolyS_nc.pow_nc k
|
||||
| .natCast n => .num n
|
||||
| .sub .. | .neg .. | .intCast .. => .num 0
|
||||
|
||||
end CommRing
|
||||
|
||||
namespace CommRing
|
||||
attribute [local instance] Semiring.natCast Ring.intCast
|
||||
@@ -109,15 +95,15 @@ def Poly.denoteS [Semiring α] (ctx : Context α) (p : Poly) : α :=
|
||||
|
||||
attribute [local simp] natCast_one natCast_zero zero_mul mul_zero one_mul mul_one add_zero zero_add denoteSInt_eq
|
||||
|
||||
theorem Poly.denoteS_ofMon {α} [CommSemiring α] (ctx : Context α) (m : Mon)
|
||||
theorem Poly.denoteS_ofMon {α} [Semiring α] (ctx : Context α) (m : Mon)
|
||||
: denoteS ctx (ofMon m) = m.denote ctx := by
|
||||
simp [ofMon, denoteS]
|
||||
|
||||
theorem Poly.denoteS_ofVar {α} [CommSemiring α] (ctx : Context α) (x : Var)
|
||||
theorem Poly.denoteS_ofVar {α} [Semiring α] (ctx : Context α) (x : Var)
|
||||
: denoteS ctx (ofVar x) = x.denote ctx := by
|
||||
simp [ofVar, denoteS_ofMon, Mon.denote_ofVar]
|
||||
|
||||
theorem Poly.denoteS_addConst {α} [CommSemiring α] (ctx : Context α) (p : Poly) (k : Int)
|
||||
theorem Poly.denoteS_addConst {α} [Semiring α] (ctx : Context α) (p : Poly) (k : Int)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (addConst p k).denoteS ctx = p.denoteS ctx + k.toNat := by
|
||||
simp [addConst, cond_eq_if]; split
|
||||
next => subst k; simp
|
||||
@@ -130,7 +116,7 @@ theorem Poly.denoteS_addConst {α} [CommSemiring α] (ctx : Context α) (p : Pol
|
||||
intro _ h; cases h
|
||||
next h₁ h₂ => simp [*, add_assoc]
|
||||
|
||||
theorem Poly.denoteS_insert {α} [CommSemiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
theorem Poly.denoteS_insert {α} [Semiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (insert k m p).denoteS ctx = k.toNat * m.denote ctx + p.denoteS ctx := by
|
||||
simp [insert, cond_eq_if] <;> split
|
||||
next => simp [*]
|
||||
@@ -157,13 +143,13 @@ theorem Poly.denoteS_insert {α} [CommSemiring α] (ctx : Context α) (k : Int)
|
||||
intro hk hn; cases hn; rename_i hn₁ hn₂
|
||||
rw [ih hk hn₂, add_left_comm]
|
||||
|
||||
theorem Poly.denoteS_concat {α} [CommSemiring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denoteS_concat {α} [Semiring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (concat p₁ p₂).denoteS ctx = p₁.denoteS ctx + p₂.denoteS ctx := by
|
||||
fun_induction concat <;> intro h₁ h₂; simp [*, denoteS]
|
||||
next => cases h₁; rw [add_comm, denoteS_addConst] <;> assumption
|
||||
next ih => cases h₁; next hn₁ hn₂ => rw [denoteS, denoteS, ih hn₂ h₂, add_assoc]
|
||||
|
||||
theorem Poly.denoteS_mulConst {α} [CommSemiring α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
theorem Poly.denoteS_mulConst {α} [Semiring α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (mulConst k p).denoteS ctx = k.toNat * p.denoteS ctx := by
|
||||
simp [mulConst, cond_eq_if] <;> split
|
||||
next => simp [denoteS, *, zero_mul]
|
||||
@@ -177,30 +163,7 @@ theorem Poly.denoteS_mulConst {α} [CommSemiring α] (ctx : Context α) (k : Int
|
||||
intro h₁ h₂; cases h₂; rename_i h₂ h₃
|
||||
rw [Int.toNat_mul, natCast_mul, left_distrib, mul_assoc, ih h₁ h₃] <;> assumption
|
||||
|
||||
theorem Poly.denoteS_mulMon {α} [CommSemiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (mulMon k m p).denoteS ctx = k.toNat * m.denote ctx * p.denoteS ctx := by
|
||||
simp [mulMon, cond_eq_if] <;> split
|
||||
next => simp [denoteS, *]
|
||||
next =>
|
||||
split
|
||||
next h =>
|
||||
intro h₁ h₂
|
||||
simp at h; simp [*, Mon.denote, denoteS_mulConst _ _ _ h₁ h₂]
|
||||
next =>
|
||||
fun_induction mulMon.go <;> simp [denoteS, *]
|
||||
next h => simp +zetaDelta at h; simp [*]
|
||||
next =>
|
||||
intro h₁ h₂; cases h₂
|
||||
rw [Int.toNat_mul]
|
||||
simp [natCast_mul, CommSemiring.mul_comm, CommSemiring.mul_left_comm, mul_assoc]
|
||||
assumption; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₂; rename_i h₂ h₃
|
||||
rw [Int.toNat_mul]
|
||||
simp [Mon.denote_mul, natCast_mul, left_distrib, CommSemiring.mul_left_comm, mul_assoc, ih h₁ h₃]
|
||||
assumption; assumption
|
||||
|
||||
theorem Poly.denoteS_combine {α} [CommSemiring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denoteS_combine {α} [Semiring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (combine p₁ p₂).denoteS ctx = p₁.denoteS ctx + p₂.denoteS ctx := by
|
||||
unfold combine; generalize hugeFuel = fuel
|
||||
fun_induction combine.go
|
||||
@@ -233,6 +196,93 @@ theorem Poly.denoteS_combine {α} [CommSemiring α] (ctx : Context α) (p₁ p
|
||||
rename_i h₂
|
||||
simp [denoteS, ih h₁ h₂, add_left_comm, add_assoc]
|
||||
|
||||
theorem Poly.denoteS_mulMon {α} [CommSemiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (mulMon k m p).denoteS ctx = k.toNat * m.denote ctx * p.denoteS ctx := by
|
||||
simp [mulMon, cond_eq_if] <;> split
|
||||
next => simp [denoteS, *]
|
||||
next =>
|
||||
split
|
||||
next h =>
|
||||
intro h₁ h₂
|
||||
simp at h; simp [*, Mon.denote, denoteS_mulConst _ _ _ h₁ h₂]
|
||||
next =>
|
||||
fun_induction mulMon.go <;> simp [denoteS, *]
|
||||
next h => simp +zetaDelta at h; simp [*]
|
||||
next =>
|
||||
intro h₁ h₂; cases h₂
|
||||
rw [Int.toNat_mul]
|
||||
simp [natCast_mul, CommSemiring.mul_comm, CommSemiring.mul_left_comm, mul_assoc]
|
||||
assumption; assumption
|
||||
next ih =>
|
||||
intro h₁ h₂; cases h₂; rename_i h₂ h₃
|
||||
rw [Int.toNat_mul]
|
||||
simp [Mon.denote_mul, natCast_mul, left_distrib, CommSemiring.mul_left_comm, mul_assoc, ih h₁ h₃]
|
||||
assumption; assumption
|
||||
|
||||
theorem Poly.addConst_NonnegCoeffs {p : Poly} {k : Int} : k ≥ 0 → p.NonnegCoeffs → (p.addConst k).NonnegCoeffs := by
|
||||
simp [addConst, cond_eq_if]; split
|
||||
next => intros; assumption
|
||||
fun_induction addConst.go
|
||||
next h _ => intro _ h; cases h; constructor; apply Int.add_nonneg <;> assumption
|
||||
next ih => intro h₁ h₂; cases h₂; constructor; assumption; apply ih <;> assumption
|
||||
|
||||
theorem Poly.insert_Nonneg (k : Int) (m : Mon) (p : Poly) : k ≥ 0 → p.NonnegCoeffs → (p.insert k m).NonnegCoeffs := by
|
||||
intro h₁ h₂
|
||||
fun_cases Poly.insert
|
||||
next => assumption
|
||||
next => apply Poly.addConst_NonnegCoeffs <;> assumption
|
||||
next =>
|
||||
fun_induction Poly.insert.go
|
||||
next => constructor <;> assumption
|
||||
next => cases h₂; assumption
|
||||
next => simp +zetaDelta; cases h₂; constructor; omega; assumption
|
||||
next => constructor <;> assumption
|
||||
next ih =>
|
||||
cases h₂; constructor
|
||||
next => assumption
|
||||
next => apply ih; assumption
|
||||
|
||||
theorem Poly.denoteS_mulMon_nc_go {α} [Semiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly) (acc : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → acc.NonnegCoeffs
|
||||
→ (mulMon_nc.go k m p acc).denoteS ctx = k.toNat * m.denote ctx * p.denoteS ctx + acc.denoteS ctx := by
|
||||
fun_induction mulMon_nc.go with simp [*]
|
||||
| case1 acc k' =>
|
||||
intro h₁ h₂ h₃; cases h₂
|
||||
have : k * k' ≥ 0 := by apply Int.mul_nonneg <;> assumption
|
||||
simp [denoteS_insert, denoteS, Int.toNat_mul, Semiring.natCast_mul, Semiring.mul_assoc, *]
|
||||
rw [← Semiring.natCast_mul_comm]
|
||||
| case2 acc k' m' p ih =>
|
||||
intro h₁ h₂ h₃; rcases h₂
|
||||
next _ h₂ =>
|
||||
have : k * k' ≥ 0 := by apply Int.mul_nonneg <;> assumption
|
||||
have : (insert (k * k') (m.mul_nc m') acc).NonnegCoeffs := by apply Poly.insert_Nonneg <;> assumption
|
||||
rw [ih h₁ h₂ this]
|
||||
simp [denoteS_insert, Int.toNat_mul, Semiring.natCast_mul, denoteS, left_distrib, Mon.denote_mul_nc, *]
|
||||
simp only [← Semiring.add_assoc]
|
||||
congr 1
|
||||
rw [Semiring.add_comm]
|
||||
congr 1
|
||||
rw [Semiring.natCast_mul_left_comm]
|
||||
conv => enter [1, 1]; rw [Semiring.natCast_mul_comm]
|
||||
simp [Semiring.mul_assoc]
|
||||
|
||||
theorem Poly.num_zero_NonnegCoeffs : (num 0).NonnegCoeffs := by
|
||||
apply NonnegCoeffs.num; simp
|
||||
|
||||
theorem Poly.denoteS_mulMon_nc {α} [Semiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: k ≥ 0 → p.NonnegCoeffs → (mulMon_nc k m p).denoteS ctx = k.toNat * m.denote ctx * p.denoteS ctx := by
|
||||
simp [mulMon_nc, cond_eq_if] <;> split
|
||||
next => simp [denoteS, *]
|
||||
next =>
|
||||
split
|
||||
next h =>
|
||||
intro h₁ h₂
|
||||
simp at h; simp [*, Mon.denote, denoteS_mulConst _ _ _ h₁ h₂]
|
||||
next =>
|
||||
intro h₁ h₂
|
||||
have := Poly.denoteS_mulMon_nc_go ctx k m p (.num 0) h₁ h₂ Poly.num_zero_NonnegCoeffs
|
||||
simp [this, denoteS]
|
||||
|
||||
theorem Poly.mulConst_NonnegCoeffs {p : Poly} {k : Int} : k ≥ 0 → p.NonnegCoeffs → (p.mulConst k).NonnegCoeffs := by
|
||||
simp [mulConst, cond_eq_if]; split
|
||||
next => intros; constructor; decide
|
||||
@@ -259,12 +309,29 @@ theorem Poly.mulMon_NonnegCoeffs {p : Poly} {k : Int} (m : Mon) : k ≥ 0 → p.
|
||||
apply Int.mul_nonneg <;> assumption
|
||||
apply ih <;> assumption
|
||||
|
||||
theorem Poly.addConst_NonnegCoeffs {p : Poly} {k : Int} : k ≥ 0 → p.NonnegCoeffs → (p.addConst k).NonnegCoeffs := by
|
||||
simp [addConst, cond_eq_if]; split
|
||||
next => intros; assumption
|
||||
fun_induction addConst.go
|
||||
next h _ => intro _ h; cases h; constructor; apply Int.add_nonneg <;> assumption
|
||||
next ih => intro h₁ h₂; cases h₂; constructor; assumption; apply ih <;> assumption
|
||||
theorem Poly.mulMon_nc_go_NonnegCoeffs {p : Poly} {k : Int} (m : Mon) {acc : Poly}
|
||||
: k ≥ 0 → p.NonnegCoeffs → acc.NonnegCoeffs → (Poly.mulMon_nc.go k m p acc).NonnegCoeffs := by
|
||||
intro h₁ h₂ h₃
|
||||
fun_induction Poly.mulMon_nc.go
|
||||
next k' =>
|
||||
cases h₂
|
||||
have : k*k' ≥ 0 := by apply Int.mul_nonneg <;> assumption
|
||||
apply Poly.insert_Nonneg <;> assumption
|
||||
next ih =>
|
||||
cases h₂; next h₂ =>
|
||||
apply ih; assumption
|
||||
apply insert_Nonneg
|
||||
next => apply Int.mul_nonneg <;> assumption
|
||||
next => assumption
|
||||
|
||||
theorem Poly.mulMon_nc_NonnegCoeffs {p : Poly} {k : Int} (m : Mon) : k ≥ 0 → p.NonnegCoeffs → (p.mulMon_nc k m).NonnegCoeffs := by
|
||||
simp [mulMon_nc, cond_eq_if]; split
|
||||
next => intros; constructor; decide
|
||||
split
|
||||
next => intros; apply mulConst_NonnegCoeffs <;> assumption
|
||||
intro h₁ h₂
|
||||
apply Poly.mulMon_nc_go_NonnegCoeffs; assumption; assumption
|
||||
exact Poly.num_zero_NonnegCoeffs
|
||||
|
||||
theorem Poly.concat_NonnegCoeffs {p₁ p₂ : Poly} : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.concat p₂).NonnegCoeffs := by
|
||||
fun_induction Poly.concat
|
||||
@@ -312,14 +379,40 @@ theorem Poly.mul_NonnegCoeffs {p₁ p₂ : Poly} : p₁.NonnegCoeffs → p₂.No
|
||||
unfold mul; intros; apply mul_go_NonnegCoeffs
|
||||
assumption; assumption; constructor; decide
|
||||
|
||||
theorem Poly.mul_nc_go_NonnegCoeffs (p₁ p₂ acc : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → acc.NonnegCoeffs → (mul_nc.go p₂ p₁ acc).NonnegCoeffs := by
|
||||
fun_induction mul_nc.go
|
||||
next =>
|
||||
intro h₁ h₂ h₃
|
||||
cases h₁; rename_i h₁
|
||||
have := mulConst_NonnegCoeffs h₁ h₂
|
||||
apply combine_NonnegCoeffs <;> assumption
|
||||
next ih =>
|
||||
intro h₁ h₂ h₃
|
||||
cases h₁
|
||||
apply ih
|
||||
assumption; assumption
|
||||
apply Poly.combine_NonnegCoeffs; assumption
|
||||
apply Poly.mulMon_nc_NonnegCoeffs <;> assumption
|
||||
|
||||
theorem Poly.mul_nc_NonnegCoeffs {p₁ p₂ : Poly} : p₁.NonnegCoeffs → p₂.NonnegCoeffs → (p₁.mul_nc p₂).NonnegCoeffs := by
|
||||
unfold mul_nc; intros; apply mul_nc_go_NonnegCoeffs
|
||||
assumption; assumption; constructor; decide
|
||||
|
||||
theorem Poly.pow_NonnegCoeffs {p : Poly} (k : Nat) : p.NonnegCoeffs → (p.pow k).NonnegCoeffs := by
|
||||
fun_induction Poly.pow
|
||||
next => intros; constructor; decide
|
||||
next => intros; assumption
|
||||
next ih => intro h; apply mul_NonnegCoeffs; assumption; apply ih; assumption
|
||||
|
||||
theorem Poly.num_zero_NonnegCoeffs : (num 0).NonnegCoeffs := by
|
||||
apply NonnegCoeffs.num; simp
|
||||
theorem Poly.pow_nc_NonnegCoeffs {p : Poly} (k : Nat) : p.NonnegCoeffs → (p.pow_nc k).NonnegCoeffs := by
|
||||
fun_induction Poly.pow_nc
|
||||
next => intros; constructor; decide
|
||||
next => intros; assumption
|
||||
next ih =>
|
||||
intro h; apply mul_nc_NonnegCoeffs
|
||||
next => apply ih; assumption
|
||||
next => assumption
|
||||
|
||||
theorem Poly.denoteS_mul_go {α} [CommSemiring α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → acc.NonnegCoeffs → (mul.go p₂ p₁ acc).denoteS ctx = acc.denoteS ctx + p₁.denoteS ctx * p₂.denoteS ctx := by
|
||||
@@ -342,6 +435,27 @@ theorem Poly.denoteS_mul {α} [CommSemiring α] (ctx : Context α) (p₁ p₂ :
|
||||
intro h₁ h₂
|
||||
simp [mul, denoteS_mul_go, denoteS, Poly.num_zero_NonnegCoeffs, *]
|
||||
|
||||
theorem Poly.denoteS_mul_nc_go {α} [Semiring α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → acc.NonnegCoeffs → (mul_nc.go p₂ p₁ acc).denoteS ctx = acc.denoteS ctx + p₁.denoteS ctx * p₂.denoteS ctx := by
|
||||
fun_induction mul_nc.go <;> intro h₁ h₂ h₃
|
||||
next k =>
|
||||
cases h₁; rename_i h₁
|
||||
have := p₂.mulConst_NonnegCoeffs h₁ h₂
|
||||
simp [denoteS, denoteS_combine, denoteS_mulConst, *]
|
||||
next acc a m p ih =>
|
||||
cases h₁; rename_i h₁ h₁'
|
||||
have := p₂.mulMon_nc_NonnegCoeffs m h₁ h₂
|
||||
have := acc.combine_NonnegCoeffs h₃ this
|
||||
replace ih := ih h₁' h₂ this
|
||||
rw [ih, denoteS_combine, denoteS_mulMon_nc]
|
||||
simp [denoteS, add_assoc, right_distrib]
|
||||
all_goals assumption
|
||||
|
||||
theorem Poly.denoteS_mul_nc {α} [Semiring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: p₁.NonnegCoeffs → p₂.NonnegCoeffs → (mul_nc p₁ p₂).denoteS ctx = p₁.denoteS ctx * p₂.denoteS ctx := by
|
||||
intro h₁ h₂
|
||||
simp [mul_nc, denoteS_mul_nc_go, denoteS, Poly.num_zero_NonnegCoeffs, *]
|
||||
|
||||
theorem Poly.denoteS_pow {α} [CommSemiring α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: p.NonnegCoeffs → (pow p k).denoteS ctx = p.denoteS ctx ^ k := by
|
||||
fun_induction pow <;> intro h₁
|
||||
@@ -353,13 +467,19 @@ theorem Poly.denoteS_pow {α} [CommSemiring α] (ctx : Context α) (p : Poly) (k
|
||||
assumption
|
||||
apply Poly.pow_NonnegCoeffs; assumption
|
||||
|
||||
end CommRing
|
||||
theorem Poly.denoteS_pow_nc {α} [Semiring α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: p.NonnegCoeffs → (pow_nc p k).denoteS ctx = p.denoteS ctx ^ k := by
|
||||
fun_induction pow_nc <;> intro h₁
|
||||
next => simp [denoteS, pow_zero]
|
||||
next => simp [pow_succ, pow_zero]
|
||||
next ih =>
|
||||
replace ih := ih h₁
|
||||
rw [denoteS_mul_nc, ih, pow_succ]
|
||||
apply Poly.pow_nc_NonnegCoeffs; assumption
|
||||
assumption
|
||||
|
||||
namespace Ring.OfSemiring
|
||||
open CommRing
|
||||
|
||||
theorem Expr.toPoly_NonnegCoeffs {e : Expr} : e.toPoly.NonnegCoeffs := by
|
||||
fun_induction toPoly
|
||||
theorem Expr.toPolyS_NonnegCoeffs {e : Expr} : e.toPolyS.NonnegCoeffs := by
|
||||
fun_induction toPolyS
|
||||
next => constructor; apply Int.natCast_nonneg
|
||||
next => simp [Poly.ofVar, Poly.ofMon]; constructor; decide; constructor; decide
|
||||
next => apply Poly.combine_NonnegCoeffs <;> assumption
|
||||
@@ -367,29 +487,89 @@ theorem Expr.toPoly_NonnegCoeffs {e : Expr} : e.toPoly.NonnegCoeffs := by
|
||||
next => constructor; apply Int.pow_nonneg; apply Int.natCast_nonneg
|
||||
next => constructor; decide; constructor; decide
|
||||
next => apply Poly.pow_NonnegCoeffs; assumption
|
||||
next => constructor; apply Int.ofNat_zero_le
|
||||
all_goals exact Poly.num_zero_NonnegCoeffs
|
||||
|
||||
theorem Expr.denoteS_toPoly {α} [CommSemiring α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly.denoteS ctx = e.denote ctx := by
|
||||
fun_induction toPoly
|
||||
<;> simp [denote, Poly.denoteS, Poly.denoteS_ofVar, denoteSInt_eq, Semiring.ofNat_eq_natCast]
|
||||
next => simp [CommRing.Var.denote, Var.denote]
|
||||
next ih₁ ih₂ => rw [Poly.denoteS_combine, ih₁, ih₂] <;> apply toPoly_NonnegCoeffs
|
||||
next ih₁ ih₂ => rw [Poly.denoteS_mul, ih₁, ih₂] <;> apply toPoly_NonnegCoeffs
|
||||
next => rw [Int.toNat_pow_of_nonneg, Semiring.natCast_pow, Int.toNat_natCast]; apply Int.natCast_nonneg
|
||||
next =>
|
||||
simp [Poly.ofMon, Poly.denoteS, denoteSInt_eq, Power.denote_eq, Mon.denote,
|
||||
Semiring.natCast_zero, Semiring.natCast_one, Semiring.one_mul, Semiring.add_zero,
|
||||
CommRing.Var.denote, Var.denote, Semiring.mul_one]
|
||||
next ih => rw [Poly.denoteS_pow, ih]; apply toPoly_NonnegCoeffs
|
||||
attribute [local simp] Expr.toPolyS_NonnegCoeffs
|
||||
|
||||
theorem Expr.toPolyS_nc_NonnegCoeffs {e : Expr} : e.toPolyS_nc.NonnegCoeffs := by
|
||||
fun_induction toPolyS_nc
|
||||
next => constructor; apply Int.natCast_nonneg
|
||||
next => simp [Poly.ofVar, Poly.ofMon]; constructor; decide; constructor; decide
|
||||
next => apply Poly.combine_NonnegCoeffs <;> assumption
|
||||
next => apply Poly.mul_nc_NonnegCoeffs <;> assumption
|
||||
next => constructor; apply Int.pow_nonneg; apply Int.natCast_nonneg
|
||||
next => constructor; decide; constructor; decide
|
||||
next => apply Poly.pow_nc_NonnegCoeffs; assumption
|
||||
next => constructor; apply Int.ofNat_zero_le
|
||||
all_goals exact Poly.num_zero_NonnegCoeffs
|
||||
|
||||
attribute [local simp] Expr.toPolyS_nc_NonnegCoeffs
|
||||
|
||||
theorem Expr.denoteS_toPolyS {α} [CommSemiring α] (ctx : Context α) (e : Expr)
|
||||
: e.toPolyS.denoteS ctx = e.denoteS ctx := by
|
||||
fun_induction toPolyS <;> simp [denoteS, Poly.denoteS, Poly.denoteS_ofVar, denoteSInt_eq]
|
||||
next => simp [Semiring.ofNat_eq_natCast]
|
||||
next => simp [Poly.denoteS_combine] <;> simp [*]
|
||||
next => simp [Poly.denoteS_mul] <;> simp [*]
|
||||
next => rw [Int.toNat_pow_of_nonneg, Semiring.natCast_pow, Int.toNat_natCast, ← Semiring.ofNat_eq_natCast]
|
||||
apply Int.natCast_nonneg
|
||||
next => simp [Poly.ofMon, Poly.denoteS, denoteSInt_eq, Power.denote_eq, Mon.denote,
|
||||
Semiring.natCast_zero, Semiring.natCast_one, Semiring.one_mul,
|
||||
CommRing.Var.denote, Var.denote, Semiring.mul_one]
|
||||
next ih => rw [Poly.denoteS_pow, ih]; apply toPolyS_NonnegCoeffs
|
||||
next => simp [Semiring.natCast_eq_ofNat]
|
||||
|
||||
theorem Expr.denoteS_toPolyS_nc {α} [Semiring α] (ctx : Context α) (e : Expr)
|
||||
: e.toPolyS_nc.denoteS ctx = e.denoteS ctx := by
|
||||
fun_induction Expr.toPolyS_nc <;> simp [denoteS, Poly.denoteS, Poly.denoteS_ofVar, denoteSInt_eq]
|
||||
next => simp [Semiring.ofNat_eq_natCast]
|
||||
next => simp [Poly.denoteS_combine] <;> simp [*]
|
||||
next => simp [Poly.denoteS_mul_nc] <;> simp [*]
|
||||
next => rw [Int.toNat_pow_of_nonneg, Semiring.natCast_pow, Int.toNat_natCast, ← Semiring.ofNat_eq_natCast]
|
||||
apply Int.natCast_nonneg
|
||||
next => simp [Poly.ofMon, Poly.denoteS, denoteSInt_eq, Power.denote_eq, Mon.denote,
|
||||
Semiring.natCast_zero, Semiring.natCast_one, Semiring.one_mul,
|
||||
CommRing.Var.denote, Var.denote, Semiring.mul_one]
|
||||
next ih => rw [Poly.denoteS_pow_nc, ih]; apply toPolyS_nc_NonnegCoeffs
|
||||
next => simp [Semiring.natCast_eq_ofNat]
|
||||
|
||||
def eq_normS_cert (lhs rhs : Expr) : Bool :=
|
||||
lhs.toPoly == rhs.toPoly
|
||||
lhs.toPolyS == rhs.toPolyS
|
||||
|
||||
theorem eq_normS {α} [CommSemiring α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: eq_normS_cert lhs rhs → lhs.denote ctx = rhs.denote ctx := by
|
||||
: eq_normS_cert lhs rhs → lhs.denoteS ctx = rhs.denoteS ctx := by
|
||||
simp [eq_normS_cert]; intro h
|
||||
replace h := congrArg (Poly.denoteS ctx) h
|
||||
simp [Expr.denoteS_toPoly, *] at h
|
||||
simp [Expr.denoteS_toPolyS, *] at h
|
||||
assumption
|
||||
|
||||
end Lean.Grind.Ring.OfSemiring
|
||||
def eq_normS_nc_cert (lhs rhs : Expr) : Bool :=
|
||||
lhs.toPolyS_nc == rhs.toPolyS_nc
|
||||
|
||||
theorem eq_normS_nc {α} [Semiring α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: eq_normS_nc_cert lhs rhs → lhs.denoteS ctx = rhs.denoteS ctx := by
|
||||
simp [eq_normS_nc_cert]; intro h
|
||||
replace h := congrArg (Poly.denoteS ctx) h
|
||||
simp [Expr.denoteS_toPolyS_nc, *] at h
|
||||
assumption
|
||||
|
||||
end CommRing
|
||||
|
||||
namespace Ring.OfSemiring
|
||||
open CommRing
|
||||
|
||||
theorem of_eq {α} [Semiring α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: lhs.denoteS ctx = rhs.denoteS ctx → lhs.denoteSAsRing ctx = rhs.denoteSAsRing ctx := by
|
||||
intro h; replace h := congrArg toQ h
|
||||
simpa [← Expr.denoteAsRing_eq] using h
|
||||
|
||||
theorem of_diseq {α} [Semiring α] [AddRightCancel α] (ctx : Context α) (lhs rhs : Expr)
|
||||
: lhs.denoteS ctx ≠ rhs.denoteS ctx → lhs.denoteSAsRing ctx ≠ rhs.denoteSAsRing ctx := by
|
||||
intro h₁ h₂
|
||||
simp [Expr.denoteAsRing_eq] at h₂
|
||||
replace h₂ := toQ_inj h₂
|
||||
contradiction
|
||||
|
||||
end Ring.OfSemiring
|
||||
end Lean.Grind
|
||||
@@ -4,27 +4,32 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Int.LemmasAux
|
||||
public import Init.Data.Hashable
|
||||
public import Init.Data.Ord.Basic
|
||||
import all Init.Data.Ord.Basic
|
||||
public import Init.Data.RArray
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ordered.Ring
|
||||
public import Init.GrindInstances.Ring.Int
|
||||
import all Init.Data.Ord.Basic
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
@[expose] public section
|
||||
|
||||
open Std
|
||||
namespace Lean.Grind.CommRing
|
||||
/-!
|
||||
Data-structures, definitions and theorems for implementing the
|
||||
`grind` solver and normalizer for commutative rings and its extensions (e.g., fields,
|
||||
commutative semirings, etc.)
|
||||
|
||||
namespace Lean.Grind
|
||||
The solver uses proof-by-reflection.
|
||||
-/
|
||||
open Std
|
||||
-- These are no longer global instances, so we need to turn them on here.
|
||||
attribute [local instance] Semiring.natCast Ring.intCast
|
||||
namespace CommRing
|
||||
abbrev Var := Nat
|
||||
|
||||
inductive Expr where
|
||||
@@ -41,18 +46,15 @@ inductive Expr where
|
||||
|
||||
abbrev Context (α : Type u) := RArray α
|
||||
|
||||
@[expose]
|
||||
def Var.denote {α} (ctx : Context α) (v : Var) : α :=
|
||||
ctx.get v
|
||||
|
||||
@[expose]
|
||||
noncomputable def denoteInt {α} [Ring α] (k : Int) : α :=
|
||||
Bool.rec
|
||||
(OfNat.ofNat (α := α) k.natAbs)
|
||||
(- OfNat.ofNat (α := α) k.natAbs)
|
||||
(Int.blt' k 0)
|
||||
|
||||
@[expose]
|
||||
noncomputable def Expr.denote {α} [Ring α] (ctx : Context α) (e : Expr) : α :=
|
||||
Expr.rec
|
||||
(fun k => denoteInt k)
|
||||
@@ -69,11 +71,7 @@ noncomputable def Expr.denote {α} [Ring α] (ctx : Context α) (e : Expr) : α
|
||||
structure Power where
|
||||
x : Var
|
||||
k : Nat
|
||||
deriving BEq, Repr, Inhabited, Hashable
|
||||
|
||||
instance : LawfulBEq Power where
|
||||
eq_of_beq {a} := by cases a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
rfl := by intro a; cases a <;> simp! [BEq.beq]
|
||||
deriving BEq, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
|
||||
|
||||
protected noncomputable def Power.beq' (pw₁ pw₂ : Power) : Bool :=
|
||||
Power.rec (fun x₁ k₁ => Power.rec (fun x₂ k₂ => Nat.beq x₁ x₂ && Nat.beq k₁ k₂) pw₂) pw₁
|
||||
@@ -81,11 +79,9 @@ protected noncomputable def Power.beq' (pw₁ pw₂ : Power) : Bool :=
|
||||
@[simp] theorem Power.beq'_eq (pw₁ pw₂ : Power) : pw₁.beq' pw₂ = (pw₁ = pw₂) := by
|
||||
cases pw₁; cases pw₂; simp [Power.beq']
|
||||
|
||||
@[expose]
|
||||
def Power.varLt (p₁ p₂ : Power) : Bool :=
|
||||
p₁.x.blt p₂.x
|
||||
|
||||
@[expose]
|
||||
def Power.denote {α} [Semiring α] (ctx : Context α) : Power → α
|
||||
| {x, k} =>
|
||||
match k with
|
||||
@@ -96,18 +92,7 @@ def Power.denote {α} [Semiring α] (ctx : Context α) : Power → α
|
||||
inductive Mon where
|
||||
| unit
|
||||
| mult (p : Power) (m : Mon)
|
||||
deriving BEq, Repr, Inhabited, Hashable
|
||||
|
||||
instance : LawfulBEq Mon where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
next p₁ m₁ p₂ m₂ ih =>
|
||||
cases p₁ <;> cases p₂ <;> simp <;> intros <;> simp [*]
|
||||
next h => exact ih h
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
assumption
|
||||
deriving BEq, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
|
||||
|
||||
protected noncomputable def Mon.beq' (m₁ : Mon) : Mon → Bool :=
|
||||
Mon.rec
|
||||
@@ -121,12 +106,10 @@ protected noncomputable def Mon.beq' (m₁ : Mon) : Mon → Bool :=
|
||||
simp [← ih m₂, ← Bool.and'_eq_and]
|
||||
rfl
|
||||
|
||||
@[expose]
|
||||
def Mon.denote {α} [Semiring α] (ctx : Context α) : Mon → α
|
||||
| unit => 1
|
||||
| .mult p m => p.denote ctx * denote ctx m
|
||||
|
||||
@[expose]
|
||||
def Mon.denote' {α} [Semiring α] (ctx : Context α) (m : Mon) : α :=
|
||||
match m with
|
||||
| .unit => 1
|
||||
@@ -137,17 +120,14 @@ where
|
||||
| .unit => acc
|
||||
| .mult pw m => go m (acc * (pw.denote ctx))
|
||||
|
||||
@[expose]
|
||||
def Mon.ofVar (x : Var) : Mon :=
|
||||
.mult { x, k := 1 } .unit
|
||||
|
||||
@[expose]
|
||||
def Mon.concat (m₁ m₂ : Mon) : Mon :=
|
||||
match m₁ with
|
||||
| .unit => m₂
|
||||
| .mult pw m₁ => .mult pw (concat m₁ m₂)
|
||||
|
||||
@[expose]
|
||||
def Mon.mulPow (pw : Power) (m : Mon) : Mon :=
|
||||
match m with
|
||||
| .unit =>
|
||||
@@ -160,15 +140,23 @@ def Mon.mulPow (pw : Power) (m : Mon) : Mon :=
|
||||
else
|
||||
.mult { x := pw.x, k := pw.k + pw'.k } m
|
||||
|
||||
@[expose]
|
||||
-- **Note**: We use the `_nc` suffix for functions for the non-commutative case
|
||||
|
||||
def Mon.mulPow_nc (pw : Power) (m : Mon) : Mon :=
|
||||
match m with
|
||||
| .unit => .mult pw .unit
|
||||
| .mult pw' m =>
|
||||
bif pw.x == pw'.x then
|
||||
.mult { x := pw.x, k := pw.k + pw'.k } m
|
||||
else
|
||||
.mult pw (.mult pw' m)
|
||||
|
||||
def Mon.length : Mon → Nat
|
||||
| .unit => 0
|
||||
| .mult _ m => 1 + length m
|
||||
|
||||
@[expose]
|
||||
def hugeFuel := 1000000
|
||||
|
||||
@[expose]
|
||||
def Mon.mul (m₁ m₂ : Mon) : Mon :=
|
||||
-- We could use `m₁.length + m₂.length` to avoid hugeFuel
|
||||
go hugeFuel m₁ m₂
|
||||
@@ -188,18 +176,21 @@ where
|
||||
else
|
||||
.mult { x := pw₁.x, k := pw₁.k + pw₂.k } (go fuel m₁ m₂)
|
||||
|
||||
@[expose]
|
||||
def Mon.mul_nc (m₁ m₂ : Mon) : Mon :=
|
||||
match m₁ with
|
||||
| .unit => m₂
|
||||
| .mult pw .unit => m₂.mulPow_nc pw
|
||||
| .mult pw m₁ => .mult pw (mul_nc m₁ m₂)
|
||||
|
||||
def Mon.degree : Mon → Nat
|
||||
| .unit => 0
|
||||
| .mult pw m => pw.k + degree m
|
||||
|
||||
@[expose]
|
||||
def Var.revlex (x y : Var) : Ordering :=
|
||||
bif x.blt y then .gt
|
||||
else bif y.blt x then .lt
|
||||
else .eq
|
||||
|
||||
@[expose]
|
||||
def powerRevlex (k₁ k₂ : Nat) : Ordering :=
|
||||
bif k₁.blt k₂ then .gt
|
||||
else bif k₂.blt k₁ then .lt
|
||||
@@ -212,11 +203,9 @@ theorem powerRevlex_k_eq_powerRevlex (k₁ k₂ : Nat) : powerRevlex_k k₁ k₂
|
||||
simp [powerRevlex_k, powerRevlex, cond] <;> split <;> simp [*]
|
||||
split <;> simp [*]
|
||||
|
||||
@[expose]
|
||||
def Power.revlex (p₁ p₂ : Power) : Ordering :=
|
||||
p₁.x.revlex p₂.x |>.then (powerRevlex p₁.k p₂.k)
|
||||
|
||||
@[expose]
|
||||
def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
|
||||
match m₁, m₂ with
|
||||
| .unit, .unit => .eq
|
||||
@@ -230,7 +219,6 @@ def Mon.revlexWF (m₁ m₂ : Mon) : Ordering :=
|
||||
else
|
||||
revlexWF (.mult pw₁ m₁) m₂ |>.then .gt
|
||||
|
||||
@[expose]
|
||||
def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
|
||||
match fuel with
|
||||
| 0 =>
|
||||
@@ -250,11 +238,9 @@ def Mon.revlexFuel (fuel : Nat) (m₁ m₂ : Mon) : Ordering :=
|
||||
else
|
||||
revlexFuel fuel (.mult pw₁ m₁) m₂ |>.then .gt
|
||||
|
||||
@[expose]
|
||||
def Mon.revlex (m₁ m₂ : Mon) : Ordering :=
|
||||
revlexFuel hugeFuel m₁ m₂
|
||||
|
||||
@[expose]
|
||||
def Mon.grevlex (m₁ m₂ : Mon) : Ordering :=
|
||||
compare m₁.degree m₂.degree |>.then (revlex m₁ m₂)
|
||||
|
||||
@@ -328,7 +314,7 @@ theorem Mon.grevlex_k_eq_grevlex (m₁ m₂ : Mon) : m₁.grevlex_k m₂ = m₁.
|
||||
inductive Poly where
|
||||
| num (k : Int)
|
||||
| add (k : Int) (v : Mon) (p : Poly)
|
||||
deriving BEq, Repr, Inhabited, Hashable
|
||||
deriving BEq, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
|
||||
|
||||
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
Poly.rec
|
||||
@@ -346,27 +332,11 @@ protected noncomputable def Poly.beq' (p₁ : Poly) : Poly → Bool :=
|
||||
intro _ _; subst k₁ m₁
|
||||
simp [← ih p₂, ← Bool.and'_eq_and]; rfl
|
||||
|
||||
instance : LawfulBEq Poly where
|
||||
eq_of_beq {a} := by
|
||||
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
|
||||
intro h₁ h₂ h₃
|
||||
rename_i m₁ p₁ _ m₂ p₂ ih
|
||||
replace h₂ : m₁ == m₂ := h₂
|
||||
simp [ih h₃, eq_of_beq h₂]
|
||||
rfl := by
|
||||
intro a
|
||||
induction a <;> simp! [BEq.beq]
|
||||
rename_i k m p ih
|
||||
change m == m ∧ p == p
|
||||
simp [ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.denote [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
| .add k m p => k • (m.denote ctx) + denote ctx p
|
||||
|
||||
@[expose]
|
||||
def Poly.denote' [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
@@ -384,21 +354,17 @@ where
|
||||
| .num k => acc + Int.cast k
|
||||
| .add k m p => go p (acc + denoteTerm k m)
|
||||
|
||||
@[expose]
|
||||
def Poly.ofMon (m : Mon) : Poly :=
|
||||
.add 1 m (.num 0)
|
||||
|
||||
@[expose]
|
||||
def Poly.ofVar (x : Var) : Poly :=
|
||||
ofMon (Mon.ofVar x)
|
||||
|
||||
@[expose]
|
||||
def Poly.isSorted : Poly → Bool
|
||||
| .num _ => true
|
||||
| .add _ _ (.num _) => true
|
||||
| .add _ m₁ (.add k m₂ p) => m₁.grevlex m₂ == .gt && (Poly.add k m₂ p).isSorted
|
||||
|
||||
@[expose]
|
||||
def Poly.addConst (p : Poly) (k : Int) : Poly :=
|
||||
bif k == 0 then
|
||||
p
|
||||
@@ -424,7 +390,6 @@ theorem Poly.addConst_k_eq_addConst (p : Poly) (k : Int) : addConst_k p k = addC
|
||||
induction p <;> simp [addConst.go]
|
||||
next ih => rw [← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.insert (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
p
|
||||
@@ -446,13 +411,11 @@ where
|
||||
| .gt => .add k m (.add k' m' p)
|
||||
| .lt => .add k' m' (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.concat (p₁ p₂ : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k₁ => p₂.addConst k₁
|
||||
| .add k m p₁ => .add k m (concat p₁ p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulConst (k : Int) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
@@ -491,7 +454,6 @@ noncomputable def Poly.mulConst_k (k : Int) (p : Poly) : Poly :=
|
||||
next => rfl
|
||||
next k m p ih => simp [mulConst.go, ← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMon (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
@@ -545,7 +507,19 @@ noncomputable def Poly.mulMon_k (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
simp [h]
|
||||
next ih => simp [← ih]
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMon_nc (k : Int) (m : Mon) (p : Poly) : Poly :=
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else bif m == .unit then
|
||||
p.mulConst k
|
||||
else
|
||||
go p (.num 0)
|
||||
where
|
||||
go (p : Poly) (acc : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => acc.insert (k*k') m
|
||||
| .add k' m' p => go p (acc.insert (k*k') (m.mul_nc m'))
|
||||
|
||||
def Poly.combine (p₁ p₂ : Poly) : Poly :=
|
||||
go hugeFuel p₁ p₂
|
||||
where
|
||||
@@ -609,7 +583,6 @@ noncomputable def Poly.combine_k : Poly → Poly → Poly :=
|
||||
next h => simp [h]; rw [← ih p₁ (add k₂ m₂ p₂)]; rfl
|
||||
next h => simp [h]; rw [← ih (add k₁ m₁ p₁) p₂]; rfl
|
||||
|
||||
@[expose]
|
||||
def Poly.mul (p₁ : Poly) (p₂ : Poly) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
@@ -618,14 +591,26 @@ where
|
||||
| .num k => acc.combine (p₂.mulConst k)
|
||||
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon k m))
|
||||
|
||||
@[expose]
|
||||
def Poly.mul_nc (p₁ : Poly) (p₂ : Poly) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combine (p₂.mulConst k)
|
||||
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon_nc k m))
|
||||
|
||||
def Poly.pow (p : Poly) (k : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mul (pow p k)
|
||||
|
||||
@[expose]
|
||||
def Poly.pow_nc (p : Poly) (k : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => (pow_nc p k).mul_nc p
|
||||
|
||||
def Expr.toPoly : Expr → Poly
|
||||
| .num k => .num k
|
||||
| .intCast k => .num k
|
||||
@@ -645,7 +630,7 @@ def Expr.toPoly : Expr → Poly
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly.pow k
|
||||
|
||||
@[expose] noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
|
||||
noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
|
||||
Expr.rec
|
||||
(fun k => .num k) (fun k => .num k) (fun k => .num k)
|
||||
(fun x => .ofVar x)
|
||||
@@ -691,6 +676,25 @@ def Expr.toPoly : Expr → Poly
|
||||
| x => a.toPoly.pow k
|
||||
cases a <;> try simp [*]
|
||||
|
||||
def Expr.toPoly_nc : Expr → Poly
|
||||
| .num k => .num k
|
||||
| .intCast k => .num k
|
||||
| .natCast k => .num k
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => a.toPoly_nc.combine b.toPoly_nc
|
||||
| .mul a b => a.toPoly_nc.mul_nc b.toPoly_nc
|
||||
| .neg a => a.toPoly_nc.mulConst (-1)
|
||||
| .sub a b => a.toPoly_nc.combine (b.toPoly_nc.mulConst (-1))
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
| .num n => .num (n^k)
|
||||
| .intCast n => .num (n^k)
|
||||
| .natCast n => .num (n^k)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly_nc.pow_nc k
|
||||
|
||||
def Poly.normEq0 (p : Poly) (c : Nat) : Poly :=
|
||||
match p with
|
||||
| .num a =>
|
||||
@@ -707,13 +711,11 @@ Once we can specialize definitions before they reach the kernel,
|
||||
we can merge the two versions. Until then, the `IsCharP` definitions will carry the `C` suffix.
|
||||
We use them whenever we can infer the characteristic using type class instance synthesis.
|
||||
-/
|
||||
@[expose]
|
||||
def Poly.addConstC (p : Poly) (k : Int) (c : Nat) : Poly :=
|
||||
match p with
|
||||
| .num k' => .num ((k' + k) % c)
|
||||
| .add k' m p => .add k' m (addConstC p k c)
|
||||
|
||||
@[expose]
|
||||
def Poly.insertC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -734,7 +736,6 @@ where
|
||||
| .gt => .add k m (.add k' m' p)
|
||||
| .lt => .add k' m' (go k p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulConstC (k : Int) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -753,7 +754,6 @@ where
|
||||
else
|
||||
.add k m (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMonC (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
@@ -777,7 +777,20 @@ where
|
||||
else
|
||||
.add k (m.mul m') (go p)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulMonC_nc (k : Int) (m : Mon) (p : Poly) (c : Nat) : Poly :=
|
||||
let k := k % c
|
||||
bif k == 0 then
|
||||
.num 0
|
||||
else bif m == .unit then
|
||||
p.mulConstC k c
|
||||
else
|
||||
go p (.num 0)
|
||||
where
|
||||
go (p : Poly) (acc : Poly) : Poly :=
|
||||
match p with
|
||||
| .num k' => acc.insert (k*k' % c) m
|
||||
| .add k' m' p => go p (acc.insert (k*k' % c) (m.mul_nc m'))
|
||||
|
||||
def Poly.combineC (p₁ p₂ : Poly) (c : Nat) : Poly :=
|
||||
go hugeFuel p₁ p₂
|
||||
where
|
||||
@@ -799,7 +812,6 @@ where
|
||||
| .gt => .add k₁ m₁ (go fuel p₁ (.add k₂ m₂ p₂))
|
||||
| .lt => .add k₂ m₂ (go fuel (.add k₁ m₁ p₁) p₂)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulC (p₁ : Poly) (p₂ : Poly) (c : Nat) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
@@ -808,14 +820,26 @@ where
|
||||
| .num k => acc.combineC (p₂.mulConstC k c) c
|
||||
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC k m c) c)
|
||||
|
||||
@[expose]
|
||||
def Poly.mulC_nc (p₁ : Poly) (p₂ : Poly) (c : Nat) : Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : Poly :=
|
||||
match p₁ with
|
||||
| .num k => acc.combineC (p₂.mulConstC k c) c
|
||||
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC_nc k m c) c)
|
||||
|
||||
def Poly.powC (p : Poly) (k : Nat) (c : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => p.mulC (powC p k c) c
|
||||
|
||||
@[expose]
|
||||
def Poly.powC_nc (p : Poly) (k : Nat) (c : Nat) : Poly :=
|
||||
match k with
|
||||
| 0 => .num 1
|
||||
| 1 => p
|
||||
| k+1 => (powC_nc p k c).mulC_nc p c
|
||||
|
||||
def Expr.toPolyC (e : Expr) (c : Nat) : Poly :=
|
||||
go e
|
||||
where
|
||||
@@ -836,6 +860,26 @@ where
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => (go a).powC k c
|
||||
|
||||
def Expr.toPolyC_nc (e : Expr) (c : Nat) : Poly :=
|
||||
go e
|
||||
where
|
||||
go : Expr → Poly
|
||||
| .num k => .num (k % c)
|
||||
| .natCast k => .num (k % c)
|
||||
| .intCast k => .num (k % c)
|
||||
| .var x => Poly.ofVar x
|
||||
| .add a b => (go a).combineC (go b) c
|
||||
| .mul a b => (go a).mulC_nc (go b) c
|
||||
| .neg a => (go a).mulConstC (-1) c
|
||||
| .sub a b => (go a).combineC ((go b).mulConstC (-1) c) c
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
| .num n => .num ((n^k) % c)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => (go a).powC_nc k c
|
||||
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings in `grind`.
|
||||
-/
|
||||
@@ -845,7 +889,7 @@ open Semiring hiding add_zero add_comm add_assoc
|
||||
open Ring hiding sub_eq_add_neg
|
||||
open CommSemiring
|
||||
|
||||
theorem denoteInt_eq {α} [CommRing α] (k : Int) : denoteInt (α := α) k = k := by
|
||||
theorem denoteInt_eq {α} [Ring α] (k : Int) : denoteInt (α := α) k = k := by
|
||||
simp [denoteInt] <;> cases h : k.blt' 0 <;> simp <;> simp at h
|
||||
next h => rw [ofNat_eq_natCast, ← intCast_natCast, ← Int.eq_natAbs_of_nonneg h]
|
||||
next h => rw [ofNat_eq_natCast, ← intCast_natCast, ← Ring.intCast_neg, ← Int.eq_neg_natAbs_of_nonpos (Int.le_of_lt h)]
|
||||
@@ -888,6 +932,13 @@ theorem Mon.denote_mulPow {α} [CommSemiring α] (ctx : Context α) (p : Power)
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [Power.denote_eq, pow_add, mul_assoc, this]
|
||||
|
||||
theorem Mon.denote_mulPow_nc {α} [Semiring α] (ctx : Context α) (p : Power) (m : Mon)
|
||||
: denote ctx (mulPow_nc p m) = p.denote ctx * m.denote ctx := by
|
||||
fun_cases mulPow_nc <;> simp [denote, *]
|
||||
next h =>
|
||||
simp at h
|
||||
simp [Power.denote_eq, pow_add, mul_assoc, h]
|
||||
|
||||
theorem Mon.denote_mul {α} [CommSemiring α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (mul m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
unfold mul
|
||||
@@ -899,6 +950,10 @@ theorem Mon.denote_mul {α} [CommSemiring α] (ctx : Context α) (m₁ m₂ : Mo
|
||||
have := eq_of_blt_false h₁ h₂
|
||||
simp [Power.denote_eq, pow_add, this]
|
||||
|
||||
theorem Mon.denote_mul_nc {α} [Semiring α] (ctx : Context α) (m₁ m₂ : Mon)
|
||||
: denote ctx (mul_nc m₁ m₂) = m₁.denote ctx * m₂.denote ctx := by
|
||||
fun_induction mul_nc <;> simp [denote, Semiring.one_mul, Semiring.mul_one, denote_mulPow_nc, Semiring.mul_assoc, *]
|
||||
|
||||
theorem Var.eq_of_revlex {x₁ x₂ : Var} : x₁.revlex x₂ = .eq → x₁ = x₂ := by
|
||||
simp [revlex, cond_eq_if] <;> split <;> simp
|
||||
next h₁ => intro h₂; exact Nat.le_antisymm h₂ (Nat.ge_of_not_lt h₁)
|
||||
@@ -954,15 +1009,15 @@ theorem Poly.denote'_eq_denote {α} [Ring α] (ctx : Context α) (p : Poly) : p.
|
||||
fun_induction denote'.go <;> simp [denote, *, Ring.intCast_zero, Semiring.add_zero, denoteTerm_eq]
|
||||
next ih => simp [denoteTerm_eq] at ih; simp [ih, Semiring.add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_ofMon {α} [CommRing α] (ctx : Context α) (m : Mon)
|
||||
theorem Poly.denote_ofMon {α} [Ring α] (ctx : Context α) (m : Mon)
|
||||
: denote ctx (ofMon m) = m.denote ctx := by
|
||||
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_ofVar {α} [CommRing α] (ctx : Context α) (x : Var)
|
||||
theorem Poly.denote_ofVar {α} [Ring α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
simp [ofVar, denote_ofMon, Mon.denote_ofVar]
|
||||
|
||||
theorem Poly.denote_addConst {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
|
||||
theorem Poly.denote_addConst {α} [Ring α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
|
||||
simp [addConst, cond_eq_if]; split
|
||||
next => simp [*, intCast_zero, add_zero]
|
||||
next =>
|
||||
@@ -970,7 +1025,7 @@ theorem Poly.denote_addConst {α} [CommRing α] (ctx : Context α) (p : Poly) (k
|
||||
next => rw [intCast_add]
|
||||
next => simp [add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_insert {α} [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
theorem Poly.denote_insert {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insert k m p).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
simp [insert, cond_eq_if] <;> split
|
||||
next => simp [*, intCast_zero, zero_mul, zero_add]
|
||||
@@ -987,13 +1042,13 @@ theorem Poly.denote_insert {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next =>
|
||||
rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_concat {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_concat {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (concat p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
fun_induction concat <;> simp [*, denote_addConst, denote]
|
||||
next => rw [add_comm]
|
||||
next => rw [add_assoc]
|
||||
|
||||
theorem Poly.denote_mulConst {α} [CommRing α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
theorem Poly.denote_mulConst {α} [Ring α] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConst k p).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConst, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
@@ -1017,7 +1072,28 @@ theorem Poly.denote_mulMon {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next => simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next => simp [Mon.denote_mul, intCast_mul, left_distrib, mul_left_comm, mul_assoc]
|
||||
|
||||
theorem Poly.denote_combine {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_mulMon_nc_go {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p acc : Poly)
|
||||
: (mulMon_nc.go k m p acc).denote ctx = k * m.denote ctx * p.denote ctx + acc.denote ctx := by
|
||||
fun_induction mulMon_nc.go <;> simp [denote, denote_insert, zsmul_eq_intCast_mul]
|
||||
next => rw [Ring.intCast_mul, Semiring.mul_assoc, Semiring.mul_assoc, ← Ring.intCast_mul_comm]
|
||||
next ih =>
|
||||
rw [ih, denote_insert, Mon.denote_mul_nc, Semiring.left_distrib, Ring.intCast_mul]
|
||||
rw [Ring.intCast_mul_left_comm]; simp [← Semiring.mul_assoc]
|
||||
conv => enter [1, 2, 1, 1, 1]; rw [Ring.intCast_mul_comm]
|
||||
simp [Semiring.add_assoc, Semiring.add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulMon_nc {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMon_nc k m p).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMon_nc, cond_eq_if] <;> split
|
||||
next => simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
split
|
||||
next h =>
|
||||
simp at h; simp [*, Mon.denote, mul_one, denote_mulConst]
|
||||
next =>
|
||||
rw [denote_mulMon_nc_go]; simp [denote, Ring.intCast_zero, add_zero]
|
||||
|
||||
theorem Poly.denote_combine {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combine p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combine; generalize hugeFuel = fuel
|
||||
fun_induction combine.go
|
||||
@@ -1038,6 +1114,15 @@ theorem Poly.denote_mul {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mul, denote_mul_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_mul_nc_go {α} [Ring α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mul_nc.go p₂ p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mul_nc.go
|
||||
<;> simp [denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon_nc, add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_mul_nc {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul_nc p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mul_nc, denote_mul_nc_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_pow {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (pow p k).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction pow
|
||||
@@ -1045,6 +1130,13 @@ theorem Poly.denote_pow {α} [CommRing α] (ctx : Context α) (p : Poly) (k : Na
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mul, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Poly.denote_pow_nc {α} [Ring α] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (pow_nc p k).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction pow_nc
|
||||
next => simp [denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mul_nc, *, pow_succ]
|
||||
|
||||
theorem Expr.denote_toPoly {α} [CommRing α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly.denote ctx = e.denote ctx := by
|
||||
fun_induction toPoly
|
||||
@@ -1056,21 +1148,37 @@ theorem Expr.denote_toPoly {α} [CommRing α] (ctx : Context α) (e : Expr)
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.denote_toPoly_nc {α} [Ring α] (ctx : Context α) (e : Expr)
|
||||
: e.toPoly_nc.denote ctx = e.denote ctx := by
|
||||
fun_induction toPoly_nc
|
||||
<;> simp [denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combine,
|
||||
Poly.denote_mul_nc, Poly.denote_mulConst, Poly.denote_pow_nc, intCast_pow, intCast_neg, intCast_one,
|
||||
neg_mul, one_mul, sub_eq_add_neg, denoteInt_eq, *]
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero]
|
||||
next => rw [Ring.intCast_natCast]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.eq_of_toPoly_eq {α} [CommRing α] (ctx : Context α) (a b : Expr) (h : a.toPoly == b.toPoly) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPoly] at h
|
||||
assumption
|
||||
|
||||
theorem Expr.eq_of_toPoly_nc_eq {α} [Ring α] (ctx : Context α) (a b : Expr) (h : a.toPoly_nc == b.toPoly_nc) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPoly_nc] at h
|
||||
assumption
|
||||
|
||||
/-!
|
||||
Theorems for justifying the procedure for commutative rings with a characteristic in `grind`.
|
||||
-/
|
||||
|
||||
theorem Poly.denote_addConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
|
||||
theorem Poly.denote_addConstC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
|
||||
fun_induction addConstC <;> simp [denote, *]
|
||||
next => rw [IsCharP.intCast_emod, intCast_add]
|
||||
next => simp [add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
theorem Poly.denote_insertC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (insertC k m p c).denote ctx = k * m.denote ctx + p.denote ctx := by
|
||||
simp [insertC, cond_eq_if] <;> split
|
||||
next =>
|
||||
@@ -1087,7 +1195,7 @@ theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
|
||||
theorem Poly.denote_mulConstC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
|
||||
: (mulConstC k p c).denote ctx = k * p.denote ctx := by
|
||||
simp [mulConstC, cond_eq_if] <;> split
|
||||
next =>
|
||||
@@ -1136,7 +1244,29 @@ theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
simp +zetaDelta [*, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
|
||||
mul_left_comm, mul_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
theorem Poly.denote_mulMonC_nc_go {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p acc : Poly)
|
||||
: (mulMonC_nc.go k m c p acc).denote ctx = k * m.denote ctx * p.denote ctx + acc.denote ctx := by
|
||||
fun_induction mulMonC_nc.go <;> simp [denote, denote_insert, zsmul_eq_intCast_mul]
|
||||
next => rw [IsCharP.intCast_emod (x := k * _) (p := c), Ring.intCast_mul, Semiring.mul_assoc, Semiring.mul_assoc, ← Ring.intCast_mul_comm]
|
||||
next ih =>
|
||||
rw [ih, denote_insert, Mon.denote_mul_nc, IsCharP.intCast_emod (x := k * _) (p := c),
|
||||
Semiring.left_distrib, Ring.intCast_mul]
|
||||
rw [Ring.intCast_mul_left_comm]; simp [← Semiring.mul_assoc]
|
||||
conv => enter [1, 2, 1, 1, 1]; rw [Ring.intCast_mul_comm]
|
||||
simp [Semiring.add_assoc, Semiring.add_comm, add_left_comm]
|
||||
|
||||
theorem Poly.denote_mulMonC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMonC_nc k m p c).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
simp [mulMonC_nc, cond_eq_if] <;> split
|
||||
next =>
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp [denote, *, intCast_zero, zero_mul]
|
||||
next =>
|
||||
split
|
||||
next h => simp at h; simp [*, Mon.denote, mul_one, denote_mulConstC, IsCharP.intCast_emod]
|
||||
next => rw [Poly.denote_mulMonC_nc_go, denote, Ring.intCast_zero, add_zero]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combineC p₁ p₂ c).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combineC; generalize hugeFuel = fuel
|
||||
fun_induction combineC.go
|
||||
@@ -1160,6 +1290,15 @@ theorem Poly.denote_mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α)
|
||||
: (mulC p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mulC, denote_mulC_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_mulC_nc_go {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mulC_nc.go p₂ c p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mulC_nc.go
|
||||
<;> simp [denote_combineC, denote_mulConstC, denote, *, right_distrib, denote_mulMonC_nc, add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_mulC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mulC_nc p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
simp [mulC_nc, denote_mulC_nc_go, denote, intCast_zero, zero_add]
|
||||
|
||||
theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (powC p k c).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction powC
|
||||
@@ -1167,6 +1306,13 @@ theorem Poly.denote_powC {α c} [CommRing α] [IsCharP α c] (ctx : Context α)
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mulC, *, pow_succ, mul_comm]
|
||||
|
||||
theorem Poly.denote_powC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Nat)
|
||||
: (powC_nc p k c).denote ctx = p.denote ctx ^ k := by
|
||||
fun_induction powC_nc
|
||||
next => simp [denote, intCast_one, pow_zero]
|
||||
next => simp [pow_succ, pow_zero, one_mul]
|
||||
next => simp [denote_mulC_nc, *, pow_succ]
|
||||
|
||||
theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (e : Expr)
|
||||
: (e.toPolyC c).denote ctx = e.denote ctx := by
|
||||
unfold toPolyC
|
||||
@@ -1182,17 +1328,37 @@ theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.denote_toPolyC_nc {α c} [Ring α] [IsCharP α c] (ctx : Context α) (e : Expr)
|
||||
: (e.toPolyC_nc c).denote ctx = e.denote ctx := by
|
||||
unfold toPolyC_nc
|
||||
fun_induction toPolyC_nc.go
|
||||
<;> simp [denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combineC,
|
||||
Poly.denote_mulC_nc, Poly.denote_mulConstC, Poly.denote_powC_nc, denoteInt_eq, *]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [IsCharP.intCast_emod, Ring.intCast_natCast]
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul, sub_eq_add_neg]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero, Ring.intCast_one]
|
||||
next => rw [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.eq_of_toPolyC_eq {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (a b : Expr)
|
||||
(h : a.toPolyC c == b.toPolyC c) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPolyC] at h
|
||||
assumption
|
||||
|
||||
theorem Expr.eq_of_toPolyC_nc_eq {α c} [Ring α] [IsCharP α c] (ctx : Context α) (a b : Expr)
|
||||
(h : a.toPolyC_nc c == b.toPolyC_nc c) : a.denote ctx = b.denote ctx := by
|
||||
have h := congrArg (Poly.denote ctx) (eq_of_beq h)
|
||||
simp [denote_toPolyC_nc] at h
|
||||
assumption
|
||||
|
||||
namespace Stepwise
|
||||
/-!
|
||||
Theorems for stepwise proof-term construction
|
||||
-/
|
||||
@[expose]
|
||||
noncomputable def core_cert (lhs rhs : Expr) (p : Poly) : Bool :=
|
||||
(lhs.sub rhs).toPoly_k.beq' p
|
||||
|
||||
@@ -1202,7 +1368,6 @@ theorem core {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
|
||||
simp [Expr.denote_toPoly, Expr.denote]
|
||||
simp [sub_eq_zero_iff]
|
||||
|
||||
@[expose]
|
||||
noncomputable def superpose_cert (k₁ : Int) (m₁ : Mon) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
(p₁.mulMon_k k₁ m₁).combine_k (p₂.mulMon_k k₂ m₂) |>.beq' p
|
||||
|
||||
@@ -1211,7 +1376,6 @@ theorem superpose {α} [CommRing α] (ctx : Context α) (k₁ : Int) (m₁ : Mon
|
||||
simp [superpose_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def simp_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
(p₁.mulConst_k k₁).combine_k (p₂.mulMon_k k₂ m₂) |>.beq' p
|
||||
|
||||
@@ -1220,32 +1384,26 @@ theorem simp {α} [CommRing α] (ctx : Context α) (k₁ : Int) (p₁ : Poly) (k
|
||||
simp [simp_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, Poly.denote_mulConst, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def mul_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
p₁.mulConst_k k |>.beq' p
|
||||
|
||||
@[expose]
|
||||
def mul {α} [CommRing α] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [mul_cert]; intro _ h; subst p
|
||||
simp [Poly.denote_mulConst, *, mul_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def div_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (p.mulConst_k k |>.beq' p₁)
|
||||
|
||||
@[expose]
|
||||
def div {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_cert]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConst, ← zsmul_eq_intCast_mul] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
noncomputable def unsat_eq_cert (p : Poly) (k : Int) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (p.beq' (.num k))
|
||||
|
||||
@[expose]
|
||||
def unsat_eq {α} [CommRing α] (ctx : Context α) [IsCharP α 0] (p : Poly) (k : Int)
|
||||
: unsat_eq_cert p k → p.denote ctx = 0 → False := by
|
||||
simp [unsat_eq_cert]; intro h _; subst p; simp [Poly.denote]
|
||||
@@ -1256,7 +1414,6 @@ def unsat_eq {α} [CommRing α] (ctx : Context α) [IsCharP α 0] (p : Poly) (k
|
||||
theorem d_init {α} [CommRing α] (ctx : Context α) (p : Poly) : (1:Int) * p.denote ctx = p.denote ctx := by
|
||||
rw [intCast_one, one_mul]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_step1_cert (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
p.beq' (p₁.combine_k (p₂.mulMon_k k₂ m₂))
|
||||
|
||||
@@ -1265,7 +1422,6 @@ theorem d_step1 {α} [CommRing α] (ctx : Context α) (k : Int) (init : Poly) (p
|
||||
simp [d_step1_cert]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, h₂, mul_zero, add_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_stepk_cert (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) : Bool :=
|
||||
p.beq' ((p₁.mulConst_k k₁).combine_k (p₂.mulMon_k k₂ m₂))
|
||||
|
||||
@@ -1275,7 +1431,6 @@ theorem d_stepk {α} [CommRing α] (ctx : Context α) (k₁ : Int) (k : Int) (in
|
||||
simp [Poly.denote_combine, Poly.denote_mulMon, Poly.denote_mulConst, h₂, mul_zero, add_zero]
|
||||
rw [intCast_mul, mul_assoc, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_1eq_cert (lhs rhs : Expr) (p₁ p₂ : Poly) : Bool :=
|
||||
(lhs.sub rhs).toPoly_k.beq' p₁ |>.and' (p₂.beq' (.num 0))
|
||||
|
||||
@@ -1284,7 +1439,6 @@ theorem imp_1eq {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p₁ p
|
||||
simp [imp_1eq_cert, intCast_one, one_mul]; intro _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPoly, Expr.denote, sub_eq_zero_iff, Poly.denote, intCast_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_keq_cert (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) : Bool :=
|
||||
!Int.beq' k 0 |>.and' ((lhs.sub rhs).toPoly_k.beq' p₁ |>.and' (p₂.beq' (.num 0)))
|
||||
|
||||
@@ -1295,7 +1449,6 @@ theorem imp_keq {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (k
|
||||
intro h; replace h := no_int_zero_divisors hnz h
|
||||
rw [← sub_eq_zero_iff, h]
|
||||
|
||||
@[expose]
|
||||
noncomputable def core_certC (lhs rhs : Expr) (p : Poly) (c : Nat) : Bool :=
|
||||
(lhs.sub rhs).toPolyC c |>.beq' p
|
||||
|
||||
@@ -1305,7 +1458,6 @@ theorem coreC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (lhs rhs :
|
||||
simp [Expr.denote_toPolyC, Expr.denote]
|
||||
simp [sub_eq_zero_iff]
|
||||
|
||||
@[expose]
|
||||
noncomputable def superpose_certC (k₁ : Int) (m₁ : Mon) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
(p₁.mulMonC k₁ m₁ c).combineC (p₂.mulMonC k₂ m₂ c) c |>.beq' p
|
||||
|
||||
@@ -1314,28 +1466,23 @@ theorem superposeC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁
|
||||
simp [superpose_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def mul_certC (p₁ : Poly) (k : Int) (p : Poly) (c : Nat) : Bool :=
|
||||
p₁.mulConstC k c |>.beq' p
|
||||
|
||||
@[expose]
|
||||
def mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: mul_certC p₁ k p c → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [mul_certC]; intro _ h; subst p
|
||||
simp [Poly.denote_mulConstC, *, mul_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def div_certC (p₁ : Poly) (k : Int) (p : Poly) (c : Nat) : Bool :=
|
||||
!Int.beq' k 0 |>.and' ((p.mulConstC k c).beq' p₁)
|
||||
|
||||
@[expose]
|
||||
def divC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_certC p₁ k p c → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_certC]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConstC, ← zsmul_eq_intCast_mul] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
noncomputable def simp_certC (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
(p₁.mulConstC k₁ c).combineC (p₂.mulMonC k₂ m₂ c) c |>.beq' p
|
||||
|
||||
@@ -1344,11 +1491,9 @@ theorem simpC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁ : Int
|
||||
simp [simp_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, Poly.denote_mulConstC, h₁, h₂, mul_zero, add_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def unsat_eq_certC (p : Poly) (k : Int) (c : Nat) : Bool :=
|
||||
!Int.beq' (k % c) 0 |>.and' (p.beq' (.num k))
|
||||
|
||||
@[expose]
|
||||
def unsat_eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int)
|
||||
: unsat_eq_certC p k c → p.denote ctx = 0 → False := by
|
||||
simp [unsat_eq_certC]; intro h _; subst p; simp [Poly.denote]
|
||||
@@ -1356,7 +1501,6 @@ def unsat_eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p : Poly)
|
||||
simp [h] at this
|
||||
assumption
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_step1_certC (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
p.beq' (p₁.combineC (p₂.mulMonC k₂ m₂ c) c)
|
||||
|
||||
@@ -1365,7 +1509,6 @@ theorem d_step1C {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int
|
||||
simp [d_step1_certC]; intro _ h₁ h₂; subst p
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, h₂, mul_zero, add_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_stepk_certC (k₁ : Int) (p₁ : Poly) (k₂ : Int) (m₂ : Mon) (p₂ : Poly) (p : Poly) (c : Nat) : Bool :=
|
||||
p.beq' ((p₁.mulConstC k₁ c).combineC (p₂.mulMonC k₂ m₂ c) c)
|
||||
|
||||
@@ -1375,7 +1518,6 @@ theorem d_stepkC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k₁ :
|
||||
simp [Poly.denote_combineC, Poly.denote_mulMonC, Poly.denote_mulConstC, h₂, mul_zero, add_zero]
|
||||
rw [intCast_mul, mul_assoc, h₁]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_1eq_certC (lhs rhs : Expr) (p₁ p₂ : Poly) (c : Nat) : Bool :=
|
||||
((lhs.sub rhs).toPolyC c).beq' p₁ |>.and' (p₂.beq' (.num 0))
|
||||
|
||||
@@ -1384,7 +1526,6 @@ theorem imp_1eqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (lhs rhs
|
||||
simp [imp_1eq_certC, intCast_one, one_mul]; intro _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPolyC, Expr.denote, sub_eq_zero_iff, Poly.denote, intCast_zero]
|
||||
|
||||
@[expose]
|
||||
noncomputable def imp_keq_certC (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) (c : Nat) : Bool :=
|
||||
!Int.beq' k 0 |>.and' (((lhs.sub rhs).toPolyC c).beq' p₁ |>.and' (p₂.beq' (.num 0)))
|
||||
|
||||
@@ -1399,7 +1540,6 @@ end Stepwise
|
||||
|
||||
/-! IntModule interface -/
|
||||
|
||||
@[expose]
|
||||
def Mon.denoteAsIntModule [CommRing α] (ctx : Context α) (m : Mon) : α :=
|
||||
match m with
|
||||
| .unit => One.one
|
||||
@@ -1410,7 +1550,6 @@ where
|
||||
| .unit => acc
|
||||
| .mult pw m => go m (acc * pw.denote ctx)
|
||||
|
||||
@[expose]
|
||||
def Poly.denoteAsIntModule [CommRing α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => k • (One.one : α)
|
||||
@@ -1511,7 +1650,6 @@ theorem inv_split {α} [Field α] (a : α) : if a = 0 then a⁻¹ = 0 else a * a
|
||||
next h => simp [h, Field.inv_zero]
|
||||
next h => rw [Field.mul_inv_cancel h]
|
||||
|
||||
@[expose]
|
||||
noncomputable def one_eq_zero_unsat_cert (p : Poly) :=
|
||||
p.beq' (.num 1) || p.beq' (.num (-1))
|
||||
|
||||
@@ -1551,7 +1689,6 @@ theorem Poly.normEq0_eq {α} [CommRing α] (ctx : Context α) (p : Poly) (c : Na
|
||||
simp [denote, normEq0, cond_eq_if]; split <;> simp [denote, zsmul_eq_intCast_mul, *]
|
||||
next h' => rw [of_mod_eq_0 h h', Semiring.zero_mul, zero_add]
|
||||
|
||||
@[expose]
|
||||
noncomputable def eq_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₁.beq' (.num c) && (p.beq' (p₂.normEq0 c))
|
||||
|
||||
@@ -1571,7 +1708,6 @@ theorem gcd_eq_0 [CommRing α] (g n m a b : Int) (h : g = a * n + b * m)
|
||||
rw [← Ring.intCast_add, h₂, zero_add, ← h] at h₁
|
||||
rw [Ring.intCast_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
def eq_gcd_cert (a b : Int) (p₁ p₂ p : Poly) : Bool :=
|
||||
match p₁ with
|
||||
| .add .. => false
|
||||
@@ -1589,7 +1725,6 @@ theorem eq_gcd {α} [CommRing α] (ctx : Context α) (a b : Int) (p₁ p₂ p :
|
||||
rename_i n m g
|
||||
apply gcd_eq_0 g n m a b
|
||||
|
||||
@[expose]
|
||||
noncomputable def d_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₂.beq' (.num c) |>.and' (p.beq' (p₁.normEq0 c))
|
||||
|
||||
@@ -1598,11 +1733,10 @@ theorem d_normEq0 {α} [CommRing α] (ctx : Context α) (k : Int) (c : Nat) (ini
|
||||
simp [d_normEq0_cert]; intro _ h₁ h₂; subst p p₂; simp [Poly.denote]
|
||||
intro h; rw [p₁.normEq0_eq] <;> assumption
|
||||
|
||||
@[expose] noncomputable def norm_int_cert (e : Expr) (p : Poly) : Bool :=
|
||||
noncomputable def norm_int_cert (e : Expr) (p : Poly) : Bool :=
|
||||
e.toPoly_k.beq' p
|
||||
|
||||
theorem norm_int (ctx : Context Int) (e : Expr) (p : Poly) : norm_int_cert e p → e.denote ctx = p.denote' ctx := by
|
||||
simp [norm_int_cert, Poly.denote'_eq_denote]; intro; subst p; simp [Expr.denote_toPoly]
|
||||
|
||||
end CommRing
|
||||
end Lean.Grind
|
||||
end Lean.Grind.CommRing
|
||||
@@ -277,6 +277,9 @@ attribute [-simp] Q.mk
|
||||
|
||||
/-! Embedding theorems -/
|
||||
|
||||
theorem toQ_zero : toQ (0 : α) = (0 : Q α) := by
|
||||
simp; apply Quot.sound; simp
|
||||
|
||||
theorem toQ_add (a b : α) : toQ (a + b) = toQ a + toQ b := by
|
||||
simp
|
||||
|
||||
|
||||
@@ -180,9 +180,14 @@ namespace Lean.Parser.Tactic
|
||||
`grind` tactic and related tactics.
|
||||
-/
|
||||
|
||||
syntax grindErase := "-" ident
|
||||
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
|
||||
syntax grindParam := grindErase <|> grindLemma
|
||||
syntax grindErase := "-" ident
|
||||
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
|
||||
/--
|
||||
The `!` modifier instructs `grind` to consider only minimal indexable subexpressions
|
||||
when selecting patterns.
|
||||
-/
|
||||
syntax grindLemmaMin := ppGroup("!" (Attr.grindMod ppSpace)? ident)
|
||||
syntax grindParam := grindErase <|> grindLemma <|> grindLemmaMin
|
||||
|
||||
/--
|
||||
`grind` is a tactic inspired by modern SMT solvers. **Picture a virtual whiteboard**:
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.LawfulBEqTactics
|
||||
|
||||
public section
|
||||
|
||||
@@ -37,11 +38,7 @@ inductive IntInterval : Type where
|
||||
io (hi : Int)
|
||||
| /-- The infinite interval `(-∞, ∞)`. -/
|
||||
ii
|
||||
deriving BEq, DecidableEq, Inhabited
|
||||
|
||||
instance : LawfulBEq IntInterval where
|
||||
rfl := by intro a; cases a <;> simp_all! [BEq.beq]
|
||||
eq_of_beq := by intro a b; cases a <;> cases b <;> simp_all! [BEq.beq]
|
||||
deriving BEq, ReflBEq, LawfulBEq, DecidableEq, Inhabited
|
||||
|
||||
namespace IntInterval
|
||||
|
||||
|
||||
104
src/Init/LawfulBEqTactics.lean
Normal file
104
src/Init/LawfulBEqTactics.lean
Normal file
@@ -0,0 +1,104 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner
|
||||
-/
|
||||
|
||||
module
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Notation
|
||||
public import Init.Tactics
|
||||
public import Init.Core
|
||||
import Init.Data.Bool
|
||||
import Init.ByCases
|
||||
|
||||
public section
|
||||
|
||||
namespace DerivingHelpers
|
||||
|
||||
macro "deriving_ReflEq_tactic" : tactic => `(tactic|(
|
||||
intro x
|
||||
induction x
|
||||
all_goals
|
||||
simp only [ BEq.refl, ↓reduceDIte, Bool.and_true, *, reduceBEq ,reduceCtorIdx]
|
||||
))
|
||||
|
||||
theorem and_true_curry {a b : Bool} {P : Prop}
|
||||
(h : a → b → P) : (a && b) → P := by
|
||||
rw [Bool.and_eq_true_iff]
|
||||
intro h'
|
||||
apply h h'.1 h'.2
|
||||
|
||||
|
||||
theorem deriving_lawful_beq_helper_dep {x y : α} [BEq α] [ReflBEq α]
|
||||
{t : (x == y) = true → Bool} {P : Prop}
|
||||
(inst : (x == y) = true → x = y)
|
||||
(k : (h : x = y) → t (h ▸ ReflBEq.rfl) = true → P) :
|
||||
(if h : (x == y) then t h else false) = true → P := by
|
||||
intro h
|
||||
by_cases hxy : x = y
|
||||
· subst hxy
|
||||
apply k rfl
|
||||
rw [dif_pos (BEq.refl x)] at h
|
||||
exact h
|
||||
· by_cases hxy' : x == y
|
||||
· exact False.elim <| hxy (inst hxy')
|
||||
· rw [dif_neg hxy'] at h
|
||||
contradiction
|
||||
|
||||
theorem deriving_lawful_beq_helper_nd {x y : α} [BEq α] [ReflBEq α]
|
||||
{P : Prop}
|
||||
(inst : (x == y) = true → x = y)
|
||||
(k : x = y → P) :
|
||||
(x == y) = true → P := by
|
||||
intro h
|
||||
by_cases hxy : x = y
|
||||
· subst hxy
|
||||
apply k rfl
|
||||
· exact False.elim <| hxy (inst h)
|
||||
|
||||
end DerivingHelpers
|
||||
|
||||
syntax "deriving_LawfulEq_tactic_step" : tactic
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| fail "deriving_LawfulEq_tactic_step failed")
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| ( with_reducible change dite (_ == _) _ _ = true → _
|
||||
refine DerivingHelpers.deriving_lawful_beq_helper_dep ?_ ?_
|
||||
· solve | apply_assumption | simp | fail "could not discharge eq_of_beq assumption"
|
||||
intro h
|
||||
cases h
|
||||
dsimp only
|
||||
))
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| ( with_reducible change (_ == _) = true → _
|
||||
refine DerivingHelpers.deriving_lawful_beq_helper_nd ?_ ?_
|
||||
· solve | apply_assumption | simp | fail "could not discharge eq_of_beq assumption"
|
||||
intro h
|
||||
subst h
|
||||
))
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| ( with_reducible change (_ == _ && _) = true → _
|
||||
refine DerivingHelpers.and_true_curry ?_))
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| rfl)
|
||||
macro_rules
|
||||
| `(tactic| deriving_LawfulEq_tactic_step) =>
|
||||
`(tactic| intro _; trivial)
|
||||
|
||||
macro "deriving_LawfulEq_tactic" : tactic => `(tactic|(
|
||||
intro x
|
||||
induction x
|
||||
all_goals
|
||||
intro y
|
||||
cases y
|
||||
all_goals
|
||||
simp only [reduceBEq, reduceCtorIdx]
|
||||
repeat deriving_LawfulEq_tactic_step
|
||||
))
|
||||
1674
src/Init/Meta.lean
1674
src/Init/Meta.lean
File diff suppressed because it is too large
Load Diff
1679
src/Init/Meta/Defs.lean
Normal file
1679
src/Init/Meta/Defs.lean
Normal file
File diff suppressed because it is too large
Load Diff
70
src/Init/MethodSpecsSimp.lean
Normal file
70
src/Init/MethodSpecsSimp.lean
Normal file
@@ -0,0 +1,70 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Joachim Breitner
|
||||
-/
|
||||
|
||||
module
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
|
||||
/-!
|
||||
This module contains theorems to be added to the `@[method_specs_simp]` simpset. When we use the
|
||||
idiom of a heterogeneous class with notation (e.g. `HAppend`) and a homogeneous class that the user
|
||||
typically instantiates, these rewrite the method specifications generated by `@[method_specs]` from
|
||||
the homogeneous form to the desired heterogeneous form.
|
||||
|
||||
Should modules within `Init` use `@[method_specs]` on such instances, they should import this file.
|
||||
-/
|
||||
|
||||
public section
|
||||
|
||||
@[method_specs_simp] theorem Add.add_eq_hAdd {α : Type u} [inst : Add α] :
|
||||
Eq (@Add.add α inst) (@HAdd.hAdd α α α (@instHAdd α inst)) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Sub.sub_eq_hSub [Sub α] :
|
||||
Eq (@Sub.sub α _) (@HSub.hSub α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Mul.mul_eq_hMul [Mul α] :
|
||||
Eq (@Mul.mul α _) (@HMul.hMul α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Div.div_eq_hDiv [Div α] :
|
||||
Eq (@Div.div α _) (@HDiv.hDiv α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Mod.mod_eq_hMod [Mod α] :
|
||||
Eq (@Mod.mod α _) (@HMod.hMod α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Pow.pow_eq_hPow {α β} [Pow α β] :
|
||||
Eq (@Pow.pow α β _) (@HPow.hPow α β α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem SMul.smul_eq_hSMul {α β} [SMul α β] :
|
||||
Eq (@SMul.smul α β _) (@HSMul.hSMul α β β _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Mul.mul_eq_smul {α} [Mul α] :
|
||||
Eq (@Mul.mul α _) (@SMul.smul α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem Append.append_eq_hAppend [Append α] :
|
||||
Eq (@Append.append α _) (@HAppend.hAppend α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem OrElse.orElse_eq_hOrElse [OrElse α] :
|
||||
Eq (@OrElse.orElse α _) (@HOrElse.hOrElse α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem AndThen.andThen_eq_hAndThen [AndThen α] :
|
||||
Eq (@AndThen.andThen α _) (@HAndThen.hAndThen α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem AndOp.andOp_hAnd [AndOp α] :
|
||||
Eq (@AndOp.and α _) (@HAnd.hAnd α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem XorOp.xor_hXor [XorOp α] :
|
||||
Eq (@XorOp.xor α _) (@HXor.hXor α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem OrOp.or_hOr [OrOp α] :
|
||||
Eq (@OrOp.or α _) (@HOr.hOr α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem ShiftLeft.shiftLeft_hShiftLeft [ShiftLeft α] :
|
||||
Eq (@ShiftLeft.shiftLeft α _) (@HShiftLeft.hShiftLeft α α α _) := rfl
|
||||
|
||||
@[method_specs_simp] theorem ShiftRight.shiftRight_hShiftRight [ShiftRight α] :
|
||||
Eq (@ShiftRight.shiftRight α _) (@HShiftRight.hShiftRight α α α _) := rfl
|
||||
|
||||
end
|
||||
@@ -19,7 +19,7 @@ namespace Lean
|
||||
Auxiliary type used to represent syntax categories. We mainly use auxiliary
|
||||
definitions with this type to attach doc strings to syntax categories.
|
||||
-/
|
||||
structure Parser.Category
|
||||
meta structure Parser.Category
|
||||
|
||||
namespace Parser.Category
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ syntax bracketedExplicitBinders := "(" withoutPosition((binderIdent ppSpace)+
|
||||
syntax explicitBinders := (ppSpace bracketedExplicitBinders)+ <|> unbracketedExplicitBinders
|
||||
|
||||
open TSyntax.Compat in
|
||||
def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax) (type? : Option Syntax) (body : Syntax) : MacroM Syntax :=
|
||||
meta def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax) (type? : Option Syntax) (body : Syntax) : MacroM Syntax :=
|
||||
let rec loop (i : Nat) (h : i ≤ idents.size) (acc : Syntax) := do
|
||||
match i with
|
||||
| 0 => pure acc
|
||||
@@ -39,7 +39,7 @@ def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax) (type
|
||||
loop i (Nat.le_of_succ_le h) acc
|
||||
loop idents.size (by simp) body
|
||||
|
||||
def expandBracketedBindersAux (combinator : Syntax) (binders : Array Syntax) (body : Syntax) : MacroM Syntax :=
|
||||
meta def expandBracketedBindersAux (combinator : Syntax) (binders : Array Syntax) (body : Syntax) : MacroM Syntax :=
|
||||
let rec loop (i : Nat) (h : i ≤ binders.size) (acc : Syntax) := do
|
||||
match i with
|
||||
| 0 => pure acc
|
||||
@@ -49,7 +49,7 @@ def expandBracketedBindersAux (combinator : Syntax) (binders : Array Syntax) (bo
|
||||
loop i (Nat.le_of_succ_le h) (← expandExplicitBindersAux combinator idents (some type) acc)
|
||||
loop binders.size (by simp) body
|
||||
|
||||
def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
meta def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
let combinator := mkCIdentFrom (← getRef) combinatorDeclName
|
||||
let explicitBinders := explicitBinders[0]
|
||||
if explicitBinders.getKind == ``Lean.unbracketedExplicitBinders then
|
||||
@@ -61,7 +61,7 @@ def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax)
|
||||
else
|
||||
Macro.throwError "unexpected explicit binder"
|
||||
|
||||
def expandBracketedBinders (combinatorDeclName : Name) (bracketedExplicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
meta def expandBracketedBinders (combinatorDeclName : Name) (bracketedExplicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
|
||||
let combinator := mkCIdentFrom (← getRef) combinatorDeclName
|
||||
expandBracketedBindersAux combinator #[bracketedExplicitBinders] body
|
||||
|
||||
|
||||
@@ -3010,218 +3010,56 @@ def List.concat {α : Type u} : List α → α → List α
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
Appends two lists. Normally used via the `++` operator.
|
||||
|
||||
Appending lists takes time proportional to the length of the first list: `O(|xs|)`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
|
||||
* `[] ++ [4, 5] = [4, 5]`.
|
||||
* `[1, 2, 3] ++ [] = [1, 2, 3]`.
|
||||
-/
|
||||
def String.utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val.toNat
|
||||
ite (LE.le v 0x7f)
|
||||
(List.cons (UInt8.ofNat v) List.nil)
|
||||
(ite (LE.le v 0x7ff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x20) 0xc0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))
|
||||
(ite (LE.le v 0xffff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x10) 0xe0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil)))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 262144) 0x08) 0xf0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))))))
|
||||
protected def List.append : (xs ys : List α) → List α
|
||||
| nil, bs => bs
|
||||
| cons a as, bs => cons a (List.append as bs)
|
||||
|
||||
/--
|
||||
A string is a sequence of Unicode code points.
|
||||
Concatenates a list of lists into a single list, preserving the order of the elements.
|
||||
|
||||
At runtime, strings are represented by [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array)
|
||||
of bytes using the UTF-8 encoding. Both the size in bytes (`String.utf8ByteSize`) and in characters
|
||||
(`String.length`) are cached and take constant time. Many operations on strings perform in-place
|
||||
modifications when the reference to the string is unique.
|
||||
`O(|flatten L|)`.
|
||||
|
||||
Examples:
|
||||
* `[["a"], ["b", "c"]].flatten = ["a", "b", "c"]`
|
||||
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flatten = ["a", "b", "c", "d", "e", "f"]`
|
||||
-/
|
||||
structure String where
|
||||
/-- Pack a `List Char` into a `String`. This function is overridden by the
|
||||
compiler and is O(n) in the length of the list. -/
|
||||
mk ::
|
||||
/-- Unpack `String` into a `List Char`. This function is overridden by the
|
||||
compiler and is O(n) in the length of the list. -/
|
||||
data : List Char
|
||||
|
||||
attribute [extern "lean_string_mk"] String.mk
|
||||
attribute [extern "lean_string_data"] String.data
|
||||
def List.flatten : List (List α) → List α
|
||||
| nil => nil
|
||||
| cons l L => List.append l (flatten L)
|
||||
|
||||
/--
|
||||
Decides whether two strings are equal. Normally used via the `DecidableEq String` instance and the
|
||||
`=` operator.
|
||||
Applies a function to each element of the list, returning the resulting list of values.
|
||||
|
||||
At runtime, this function is overridden with an efficient native implementation.
|
||||
`O(|l|)`.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].map f = [f a, f b, f c]`
|
||||
* `[].map Nat.succ = []`
|
||||
* `["one", "two", "three"].map (·.length) = [3, 3, 5]`
|
||||
* `["one", "two", "three"].map (·.reverse) = ["eno", "owt", "eerht"]`
|
||||
-/
|
||||
@[extern "lean_string_dec_eq"]
|
||||
def String.decEq (s₁ s₂ : @& String) : Decidable (Eq s₁ s₂) :=
|
||||
match s₁, s₂ with
|
||||
| ⟨s₁⟩, ⟨s₂⟩ =>
|
||||
dite (Eq s₁ s₂) (fun h => isTrue (congrArg _ h)) (fun h => isFalse (fun h' => String.noConfusion h' (fun h' => absurd h' h)))
|
||||
|
||||
instance : DecidableEq String := String.decEq
|
||||
@[specialize] def List.map (f : α → β) : (l : List α) → List β
|
||||
| nil => nil
|
||||
| cons a as => cons (f a) (map f as)
|
||||
|
||||
/--
|
||||
A byte position in a `String`, according to its UTF-8 encoding.
|
||||
Applies a function that returns a list to each element of a list, and concatenates the resulting
|
||||
lists.
|
||||
|
||||
Character positions (counting the Unicode code points rather than bytes) are represented by plain
|
||||
`Nat`s. Indexing a `String` by a `String.Pos` takes constant time, while character positions need to
|
||||
be translated internally to byte positions, which takes linear time.
|
||||
|
||||
A byte position `p` is *valid* for a string `s` if `0 ≤ p ≤ s.endPos` and `p` lies on a UTF-8
|
||||
character boundary.
|
||||
Examples:
|
||||
* `[2, 3, 2].flatMap List.range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
* `["red", "blue"].flatMap String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
|
||||
-/
|
||||
structure String.Pos where
|
||||
/-- Get the underlying byte index of a `String.Pos` -/
|
||||
byteIdx : Nat := 0
|
||||
|
||||
instance : Inhabited String.Pos where
|
||||
default := {}
|
||||
|
||||
instance : DecidableEq String.Pos :=
|
||||
fun ⟨a⟩ ⟨b⟩ => match decEq a b with
|
||||
| isTrue h => isTrue (h ▸ rfl)
|
||||
| isFalse h => isFalse (fun he => String.Pos.noConfusion he fun he => absurd he h)
|
||||
|
||||
/--
|
||||
A region or slice of some underlying string.
|
||||
|
||||
A substring contains an string together with the start and end byte positions of a region of
|
||||
interest. Actually extracting a substring requires copying and memory allocation, while many
|
||||
substrings of the same underlying string may exist with very little overhead, and they are more
|
||||
convenient than tracking the bounds by hand.
|
||||
|
||||
Using its constructor explicitly, it is possible to construct a `Substring` in which one or both of
|
||||
the positions is invalid for the string. Many operations will return unexpected or confusing results
|
||||
if the start and stop positions are not valid. Instead, it's better to use API functions that ensure
|
||||
the validity of the positions in a substring to create and manipulate them.
|
||||
-/
|
||||
structure Substring where
|
||||
/-- The underlying string. -/
|
||||
str : String
|
||||
/-- The byte position of the start of the string slice. -/
|
||||
startPos : String.Pos
|
||||
/-- The byte position of the end of the string slice. -/
|
||||
stopPos : String.Pos
|
||||
|
||||
instance : Inhabited Substring where
|
||||
default := ⟨"", {}, {}⟩
|
||||
|
||||
/--
|
||||
The number of bytes used by the string's UTF-8 encoding.
|
||||
-/
|
||||
@[inline, expose] def Substring.bsize : Substring → Nat
|
||||
| ⟨_, b, e⟩ => e.byteIdx.sub b.byteIdx
|
||||
|
||||
/--
|
||||
The number of bytes used by the string's UTF-8 encoding.
|
||||
|
||||
At runtime, this function takes constant time because the byte length of strings is cached.
|
||||
-/
|
||||
@[extern "lean_string_utf8_byte_size"]
|
||||
def String.utf8ByteSize : (@& String) → Nat
|
||||
| ⟨s⟩ => go s
|
||||
where
|
||||
go : List Char → Nat
|
||||
| .nil => 0
|
||||
| .cons c cs => hAdd (go cs) c.utf8Size
|
||||
|
||||
/--
|
||||
A UTF-8 byte position that points at the end of a string, just after the last character.
|
||||
|
||||
* `"abc".endPos = ⟨3⟩`
|
||||
* `"L∃∀N".endPos = ⟨8⟩`
|
||||
-/
|
||||
@[inline] def String.endPos (s : String) : String.Pos where
|
||||
byteIdx := utf8ByteSize s
|
||||
|
||||
/--
|
||||
Converts a `String` into a `Substring` that denotes the entire string.
|
||||
-/
|
||||
@[inline] def String.toSubstring (s : String) : Substring where
|
||||
str := s
|
||||
startPos := {}
|
||||
stopPos := s.endPos
|
||||
|
||||
/--
|
||||
Converts a `String` into a `Substring` that denotes the entire string.
|
||||
|
||||
This is a version of `String.toSubstring` that doesn't have an `@[inline]` annotation.
|
||||
-/
|
||||
def String.toSubstring' (s : String) : Substring :=
|
||||
s.toSubstring
|
||||
|
||||
/--
|
||||
This function will cast a value of type `α` to type `β`, and is a no-op in the
|
||||
compiler. This function is **extremely dangerous** because there is no guarantee
|
||||
that types `α` and `β` have the same data representation, and this can lead to
|
||||
memory unsafety. It is also logically unsound, since you could just cast
|
||||
`True` to `False`. For all those reasons this function is marked as `unsafe`.
|
||||
|
||||
It is implemented by lifting both `α` and `β` into a common universe, and then
|
||||
using `cast (lcProof : ULift (PLift α) = ULift (PLift β))` to actually perform
|
||||
the cast. All these operations are no-ops in the compiler.
|
||||
|
||||
Using this function correctly requires some knowledge of the data representation
|
||||
of the source and target types. Some general classes of casts which are safe in
|
||||
the current runtime:
|
||||
|
||||
* `Array α` to `Array β` where `α` and `β` have compatible representations,
|
||||
or more generally for other inductive types.
|
||||
* `Quot α r` and `α`.
|
||||
* `@Subtype α p` and `α`, or generally any structure containing only one
|
||||
non-`Prop` field of type `α`.
|
||||
* Casting `α` to/from `NonScalar` when `α` is a boxed generic type
|
||||
(i.e. a function that accepts an arbitrary type `α` and is not specialized to
|
||||
a scalar type like `UInt8`).
|
||||
-/
|
||||
unsafe def unsafeCast {α : Sort u} {β : Sort v} (a : α) : β :=
|
||||
PLift.down (ULift.down.{max u v} (cast lcProof (ULift.up.{max u v} (PLift.up a))))
|
||||
|
||||
|
||||
/-- Auxiliary definition for `panic`. -/
|
||||
/-
|
||||
This is a workaround for `panic` occurring in monadic code. See issue #695.
|
||||
The `panicCore` definition cannot be specialized since it is an extern.
|
||||
When `panic` occurs in monadic code, the `Inhabited α` parameter depends on a
|
||||
`[inst : Monad m]` instance. The `inst` parameter will not be eliminated during
|
||||
specialization if it occurs inside of a binder (to avoid work duplication), and
|
||||
will prevent the actual monad from being "copied" to the code being specialized.
|
||||
When we reimplement the specializer, we may consider copying `inst` if it also
|
||||
occurs outside binders or if it is an instance.
|
||||
-/
|
||||
@[never_extract, extern "lean_panic_fn"]
|
||||
def panicCore {α : Sort u} [Inhabited α] (msg : String) : α := default
|
||||
|
||||
/--
|
||||
`(panic "msg" : α)` has a built-in implementation which prints `msg` to
|
||||
the error buffer. It *does not* terminate execution, and because it is a safe
|
||||
function, it still has to return an element of `α`, so it takes `[Inhabited α]`
|
||||
and returns `default`. It is primarily intended for debugging in pure contexts,
|
||||
and assertion failures.
|
||||
|
||||
Because this is a pure function with side effects, it is marked as
|
||||
`@[never_extract]` so that the compiler will not perform common sub-expression
|
||||
elimination and other optimizations that assume that the expression is pure.
|
||||
-/
|
||||
@[noinline, never_extract]
|
||||
def panic {α : Sort u} [Inhabited α] (msg : String) : α :=
|
||||
panicCore msg
|
||||
|
||||
-- TODO: this be applied directly to `Inhabited`'s definition when we remove the above workaround
|
||||
attribute [nospecialize] Inhabited
|
||||
@[inline] def List.flatMap {α : Type u} {β : Type v} (b : α → List β) (as : List α) : List β := flatten (map b as)
|
||||
|
||||
/--
|
||||
`Array α` is the type of [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array) with elements
|
||||
@@ -3452,6 +3290,276 @@ def Array.extract (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : A
|
||||
let sz' := Nat.sub (min stop as.size) start
|
||||
loop sz' start (emptyWithCapacity sz')
|
||||
|
||||
/-- `ByteArray` is like `Array UInt8`, but with an efficient run-time representation as a packed
|
||||
byte buffer. -/
|
||||
structure ByteArray where
|
||||
/-- The data contained in the byte array. -/
|
||||
data : Array UInt8
|
||||
|
||||
attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
/--
|
||||
Constructs a new empty byte array with initial capacity `c`.
|
||||
-/
|
||||
@[extern "lean_mk_empty_byte_array"]
|
||||
def ByteArray.emptyWithCapacity (c : @& Nat) : ByteArray :=
|
||||
{ data := Array.empty }
|
||||
|
||||
/--
|
||||
Constructs a new empty byte array with initial capacity `0`.
|
||||
|
||||
Use `ByteArray.emptyWithCapacity` to create an array with a greater initial capacity.
|
||||
-/
|
||||
def ByteArray.empty : ByteArray := emptyWithCapacity 0
|
||||
|
||||
/--
|
||||
Adds an element to the end of an array. The resulting array's size is one greater than the input
|
||||
array. If there are no other references to the array, then it is modified in-place.
|
||||
|
||||
This takes amortized `O(1)` time because `Array α` is represented by a dynamic array.
|
||||
-/
|
||||
@[extern "lean_byte_array_push"]
|
||||
def ByteArray.push : ByteArray → UInt8 → ByteArray
|
||||
| ⟨bs⟩, b => ⟨bs.push b⟩
|
||||
|
||||
/--
|
||||
Converts a list of bytes into a `ByteArray`.
|
||||
-/
|
||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
let rec loop
|
||||
| nil, r => r
|
||||
| cons b bs, r => loop bs (r.push b)
|
||||
loop bs ByteArray.empty
|
||||
|
||||
/-- Returns the size of the byte array. -/
|
||||
@[extern "lean_byte_array_size"]
|
||||
def ByteArray.size : (@& ByteArray) → Nat
|
||||
| ⟨bs⟩ => bs.size
|
||||
|
||||
/--
|
||||
Returns the sequence of bytes in a character's UTF-8 encoding.
|
||||
-/
|
||||
def String.utf8EncodeChar (c : Char) : List UInt8 :=
|
||||
let v := c.val.toNat
|
||||
ite (LE.le v 0x7f)
|
||||
(List.cons (UInt8.ofNat v) List.nil)
|
||||
(ite (LE.le v 0x7ff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x20) 0xc0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))
|
||||
(ite (LE.le v 0xffff)
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x10) 0xe0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil)))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 262144) 0x08) 0xf0))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 4096) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod (HDiv.hDiv v 64) 0x40) 0x80))
|
||||
(List.cons
|
||||
(UInt8.ofNat (HAdd.hAdd (HMod.hMod v 0x40) 0x80))
|
||||
List.nil))))))
|
||||
|
||||
/-- Encode a list of characters (Unicode scalar value) in UTF-8. This is an inefficient model
|
||||
implementation. Use `List.asString` instead. -/
|
||||
def List.utf8Encode (l : List Char) : ByteArray :=
|
||||
l.flatMap String.utf8EncodeChar |>.toByteArray
|
||||
|
||||
/-- A byte array is valid UTF-8 if it is of the form `List.Internal.utf8Encode m` for some `m`.
|
||||
|
||||
Note that in order for this definition to be well-behaved it is necessary to know that this `m`
|
||||
is unique. To show this, one defines UTF-8 decoding and shows that encoding and decoding are
|
||||
mutually inverse. -/
|
||||
inductive ByteArray.IsValidUtf8 (b : ByteArray) : Prop
|
||||
/-- Show that a byte -/
|
||||
| intro (m : List Char) (hm : Eq b (List.utf8Encode m))
|
||||
|
||||
/--
|
||||
A string is a sequence of Unicode scalar values.
|
||||
|
||||
At runtime, strings are represented by [dynamic arrays](https://en.wikipedia.org/wiki/Dynamic_array)
|
||||
of bytes using the UTF-8 encoding. Both the size in bytes (`String.utf8ByteSize`) and in characters
|
||||
(`String.length`) are cached and take constant time. Many operations on strings perform in-place
|
||||
modifications when the reference to the string is unique.
|
||||
-/
|
||||
structure String where ofByteArray ::
|
||||
/-- The bytes of the UTF-8 encoding of the string. -/
|
||||
bytes : ByteArray
|
||||
/-- The bytes of the string form valid UTF-8. -/
|
||||
isValidUtf8 : ByteArray.IsValidUtf8 bytes
|
||||
|
||||
attribute [extern "lean_string_to_utf8"] String.bytes
|
||||
|
||||
/--
|
||||
Decides whether two strings are equal. Normally used via the `DecidableEq String` instance and the
|
||||
`=` operator.
|
||||
|
||||
At runtime, this function is overridden with an efficient native implementation.
|
||||
-/
|
||||
@[extern "lean_string_dec_eq"]
|
||||
def String.decEq (s₁ s₂ : @& String) : Decidable (Eq s₁ s₂) :=
|
||||
match s₁, s₂ with
|
||||
| ⟨⟨⟨s₁⟩⟩, _⟩, ⟨⟨⟨s₂⟩⟩, _⟩ =>
|
||||
dite (Eq s₁ s₂) (fun h => match s₁, s₂, h with | _, _, Eq.refl _ => isTrue rfl)
|
||||
(fun h => isFalse
|
||||
(fun h' => h (congrArg (fun s => Array.toList (ByteArray.data (String.bytes s))) h')))
|
||||
|
||||
instance : DecidableEq String := String.decEq
|
||||
|
||||
/--
|
||||
A byte position in a `String`, according to its UTF-8 encoding.
|
||||
|
||||
Character positions (counting the Unicode code points rather than bytes) are represented by plain
|
||||
`Nat`s. Indexing a `String` by a `String.Pos` takes constant time, while character positions need to
|
||||
be translated internally to byte positions, which takes linear time.
|
||||
|
||||
A byte position `p` is *valid* for a string `s` if `0 ≤ p ≤ s.endPos` and `p` lies on a UTF-8
|
||||
character boundary.
|
||||
-/
|
||||
structure String.Pos where
|
||||
/-- Get the underlying byte index of a `String.Pos` -/
|
||||
byteIdx : Nat := 0
|
||||
|
||||
instance : Inhabited String.Pos where
|
||||
default := {}
|
||||
|
||||
instance : DecidableEq String.Pos :=
|
||||
fun ⟨a⟩ ⟨b⟩ => match decEq a b with
|
||||
| isTrue h => isTrue (h ▸ rfl)
|
||||
| isFalse h => isFalse (fun he => String.Pos.noConfusion he fun he => absurd he h)
|
||||
|
||||
/--
|
||||
A region or slice of some underlying string.
|
||||
|
||||
A substring contains an string together with the start and end byte positions of a region of
|
||||
interest. Actually extracting a substring requires copying and memory allocation, while many
|
||||
substrings of the same underlying string may exist with very little overhead, and they are more
|
||||
convenient than tracking the bounds by hand.
|
||||
|
||||
Using its constructor explicitly, it is possible to construct a `Substring` in which one or both of
|
||||
the positions is invalid for the string. Many operations will return unexpected or confusing results
|
||||
if the start and stop positions are not valid. Instead, it's better to use API functions that ensure
|
||||
the validity of the positions in a substring to create and manipulate them.
|
||||
-/
|
||||
structure Substring where
|
||||
/-- The underlying string. -/
|
||||
str : String
|
||||
/-- The byte position of the start of the string slice. -/
|
||||
startPos : String.Pos
|
||||
/-- The byte position of the end of the string slice. -/
|
||||
stopPos : String.Pos
|
||||
|
||||
instance : Inhabited Substring where
|
||||
default := ⟨"", {}, {}⟩
|
||||
|
||||
/--
|
||||
The number of bytes used by the string's UTF-8 encoding.
|
||||
-/
|
||||
@[inline, expose] def Substring.bsize : Substring → Nat
|
||||
| ⟨_, b, e⟩ => e.byteIdx.sub b.byteIdx
|
||||
|
||||
/--
|
||||
The number of bytes used by the string's UTF-8 encoding.
|
||||
|
||||
At runtime, this function takes constant time because the byte length of strings is cached.
|
||||
-/
|
||||
@[extern "lean_string_utf8_byte_size"]
|
||||
def String.utf8ByteSize (s : @& String) : Nat :=
|
||||
s.bytes.size
|
||||
|
||||
/--
|
||||
A UTF-8 byte position that points at the end of a string, just after the last character.
|
||||
|
||||
* `"abc".endPos = ⟨3⟩`
|
||||
* `"L∃∀N".endPos = ⟨8⟩`
|
||||
-/
|
||||
@[inline] def String.endPos (s : String) : String.Pos where
|
||||
byteIdx := utf8ByteSize s
|
||||
|
||||
/--
|
||||
Converts a `String` into a `Substring` that denotes the entire string.
|
||||
-/
|
||||
@[inline] def String.toSubstring (s : String) : Substring where
|
||||
str := s
|
||||
startPos := {}
|
||||
stopPos := s.endPos
|
||||
|
||||
/--
|
||||
Converts a `String` into a `Substring` that denotes the entire string.
|
||||
|
||||
This is a version of `String.toSubstring` that doesn't have an `@[inline]` annotation.
|
||||
-/
|
||||
def String.toSubstring' (s : String) : Substring :=
|
||||
s.toSubstring
|
||||
|
||||
/--
|
||||
This function will cast a value of type `α` to type `β`, and is a no-op in the
|
||||
compiler. This function is **extremely dangerous** because there is no guarantee
|
||||
that types `α` and `β` have the same data representation, and this can lead to
|
||||
memory unsafety. It is also logically unsound, since you could just cast
|
||||
`True` to `False`. For all those reasons this function is marked as `unsafe`.
|
||||
|
||||
It is implemented by lifting both `α` and `β` into a common universe, and then
|
||||
using `cast (lcProof : ULift (PLift α) = ULift (PLift β))` to actually perform
|
||||
the cast. All these operations are no-ops in the compiler.
|
||||
|
||||
Using this function correctly requires some knowledge of the data representation
|
||||
of the source and target types. Some general classes of casts which are safe in
|
||||
the current runtime:
|
||||
|
||||
* `Array α` to `Array β` where `α` and `β` have compatible representations,
|
||||
or more generally for other inductive types.
|
||||
* `Quot α r` and `α`.
|
||||
* `@Subtype α p` and `α`, or generally any structure containing only one
|
||||
non-`Prop` field of type `α`.
|
||||
* Casting `α` to/from `NonScalar` when `α` is a boxed generic type
|
||||
(i.e. a function that accepts an arbitrary type `α` and is not specialized to
|
||||
a scalar type like `UInt8`).
|
||||
-/
|
||||
unsafe def unsafeCast {α : Sort u} {β : Sort v} (a : α) : β :=
|
||||
PLift.down (ULift.down.{max u v} (cast lcProof (ULift.up.{max u v} (PLift.up a))))
|
||||
|
||||
|
||||
/-- Auxiliary definition for `panic`. -/
|
||||
/-
|
||||
This is a workaround for `panic` occurring in monadic code. See issue #695.
|
||||
The `panicCore` definition cannot be specialized since it is an extern.
|
||||
When `panic` occurs in monadic code, the `Inhabited α` parameter depends on a
|
||||
`[inst : Monad m]` instance. The `inst` parameter will not be eliminated during
|
||||
specialization if it occurs inside of a binder (to avoid work duplication), and
|
||||
will prevent the actual monad from being "copied" to the code being specialized.
|
||||
When we reimplement the specializer, we may consider copying `inst` if it also
|
||||
occurs outside binders or if it is an instance.
|
||||
-/
|
||||
@[never_extract, extern "lean_panic_fn"]
|
||||
def panicCore {α : Sort u} [Inhabited α] (msg : String) : α := default
|
||||
|
||||
/--
|
||||
`(panic "msg" : α)` has a built-in implementation which prints `msg` to
|
||||
the error buffer. It *does not* terminate execution, and because it is a safe
|
||||
function, it still has to return an element of `α`, so it takes `[Inhabited α]`
|
||||
and returns `default`. It is primarily intended for debugging in pure contexts,
|
||||
and assertion failures.
|
||||
|
||||
Because this is a pure function with side effects, it is marked as
|
||||
`@[never_extract]` so that the compiler will not perform common sub-expression
|
||||
elimination and other optimizations that assume that the expression is pure.
|
||||
-/
|
||||
@[noinline, never_extract]
|
||||
def panic {α : Sort u} [Inhabited α] (msg : String) : α :=
|
||||
panicCore msg
|
||||
|
||||
-- TODO: this be applied directly to `Inhabited`'s definition when we remove the above workaround
|
||||
attribute [nospecialize] Inhabited
|
||||
|
||||
/--
|
||||
The `>>=` operator is overloaded via instances of `bind`.
|
||||
|
||||
@@ -5125,12 +5233,32 @@ inductive ParserDescr where
|
||||
The precedence `prec` and `lhsPrec` are used to determine whether the parser
|
||||
should apply. -/
|
||||
| trailingNode (kind : SyntaxNodeKind) (prec lhsPrec : Nat) (p : ParserDescr)
|
||||
/-- A literal symbol parser: parses `val` as a literal.
|
||||
This parser does not work on identifiers, so `symbol` arguments are declared
|
||||
as "keywords" and cannot be used as identifiers anywhere in the file. -/
|
||||
/--
|
||||
Parses the literal symbol.
|
||||
|
||||
The symbol is automatically included in the set of reserved tokens ("keywords").
|
||||
Keywords cannot be used as identifiers, unless the identifier is otherwise escaped.
|
||||
For example, `"fun"` reserves `fun` as a keyword; to refer an identifier named `fun` one can write `«fun»`.
|
||||
Adding a `&` prefix prevents it from being reserved, for example `&"true"`.
|
||||
|
||||
Whitespace before or after the atom is used as a pretty printing hint.
|
||||
For example, `" + "` parses `+` and pretty prints it with whitespace on both sides.
|
||||
The whitespace has no effect on parsing behavior.
|
||||
-/
|
||||
| symbol (val : String)
|
||||
/-- Like `symbol`, but without reserving `val` as a keyword.
|
||||
If `includeIdent` is true then `ident` will be reinterpreted as `atom` if it matches. -/
|
||||
/--
|
||||
Parses a literal symbol. The `&` prefix prevents it from being included in the set of reserved tokens ("keywords").
|
||||
This means that the symbol can still be recognized as an identifier by other parsers.
|
||||
|
||||
Some syntax categories, such as `tactic`, automatically apply `&` to the first symbol.
|
||||
|
||||
Whitespace before or after the atom is used as a pretty printing hint.
|
||||
For example, `" + "` parses `+` and pretty prints it with whitespace on both sides.
|
||||
The whitespace has no effect on parsing behavior.
|
||||
|
||||
(Not exposed by parser description syntax:
|
||||
If the `includeIdent` argument is true, lets `ident` be reinterpreted as `atom` if it matches.)
|
||||
-/
|
||||
| nonReservedSymbol (val : String) (includeIdent : Bool)
|
||||
/-- Parses using the category parser `catName` with right binding power
|
||||
(i.e. precedence) `rbp`. -/
|
||||
@@ -5150,6 +5278,19 @@ inductive ParserDescr where
|
||||
/-- `sepBy1` is just like `sepBy`, except it takes 1 or more instead of
|
||||
0 or more occurrences of `p`. -/
|
||||
| sepBy1 (p : ParserDescr) (sep : String) (psep : ParserDescr) (allowTrailingSep : Bool := false)
|
||||
/--
|
||||
- `unicode("→", "->")` parses a symbol matching either `→` or `->`. Each symbol is reserved.
|
||||
The second symbol is an ASCII version of the first.
|
||||
The `pp.unicode` option controls which is used when pretty printing.
|
||||
- `unicode("→", "->", preserveForPP)` is the same except for pretty printing behavior.
|
||||
When the `pp.unicode` option is enabled, then the pretty printer uses whichever symbol
|
||||
matches the underlying atom in the syntax.
|
||||
The intent is that `preserveForPP` means that the ASCII variant is preferred.
|
||||
For example, `fun` notation uses `preserveForPP` for its arrow; the delaborator chooses
|
||||
`↦` or `=>` depending on the value of `pp.unicode.fun`, letting users opt-in to formatting with `↦`.
|
||||
Note that `notation` creates a pretty printer preferring the ASCII version.
|
||||
-/
|
||||
| unicodeSymbol (val asciiVal : String) (preserveForPP : Bool)
|
||||
|
||||
instance : Inhabited ParserDescr where
|
||||
default := ParserDescr.symbol ""
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.NotationExtra
|
||||
import Init.Data.ToString.Name
|
||||
public meta import Init.Data.ToString.Name
|
||||
|
||||
public section
|
||||
|
||||
@@ -131,7 +131,7 @@ macro_rules
|
||||
`($[$doc?:docComment]? def $n:ident : $(mkIdent simprocType) := $body
|
||||
builtin_simproc_pattern% $pattern => $n)
|
||||
|
||||
private def mkAttributeCmds
|
||||
private meta def mkAttributeCmds
|
||||
(kind : TSyntax `Lean.Parser.Term.attrKind)
|
||||
(pre? : Option (TSyntax [`Lean.Parser.Tactic.simpPre, `Lean.Parser.Tactic.simpPost]))
|
||||
(ids? : Option (Syntax.TSepArray `ident ","))
|
||||
|
||||
@@ -84,10 +84,11 @@ deriving instance SizeOf for USize
|
||||
deriving instance SizeOf for Char
|
||||
deriving instance SizeOf for Option
|
||||
deriving instance SizeOf for List
|
||||
deriving instance SizeOf for Array
|
||||
deriving instance SizeOf for ByteArray
|
||||
deriving instance SizeOf for String
|
||||
deriving instance SizeOf for String.Pos
|
||||
deriving instance SizeOf for Substring
|
||||
deriving instance SizeOf for Array
|
||||
deriving instance SizeOf for Except
|
||||
deriving instance SizeOf for EStateM.Result
|
||||
|
||||
|
||||
@@ -16,10 +16,6 @@ namespace IO
|
||||
|
||||
private opaque PromisePointed : NonemptyType.{0}
|
||||
|
||||
private structure PromiseImpl (α : Type) : Type where
|
||||
prom : PromisePointed.type
|
||||
h : Nonempty α
|
||||
|
||||
/--
|
||||
`Promise α` allows you to create a `Task α` whose value is provided later by calling `resolve`.
|
||||
|
||||
@@ -33,7 +29,9 @@ Typical usage is as follows:
|
||||
If the promise is dropped without ever being resolved, `promise.result?.get` will return `none`.
|
||||
See `Promise.result!/resultD` for other ways to handle this case.
|
||||
-/
|
||||
def Promise (α : Type) : Type := PromiseImpl α
|
||||
structure Promise (α : Type) : Type where
|
||||
private prom : PromisePointed.type
|
||||
private h : Nonempty α
|
||||
|
||||
instance [s : Nonempty α] : Nonempty (Promise α) :=
|
||||
by exact Nonempty.intro { prom := Classical.choice PromisePointed.property, h := s }
|
||||
|
||||
@@ -477,7 +477,7 @@ syntax negConfigItem := " -" noWs ident
|
||||
|
||||
As a special case, `(config := ...)` sets the entire configuration.
|
||||
-/
|
||||
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") (ident <|> &"config")) " := " withoutPosition(term) ")"
|
||||
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") ident " := ") withoutPosition(term) ")"
|
||||
/-- A configuration item for a tactic configuration. -/
|
||||
syntax configItem := posConfigItem <|> negConfigItem <|> valConfigItem
|
||||
|
||||
@@ -2262,6 +2262,18 @@ such as replacing `if c then _ else _` with `if h : c then _ else _` or `xs.map`
|
||||
-/
|
||||
syntax (name := wf_preprocess) "wf_preprocess" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
/--
|
||||
Theorems tagged with the `method_specs_simp` attribute are used by `@[method_specs]` to further
|
||||
rewrite the theorem statement. This is primarily used to rewrite type class methods further to
|
||||
the desired user-visible form, e.g. from `Append.append` to `HAppend.hAppend`, which has the familiar
|
||||
notation associated.
|
||||
|
||||
The `method_specs` theorems are created on demand (using the realizable constant feature). Thus,
|
||||
this simp set should behave the same in all modules. Do not add theorems to it except in the module
|
||||
defining the thing you are rewriting.
|
||||
-/
|
||||
syntax (name := method_specs_simp) "method_specs_simp" (Tactic.simpPre <|> Tactic.simpPost)? patternIgnore("← " <|> "<- ")? (ppSpace prio)? : attr
|
||||
|
||||
/-- The possible `norm_cast` kinds: `elim`, `move`, or `squash`. -/
|
||||
syntax normCastLabel := &"elim" <|> &"move" <|> &"squash"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Extra tactics and implementation for some tactics defined at `Init/Tactic.lean`
|
||||
-/
|
||||
namespace Lean.Parser.Tactic
|
||||
|
||||
private def expandIfThenElse
|
||||
private meta def expandIfThenElse
|
||||
(ifTk thenTk elseTk pos neg : Syntax)
|
||||
(mkIf : Term → Term → MacroM Term) : MacroM (TSyntax `tactic) := do
|
||||
let mkCase tk holeOrTacticSeq mkName : MacroM (Term × Array (TSyntax `tactic)) := do
|
||||
@@ -24,14 +24,17 @@ private def expandIfThenElse
|
||||
pure (⟨holeOrTacticSeq⟩, #[])
|
||||
else if holeOrTacticSeq.isOfKind `Lean.Parser.Term.hole then
|
||||
pure (← mkName, #[])
|
||||
else if tk.isMissing then
|
||||
pure (← `(sorry), #[])
|
||||
else
|
||||
let hole ← withFreshMacroScope mkName
|
||||
let holeId := hole.raw[1]
|
||||
let case ← (open TSyntax.Compat in `(tactic|
|
||||
case $holeId:ident =>%$tk
|
||||
-- annotate `then/else` with state after `case`
|
||||
with_annotate_state $tk skip
|
||||
$holeOrTacticSeq))
|
||||
let holeId : Ident := ⟨hole.raw[1]⟩
|
||||
let tacticSeq : TSyntax `Lean.Parser.Tactic.tacticSeq := ⟨holeOrTacticSeq⟩
|
||||
-- Use `missing` for ref to ensure that the source range is the same as `holeOrTacticSeq`'s.
|
||||
let tacticSeq : TSyntax `Lean.Parser.Tactic.tacticSeq ← MonadRef.withRef .missing `(tacticSeq|
|
||||
with_annotate_state $tk skip
|
||||
($tacticSeq))
|
||||
let case ← withRef tk <| `(tactic| case $holeId:ident =>%$tk $tacticSeq:tacticSeq)
|
||||
pure (hole, #[case])
|
||||
let (posHole, posCase) ← mkCase thenTk pos `(?pos)
|
||||
let (negHole, negCase) ← mkCase elseTk neg `(?neg)
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Lean.CoreM
|
||||
public import Lean.MonadEnv
|
||||
public import Lean.Compiler.MetaAttr
|
||||
|
||||
public section
|
||||
|
||||
@@ -141,6 +142,15 @@ def throwAttrNotInAsyncCtx (attrName declName : Name) (asyncPrefix? : Option Nam
|
||||
def throwAttrDeclNotOfExpectedType (attrName declName : Name) (givenType expectedType : Expr) : m α :=
|
||||
throwError m!"Cannot add attribute `[{attrName}]`: Declaration `{.ofConstName declName}` has type{indentExpr givenType}\n\
|
||||
but `[{attrName}]` can only be added to declarations of type{indentExpr expectedType}"
|
||||
|
||||
def ensureAttrDeclIsMeta [MonadEnv m] (attrName declName : Name) (attrKind : AttributeKind) : m Unit := do
|
||||
if (← getEnv).header.isModule && !isMeta (← getEnv) declName then
|
||||
throwError m!"Cannot add attribute `[{attrName}]`: Declaration `{.ofConstName declName}` must be marked as `meta`"
|
||||
-- Make sure attributed decls can't refer to private meta imports, which is already checked for
|
||||
-- public decls.
|
||||
if (← getEnv).header.isModule && attrKind == .global && !((← getEnv).setExporting true).contains declName then
|
||||
throwError m!"Cannot add attribute `[{attrName}]`: Declaration `{.ofConstName declName}` must be public"
|
||||
|
||||
end
|
||||
|
||||
/--
|
||||
|
||||
@@ -62,6 +62,7 @@ builtin_initialize exportAttr : ParametricAttribute Name ←
|
||||
return exportName
|
||||
}
|
||||
|
||||
@[export lean_get_export_name_for]
|
||||
def getExportNameFor? (env : Environment) (n : Name) : Option Name :=
|
||||
exportAttr.getParam? env n
|
||||
|
||||
|
||||
@@ -214,9 +214,9 @@ def getSorryDep (env : Environment) (declName : Name) : Option Name :=
|
||||
|
||||
/-- Returns additional names that compiler env exts may want to call `getModuleIdxFor?` on. -/
|
||||
@[export lean_get_ir_extra_const_names]
|
||||
private def getIRExtraConstNames (env : Environment) (level : OLeanLevel) : Array Name :=
|
||||
private def getIRExtraConstNames (env : Environment) (level : OLeanLevel) (includeDecls := false) : Array Name :=
|
||||
declMapExt.getEntries env |>.toArray.map (·.name)
|
||||
|>.filter fun n => !env.contains n &&
|
||||
|>.filter fun n => (includeDecls || !env.contains n) &&
|
||||
(level == .private || Compiler.LCNF.isDeclPublic env n || isDeclMeta env n)
|
||||
|
||||
end IR
|
||||
|
||||
@@ -44,7 +44,7 @@ partial def inferMeta (decls : Array Decl) : CompilerM Unit := do
|
||||
if !(← getEnv).header.isModule then
|
||||
return
|
||||
for decl in decls do
|
||||
if metaExt.isTagged (← getEnv) decl.name then
|
||||
if isMeta (← getEnv) decl.name then
|
||||
trace[compiler.ir.inferMeta] m!"Marking {decl.name} as meta because it is tagged with `meta`"
|
||||
modifyEnv (setDeclMeta · decl.name)
|
||||
setClosureMeta decl
|
||||
|
||||
@@ -311,21 +311,25 @@ private def isPersistent : Expr → Bool
|
||||
| .fap _ xs => xs.isEmpty -- all global constants are persistent objects
|
||||
| _ => false
|
||||
|
||||
/-- Return true iff `v` at runtime is a scalar value stored in a tagged pointer.
|
||||
We do not need RC operations for this kind of value. -/
|
||||
private def typeForScalarBoxedInTaggedPtr? (v : Expr) : Option IRType :=
|
||||
match v with
|
||||
| .ctor c _ =>
|
||||
some c.type
|
||||
| .lit (.num n) =>
|
||||
if n ≤ maxSmallNat then
|
||||
some .tagged
|
||||
else
|
||||
some .tobject
|
||||
| _ => none
|
||||
/--
|
||||
If `v` is a value that does not need ref counting return `.tagged` so it is never ref counted,
|
||||
otherwise `origt` unmodified.
|
||||
-/
|
||||
private def refineTypeForExpr (v : Expr) (origt : IRType) : IRType :=
|
||||
if origt.isScalar then
|
||||
origt
|
||||
else
|
||||
match v with
|
||||
| .ctor c _ => c.type
|
||||
| .lit (.num n) =>
|
||||
if n ≤ maxSmallNat then
|
||||
.tagged
|
||||
else
|
||||
origt
|
||||
| _ => origt
|
||||
|
||||
private def updateVarInfo (ctx : Context) (x : VarId) (t : IRType) (v : Expr) : Context :=
|
||||
let type := typeForScalarBoxedInTaggedPtr? v |>.getD t
|
||||
let type := refineTypeForExpr v t
|
||||
let isPossibleRef := type.isPossibleRef
|
||||
let isDefiniteRef := type.isDefiniteRef
|
||||
{ ctx with
|
||||
|
||||
@@ -85,6 +85,8 @@ unsafe def registerInitAttrUnsafe (attrName : Name) (runAfterImport : Bool) (ref
|
||||
continue
|
||||
interpretedModInits.modify (·.insert mod)
|
||||
for (decl, initDecl) in modEntries do
|
||||
if getIRPhases ctx.env decl == .runtime then
|
||||
continue
|
||||
if initDecl.isAnonymous then
|
||||
let initFn ← IO.ofExcept <| ctx.env.evalConst (IO Unit) ctx.opts decl
|
||||
initFn
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user