Compare commits

..

1 Commits

Author SHA1 Message Date
Leonardo de Moura
b0cd5e216e fix: unnecessary NatModules in grind linarith
This PR fixes a performance issue in `grind linarith`. It was creating
unnecessary `NatModule`/`IntModule` structures for commutative rings
without an order. This kind of type should be handled by `grind ring` only.
2025-09-09 20:37:20 -07:00
1574 changed files with 7648 additions and 25284 deletions

6
.gitattributes vendored
View File

@@ -4,9 +4,3 @@ RELEASES.md merge=union
stage0/** binary linguist-generated
# The following file is often manually edited, so do show it in diffs
stage0/src/stdlib_flags.h -binary -linguist-generated
# These files should not have line endings translated on Windows, because
# it throws off parser tests. Later lines override earlier ones, so the
# runner code is still treated as ordinary text.
tests/lean/docparse/* eol=lf
tests/lean/docparse/*.lean eol=auto
tests/lean/docparse/*.sh eol=auto

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: actionlint
uses: raven-actions/actionlint@v2
with:

View File

@@ -70,7 +70,7 @@ jobs:
if: runner.os == 'macOS'
- name: Checkout
if: (!endsWith(matrix.os, '-with-cache'))
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -8,7 +8,7 @@ jobs:
check-stage0-on-queue:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
filter: blob:none

View File

@@ -54,7 +54,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
# don't schedule nightlies on forks
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
- name: Set Nightly
@@ -363,7 +363,7 @@ jobs:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
path: artifacts
- name: Release
@@ -388,12 +388,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
# needed for tagging
fetch-depth: 0
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare Nightly Release

View File

@@ -6,7 +6,7 @@ jobs:
check-lean-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Verify .lean files start with a copyright header.
run: |

View File

@@ -395,7 +395,7 @@ jobs:
# Checkout the Batteries repository with all branches
- name: Checkout Batteries repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: leanprover-community/batteries
token: ${{ secrets.MATHLIB4_BOT }}
@@ -454,7 +454,7 @@ jobs:
# Checkout the mathlib4 repository with all branches
- name: Checkout mathlib4 repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: leanprover-community/mathlib4-nightly-testing
token: ${{ secrets.MATHLIB4_BOT }}
@@ -524,7 +524,7 @@ jobs:
# Checkout the reference manual repository with all branches
- name: Checkout mathlib4 repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: leanprover/reference-manual
token: ${{ secrets.MANUAL_PR_BOT }}

View File

@@ -21,13 +21,11 @@ jobs:
runs-on: nscloud-ubuntu-22.04-amd64-8x16
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPRESS: true
CCACHE_MAXSIZE: 400M
steps:
# This action should push to an otherwise protected branch, so it
# uses a deploy key with write permissions, as suggested at
# https://stackoverflow.com/a/76135647/946226
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
@@ -74,14 +72,10 @@ jobs:
restore-keys: |
Linux Lake-build-v3
- if: env.should_update_stage0 == 'yes'
# sync options with `Linux Lake` to ensure cache reuse
run: |
mkdir -p build
cmake --preset release -B build -DLEAN_EXTRA_MAKE_OPTS=-DwarningAsError=true
run: cmake --preset release
shell: 'nix develop -c bash -euxo pipefail {0}'
- if: env.should_update_stage0 == 'yes'
run: |
make -j$NPROC -C build update-stage0-commit
run: make -j$NPROC -C build/release update-stage0-commit
shell: 'nix develop -c bash -euxo pipefail {0}'
- if: env.should_update_stage0 == 'yes'
run: git show --stat

View File

@@ -2,19 +2,19 @@ This is the repository for **Lean 4**.
# About
- [Quickstart](https://lean-lang.org/install/)
- [Quickstart](https://lean-lang.org/documentation/setup/)
- [Homepage](https://lean-lang.org)
- [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/)
- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/)
- [Documentation Overview](https://lean-lang.org/learn/)
- [Documentation Overview](https://lean-lang.org/documentation/)
- [Language Reference](https://lean-lang.org/doc/reference/latest/)
- [Release notes](RELEASES.md) starting at v4.0.0-m3
- [Examples](https://lean-lang.org/examples/)
- [Examples](https://lean-lang.org/lean4/doc/examples.html)
- [External Contribution Guidelines](CONTRIBUTING.md)
# Installation
See [Install Lean](https://lean-lang.org/install/).
See [Setting Up Lean](https://lean-lang.org/documentation/setup/).
# Contributing

View File

@@ -99,19 +99,3 @@ on to `nightly-with-manual` branch. (It is fine to force push after rebasing.)
CI will generate a branch of the reference manual called `lean-pr-testing-NNNN`
in `leanprover/reference-manual`. This branch uses the toolchain for your PR,
and will report back to the Lean PR with results from Mathlib CI.
### Avoiding rebuilds for downstream projects
If you want to test changes to Lean on downstream projects and would like to avoid rebuilding modules you have already built/fetched using the project's configured Lean toolchain, you can often do so as long as your build of Lean is close enough to that Lean toolchain (compatible .olean format including structure of all relevant environment extensions).
To override the toolchain without rebuilding for a single command, for example `lake build` or `lake lean`, you can use the prefix
```
LEAN_GITHASH=$(lean --githash) lake +lean4 ...
```
Alternatively, use
```
export LEAN_GITHASH=$(lean --githash)
export ELAN_TOOLCHAIN=lean4
```
to persist these changes for the lifetime of the current shell, which will affect any processes spawned from it such as VS Code started via `code .`.
If you use a setup where you cannot directly start your editor from the command line, such as VS Code Remote, you might want to consider using [direnv](https://direnv.net/) together with an editor extension for it instead so that you can put the lines above into `.envrc`.

View File

@@ -37,15 +37,6 @@
"isDefault": true
}
},
{
"label": "build-old",
"type": "shell",
"command": "make -C build/release -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) LAKE_EXTRA_ARGS=--old",
"problemMatcher": [],
"group": {
"kind": "build"
}
},
{
"label": "test",
"type": "shell",

View File

@@ -5,7 +5,6 @@ Merge a tag into a branch on a GitHub repository.
This script checks if a specified tag can be merged cleanly into a branch and performs
the merge if possible. If the merge cannot be done cleanly, it prints a helpful message.
Merge conflicts in the lean-toolchain file are automatically resolved by accepting the incoming changes.
Usage:
python3 merge_remote.py <org/repo> <branch> <tag>
@@ -59,32 +58,6 @@ def clone_repo(repo, temp_dir):
return True
def get_conflicted_files():
"""Get list of files with merge conflicts."""
result = run_command("git diff --name-only --diff-filter=U", check=False)
if result.returncode == 0:
return result.stdout.strip().split('\n') if result.stdout.strip() else []
return []
def resolve_lean_toolchain_conflict(tag):
"""Resolve lean-toolchain conflict by accepting incoming (tag) changes."""
print("Resolving lean-toolchain conflict by accepting incoming changes...")
# Accept theirs (incoming) version for lean-toolchain
result = run_command(f"git checkout --theirs lean-toolchain", check=False)
if result.returncode != 0:
print("Failed to resolve lean-toolchain conflict")
return False
# Add the resolved file
add_result = run_command("git add lean-toolchain", check=False)
if add_result.returncode != 0:
print("Failed to stage resolved lean-toolchain")
return False
return True
def check_and_merge(repo, branch, tag, temp_dir):
"""Check if tag can be merged into branch and perform the merge if possible."""
# Change to the temporary directory
@@ -125,37 +98,12 @@ def check_and_merge(repo, branch, tag, temp_dir):
# Try merging the tag directly
print(f"Merging {tag} into {branch}...")
merge_result = run_command(f"git merge {tag} --no-edit", check=False)
if merge_result.returncode != 0:
# Check which files have conflicts
conflicted_files = get_conflicted_files()
if conflicted_files == ['lean-toolchain']:
# Only lean-toolchain has conflicts, resolve it
print("Merge conflict detected only in lean-toolchain.")
if resolve_lean_toolchain_conflict(tag):
# Continue the merge with the resolved conflict
print("Continuing merge with resolved lean-toolchain...")
continue_result = run_command(f"git commit --no-edit", check=False)
if continue_result.returncode != 0:
print("Failed to complete merge after resolving lean-toolchain")
run_command("git merge --abort")
return False
else:
print("Failed to resolve lean-toolchain conflict")
run_command("git merge --abort")
return False
else:
# Other files have conflicts, or unable to determine
if conflicted_files:
print(f"Cannot merge {tag} cleanly into {branch}.")
print(f"Merge conflicts in: {', '.join(conflicted_files)}")
else:
print(f"Cannot merge {tag} cleanly into {branch}.")
print("Merge conflicts would occur.")
print("Aborting merge.")
run_command("git merge --abort")
return False
print(f"Cannot merge {tag} cleanly into {branch}.")
print("Merge conflicts would occur. Aborting merge.")
run_command("git merge --abort")
return False
print(f"Pushing changes to remote...")
push_result = run_command(f"git push origin {branch}")

View File

@@ -1,11 +1,4 @@
repositories:
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: batteries
url: https://github.com/leanprover-community/batteries
toolchain-tag: true
@@ -14,13 +7,6 @@ repositories:
bump-branch: true
dependencies: []
- name: verso
url: https://github.com/leanprover/verso
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: lean4checker
url: https://github.com/leanprover/lean4checker
toolchain-tag: true
@@ -35,6 +21,20 @@ repositories:
branch: master
dependencies: []
- name: lean4-cli
url: https://github.com/leanprover/lean4-cli
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: verso
url: https://github.com/leanprover/verso
toolchain-tag: true
stable-branch: false
branch: main
dependencies: []
- name: plausible
url: https://github.com/leanprover-community/plausible
toolchain-tag: true
@@ -96,15 +96,6 @@ repositories:
- import-graph
- plausible
- name: cslib
url: https://github.com/leanprover/cslib
toolchain-tag: true
stable-branch: true
branch: main
bump-branch: true
dependencies:
- mathlib4
- name: repl
url: https://github.com/leanprover-community/repl
toolchain-tag: true

View File

@@ -377,21 +377,6 @@ def execute_release_steps(repo, version, config):
except subprocess.CalledProcessError as e:
print(red("Tests failed, but continuing with PR creation..."))
print(red(f"Test error: {e}"))
elif repo_name == "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)

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 25)
set(LEAN_VERSION_MINOR 24)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")

View File

@@ -42,8 +42,5 @@ public import Init.While
public import Init.Syntax
public import Init.Internal
public import Init.Try
public meta import Init.Try -- make sure `Try.Config` can be evaluated anywhere
public import Init.BinderNameHint
public import Init.Task
public import Init.MethodSpecsSimp
public import Init.LawfulBEqTactics

View File

@@ -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

View File

@@ -2546,3 +2546,7 @@ class Irrefl (r : αα → Prop) : Prop where
irrefl : a, ¬r a a
end Std
/-- Deprecated alias for `XorOp`. -/
@[deprecated XorOp (since := "2025-07-30")]
abbrev Xor := XorOp

View File

@@ -121,7 +121,7 @@ theorem pmap_eq_map {p : α → Prop} {f : α → β} {xs : Array α} (H) :
theorem pmap_congr_left {p q : α Prop} {f : a, p a β} {g : a, q a β} (xs : Array α) {H₁ H₂}
(h : a xs, (h₁ h₂), f a h₁ = g a h₂) : pmap f xs H₁ = pmap g xs H₂ := by
cases xs
simp only [List.mem_toArray] at h
simp only [mem_toArray] at h
simp only [List.pmap_toArray, mk.injEq]
rw [List.pmap_congr_left _ h]
@@ -194,14 +194,14 @@ 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)
rcases this with _, _, m, rfl
exact m
@[simp, grind =]
@[simp, grind]
theorem mem_attachWith {xs : Array α} {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
cases xs
@@ -212,13 +212,12 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs H b} :
b pmap f xs H (a : _) (h : a xs), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
@[grind]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {xs H} {a} (h : a xs) :
f a (H a h) pmap f xs H := by
rw [mem_pmap]
exact a, h, rfl
grind_pattern mem_pmap_of_mem => _ pmap f xs H, a xs
@[simp, grind =]
theorem size_pmap {p : α Prop} {f : a, p a β} {xs H} : (pmap f xs H).size = xs.size := by
cases xs; simp
@@ -346,7 +345,7 @@ theorem foldl_attach {xs : Array α} {f : β → α → β} {b : β} :
xs.attach.foldl (fun acc t => f acc t.1) b = xs.foldl f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.foldl_toArray', List.mem_toArray, List.foldl_subtype]
List.foldl_toArray', mem_toArray, List.foldl_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
@@ -365,7 +364,7 @@ theorem foldr_attach {xs : Array α} {f : α → β → β} {b : β} :
xs.attach.foldr (fun t acc => f t.1 acc) b = xs.foldr f b := by
rcases xs with xs
simp only [List.attach_toArray, List.attachWith_mem_toArray, List.size_toArray,
List.foldr_toArray', List.mem_toArray, List.foldr_subtype]
List.foldr_toArray', mem_toArray, List.foldr_subtype]
congr
ext
simpa using fun a => List.mem_of_getElem? a
@@ -707,7 +706,7 @@ and simplifies these to the function directly taking the value.
{f : { x // p x } Array β} {g : α Array β} (hf : x h, f x, h = g x) :
(xs.flatMap f) = xs.unattach.flatMap g := by
cases xs
simp only [List.flatMap_toArray, List.unattach_toArray,
simp only [List.flatMap_toArray, List.unattach_toArray,
mk.injEq]
rw [List.flatMap_subtype]
simp [hf]

View File

@@ -40,11 +40,11 @@ namespace Array
/-! ### Preliminary theorems -/
@[simp, grind =] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
@[simp, grind] theorem size_set {xs : Array α} {i : Nat} {v : α} (h : i < xs.size) :
(set xs i v h).size = xs.size :=
List.length_set ..
@[simp, grind =] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
@[simp, grind] theorem size_push {xs : Array α} (v : α) : (push xs v).size = xs.size + 1 :=
List.length_concat ..
theorem ext {xs ys : Array α}
@@ -108,19 +108,13 @@ instance : Membership α (Array α) where
theorem mem_def {a : α} {as : Array α} : a as a as.toList :=
fun | .mk h => h, Array.Mem.mk
@[simp, grind =] theorem _root_.List.mem_toArray {a : α} {l : List α} : a l.toArray a l := by
@[simp, grind =] theorem mem_toArray {a : α} {l : List α} : a l.toArray a l := by
simp [mem_def]
@[deprecated List.mem_toArray (since := "2025-09-04")]
theorem mem_toArray {a : α} {l : List α} : a l.toArray a l :=
List.mem_toArray
@[simp] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
@[simp, grind] theorem getElem_mem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i] xs := by
rw [Array.mem_def, getElem_toList]
apply List.getElem_mem
grind_pattern getElem_mem => xs[i] xs
@[simp, grind =] theorem emptyWithCapacity_eq {α n} : @emptyWithCapacity α n = #[] := rfl
@[simp] theorem mkEmpty_eq {α n} : @mkEmpty α n = #[] := rfl
@@ -138,7 +132,7 @@ theorem toList_toArray {as : List α} : as.toArray.toList = as := rfl
@[deprecated toList_toArray (since := "2025-02-17")]
abbrev _root_.Array.toList_toArray := @List.toList_toArray
@[simp, grind =] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[simp, grind] theorem size_toArray {as : List α} : as.toArray.size = as.length := by simp [Array.size]
@[deprecated size_toArray (since := "2025-02-17")]
abbrev _root_.Array.size_toArray := @List.size_toArray
@@ -203,7 +197,7 @@ Examples:
def pop (xs : Array α) : Array α where
toList := xs.toList.dropLast
@[simp, grind =] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
@[simp, grind] theorem size_pop {xs : Array α} : xs.pop.size = xs.size - 1 := by
match xs with
| [] => rfl
| a::as => simp [pop, Nat.succ_sub_succ_eq_sub, size]

View File

@@ -91,7 +91,7 @@ theorem mem_of_mem_eraseP {xs : Array α} : a ∈ xs.eraseP p → a ∈ xs := by
rcases xs with xs
simpa using List.mem_of_mem_eraseP
@[simp, grind =] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
@[simp, grind] theorem mem_eraseP_of_neg {xs : Array α} (pa : ¬p a) : a xs.eraseP p a xs := by
rcases xs with xs
simpa using List.mem_eraseP_of_neg pa
@@ -240,7 +240,7 @@ theorem mem_of_mem_erase {a b : α} {xs : Array α} (h : a ∈ xs.erase b) : a
rcases xs with xs
simpa using List.mem_of_mem_erase (by simpa using h)
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {xs : Array α} (ab : a b) :
a xs.erase b a xs :=
erase_eq_eraseP b xs mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@@ -271,7 +271,7 @@ theorem erase_append [LawfulBEq α] {a : α} {xs ys : Array α} :
(xs ++ ys).erase a = if a xs then xs.erase a ++ ys else xs ++ ys.erase a := by
rcases xs with xs
rcases ys with ys
simp only [List.append_toArray, List.erase_toArray, List.erase_append, List.mem_toArray]
simp only [List.append_toArray, List.erase_toArray, List.erase_append, mem_toArray]
split <;> simp
@[grind =]

View File

@@ -27,11 +27,11 @@ open Nat
/-! ### findSome? -/
@[simp, grind =] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
@[simp, grind =] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
@[simp, grind] theorem findSome?_empty : (#[] : Array α).findSome? f = none := rfl
@[simp, grind] theorem findSome?_push {xs : Array α} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
cases xs; simp [List.findSome?_append]
@[grind =]
@[grind]
theorem findSome?_singleton {a : α} {f : α Option β} : #[a].findSome? f = f a := by
simp
@@ -228,12 +228,11 @@ theorem mem_of_find?_eq_some {xs : Array α} (h : find? p xs = some a) : a ∈ x
simp at h
simpa using List.mem_of_find?_eq_some h
@[grind]
theorem get_find?_mem {xs : Array α} (h) : (xs.find? p).get h xs := by
cases xs
simp [List.get_find?_mem]
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] theorem find?_filter {xs : Array α} (p q : α Bool) :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
cases xs; simp
@@ -396,6 +395,7 @@ theorem findIdx_singleton {a : α} {p : α → Bool} :
#[a].findIdx p = if p a then 0 else 1 := by
simp
@[grind ]
theorem findIdx_of_getElem?_eq_some {xs : Array α} (w : xs[xs.findIdx p]? = some y) : p y := by
rcases xs with xs
exact List.findIdx_of_getElem?_eq_some (by simpa using w)

File diff suppressed because it is too large Load Diff

View File

@@ -167,7 +167,7 @@ theorem foldrM_filter [Monad m] [LawfulMonad m] {p : α → Bool} {g : α → β
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
forIn' as b f = forIn' bs b' g := by
cases as <;> cases bs
simp only [mk.injEq, List.mem_toArray, List.forIn'_toArray] at w h
simp only [mk.injEq, mem_toArray, List.forIn'_toArray] at w h
exact List.forIn'_congr w hb h
/--

View File

@@ -116,7 +116,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat Bool} :
(range' s n).find? p = some i p i i range' s n j, s j j < i !p j := by
rw [ List.toArray_range']
simp only [List.find?_toArray, List.mem_toArray]
simp only [List.find?_toArray, mem_toArray]
simp [List.find?_range'_eq_some]
@[simp] theorem find?_range'_eq_none {s n : Nat} {p : Nat Bool} :

View File

@@ -19,7 +19,7 @@ theorem testBit_toNat (x : BitVec w) : x.toNat.testBit i = x.getLsbD i := rfl
@[simp, grind =] theorem getLsbD_ofFin (x : Fin (2^n)) (i : Nat) :
getLsbD (BitVec.ofFin x) i = x.val.testBit i := rfl
@[simp, grind =] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getLsbD x i = false := by
@[simp, grind] theorem getLsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getLsbD x i = false := by
let x, x_lt := x
simp only [getLsbD_ofFin]
apply Nat.testBit_lt_two_pow

View File

@@ -37,7 +37,7 @@ namespace BitVec
@[simp] theorem getElem_ofFin (x : Fin (2^n)) (i : Nat) (h : i < n) :
(BitVec.ofFin x)[i] = x.val.testBit i := rfl
@[simp, grind =] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsbD x i = false := by
@[simp, grind] theorem getMsbD_of_ge (x : BitVec w) (i : Nat) (ge : w i) : getMsbD x i = false := by
rw [getMsbD]
simp only [Bool.and_eq_false_imp, decide_eq_true_eq]
omega

View File

@@ -122,7 +122,7 @@ private theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i
rw [foldlM_loop_lt _ _ h', foldlM_loop]; rfl
else
cases Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.not_lt.1 h')
rw [foldlM_loop_lt _ _ h]
rw [foldlM_loop_lt]
congr; funext
rw [foldlM_loop_eq, foldlM_loop_eq]
termination_by n - i

View File

@@ -34,104 +34,20 @@ Examples:
@[inline, expose]
def uncurry : (α β φ) α × β φ := fun f a => f a.1 a.2
@[simp, grind =]
@[simp, grind]
theorem curry_uncurry (f : α β φ) : curry (uncurry f) = f :=
rfl
@[simp, grind =]
@[simp, grind]
theorem uncurry_curry (f : α × β φ) : uncurry (curry f) = f :=
funext fun _a, _b => rfl
@[simp, grind =]
@[simp, grind]
theorem uncurry_apply_pair {α β γ} (f : α β γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
rfl
@[simp, grind =]
@[simp, grind]
theorem curry_apply {α β γ} (f : α × β γ) (x : α) (y : β) : curry f x y = f (x, y) :=
rfl
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
def Injective (f : α β) : Prop :=
a₁ a₂, f a₁ = f a₂ a₁ = a₂
theorem Injective.comp {α β γ} {g : β γ} {f : α β} (hg : Injective g) (hf : Injective f) :
Injective (g f) := fun _a₁ _a₂ => fun h => hf (hg h)
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
for some `a : α`. -/
def Surjective (f : α β) : Prop :=
b, Exists fun a => f a = b
theorem Surjective.comp {α β γ} {g : β γ} {f : α β} (hg : Surjective g) (hf : Surjective f) :
Surjective (g f) := fun c : γ =>
Exists.elim (hg c) fun b hb =>
Exists.elim (hf b) fun a ha =>
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
@[grind]
def LeftInverse {α β} (g : β α) (f : α β) : Prop :=
x, g (f x) = x
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
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]
def RightInverse {α β} (g : β α) (f : α β) : Prop :=
LeftInverse f g
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
def HasRightInverse {α β} (f : α β) : Prop :=
Exists fun finv : β α => RightInverse finv f
theorem LeftInverse.injective {α β} {g : β α} {f : α β} : LeftInverse g f Injective f :=
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
theorem HasLeftInverse.injective {α β} {f : α β} : HasLeftInverse f Injective f := fun h =>
Exists.elim h fun _finv inv => inv.injective
theorem rightInverse_of_injective_of_leftInverse {α β} {f : α β} {g : β α} (injf : Injective f)
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
have h : f (g (f x)) = f x := lfg (f x)
injf h
theorem RightInverse.surjective {α β} {f : α β} {g : β α} (h : RightInverse g f) : Surjective f :=
fun y => g y, h y
theorem HasRightInverse.surjective {α β} {f : α β} : HasRightInverse f Surjective f
| _finv, inv => inv.surjective
theorem leftInverse_of_surjective_of_rightInverse {α β} {f : α β} {g : β α} (surjf : Surjective f)
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
Exists.elim (surjf y) fun x hx => ((hx rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) rfl)).trans hx
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
theorem surjective_id : Surjective (@id α) := fun a => a, rfl
variable {f : α β}
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b a = b :=
@I _ _, congrArg f
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c a = b :=
h I.eq_iff
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ a₂ f a₁ f a₂ :=
mt fun h hf h
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x f y x y :=
mt <| congrArg f, hf.ne
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x z x y :=
h hf.ne_iff
protected theorem LeftInverse.id {α β} {g : β α} {f : α β} (h : LeftInverse g f) : g f = id :=
funext h
protected theorem RightInverse.id {α β} {g : β α} {f : α β} (h : RightInverse g f) : f g = id :=
funext h
end Function

View File

@@ -17,7 +17,6 @@ import all Init.Data.Int.Gcd
public import Init.Data.RArray
public import Init.Data.AC
import all Init.Data.AC
import Init.LawfulBEqTactics
public section
@@ -55,7 +54,7 @@ def Expr.denote (ctx : Context) : Expr → Int
inductive Poly where
| num (k : Int)
| add (k : Int) (v : Var) (p : Poly)
deriving @[expose] BEq, ReflBEq, LawfulBEq
deriving @[expose] BEq
@[expose]
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly Bool :=
@@ -526,6 +525,18 @@ theorem Expr.denote_norm (ctx : Context) (e : Expr) : e.norm.denote ctx = e.deno
simp [norm, toPoly', Expr.denote_toPoly'_go]
attribute [local simp] Expr.denote_norm
instance : LawfulBEq Poly where
eq_of_beq {a} := by
induction a <;> intro b <;> cases b <;> simp_all! [BEq.beq]
next ih =>
intro _ _ h
exact ih h
rfl := by
intro a
induction a <;> simp! [BEq.beq]
assumption
attribute [local simp] Poly.denote'_eq_denote
theorem Expr.eq_of_norm_eq (ctx : Context) (e : Expr) (p : Poly) (h : e.norm.beq' p) : e.denote ctx = p.denote' ctx := by

View File

@@ -139,7 +139,7 @@ def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
@[always_inline, inline, expose, inherit_doc IterM.size]
@[always_inline, inline, inherit_doc IterM.size]
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorSize α Id]
(it : Iter (α := α) β) : Nat :=
(IteratorSize.size it.toIterM).run.down

View File

@@ -57,6 +57,6 @@ theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Mona
[LawfulMonad m] [LawfulIteratorCollect α m m] :
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
rw [ toArray_toList, toArray_toList, map_unattach_toList_attachWith (it := it) (hP := hP)]
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
simp [-map_unattach_toList_attachWith]
end Std.Iterators

View File

@@ -53,6 +53,6 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
[LawfulIteratorCollect α Id Id] :
it.uLift.toArray = it.toArray.map ULift.up := by
rw [ toArray_toList, toArray_toList, toList_uLift]
simp [-toArray_toList]
simp
end Std.Iterators

View File

@@ -44,13 +44,11 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
it.toIter.toListRev = it.toListRev.run :=
(rfl)
@[simp]
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
it.toArray.toList = it.toList := by
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, IterM.toList_toArray]
@[simp]
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
it.toList.toArray = it.toArray := by

View File

@@ -14,7 +14,6 @@ public import Init.Data.Iterators.Consumers.Loop
import all Init.Data.Iterators.Consumers.Loop
public import Init.Data.Iterators.Consumers.Monadic.Collect
import all Init.Data.Iterators.Consumers.Monadic.Collect
import Init.Data.Array.Monadic
public section
@@ -44,20 +43,6 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
f out acc) := by
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
@[congr] theorem Iter.forIn'_congr {α β : Type w}
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
{ita itb : Iter (α := α) β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) _ γ Id (ForInStep γ)}
{g : (a' : β) _ γ Id (ForInStep γ)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
letI : ForIn' Id (Iter (α := α) β) β _ := Iter.instForIn'
forIn' ita b f = forIn' itb b' g := by
subst_eqs
simp only [ funext_iff] at h
rw [ h]
rfl
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type w Type w''} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -203,13 +188,6 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
obtain step, h₁, rfl := h₁
simp [heq, IterStep.successor] at h₁
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
[IteratorCollect α Id Id] [Finite α Id]
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
{it : Iter (α := α) β} {out : β} :
out it.toArray it.IsPlausibleIndirectOutput out := by
rw [ Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -244,17 +222,6 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
simp only [ihs h (f := fun out h acc => f out (this h) acc)]
· simp
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) _ γ m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it.toArray init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mpr h) acc) := by
simp only [ Iter.toArray_toList (it := it), List.forIn'_toArray, Iter.forIn'_toList]
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -267,18 +234,6 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
simp only [forIn'_toList]
congr
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
[LawfulDeterministicIterator α Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : (out : β) _ γ m (ForInStep γ)} :
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
simp only [forIn'_toArray]
congr
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -305,15 +260,6 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
rw [ihs h]
· simp
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{γ : Type x} {it : Iter (α := α) β} {init : γ}
{f : β γ m (ForInStep γ)} :
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
simp only [ Iter.toArray_toList, List.forIn_toArray, forIn_toList]
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x Type x'} [Monad m] [IteratorLoop α Id m] {f : γ β m γ}
{init : γ} {it : Iter (α := α) β} :
@@ -355,14 +301,6 @@ theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [F
rw [Iter.foldM_eq_forIn, Iter.forIn_toList]
simp only [List.forIn_yield_eq_foldlM, id_map']
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
{m : Type x Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{f : γ β m γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
rw [Iter.foldM_eq_forIn, Iter.forIn_toArray]
simp only [Array.forIn_yield_eq_foldlM, id_map']
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
[Finite α Id] {m : Type x Type x'} [Monad m] [LawfulMonad m]
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
@@ -386,12 +324,6 @@ theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
simp [foldM_eq_forIn, fold_eq_forIn]
theorem Iter.fold_eq_fold_toIterM {α β : Type w} {γ : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
it.fold (init := init) f = (it.toIterM.fold (init := init) f).run := by
rw [fold_eq_foldM, foldM_eq_foldM_toIterM, IterM.fold_eq_foldM]
@[simp]
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β γ γ} {init : γ}
@@ -412,38 +344,6 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
generalize it.step = step
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem Iter.fold_hom [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
{it : Iter (α := α) β}
(f : γ₁ γ₂) {g₁ : γ₁ β γ₁} {g₂ : γ₂ β γ₂} {init : γ₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) :
it.fold g₂ (f init) = f (it.fold g₁ init) := by
-- We cannot reduce to `IterM.fold_hom` because `IterM.fold` is necessarily more restrictive
-- w.r.t. the universe of the output.
induction it using Iter.inductSteps generalizing init with | step it ihy ihs =>
rw [fold_eq_match_step, fold_eq_match_step]
split
· rw [H, ihy _]
· rw [ihs _]
· simp
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{it : Iter (α := α) β} :
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{it : Iter (α := α) β} :
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
simp only [ toArray_toList, toList_eq_fold]
rw [ fold_hom (List.toArray)]
simp
@[simp]
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
@@ -452,14 +352,6 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
it.toList.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, List.foldl_eq_foldlM, Iter.foldlM_toList]
@[simp]
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
{f : γ β γ} {init : γ} {it : Iter (α := α) β} :
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
rw [fold_eq_foldM, Array.foldl_eq_foldlM, Iter.foldlM_toArray]
@[simp]
theorem Iter.size_toArray_eq_size {α β : Type w} [Iterator α Id β] [Finite α Id]
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]

View File

@@ -67,17 +67,15 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
simp [bind_pure_comp, pure_bind]
@[simp]
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
{it : IterM (α := α) m β} :
Array.toList <$> it.toArray = it.toList := by
simp [IterM.toList]
@[simp]
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
[IteratorCollect α m m] {it : IterM (α := α) m β} :
List.toArray <$> it.toList = it.toArray := by
simp [IterM.toList, -toList_toArray]
simp [IterM.toList]
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
@@ -155,6 +153,6 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
[hl : LawfulIteratorCollect α m m]
{it : IterM (α := α) m β} :
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
simp [IterM.toList, toArray_eq]
end Std.Iterators

View File

@@ -60,20 +60,6 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (·, .intro) <$> f out acc) := by
simp only [ForIn.forIn, forIn'_eq]
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w Type w'} [Monad m]
[Iterator α m β] [Finite α m] [IteratorLoop α m m]
{ita itb : IterM (α := α) m β} (w : ita = itb)
{b b' : γ} (hb : b = b')
{f : (a' : β) _ γ m (ForInStep γ)}
{g : (a' : β) _ γ m (ForInStep γ)}
(h : a m b, f a (by simpa [w] using m) b = g a m b) :
letI : ForIn' m (IterM (α := α) m β) β _ := IterM.instForIn'
forIn' ita b f = forIn' itb b' g := by
subst_eqs
simp only [ funext_iff] at h
rw [ h]
rfl
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] {n : Type w Type w''} [Monad m] [Monad n] [LawfulMonad n]
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
@@ -214,23 +200,6 @@ theorem IterM.fold_eq_match_step {α β γ : Type w} {m : Type w → Type w'} [I
intro step
cases step using PlausibleIterStep.casesOn <;> simp
-- The argument `f : γ₁ → γ₂` is intentionally explicit, as it is sometimes not found by unification.
theorem IterM.fold_hom {m : Type w Type w'} [Iterator α m β] [Finite α m]
[Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
{it : IterM (α := α) m β}
(f : γ₁ γ₂) {g₁ : γ₁ β γ₁} {g₂ : γ₂ β γ₂} {init : γ₁}
(H : x y, g₂ (f x) y = f (g₁ x y)) :
it.fold g₂ (f init) = f <$> (it.fold g₁ init) := by
induction it using IterM.inductSteps generalizing init with | step it ihy ihs =>
rw [fold_eq_match_step, fold_eq_match_step, map_eq_pure_bind, bind_assoc]
apply bind_congr
intro step
rw [bind_pure_comp]
split
· rw [H, ihy _]
· rw [ihs _]
· simp
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
@@ -254,15 +223,6 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
simp [ihs h]
· simp
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β]
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
{it : IterM (α := α) m β} :
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
simp only [ toArray_toList, toList_eq_fold]
rw [ fold_hom]
simp
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w Type w'} [Iterator α m β] [Finite α m]
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=

View File

@@ -167,14 +167,14 @@ 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)
rcases this with _, _, m, rfl
exact m
@[simp, grind =]
@[simp, grind]
theorem mem_attachWith {l : List α} {q : α Prop} (H) (x : {x // q x}) :
x l.attachWith q H x.1 l := by
induction l with
@@ -192,13 +192,12 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
b pmap f l H (a : _) (h : a l), f a (H a h) = b := by
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
@[grind]
theorem mem_pmap_of_mem {p : α Prop} {f : a, p a β} {l H} {a} (h : a l) :
f a (H a h) pmap f l H := by
rw [mem_pmap]
exact a, h, rfl
grind_pattern mem_pmap_of_mem => _ pmap f l H, a l
@[simp, grind =]
theorem length_pmap {p : α Prop} {f : a, p a β} {l H} : (pmap f l H).length = l.length := by
induction l
@@ -371,13 +370,13 @@ theorem getElem_attach {xs : List α} {i : Nat} (h : i < xs.attach.length) :
xs.attach.tail = xs.tail.attach.map (fun x, h => x, mem_of_mem_tail h) := by
cases xs <;> simp
@[grind =]
@[grind]
theorem foldl_pmap {l : List α} {P : α Prop} {f : (a : α) P a β}
(H : (a : α), a l P a) (g : γ β γ) (x : γ) :
(l.pmap f H).foldl g x = l.attach.foldl (fun acc a => g acc (f a.1 (H _ a.2))) x := by
rw [pmap_eq_map_attach, foldl_map]
@[grind =]
@[grind]
theorem foldr_pmap {l : List α} {P : α Prop} {f : (a : α) P a β}
(H : (a : α), a l P a) (g : β γ γ) (x : γ) :
(l.pmap f H).foldr g x = l.attach.foldr (fun a acc => g (f a.1 (H _ a.2)) acc) x := by

View File

@@ -80,17 +80,17 @@ namespace List
/-! ### length -/
@[simp, grind =] theorem length_nil : length ([] : List α) = 0 :=
@[simp, grind] theorem length_nil : length ([] : List α) = 0 :=
rfl
@[simp] theorem length_singleton {a : α} : length [a] = 1 := rfl
@[simp, grind =] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
@[simp, grind] theorem length_cons {a : α} {as : List α} : (cons a as).length = as.length + 1 :=
rfl
/-! ### set -/
@[simp, grind =] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
@[simp, grind] theorem length_set {as : List α} {i : Nat} {a : α} : (as.set i a).length = as.length := by
induction as generalizing i with
| nil => rfl
| cons x xs ih =>
@@ -101,8 +101,8 @@ namespace List
/-! ### foldl -/
-- As `List.foldl` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp, grind =] theorem foldl_nil : [].foldl f b = b := rfl
@[simp, grind =] theorem foldl_cons {l : List α} {f : β α β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
@[simp, grind] theorem foldl_nil : [].foldl f b = b := rfl
@[simp, grind] theorem foldl_cons {l : List α} {f : β α β} {b : β} : (a :: l).foldl f b = l.foldl f (f b a) := rfl
/-! ### concat -/
@@ -332,7 +332,7 @@ def getLast? : List α → Option α
| [] => none
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
@[simp, grind] theorem getLast?_nil : @getLast? α [] = none := rfl
/-! ### getLastD -/
@@ -365,7 +365,7 @@ Returns the first element of a non-empty list.
def head : (as : List α) as [] α
| a::_, _ => a
@[simp, grind =] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
@[simp, grind] theorem head_cons {a : α} {l : List α} {h} : head (a::l) h = a := rfl
/-! ### head? -/
@@ -383,8 +383,8 @@ def head? : List α → Option α
| [] => none
| a::_ => some a
@[simp, grind =] theorem head?_nil : head? ([] : List α) = none := rfl
@[simp, grind =] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
@[simp, grind] theorem head?_nil : head? ([] : List α) = none := rfl
@[simp, grind] theorem head?_cons {a : α} {l : List α} : head? (a::l) = some a := rfl
/-! ### headD -/
@@ -420,8 +420,8 @@ def tail : List α → List α
| [] => []
| _::as => as
@[simp, grind =] theorem tail_nil : tail ([] : List α) = [] := rfl
@[simp, grind =] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
@[simp, grind] theorem tail_nil : tail ([] : List α) = [] := rfl
@[simp, grind] theorem tail_cons {a : α} {as : List α} : tail (a::as) = as := rfl
/-! ### tail? -/
@@ -441,8 +441,8 @@ def tail? : List α → Option (List α)
| [] => none
| _::as => some as
@[simp, grind =] theorem tail?_nil : tail? ([] : List α) = none := rfl
@[simp, grind =] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
@[simp, grind] theorem tail?_nil : tail? ([] : List α) = none := rfl
@[simp, grind] theorem tail?_cons {a : α} {l : List α} : tail? (a::l) = some l := rfl
/-! ### tailD -/
@@ -490,8 +490,8 @@ Examples:
| [] => []
| 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
@[simp, grind] theorem map_nil {f : α β} : map f [] = [] := rfl
@[simp, grind] theorem map_cons {f : α β} {a : α} {l : List α} : map f (a :: l) = f a :: map f l := rfl
/-! ### filter -/
@@ -511,7 +511,7 @@ def filter (p : α → Bool) : (l : List α) → List α
| true => a :: filter p as
| false => filter p as
@[simp, grind =] theorem filter_nil {p : α Bool} : filter p [] = [] := rfl
@[simp, grind] theorem filter_nil {p : α Bool} : filter p [] = [] := rfl
/-! ### filterMap -/
@@ -537,8 +537,8 @@ Example:
| none => filterMap f as
| some b => b :: filterMap f as
@[simp, grind =] theorem filterMap_nil {f : α Option β} : filterMap f [] = [] := rfl
@[grind =] theorem filterMap_cons {f : α Option β} {a : α} {l : List α} :
@[simp, grind] theorem filterMap_nil {f : α Option β} : filterMap f [] = [] := rfl
@[grind] theorem filterMap_cons {f : α Option β} {a : α} {l : List α} :
filterMap f (a :: l) =
match f a with
| none => filterMap f l
@@ -561,8 +561,8 @@ Examples:
| [] => init
| a :: l => f a (foldr f init l)
@[simp, grind =] theorem foldr_nil : [].foldr f b = b := rfl
@[simp, grind =] theorem foldr_cons {a} {l : List α} {f : α β β} {b} :
@[simp, grind] theorem foldr_nil : [].foldr f b = b := rfl
@[simp, grind] theorem foldr_cons {a} {l : List α} {f : α β β} {b} :
(a :: l).foldr f b = f a (l.foldr f b) := rfl
/-! ### reverse -/
@@ -591,7 +591,7 @@ Examples:
@[expose] def reverse (as : List α) : List α :=
reverseAux as []
@[simp, grind =] theorem reverse_nil : reverse ([] : List α) = [] := rfl
@[simp, grind] theorem reverse_nil : reverse ([] : List α) = [] := rfl
theorem reverseAux_reverseAux {as bs cs : List α} :
reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
@@ -645,10 +645,10 @@ instance : Append (List α) := ⟨List.append⟩
@[simp] theorem append_eq {as bs : List α} : List.append as bs = as ++ bs := rfl
@[simp, grind =] theorem nil_append (as : List α) : [] ++ as = as := rfl
@[simp, grind] theorem nil_append (as : List α) : [] ++ as = as := rfl
@[simp, grind _=_] theorem cons_append {a : α} {as bs : List α} : (a::as) ++ bs = a::(as ++ bs) := rfl
@[simp, grind =] theorem append_nil (as : List α) : as ++ [] = as := by
@[simp, grind] theorem append_nil (as : List α) : as ++ [] = as := by
induction as with
| nil => rfl
| cons a as ih =>
@@ -658,7 +658,7 @@ instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] where
left_id := nil_append
right_id := append_nil
@[simp, grind =] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
@[simp, grind] theorem length_append {as bs : List α} : (as ++ bs).length = as.length + bs.length := by
induction as with
| nil => simp
| cons _ as ih => simp [ih, Nat.succ_add]
@@ -685,7 +685,7 @@ theorem reverseAux_eq_append {as bs : List α} : reverseAux as bs = reverseAux a
rw [ih (bs := a :: bs), ih (bs := [a]), append_assoc]
rfl
@[simp, grind =] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
@[simp, grind] theorem reverse_cons {a : α} {as : List α} : reverse (a :: as) = reverse as ++ [a] := by
simp [reverse, reverseAux]
rw [ reverseAux_eq_append]
@@ -704,8 +704,8 @@ 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
@[simp, grind] theorem flatten_nil : List.flatten ([] : List (List α)) = [] := rfl
@[simp, grind] theorem flatten_cons : (l :: L).flatten = l ++ L.flatten := rfl
/-! ### singleton -/
@@ -731,8 +731,8 @@ Examples:
-/
@[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 β} :
@[simp, grind] theorem flatMap_nil {f : α List β} : List.flatMap f [] = [] := by simp [List.flatMap]
@[simp, grind] theorem flatMap_cons {x : α} {xs : List α} {f : α List β} :
List.flatMap f (x :: xs) = f x ++ List.flatMap f xs := by simp [List.flatMap]
/-! ### replicate -/
@@ -748,10 +748,10 @@ def replicate : (n : Nat) → (a : α) → List α
| 0, _ => []
| n+1, a => a :: replicate n a
@[simp, grind =] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
@[grind =] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
@[simp, grind] theorem replicate_zero {a : α} : replicate 0 a = [] := rfl
@[grind] theorem replicate_succ {a : α} {n : Nat} : replicate (n+1) a = a :: replicate n a := rfl
@[simp, grind =] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
@[simp, grind] theorem length_replicate {n : Nat} {a : α} : (replicate n a).length = n := by
induction n with
| zero => simp
| succ n ih => simp only [ih, replicate_succ, length_cons]
@@ -819,8 +819,8 @@ def isEmpty : List α → Bool
| [] => true
| _ :: _ => false
@[simp, grind =] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
@[simp, grind =] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
@[simp, grind] theorem isEmpty_nil : ([] : List α).isEmpty = true := rfl
@[simp, grind] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false := rfl
/-! ### elem -/
@@ -842,7 +842,7 @@ def elem [BEq α] (a : α) : (l : List α) → Bool
| true => true
| false => elem a bs
@[simp, grind =] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
@[simp, grind] theorem elem_nil [BEq α] : ([] : List α).elem a = false := rfl
theorem elem_cons [BEq α] {a : α} :
(b::bs).elem a = match a == b with | true => true | false => bs.elem a := rfl
@@ -958,9 +958,9 @@ def take : (n : Nat) → (xs : List α) → List α
| _+1, [] => []
| n+1, a::as => a :: take n as
@[simp, grind =] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
@[simp, grind =] theorem take_zero {l : List α} : l.take 0 = [] := rfl
@[simp, grind =] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
@[simp, grind] theorem take_nil {i : Nat} : ([] : List α).take i = [] := by cases i <;> rfl
@[simp, grind] theorem take_zero {l : List α} : l.take 0 = [] := rfl
@[simp, grind] theorem take_succ_cons {a : α} {as : List α} {i : Nat} : (a::as).take (i+1) = a :: as.take i := rfl
/-! ### drop -/
@@ -980,10 +980,10 @@ def drop : (n : Nat) → (xs : List α) → List α
| _+1, [] => []
| n+1, _::as => drop n as
@[simp, grind =] theorem drop_nil : ([] : List α).drop i = [] := by
@[simp, grind] theorem drop_nil : ([] : List α).drop i = [] := by
cases i <;> rfl
@[simp, grind =] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
@[simp, grind =] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
@[simp, grind] theorem drop_zero {l : List α} : l.drop 0 = l := rfl
@[simp, grind] theorem drop_succ_cons {a : α} {l : List α} {i : Nat} : (a :: l).drop (i + 1) = l.drop i := rfl
theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length i) : as.drop i = [] := by
match as, i with
@@ -1094,13 +1094,13 @@ def dropLast {α} : List α → List α
| [_] => []
| a::as => a :: dropLast as
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
@[simp, grind] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
@[simp, grind] theorem dropLast_singleton : [x].dropLast = [] := rfl
@[deprecated dropLast_singleton (since := "2025-04-16")]
theorem dropLast_single : [x].dropLast = [] := dropLast_singleton
@[simp, grind =] theorem dropLast_cons₂ :
@[simp, grind] theorem dropLast_cons₂ :
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
@@ -1439,8 +1439,8 @@ def replace [BEq α] : (l : List α) → (a : α) → (b : α) → List α
| true => c::as
| false => a :: replace as b c
@[simp, grind =] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
@[grind =] theorem replace_cons [BEq α] {a : α} :
@[simp, grind] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] := rfl
@[grind] theorem replace_cons [BEq α] {a : α} :
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
rfl
@@ -1648,8 +1648,8 @@ def findSome? (f : α → Option β) : List α → Option β
| some b => some b
| none => findSome? f as
@[simp, grind =] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
@[grind =] theorem findSome?_cons {f : α Option β} :
@[simp, grind] theorem findSome?_nil : ([] : List α).findSome? f = none := rfl
@[grind] theorem findSome?_cons {f : α Option β} :
(a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f :=
rfl
@@ -1906,8 +1906,8 @@ def any : (l : List α) → (p : α → Bool) → Bool
| [], _ => false
| h :: t, p => p h || any t p
@[simp, grind =] theorem any_nil : [].any f = false := rfl
@[simp, grind =] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
@[simp, grind] theorem any_nil : [].any f = false := rfl
@[simp, grind] theorem any_cons : (a::l).any f = (f a || l.any f) := rfl
/-! ### all -/
@@ -1925,8 +1925,8 @@ def all : List α → (α → Bool) → Bool
| [], _ => true
| h :: t, p => p h && all t p
@[simp, grind =] theorem all_nil : [].all f = true := rfl
@[simp, grind =] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
@[simp, grind] theorem all_nil : [].all f = true := rfl
@[simp, grind] theorem all_cons : (a::l).all f = (f a && l.all f) := rfl
/-! ### or -/
@@ -2066,8 +2066,8 @@ Examples:
def sum {α} [Add α] [Zero α] : List α α :=
foldr (· + ·) 0
@[simp, grind =] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
@[simp, grind =] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
@[simp, grind] theorem sum_nil [Add α] [Zero α] : ([] : List α).sum = 0 := rfl
@[simp, grind] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
/-! ### range -/

View File

@@ -223,7 +223,7 @@ variable [BEq α]
@[simp, grind =] theorem count_nil {a : α} : count a [] = 0 := rfl
@[grind =]
@[grind]
theorem count_cons {a b : α} {l : List α} :
count a (b :: l) = count a l + if b == a then 1 else 0 := by
simp [count, countP_cons]
@@ -237,7 +237,7 @@ theorem count_eq_countP' {a : α} : count a = countP (· == a) := by
theorem count_eq_length_filter {a : α} {l : List α} : count a l = (filter (· == a) l).length := by
simp [count, countP_eq_length_filter]
@[grind =]
@[grind]
theorem count_tail : {l : List α} {a : α},
l.tail.count a = l.count a - if l.head? == some a then 1 else 0
| [], a => by simp
@@ -380,7 +380,7 @@ theorem count_filterMap {α} [BEq β] {b : β} {f : α → Option β} {l : List
theorem count_flatMap {α} [BEq β] {l : List α} {f : α List β} {x : β} :
count x (l.flatMap f) = sum (map (count x f) l) := countP_flatMap
@[grind =]
@[grind]
theorem count_erase {a b : α} :
{l : List α}, count a (l.erase b) = count a l - if b == a then 1 else 0
| [] => by simp

View File

@@ -130,7 +130,7 @@ theorem le_length_eraseP {l : List α} : l.length - 1 ≤ (l.eraseP p).length :=
@[grind ]
theorem mem_of_mem_eraseP {l : List α} : a l.eraseP p a l := (eraseP_subset ·)
@[simp, grind =] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a l.eraseP p a l := by
@[simp, grind] theorem mem_eraseP_of_neg {l : List α} (pa : ¬p a) : a l.eraseP p a l := by
refine mem_of_mem_eraseP, fun al => ?_
match exists_or_eq_self_of_eraseP p l with
| .inl h => rw [h]; assumption
@@ -265,18 +265,14 @@ theorem eraseP_eq_iff {p} {l : List α} :
subst p
simp_all
@[grind ]
theorem Pairwise.eraseP (q) : Pairwise p l Pairwise p (l.eraseP q) :=
Pairwise.sublist <| eraseP_sublist
grind_pattern Pairwise.eraseP => Pairwise p (l.eraseP q)
grind_pattern Pairwise.eraseP => Pairwise p l, l.eraseP q
@[grind ]
theorem Nodup.eraseP (p) : Nodup l Nodup (l.eraseP p) :=
Pairwise.eraseP p
grind_pattern Nodup.eraseP => Nodup (l.eraseP p)
grind_pattern Nodup.eraseP => Nodup l, l.eraseP p
@[grind =]
theorem eraseP_comm {l : List α} (h : a l, ¬ p a ¬ q a) :
(l.eraseP p).eraseP q = (l.eraseP q).eraseP p := by
@@ -397,7 +393,7 @@ theorem le_length_erase [LawfulBEq α] {a : α} {l : List α} : l.length - 1 ≤
@[grind ]
theorem mem_of_mem_erase {a b : α} {l : List α} (h : a l.erase b) : a l := erase_subset h
@[simp, grind =] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a b) :
@[simp, grind] theorem mem_erase_of_ne [LawfulBEq α] {a b : α} {l : List α} (ab : a b) :
a l.erase b a l :=
erase_eq_eraseP b l mem_eraseP_of_neg (mt eq_of_beq ab.symm)
@@ -512,12 +508,10 @@ theorem Nodup.not_mem_erase [LawfulBEq α] {a : α} (h : Nodup l) : a ∉ l.eras
-- Only activate `not_mem_erase` when `l.Nodup` is already available.
grind_pattern List.Nodup.not_mem_erase => a l.erase a, l.Nodup
@[grind]
theorem Nodup.erase [LawfulBEq α] (a : α) : Nodup l Nodup (l.erase a) :=
Pairwise.erase a
grind_pattern Nodup.erase => Nodup (l.erase a)
grind_pattern Nodup.erase => Nodup l, l.erase a
theorem head_erase_mem (xs : List α) (a : α) (h) : (xs.erase a).head h xs :=
erase_sublist.head_mem h
@@ -584,21 +578,21 @@ theorem eraseIdx_ne_nil_iff {l : List α} {i : Nat} : eraseIdx l i ≠ [] ↔ 2
| [a]
| a::b::l => simp
@[grind]
theorem eraseIdx_sublist : (l : List α) (k : Nat), eraseIdx l k <+ l
| [], _ => by simp
| a::l, 0 => by simp
| a::l, k + 1 => by simp [eraseIdx_sublist]
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ <+ l
theorem mem_of_mem_eraseIdx {l : List α} {i : Nat} {a : α} (h : a l.eraseIdx i) : a l :=
(eraseIdx_sublist _ _).mem h
@[grind]
theorem eraseIdx_subset {l : List α} {k : Nat} : eraseIdx l k l :=
(eraseIdx_sublist _ _).subset
grind_pattern eraseIdx_sublist => l.eraseIdx k, _ l
@[simp]
theorem eraseIdx_eq_self : {l : List α} {k : Nat}, eraseIdx l k = l length l k
| [], _ => by simp
@@ -655,18 +649,15 @@ theorem eraseIdx_replicate {n : Nat} {a : α} {k : Nat} :
exact m.2
· rw [eraseIdx_of_length_le (by simpa using h)]
@[grind ]
theorem Pairwise.eraseIdx {l : List α} (k) : Pairwise p l Pairwise p (l.eraseIdx k) :=
Pairwise.sublist <| eraseIdx_sublist _ _
grind_pattern Pairwise.eraseIdx => Pairwise p (l.eraseIdx k)
grind_pattern Pairwise.eraseIdx => Pairwise p l, l.eraseIdx k
@[grind ]
theorem Nodup.eraseIdx {l : List α} (k) : Nodup l Nodup (l.eraseIdx k) :=
Pairwise.eraseIdx k
grind_pattern Nodup.eraseIdx => Nodup (l.eraseIdx k)
grind_pattern Nodup.eraseIdx => Nodup l, l.eraseIdx k
@[grind ]
protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
eraseIdx l k <+: eraseIdx l' k := by
rcases h with t, rfl
@@ -676,10 +667,6 @@ protected theorem IsPrefix.eraseIdx {l l' : List α} (h : l <+: l') (k : Nat) :
rw [Nat.not_lt] at hkl
simp [eraseIdx_append_of_length_le hkl, eraseIdx_of_length_le hkl]
grind_pattern IsPrefix.eraseIdx => eraseIdx l k <+: eraseIdx l' k
grind_pattern IsPrefix.eraseIdx => eraseIdx l k, l <+: l'
grind_pattern IsPrefix.eraseIdx => eraseIdx l' k, l <+: l'
-- See also `mem_eraseIdx_iff_getElem` and `mem_eraseIdx_iff_getElem?` in
-- `Init/Data/List/Nat/Basic.lean`.
@@ -699,4 +686,6 @@ theorem erase_eq_eraseIdx_of_idxOf [BEq α] [LawfulBEq α]
rw [eq_comm, eraseIdx_eq_self]
exact Nat.le_of_eq (idxOf_eq_length h).symm
end List

View File

@@ -293,6 +293,7 @@ theorem mem_of_find?_eq_some : ∀ {l}, find? p l = some a → a ∈ l
· exact H .head _
· exact .tail _ (mem_of_find?_eq_some H)
@[grind]
theorem get_find?_mem {xs : List α} {p : α Bool} (h) : (xs.find? p).get h xs := by
induction xs with
| nil => simp at h
@@ -304,8 +305,6 @@ theorem get_find?_mem {xs : List α} {p : α → Bool} (h) : (xs.find? p).get h
right
apply ih
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] theorem find?_filter {xs : List α} {p : α Bool} {q : α Bool} :
(xs.filter p).find? q = xs.find? (fun a => p a q a) := by
induction xs with
@@ -559,6 +558,7 @@ where
@[simp] theorem findIdx_singleton {a : α} {p : α Bool} : [a].findIdx p = if p a then 0 else 1 := by
simp [findIdx_cons, findIdx_nil]
@[grind ]
theorem findIdx_of_getElem?_eq_some {xs : List α} (w : xs[xs.findIdx p]? = some y) : p y := by
induction xs with
| nil => simp_all

View File

@@ -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 characterizing `x ∈ f L` (often but not always `@[simp]`)
* conditions characterising `x ∈ f L` (often but not always `@[simp]`)
* injectivity statements, or congruence statements of the form `p L M → f L = f M`.
* conditions characterizing the result, i.e. of the form `f L = M ↔ p M` for some predicate `p`,
* conditions characterising 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 characterizations are also useful, e.g. `List.cons_ne_nil`
* negative characterisations 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)
* characterizing `(∀ (i) (_ : i ∈ f L), P i)`, for some predicate `P`
* characterising `(∀ (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.
@@ -306,7 +306,7 @@ theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
match i, h with
| 0, _ => rfl
@[grind =]
@[grind]
theorem getElem?_singleton {a : α} {i : Nat} : [a][i]? = if i = 0 then some a else none := by
simp [getElem?_cons]
@@ -382,20 +382,14 @@ theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! :=
@[simp] theorem not_mem_nil {a : α} : ¬ a [] := nofun
@[simp, grind =] theorem mem_cons : a b :: l a = b a l :=
@[simp] theorem mem_cons : a b :: l a = b a l :=
fun h => by cases h <;> simp [Membership.mem, *],
fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption
theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
@[grind] theorem eq_or_mem_of_mem_cons {a b : α} {l : List α} :
a b :: l a = b a l := List.mem_cons.mp
-- This pattern may be excessively general:
-- it fires anytime we ae thinking about membership of lists,
-- and constructing a list via `cons`, even if the elements are unrelated.
-- Nevertheless in practice it is quite helpful!
grind_pattern eq_or_mem_of_mem_cons => b :: l, a l
theorem mem_cons_self {a : α} {l : List α} : a a :: l := .head ..
@[grind] theorem mem_cons_self {a : α} {l : List α} : a a :: l := .head ..
theorem mem_concat_self {xs : List α} {a : α} : a xs ++ [a] :=
mem_append_right xs mem_cons_self
@@ -417,7 +411,7 @@ theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) :
· obtain as, bs, rfl, h := ih h
exact x :: as, bs, rfl, by simp_all
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
@[grind] theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a l a y :: l := .tail _
-- The argument `l : List α` is intentionally explicit,
-- as a tactic may generate `h` without determining `l`.
@@ -553,10 +547,10 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
elem a as = decide (a as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
as.contains a = decide (a as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
@[simp, grind =] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
@[simp, grind] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
(a :: l).contains b = (b == a || l.contains b) := by
simp only [contains, elem_cons]
split <;> simp_all
@@ -611,7 +605,7 @@ theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
@[simp] theorem all_eq_false {l : List α} : l.all p = false x, x l ¬p x := by
simp [all_eq]
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
@[grind] theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
induction l <;> simp_all [contains_cons]
/-- Variant of `any_beq` with `==` reversed. -/
@@ -619,7 +613,7 @@ theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
(l.any fun x => x == a) = l.contains a := by
simp only [BEq.comm, any_beq]
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
@[grind] theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
induction l <;> simp_all [bne]
/-- Variant of `all_bne` with `!=` reversed. -/
@@ -630,10 +624,10 @@ theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
/-! ### set -/
-- As `List.set` is defined in `Init.Prelude`, we write the basic simplification lemmas here.
@[simp, grind =] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
@[simp, grind =] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
@[simp, grind] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
@[simp, grind] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
(x :: xs).set 0 a = a :: xs := rfl
@[simp, grind =] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
@[simp, grind] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
(x :: xs).set (i + 1) a = x :: xs.set i a := rfl
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
@@ -676,14 +670,14 @@ theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
simp_all
· rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
@[grind =] theorem getElem_set {l : List α} {i j} {a} (h) :
@[grind] theorem getElem_set {l : List α} {i j} {a} (h) :
(set l i a)[j]'h = if i = j then a else l[j]'(length_set .. h) := by
if h : i = j then
subst h; simp only [getElem_set_self, reduceIte]
else
simp [h]
@[grind =] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
@[grind] theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
(l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
if h : i = j then
subst h
@@ -753,10 +747,10 @@ theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.s
/-! ### BEq -/
@[simp, grind =] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
@[simp, grind] theorem beq_nil_eq [BEq α] {l : List α} : (l == []) = l.isEmpty := by
cases l <;> rfl
@[simp, grind =] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
@[simp, grind] theorem nil_beq_eq [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
cases l <;> rfl
@[deprecated beq_nil_eq (since := "2025-04-04")]
@@ -765,7 +759,7 @@ abbrev beq_nil_iff := @beq_nil_eq
@[deprecated nil_beq_eq (since := "2025-04-04")]
abbrev nil_beq_iff := @nil_beq_eq
@[simp, grind =] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
@[simp, grind] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
(a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
@@ -831,7 +825,7 @@ theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l
/-! ### getLast -/
@[grind =]
@[grind]
theorem getLast_eq_getElem : {l : List α} (h : l []),
getLast l h = l[l.length - 1]'(by
match l with
@@ -845,7 +839,7 @@ theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.le
l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
rw [ getLast_eq_getElem]
@[simp, grind =] theorem getLast_cons_cons {a : α} {l : List α} :
@[simp, grind] theorem getLast_cons_cons {a : α} {l : List α} :
getLast (a :: b :: l) (by simp) = getLast (b :: l) (by simp) :=
rfl
@@ -858,10 +852,10 @@ theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
cases l <;> rfl
@[simp, grind =] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
@[simp, grind] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
cases l <;> rfl
@[simp, grind =] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
@[simp, grind] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
simp [getLast!, getLast_eq_getLastD]
@@ -894,7 +888,7 @@ theorem getLast?_eq_getLast : ∀ {l : List α} h, l.getLast? = some (l.getLast
| [], h => nomatch h rfl
| _ :: _, _ => rfl
@[grind =] theorem getLast?_eq_getElem? : {l : List α}, l.getLast? = l[l.length - 1]?
@[grind] theorem getLast?_eq_getElem? : {l : List α}, l.getLast? = l[l.length - 1]?
| [] => rfl
| a::l => by
rw [getLast?_eq_getLast (l := a :: l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
@@ -907,14 +901,14 @@ theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
-- `getLast?_eq_none_iff`, `getLast?_eq_some_iff`, `getLast?_isSome`, and `getLast_mem`
-- are proved later once more `reverse` theorems are available.
@[grind =]
@[grind]
theorem getLast?_cons {a : α} : (a::l).getLast? = some (l.getLast?.getD a) := by
cases l <;> simp [getLast?, getLast]
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
simp [getLast?_cons]
@[grind =]
@[grind]
theorem getLast?_concat {l : List α} {a : α} : (l ++ [a]).getLast? = some a := by
simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
@@ -933,14 +927,14 @@ theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
theorem getLast!_of_getLast? [Inhabited α] : {l : List α}, getLast? l = some a getLast! l = a
| _ :: _, rfl => rfl
@[grind =]
@[grind]
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
cases l with
| nil => simp
| cons _ _ =>
apply getLast!_of_getLast?
rw [getLast?_eq_getElem?]
simp
rw [getElem!_pos, getElem_cons_length (h := by simp)]
rfl
/-! ## Head and tail -/
@@ -961,7 +955,7 @@ theorem head?_eq_getElem? : ∀ {l : List α}, l.head? = l[0]?
theorem head_singleton {a : α} : head [a] (by simp) = a := by simp
@[grind =]
@[grind]
theorem head_eq_getElem {l : List α} (h : l []) : head l h = l[0]'(length_pos_iff.mpr h) := by
cases l with
| nil => simp at h
@@ -1023,18 +1017,18 @@ theorem head_of_mem_head? {l : List α} {x} (hx : x ∈ l.head?) :
/-! ### headD -/
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
@[simp, grind =] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
@[simp, grind] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
cases l <;> simp [headD]
/-! ### tailD -/
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
@[simp, grind =] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
@[simp, grind] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
cases l <;> rfl
/-! ### tail -/
@[simp, grind =] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
@[simp, grind] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
theorem tail_eq_tailD {l : List α} : l.tail = tailD l [] := by cases l <;> rfl
@@ -1046,13 +1040,13 @@ theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := b
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail [] l [] := by
cases l <;> simp
@[simp, grind =] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
@[simp, grind] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
(tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
cases l with
| nil => simp at h
| cons _ l => simp
@[simp, grind =] theorem getElem?_tail {l : List α} {i : Nat} :
@[simp, grind] theorem getElem?_tail {l : List α} {i : Nat} :
(tail l)[i]? = l[i + 1]? := by
cases l <;> simp
@@ -1076,7 +1070,7 @@ theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.l
@[simp] theorem head?_tail {l : List α} : (tail l).head? = l[1]? := by
simp [head?_eq_getElem?]
@[simp, grind =] theorem getLast_tail {l : List α} (h : l.tail []) :
@[simp, grind] theorem getLast_tail {l : List α} (h : l.tail []) :
(tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
simp only [getLast_eq_getElem, length_tail, getElem_tail]
congr
@@ -1102,7 +1096,7 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
/-! ### map -/
@[simp, grind =] theorem length_map {as : List α} (f : α β) : (as.map f).length = as.length := by
@[simp, grind] theorem length_map {as : List α} (f : α β) : (as.map f).length = as.length := by
induction as with
| nil => simp [List.map]
| cons _ as ih => simp [List.map, ih]
@@ -1110,13 +1104,13 @@ theorem cons_head_tail (h : l ≠ []) : l.head h :: l.tail = l := by
@[simp] theorem isEmpty_map {l : List α} {f : α β} : (l.map f).isEmpty = l.isEmpty := by
cases l <;> simp
@[simp, grind =] theorem getElem?_map {f : α β} : {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
@[simp, grind] theorem getElem?_map {f : α β} : {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
| [], _ => rfl
| _ :: _, 0 => by simp
| _ :: l, i+1 => by simp [getElem?_map]
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
@[simp, grind =] theorem getElem_map (f : α β) {l} {i : Nat} {h : i < (map f l).length} :
@[simp, grind] theorem getElem_map (f : α β) {l} {i : Nat} {h : i < (map f l).length} :
(map f l)[i] = f (l[i]'(length_map f h)) :=
Option.some.inj <| by rw [ getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
@@ -1162,9 +1156,7 @@ 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
-- 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.
@[grind ]
theorem eq_nil_of_map_eq_nil {f : α β} {l : List α} (h : map f l = []) : l = [] :=
map_eq_nil_iff.mp h
@@ -1284,7 +1276,7 @@ theorem getLastD_map {f : α → β} {l : List α} {a : α} : (map f l).getLastD
@[simp] theorem filter_cons_of_neg {p : α Bool} {a : α} {l} (pa : ¬ p a) :
filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
@[grind =] theorem filter_cons :
@[grind] theorem filter_cons :
(x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
split <;> simp [*]
@@ -1323,7 +1315,7 @@ theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀
@[deprecated length_filter_eq_length_iff (since := "2025-04-04")]
abbrev filter_length_eq_length := @length_filter_eq_length_iff
@[simp, grind =] theorem mem_filter : x filter p as x as p x := by
@[simp, grind] theorem mem_filter : x filter p as x as p x := by
induction as with
| nil => simp
| cons a as ih =>
@@ -1338,15 +1330,13 @@ theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
( (i) (_ : i l.filter p), P i) (j) (_ : j l), p j P j := by
simp
theorem getElem_filter {xs : List α} {p : α Bool} {i : Nat} (h : i < (xs.filter p).length) :
@[grind] theorem getElem_filter {xs : List α} {p : α Bool} {i : Nat} (h : i < (xs.filter p).length) :
p (xs.filter p)[i] :=
(mem_filter.mp (getElem_mem h)).2
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 h] at w
rw [getElem?_eq_getElem] at w
simp only [Option.some.injEq] at w
rw [ w]
apply getElem_filter h
@@ -1387,7 +1377,7 @@ theorem map_filter_eq_foldr {f : α → β} {p : α → Bool} {as : List α} :
simp only [foldr]
cases hp : p head <;> simp [filter, *]
@[simp, grind =] theorem filter_append {p : α Bool} :
@[simp, grind] theorem filter_append {p : α Bool} :
(l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
| [], _ => rfl
| a :: l₁, l₂ => by simp only [cons_append, filter]; split <;> simp [filter_append l₁]
@@ -1452,7 +1442,7 @@ theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
erw [filterMap_eq_map]
simp
@[simp, grind =] theorem filterMap_some {l : List α} : filterMap some l = l := by
@[simp, grind] theorem filterMap_some {l : List α} : filterMap some l = l := by
rw [filterMap_some_fun, id]
theorem map_filterMap_some_eq_filter_map_isSome {f : α Option β} {l : List α} :
@@ -1487,19 +1477,19 @@ theorem filterMap_eq_filter {p : α → Bool} :
| nil => rfl
| cons a l IH => by_cases pa : p a <;> simp [Option.guard, pa, IH]
@[grind =]
@[grind]
theorem filterMap_filterMap {f : α Option β} {g : β Option γ} {l : List α} :
filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by
induction l with
| nil => rfl
| cons a l IH => cases h : f a <;> simp [filterMap_cons, *]
@[grind =]
@[grind]
theorem map_filterMap {f : α Option β} {g : β γ} {l : List α} :
map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by
simp only [ filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind]
@[simp, grind =]
@[simp, grind]
theorem filterMap_map {f : α β} {g : β Option γ} {l : List α} :
filterMap g (map f l) = filterMap (g f) l := by
rw [ filterMap_eq_map, filterMap_filterMap]; rfl
@@ -1514,7 +1504,7 @@ theorem filterMap_filter {p : α → Bool} {f : α → Option β} {l : List α}
rw [ filterMap_eq_filter, filterMap_filterMap]
congr; funext x; by_cases h : p x <;> simp [Option.guard, h]
@[simp, grind =] theorem mem_filterMap {f : α Option β} {l : List α} {b : β} :
@[simp, grind] theorem mem_filterMap {f : α Option β} {l : List α} {b : β} :
b filterMap f l a, a l f a = some b := by
induction l <;> simp [filterMap_cons]; split <;> simp [*, eq_comm]
@@ -1526,7 +1516,7 @@ theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Pr
intro a
rw [forall_comm]
@[simp, grind =] theorem filterMap_append {l l' : List α} {f : α Option β} :
@[simp, grind] theorem filterMap_append {l l' : List α} {f : α Option β} :
filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by
induction l <;> simp [filterMap_cons]; split <;> simp [*]
@@ -1598,7 +1588,7 @@ theorem filterMap_eq_cons_iff {l} {b} {bs} :
@[simp] theorem cons_append_fun {a : α} {as : List α} :
(fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
@[simp, grind =] theorem mem_append {a : α} {s t : List α} : a s ++ t a s a t := by
@[simp, grind] theorem mem_append {a : α} {s t : List α} : a s ++ t a s a t := by
induction s <;> simp_all [or_assoc]
theorem not_mem_append {a : α} {s t : List α} (h₁ : a s) (h₂ : a t) : a s ++ t :=
@@ -1621,7 +1611,7 @@ theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
( (x) (_ : x l₁ ++ l₂), p x) ( (x) (_ : x l₁), p x) ( (x) (_ : x l₂), p x) := by
simp only [mem_append, or_imp, forall_and]
@[grind =] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
@[grind] theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
(l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
split <;> rename_i h'
· rw [getElem_append_left h']
@@ -1640,7 +1630,7 @@ theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length
rw [cons_append]
simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
@[grind =] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
@[grind] theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
(l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
split <;> rename_i h
· exact getElem?_append_left h
@@ -1719,6 +1709,7 @@ theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp
theorem nil_eq_append_iff : [] = a ++ b a = [] b = [] := by
simp
@[grind ]
theorem eq_nil_of_append_eq_nil {l₁ l₂ : List α} (h : l₁ ++ l₂ = []) : l₁ = [] l₂ = [] :=
append_eq_nil_iff.mp h
@@ -1748,12 +1739,12 @@ theorem append_eq_append_iff {ws xs ys zs : List α} :
| nil => simp_all
| cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
@[simp, grind =] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
@[simp, grind] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
head (l ++ l') w₁ = head l w₂ := by
match l, w₂ with
| a :: l, _ => rfl
@[grind =] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ []) :
@[grind] theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ []) :
head (l₁ ++ l₂) w =
if h : l₁.isEmpty then
head l₂ (by simp_all [isEmpty_iff])
@@ -1774,28 +1765,28 @@ theorem head_append_right {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l
head (l₁ ++ l₂) w = head l₂ (by simp_all) := by
rw [head_append, dif_pos (by simp_all)]
@[simp, grind =] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
@[simp, grind] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
cases l <;> simp
-- Note:
-- `getLast_append_of_ne_nil`, `getLast_append` and `getLast?_append`
-- are stated and proved later in the `reverse` section.
@[grind =] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
@[grind] theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
cases l <;> simp
theorem tail?_append_of_ne_nil {l l' : List α} (_ : l []) : (l ++ l').tail? = some (l.tail ++ l') :=
match l with
| _ :: _ => by simp
@[grind =] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
@[grind] theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
cases l <;> simp
@[simp] theorem tail_append_of_ne_nil {xs ys : List α} (h : xs []) :
(xs ++ ys).tail = xs.tail ++ ys := by
simp_all [tail_append]
@[grind =] theorem set_append {s t : List α} :
@[grind] theorem set_append {s t : List α} :
(s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
induction s generalizing i with
| nil => simp
@@ -1853,7 +1844,7 @@ theorem append_eq_filter_iff {p : α → Bool} :
L₁ ++ L₂ = filter p l l₁ l₂, l = l₁ ++ l₂ filter p l₁ = L₁ filter p l₂ = L₂ := by
rw [eq_comm, filter_eq_append_iff]
@[simp, grind =] theorem map_append {f : α β} : {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
@[simp, grind] theorem map_append {f : α β} : {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
intro l₁; induction l₁ <;> intros <;> simp_all
theorem map_eq_append_iff {f : α β} :
@@ -1926,7 +1917,7 @@ theorem eq_nil_or_concat : ∀ l : List α, l = [] ∃ l' b, l = concat l' b
| cons =>
simp [flatten, length_append, *]
@[grind =] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
@[grind] theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
@[simp] theorem mem_flatten : {L : List (List α)}, a L.flatten l, l L a l
| [] => by simp
@@ -2101,7 +2092,7 @@ theorem length_flatMap {l : List α} {f : α → List β} :
length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
rw [List.flatMap, length_flatten, map_map, Function.comp_def]
@[simp, grind =] theorem mem_flatMap {f : α List β} {b} {l : List α} : b l.flatMap f a, a l b f a := by
@[simp, grind] theorem mem_flatMap {f : α List β} {b} {l : List α} : b l.flatMap f a, a l b f a := by
simp [flatMap_def, mem_flatten]
exact fun _, a, h₁, rfl, h₂ => a, h₁, h₂, fun a, h₁, h₂ => _, a, h₁, rfl, h₂
@@ -2128,7 +2119,7 @@ theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
@[simp] theorem flatMap_singleton' (l : List α) : (l.flatMap fun x => [x]) = l := by
induction l <;> simp [*]
@[grind =] theorem head?_flatMap {l : List α} {f : α List β} :
@[grind] theorem head?_flatMap {l : List α} {f : α List β} :
(l.flatMap f).head? = l.findSome? fun a => (f a).head? := by
induction l with
| nil => rfl
@@ -2181,7 +2172,7 @@ theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
induction n <;> simp_all [replicate_succ, cons_append]
@[simp, grind =] theorem mem_replicate {a b : α} : {n}, b replicate n a n 0 b = a
@[simp, grind] theorem mem_replicate {a b : α} : {n}, b replicate n a n 0 b = a
| 0 => by simp
| n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
@@ -2206,11 +2197,11 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicate n a = [] n = 0 := by
cases n <;> simp
@[simp, grind =] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
@[simp, grind] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
(replicate n a)[i] = a :=
eq_of_mem_replicate (getElem_mem _)
@[grind =] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
@[grind] theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
by_cases h : i < n
· rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
· rw [getElem?_eq_none (by simpa using h), if_neg h]
@@ -2218,7 +2209,7 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
simp [h]
@[grind =] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
@[grind] theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
cases n <;> simp [replicate_succ]
@[simp] theorem head_replicate (w : replicate n a []) : (replicate n a).head w = a := by
@@ -2307,7 +2298,7 @@ theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
simp only [getElem?_map, getElem?_replicate]
split <;> simp
@[grind =] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
@[grind] theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
cases n with
| zero => simp
| succ n =>
@@ -2410,7 +2401,7 @@ termination_by l.length
/-! ### reverse -/
@[simp, grind =] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
@[simp, grind] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
induction as with
| nil => rfl
| cons a as ih => simp [ih]
@@ -2419,7 +2410,7 @@ theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈
| [], _ => .inr, fun | .inr h => h
| a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons]
@[simp, grind =] theorem mem_reverse {x : α} {as : List α} : x reverse as x as := by
@[simp, grind] theorem mem_reverse {x : α} {as : List α} : x reverse as x as := by
simp [reverse, mem_reverseAux]
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] xs = [] := by
@@ -2443,14 +2434,14 @@ theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
rw [getElem?_append_left, getElem?_reverse' this]
rw [length_reverse, this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
@[simp, grind =]
@[simp, grind]
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
l.reverse[i]? = l[l.length - 1 - i]? :=
getElem?_reverse' <| by
rw [Nat.add_sub_of_le (Nat.le_sub_one_of_lt h),
Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]
@[simp, grind =]
@[simp, grind]
theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h)) := by
apply Option.some.inj
@@ -2463,7 +2454,7 @@ theorem reverseAux_reverseAux_nil {as bs : List α} : reverseAux (reverseAux as
| cons a as ih => simp [reverseAux, ih]
-- The argument `as : List α` is explicit to allow rewriting from right to left.
@[simp, grind =] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
@[simp, grind] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
simp only [reverse]; rw [reverseAux_reverseAux_nil]; rfl
theorem reverse_eq_iff {as bs : List α} : as.reverse = bs as = bs.reverse := by
@@ -2476,10 +2467,10 @@ theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse :
xs.reverse = a :: ys xs = ys.reverse ++ [a] := by
rw [reverse_eq_iff, reverse_cons]
@[simp, grind =] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
@[simp, grind] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
cases l <;> simp [getLast?_concat]
@[simp, grind =] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
@[simp, grind] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
rw [ getLast?_reverse, reverse_reverse]
theorem getLast?_eq_head?_reverse {xs : List α} : xs.getLast? = xs.reverse.head? := by
@@ -2543,16 +2534,16 @@ theorem flatten_reverse {L : List (List α)} :
L.reverse.flatten = (L.map reverse).flatten.reverse := by
induction L <;> simp_all
@[grind =] theorem reverse_flatMap {β} {l : List α} {f : α List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
@[grind] theorem reverse_flatMap {β} {l : List α} {f : α List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse f) := by
induction l <;> simp_all
@[grind =] theorem flatMap_reverse {β} {l : List α} {f : α List β} : (l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
@[grind] theorem flatMap_reverse {β} {l : List α} {f : α List β} : (l.reverse.flatMap f) = (l.flatMap (reverse f)).reverse := by
induction l <;> simp_all
@[simp] theorem reverseAux_eq {as bs : List α} : reverseAux as bs = reverse as ++ bs :=
reverseAux_eq_append ..
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : (replicate n a).reverse = replicate n a :=
eq_replicate_iff.2
by rw [length_reverse, length_replicate],
fun _ h => eq_of_mem_replicate (mem_reverse.1 h)
@@ -2564,7 +2555,7 @@ theorem flatten_reverse {L : List (List α)} :
(l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
induction l generalizing b <;> simp [*]
@[simp, grind =] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α β m β} {b : β} :
@[simp, grind] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α β m β} {b : β} :
(a :: l).foldrM f b = l.foldrM f b >>= f a := by
simp only [foldrM]
induction l <;> simp_all
@@ -2608,37 +2599,37 @@ theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
/-! ### foldl and foldr -/
@[simp] theorem foldr_cons_eq_append {l : List α} {f : α β} {l' : List β} :
@[simp, grind] theorem foldr_cons_eq_append {l : List α} {f : α β} {l' : List β} :
l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
induction l <;> simp [*]
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
@[simp, grind =] theorem foldr_cons_eq_append' {l l' : List β} :
@[simp, grind] theorem foldr_cons_eq_append' {l l' : List β} :
l.foldr cons l' = l ++ l' := by
induction l <;> simp [*]
@[simp] theorem foldl_flip_cons_eq_append {l : List α} {f : α β} {l' : List β} :
@[simp, grind] theorem foldl_flip_cons_eq_append {l : List α} {f : α β} {l' : List β} :
l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
induction l generalizing l' <;> simp [*]
/-- Variant of `foldl_flip_cons_eq_append` specalized to `f = id`. -/
theorem foldl_flip_cons_eq_append' {l l' : List α} :
@[grind] theorem foldl_flip_cons_eq_append' {l l' : List α} :
l.foldl (fun xs y => y :: xs) l' = l.reverse ++ l' := by
simp
@[simp] theorem foldr_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp, grind] theorem foldr_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l' := by
induction l <;> simp [*]
@[simp] theorem foldl_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp, grind] theorem foldl_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten := by
induction l generalizing l'<;> simp [*]
@[simp] theorem foldr_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp, grind] theorem foldr_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
induction l generalizing l' <;> simp [*]
@[simp] theorem foldl_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
@[simp, grind] theorem foldl_flip_append_eq_append {l : List α} {f : α List β} {l' : List β} :
l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
induction l generalizing l' <;> simp [*]
@@ -2692,19 +2683,19 @@ theorem foldr_map_hom {g : α → β} {f : ααα} {f' : β → β →
@[simp, grind _=_] theorem foldr_append {f : α β β} {b : β} {l l' : List α} :
(l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM, -foldrM_pure]
@[grind =] theorem foldl_flatten {f : β α β} {b : β} {L : List (List α)} :
@[grind] theorem foldl_flatten {f : β α β} {b : β} {L : List (List α)} :
(flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
induction L generalizing b <;> simp_all
@[grind =] theorem foldr_flatten {f : α β β} {b : β} {L : List (List α)} :
@[grind] theorem foldr_flatten {f : α β β} {b : β} {L : List (List α)} :
(flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
induction L <;> simp_all
@[simp, grind =] theorem foldl_reverse {l : List α} {f : β α β} {b : β} :
@[simp, grind] theorem foldl_reverse {l : List α} {f : β α β} {b : β} :
l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by
simp [foldl_eq_foldlM, foldr_eq_foldrM, -foldrM_pure]
@[simp, grind =] theorem foldr_reverse {l : List α} {f : α β β} {b : β} :
@[simp, grind] theorem foldr_reverse {l : List α} {f : α β β} {b : β} :
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
@@ -2858,7 +2849,7 @@ theorem foldr_rel {l : List α} {f : α → β → β} {g : αγγ} {a
/-! #### Further results about `getLast` and `getLast?` -/
@[simp, grind =] theorem head_reverse {l : List α} (h : l.reverse []) :
@[simp, grind] theorem head_reverse {l : List α} (h : l.reverse []) :
l.reverse.head h = getLast l (by simp_all) := by
induction l with
| nil => contradiction
@@ -2888,7 +2879,7 @@ theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔
rw [getLast?_eq_head?_reverse, isSome_head?]
simp
@[simp, grind =] theorem getLast_reverse {l : List α} (h : l.reverse []) :
@[simp, grind] theorem getLast_reverse {l : List α} (h : l.reverse []) :
l.reverse.getLast h = l.head (by simp_all) := by
simp [getLast_eq_head_reverse]
@@ -2901,7 +2892,7 @@ theorem head_eq_getLast_reverse {l : List α} (h : l ≠ []) :
simp only [getLast_eq_head_reverse, reverse_append]
rw [head_append_of_ne_nil]
@[grind =] theorem getLast_append {l : List α} (h : l ++ l' []) :
@[grind] theorem getLast_append {l : List α} (h : l ++ l' []) :
(l ++ l').getLast h =
if h' : l'.isEmpty then
l.getLast (by simp_all [isEmpty_iff])
@@ -2922,7 +2913,7 @@ theorem getLast_append_left {l : List α} (w : l ++ l' ≠ []) (h : l' = []) :
(l ++ l').getLast w = l.getLast (by simp_all) := by
rw [getLast_append, dif_pos (by simp_all)]
@[simp, grind =] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
@[simp, grind] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
simp [ head?_reverse]
theorem getLast_filter_of_pos {p : α Bool} {l : List α} (w : l []) (h : p (getLast l w) = true) :
@@ -2958,7 +2949,7 @@ theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n
/-! ### leftpad -/
-- We unfold `leftpad` and `rightpad` for verification purposes.
attribute [simp, grind =] leftpad rightpad
attribute [simp, grind] leftpad rightpad
-- `length_leftpad` and `length_rightpad` are in `Init.Data.List.Nat.Basic`.
@@ -2987,21 +2978,17 @@ theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
l.contains a a' l, a == a' := by
induction l <;> simp_all
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => l.contains a
@[grind _=_]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
l.contains a a l := by
simp
@[simp, grind =]
@[simp, grind]
theorem contains_map [BEq β] {l : List α} {x : β} {f : α β} :
(l.map f).contains x = l.any (fun a => x == f a) := by
induction l with simp_all
@[simp, grind =]
@[simp, grind]
theorem contains_filter [BEq α] {l : List α} {x : α} {p : α Bool} :
(l.filter p).contains x = l.any (fun a => x == a && p a) := by
induction l with
@@ -3010,7 +2997,7 @@ theorem contains_filter [BEq α] {l : List α} {x : α} {p : α → Bool} :
simp only [filter_cons, any_cons]
split <;> simp_all
@[simp, grind =]
@[simp, grind]
theorem contains_filterMap [BEq β] {l : List α} {x : β} {f : α Option β} :
(l.filterMap f).contains x = l.any (fun a => (f a).any fun b => x == b) := by
induction l with
@@ -3026,21 +3013,21 @@ theorem contains_append [BEq α] {l₁ l₂ : List α} {x : α} :
| nil => simp
| cons a l ih => simp [ih, Bool.or_assoc]
@[simp, grind =]
@[simp, grind]
theorem contains_flatten [BEq α] {l : List (List α)} {x : α} :
l.flatten.contains x = l.any fun l => l.contains x := by
induction l with
| nil => simp
| cons _ l ih => simp [ih]
@[simp, grind =]
@[simp, grind]
theorem contains_reverse [BEq α] {l : List α} {x : α} :
(l.reverse).contains x = l.contains x := by
induction l with
| nil => simp
| cons a l ih => simp [ih, Bool.or_comm]
@[simp, grind =]
@[simp, grind]
theorem contains_flatMap [BEq β] {l : List α} {f : α List β} {x : β} :
(l.flatMap f).contains x = l.any fun a => (f a).contains x := by
induction l with
@@ -3055,7 +3042,7 @@ Because we immediately simplify `partition` into two `filter`s for verification
we do not separately develop much theory about it.
-/
@[simp, grind =] theorem partition_eq_filter_filter {p : α Bool} {l : List α} :
@[simp, grind] theorem partition_eq_filter_filter {p : α Bool} {l : List α} :
partition p l = (filter p l, filter (not p) l) := by simp [partition, aux]
where
aux : l {as bs}, partition.loop p l (as, bs) =
@@ -3075,16 +3062,16 @@ grind_pattern mem_partition => a ∈ (partition p l).2
are often used for theorems about `Array.pop`.
-/
@[simp, grind =] theorem length_dropLast : {xs : List α}, xs.dropLast.length = xs.length - 1
@[simp, grind] theorem length_dropLast : {xs : List α}, xs.dropLast.length = xs.length - 1
| [] => rfl
| x::xs => by simp
@[simp, grind =] theorem getElem_dropLast : {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
@[simp, grind] theorem getElem_dropLast : {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. Nat.pred_le _))
| _ :: _ :: _, 0, _ => rfl
| _ :: _ :: _, _ + 1, h => getElem_dropLast (Nat.add_one_lt_add_one_iff.mp h)
@[grind =] theorem getElem?_dropLast {xs : List α} {i : Nat} :
@[grind] theorem getElem?_dropLast {xs : List α} {i : Nat} :
xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
split
· rw [getElem?_eq_getElem, getElem?_eq_getElem, getElem_dropLast]
@@ -3282,24 +3269,24 @@ theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!
| nil => rfl
| cons h t ih => simp_all [Bool.and_assoc]
@[simp, grind =] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
@[simp, grind] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
induction l <;> simp_all
@[simp, grind =] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
@[simp, grind] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
induction l <;> simp_all
@[simp, grind =] theorem any_flatMap {l : List α} {f : α List β} :
@[simp, grind] theorem any_flatMap {l : List α} {f : α List β} :
(l.flatMap f).any p = l.any fun a => (f a).any p := by
induction l <;> simp_all
@[simp, grind =] theorem all_flatMap {l : List α} {f : α List β} :
@[simp, grind] theorem all_flatMap {l : List α} {f : α List β} :
(l.flatMap f).all p = l.all fun a => (f a).all p := by
induction l <;> simp_all
@[simp, grind =] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
@[simp, grind] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
induction l <;> simp_all [Bool.or_comm]
@[simp, grind =] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
@[simp, grind] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
induction l <;> simp_all [Bool.and_comm]
@[simp] theorem any_replicate {n : Nat} {a : α} :
@@ -3349,14 +3336,14 @@ variable [BEq α]
simp only [replace_cons]
split <;> simp_all
@[simp, grind =] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
@[simp, grind] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
induction l with
| nil => simp
| cons x l ih =>
simp only [replace_cons]
split <;> simp_all
@[grind =] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
@[grind] theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
(l.replace a b)[i]? = if l[i]? == some a then if a l.take i then some a else some b else l[i]? := by
induction l generalizing i with
| nil => cases i <;> simp
@@ -3369,7 +3356,7 @@ theorem getElem?_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} (h : l[i]?
(l.replace a b)[i]? = l[i]? := by
simp_all [getElem?_replace]
@[grind =] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
@[grind] theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
(l.replace a b)[i]'(by simpa) = if l[i] == a then if a l.take i then a else b else l[i] := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_replace]
@@ -3399,7 +3386,7 @@ theorem head_replace {l : List α} {a b : α} (w) :
apply Option.some.inj
rw [ head?_eq_head, head?_replace, head?_eq_head]
@[grind =] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
@[grind] theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
(l₁ ++ l₂).replace a b = if a l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b := by
induction l₁ with
| nil => simp
@@ -3443,9 +3430,9 @@ end replace
section insert
variable [BEq α]
@[simp, grind =] theorem insert_nil (a : α) : [].insert a = [a] := rfl
@[simp, grind] theorem insert_nil (a : α) : [].insert a = [a] := rfl
@[simp, grind =] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
@[simp, grind] theorem contains_insert [PartialEquivBEq α] {l : List α} {a : α} {x : α} :
(l.insert a).contains x = (x == a || l.contains x) := by
simp only [List.insert]
split <;> rename_i h
@@ -3462,7 +3449,7 @@ variable [LawfulBEq α]
@[simp] theorem insert_of_not_mem {l : List α} (h : a l) : l.insert a = a :: l := by
simp [List.insert, h]
@[simp, grind =] theorem mem_insert_iff {l : List α} : a l.insert b a = b a l := by
@[simp, grind] theorem mem_insert_iff {l : List α} : a l.insert b a = b a l := by
if h : b l then
rw [insert_of_mem h]
constructor; {apply Or.inr}
@@ -3486,7 +3473,7 @@ theorem eq_or_mem_of_mem_insert {l : List α} (h : a ∈ l.insert b) : a = b
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a l) :
length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
@[grind =] theorem length_insert {l : List α} :
@[grind] theorem length_insert {l : List α} :
(l.insert a).length = l.length + if a l then 0 else 1 := by
split <;> simp_all
@@ -3521,13 +3508,13 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
simp only [insert_eq]
split <;> simp
@[grind =] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
@[grind] theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
(l.insert a)[i]? = if a l then l[i]? else if i = 0 then some a else l[i-1]? := by
cases i
· simp [getElem?_insert_zero]
· simp [getElem?_insert_succ]
@[grind =] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
@[grind] theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
(l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) =
if a l then l[i] else if i = 0 then a else l[i-1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h) := by
apply Option.some.inj
@@ -3551,7 +3538,7 @@ theorem head_insert {l : List α} {a : α} (w) :
apply Option.some.inj
rw [ head?_eq_head, head?_insert]
@[grind =] theorem insert_append {l₁ l₂ : List α} {a : α} :
@[grind] theorem insert_append {l₁ l₂ : List α} {a : α} :
(l₁ ++ l₂).insert a = if a l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂ := by
simp only [insert_eq, mem_append]
(repeat split) <;> simp_all
@@ -3564,7 +3551,7 @@ theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂)
(l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
simp [insert_append, h]
@[simp, grind =] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
@[simp, grind] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
cases n <;> simp_all
@[simp] theorem insert_replicate_ne {a b : α} (h : !b == a) :

View File

@@ -248,10 +248,11 @@ theorem pairwise_le_range {n : Nat} : Pairwise (· ≤ ·) (range n) :=
theorem nodup_range {n : Nat} : Nodup (range n) := by
simp +decide only [range_eq_range', nodup_range']
@[simp] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
@[simp, grind] theorem find?_range_eq_some {n : Nat} {i : Nat} {p : Nat Bool} :
(range n).find? p = some i p i i range n j, j < i !p j := by
simp [range_eq_range']
@[grind]
theorem find?_range_eq_none {n : Nat} {p : Nat Bool} :
(range n).find? p = none i, i < n !p i := by
simp

View File

@@ -567,10 +567,9 @@ theorem getElem_zipWith {f : α → β → γ} {l : List α} {l' : List β}
f (l[i]'(lt_length_left_of_zipWith h))
(l'[i]'(lt_length_right_of_zipWith h)) := by
rw [ Option.some_inj, getElem?_eq_getElem, getElem?_zipWith_eq_some]
have := lt_length_right_of_zipWith h
exact
l[i]'(lt_length_left_of_zipWith h), l'[i],
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem this]; exact rfl, rfl
l[i]'(lt_length_left_of_zipWith h), l'[i]'(lt_length_right_of_zipWith h),
by rw [getElem?_eq_getElem], by rw [getElem?_eq_getElem]; exact rfl, rfl
theorem zipWith_eq_zipWith_take_min : {l₁ : List α} {l₂ : List β},
zipWith f l₁ l₂ = zipWith f (l₁.take (min l₁.length l₂.length)) (l₂.take (min l₁.length l₂.length))

View File

@@ -43,7 +43,7 @@ theorem rel_of_pairwise_cons (p : (a :: l).Pairwise R) : ∀ {a'}, a' ∈ l →
(pairwise_cons.1 p).2
set_option linter.unusedVariables false in
@[grind ] theorem Pairwise.tail : {l : List α} (h : Pairwise R l), Pairwise R l.tail
@[grind] theorem Pairwise.tail : {l : List α} (h : Pairwise R l), Pairwise R l.tail
| [], h => h
| _ :: _, h => h.of_cons
@@ -103,7 +103,7 @@ theorem Pairwise.forall_of_forall_of_flip (h₁ : ∀ x ∈ l, R x x) (h₂ : Pa
· exact h₃.1 _ hx
· exact ih (fun x hx => h₁ _ <| mem_cons_of_mem _ hx) h₂.2 h₃.2 hx hy
@[grind ] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
@[grind] theorem pairwise_singleton (R) (a : α) : Pairwise R [a] := by simp
@[grind =] theorem pairwise_pair {a b : α} : Pairwise R [a, b] R a b := by simp
@@ -117,7 +117,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
(p : Pairwise S (map f l)) : Pairwise R l :=
(pairwise_map.1 p).imp (H _ _)
@[grind <=] theorem Pairwise.map {S : β β Prop} (f : α β) (H : a b : α, R a b S (f a) (f b))
@[grind] theorem Pairwise.map {S : β β Prop} (f : α β) (H : a b : α, R a b S (f a) (f b))
(p : Pairwise R l) : Pairwise S (map f l) :=
pairwise_map.2 <| p.imp (H _ _)
@@ -136,7 +136,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
simpa [IH, e] using fun _ =>
fun h a ha b hab => h _ _ ha hab, fun h a b ha hab => h _ ha _ hab
@[grind <=] theorem Pairwise.filterMap {S : β β Prop} (f : α Option β)
@[grind] theorem Pairwise.filterMap {S : β β Prop} (f : α Option β)
(H : a a' : α, R a a' b, f a = some b b', f a' = some b' S b b') {l : List α} (p : Pairwise R l) :
Pairwise S (filterMap f l) :=
pairwise_filterMap.2 <| p.imp (H _ _)
@@ -146,7 +146,7 @@ theorem Pairwise.of_map {S : β → β → Prop} (f : α → β) (H : ∀ a b :
rw [ filterMap_eq_filter, pairwise_filterMap]
simp
@[grind ] theorem Pairwise.filter (p : α Bool) : Pairwise R l Pairwise R (filter p l) :=
@[grind] theorem Pairwise.filter (p : α Bool) : Pairwise R l Pairwise R (filter p l) :=
Pairwise.sublist filter_sublist
@[grind =] theorem pairwise_append {l₁ l₂ : List α} :
@@ -207,10 +207,10 @@ theorem pairwise_append_comm {R : αα → Prop} (s : ∀ {x y}, R x y →
simp
· exact fun _ => h, Or.inr h
@[grind ] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
@[grind] theorem Pairwise.drop {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.drop i) :=
h.sublist (drop_sublist _ _)
@[grind ] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
@[grind] theorem Pairwise.take {l : List α} {i : Nat} (h : List.Pairwise R l) : List.Pairwise R (l.take i) :=
h.sublist (take_sublist _ _)
-- This theorem is not annotated with `grind` because it leads to a loop of instantiations with `Pairwise.sublist`.
@@ -266,7 +266,7 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : αα → Prop} (h :
rintro H _ b hb rfl
exact H b hb _ _
@[grind <=] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α Prop} {f : a, p a β}
@[grind] theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α Prop} {f : a, p a β}
(h : x l, p x) {S : β β Prop}
(hS : x (hx : p x) y (hy : p y), R x y S (f x hx) (f y hy)) :
Pairwise S (l.pmap f h) := by
@@ -277,12 +277,10 @@ theorem pairwise_of_forall_mem_list {l : List α} {r : αα → Prop} (h :
@[grind =] theorem nodup_iff_pairwise_ne : List.Nodup l List.Pairwise (· ·) l := Iff.rfl
@[simp]
@[simp, grind]
theorem nodup_nil : @Nodup α [] :=
Pairwise.nil
grind_pattern nodup_nil => @Nodup α []
@[simp, grind =]
theorem nodup_cons {a : α} {l : List α} : Nodup (a :: l) a l Nodup l := by
simp only [Nodup, pairwise_cons, forall_mem_ne]

View File

@@ -151,11 +151,11 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
/-! ### Sublist and isSublist -/
@[simp, grind ] theorem nil_sublist : l : List α, [] <+ l
@[simp, grind] theorem nil_sublist : l : List α, [] <+ l
| [] => .slnil
| a :: l => (nil_sublist l).cons a
@[simp, grind ] theorem Sublist.refl : l : List α, l <+ l
@[simp, grind] theorem Sublist.refl : l : List α, l <+ l
| [] => .slnil
| a :: l => (Sublist.refl l).cons₂ a
@@ -172,7 +172,7 @@ theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l
instance : Trans (@Sublist α) Sublist Sublist := Sublist.trans
attribute [simp, grind ] Sublist.cons
attribute [simp, grind] Sublist.cons
theorem sublist_cons_self (a : α) (l : List α) : l <+ a :: l := (Sublist.refl l).cons _
@@ -202,18 +202,12 @@ theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l
protected theorem Sublist.mem (hx : a l₁) (hl : l₁ <+ l₂) : a l₂ :=
hl.subset hx
theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h xs :=
@[grind] theorem Sublist.head_mem (s : ys <+ xs) (h) : ys.head h xs :=
s.mem (List.head_mem h)
grind_pattern Sublist.head_mem => ys <+ xs, ys.head h
grind_pattern Sublist.head_mem => ys.head h xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h xs :=
@[grind] theorem Sublist.getLast_mem (s : ys <+ xs) (h) : ys.getLast h xs :=
s.mem (List.getLast_mem h)
grind_pattern Sublist.getLast_mem => ys <+ xs, ys.getLast h
grind_pattern Sublist.getLast_mem => ys.getLast h xs -- This is somewhat aggressive, as it initiates sublist based reasoning.
instance : Trans (@Sublist α) Subset Subset :=
fun h₁ h₂ => trans h₁.subset h₂
@@ -254,13 +248,12 @@ theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l
theorem Sublist.length_eq (s : l₁ <+ l₂) : length l₁ = length l₂ l₁ = l₂ :=
s.eq_of_length, congrArg _
@[grind]
theorem tail_sublist : l : List α, tail l <+ l
| [] => .slnil
| a::l => sublist_cons_self a l
grind_pattern tail_sublist => tail l <+ _
@[grind ]
@[grind]
protected theorem Sublist.tail : {l₁ l₂ : List α}, l₁ <+ l₂ tail l₁ <+ tail l₂
| _, _, slnil => .slnil
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
@@ -270,7 +263,7 @@ protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tai
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
h.tail
@[grind ]
@[grind]
protected theorem Sublist.map (f : α β) {l₁ l₂} (s : l₁ <+ l₂) : map f l₁ <+ map f l₂ := by
induction s with
| slnil => simp
@@ -282,7 +275,7 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
@[grind ]
@[grind]
protected theorem Sublist.filterMap (f : α Option β) (s : l₁ <+ l₂) :
filterMap f l₁ <+ filterMap f l₂ := by
induction s <;> simp [filterMap_cons] <;> split <;> simp [*, cons]
@@ -290,7 +283,7 @@ protected theorem Sublist.filterMap (f : α → Option β) (s : l₁ <+ l₂) :
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₁
grind_pattern Sublist.filterMap => l₁ <+ l₂, filterMap f l₂
@[grind ]
@[grind]
protected theorem Sublist.filter (p : α Bool) {l₁ l₂} (s : l₁ <+ l₂) : filter p l₁ <+ filter p l₂ := by
rw [ filterMap_eq_filter]; apply s.filterMap
@@ -488,7 +481,7 @@ theorem Sublist.of_sublist_append_right (w : ∀ a, a ∈ l → a ∉ l₁) (h :
exact fun x m => w x (mem_append_left l₂' m) (h₁.mem m)
simp_all
@[grind ]
@[grind]
theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l₁ ++ a :: l₂ := by
rw [sublist_append_iff] at h
obtain l₁', l₂', rfl, h₁, h₂ := h
@@ -631,28 +624,22 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
decidable_of_iff (l₁.isSublist l₂) isSublist_iff_sublist
@[grind ]
@[grind]
protected theorem Sublist.drop : {l₁ l₂ : List α}, l₁ <+ l₂ i, l₁.drop i <+ l₂.drop i
| _, _, h, 0 => h
| _, _, h, i + 1 => by rw [ drop_tail, drop_tail]; exact h.tail.drop i
/-! ### IsPrefix / IsSuffix / IsInfix -/
@[simp] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := l₂, rfl
@[simp, grind] theorem prefix_append (l₁ l₂ : List α) : l₁ <+: l₁ ++ l₂ := l₂, rfl
grind_pattern prefix_append => l₁ <+: l₁ ++ l₂
@[simp] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := l₁, rfl
grind_pattern suffix_append => l₂ <:+ l₁ ++ l₂
@[simp, grind] theorem suffix_append (l₁ l₂ : List α) : l₂ <:+ l₁ ++ l₂ := l₁, rfl
theorem infix_append (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ l₂ ++ l₃ := l₁, l₃, rfl
@[simp] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
@[simp, grind] theorem infix_append' (l₁ l₂ l₃ : List α) : l₂ <:+: l₁ ++ (l₂ ++ l₃) := by
rw [ List.append_assoc]; apply infix_append
grind_pattern infix_append' => l₂ <:+: l₁ ++ (l₂ ++ l₃)
theorem infix_append_left : l₁ <:+: l₁ ++ l₂ := [], l₂, rfl
theorem infix_append_right : l₂ <:+: l₁ ++ l₂ := l₁, [], by simp
@@ -664,24 +651,22 @@ theorem IsSuffix.isInfix : l₁ <:+ l₂ → l₁ <:+: l₂ := fun ⟨t, h⟩ =>
grind_pattern IsSuffix.isInfix => l₁ <:+ l₂, IsInfix
@[simp, grind ] theorem nil_prefix {l : List α} : [] <+: l := l, rfl
@[simp, grind] theorem nil_prefix {l : List α} : [] <+: l := l, rfl
@[simp, grind ] theorem nil_suffix {l : List α} : [] <:+ l := l, append_nil _
@[simp, grind] theorem nil_suffix {l : List α} : [] <:+ l := l, append_nil _
@[simp, grind ] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
@[simp, grind] theorem nil_infix {l : List α} : [] <:+: l := nil_prefix.isInfix
theorem prefix_refl (l : List α) : l <+: l := [], append_nil _
@[simp, grind ] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
@[simp, grind] theorem prefix_rfl {l : List α} : l <+: l := prefix_refl l
theorem suffix_refl (l : List α) : l <:+ l := [], rfl
@[simp, grind ] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
@[simp, grind] theorem suffix_rfl {l : List α} : l <:+ l := suffix_refl l
theorem infix_refl (l : List α) : l <:+: l := prefix_rfl.isInfix
@[simp, grind ] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
@[simp, grind] theorem infix_rfl {l : List α} : l <:+: l := infix_refl l
@[simp] theorem suffix_cons (a : α) : l, l <:+ a :: l := suffix_append [a]
grind_pattern suffix_cons => _ <:+ a :: l
@[simp, grind] theorem suffix_cons (a : α) : l, l <:+ a :: l := suffix_append [a]
theorem infix_cons : l₁ <:+: l₂ l₁ <:+: a :: l₂ := fun l₁', l₂', h => a :: l₁', l₂', h rfl
@@ -1123,36 +1108,24 @@ theorem infix_of_mem_flatten : ∀ {L : List (List α)}, l ∈ L → l <:+: flat
theorem prefix_cons_inj (a) : a :: l₁ <+: a :: l₂ l₁ <+: l₂ :=
prefix_append_right_inj [a]
theorem take_prefix (i) (l : List α) : take i l <+: l :=
@[grind] theorem take_prefix (i) (l : List α) : take i l <+: l :=
_, take_append_drop _ _
grind_pattern take_prefix => take i l <+: _
theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
@[grind] theorem drop_suffix (i) (l : List α) : drop i l <:+ l :=
_, take_append_drop _ _
grind_pattern drop_suffix => drop i l <+: _
theorem take_sublist (i) (l : List α) : take i l <+ l :=
@[grind] theorem take_sublist (i) (l : List α) : take i l <+ l :=
(take_prefix i l).sublist
grind_pattern take_sublist => take i l <+ l
theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
@[grind] theorem drop_sublist (i) (l : List α) : drop i l <+ l :=
(drop_suffix i l).sublist
grind_pattern drop_sublist => drop i l <+ l
theorem take_subset (i) (l : List α) : take i l l :=
(take_sublist i l).subset
grind_pattern take_subset => take i l l
theorem drop_subset (i) (l : List α) : drop i l l :=
(drop_sublist i l).subset
grind_pattern drop_subset => drop i l l
theorem mem_of_mem_take {l : List α} (h : a l.take i) : a l :=
take_subset _ _ h
@@ -1165,84 +1138,64 @@ theorem drop_suffix_drop_left (l : List α) {i j : Nat} (h : i ≤ j) : drop j l
-- See `Init.Data.List.Nat.TakeDrop` for `take_prefix_take_left`.
@[grind ] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l <+ drop i l :=
@[grind] theorem drop_sublist_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l <+ drop i l :=
(drop_suffix_drop_left l h).sublist
@[grind ] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l drop i l :=
@[grind] theorem drop_subset_drop_left (l : List α) {i j : Nat} (h : i j) : drop j l drop i l :=
(drop_sublist_drop_left l h).subset
theorem takeWhile_prefix (p : α Bool) : l.takeWhile p <+: l :=
@[grind] theorem takeWhile_prefix (p : α Bool) : l.takeWhile p <+: l :=
l.dropWhile p, takeWhile_append_dropWhile
grind_pattern takeWhile_prefix => l.takeWhile p <+: _
theorem dropWhile_suffix (p : α Bool) : l.dropWhile p <:+ l :=
@[grind] theorem dropWhile_suffix (p : α Bool) : l.dropWhile p <:+ l :=
l.takeWhile p, takeWhile_append_dropWhile
grind_pattern dropWhile_suffix => l.dropWhile p <+: _
theorem takeWhile_sublist (p : α Bool) : l.takeWhile p <+ l :=
@[grind] theorem takeWhile_sublist (p : α Bool) : l.takeWhile p <+ l :=
(takeWhile_prefix p).sublist
grind_pattern takeWhile_sublist => l.takeWhile p <+ _
theorem dropWhile_sublist (p : α Bool) : l.dropWhile p <+ l :=
@[grind] theorem dropWhile_sublist (p : α Bool) : l.dropWhile p <+ l :=
(dropWhile_suffix p).sublist
grind_pattern dropWhile_sublist => l.dropWhile p <+ _
theorem takeWhile_subset {l : List α} (p : α Bool) : l.takeWhile p l :=
(takeWhile_sublist p).subset
grind_pattern takeWhile_subset => l.takeWhile p _
theorem dropWhile_subset {l : List α} (p : α Bool) : l.dropWhile p l :=
(dropWhile_sublist p).subset
grind_pattern dropWhile_subset => l.dropWhile p _
theorem dropLast_prefix : l : List α, l.dropLast <+: l
@[grind] theorem dropLast_prefix : l : List α, l.dropLast <+: l
| [] => nil, by rw [dropLast, List.append_nil]
| a :: l => _, dropLast_concat_getLast (cons_ne_nil a l)
grind_pattern dropLast_prefix => l.dropLast <+: _
theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
@[grind] theorem dropLast_sublist (l : List α) : l.dropLast <+ l :=
(dropLast_prefix l).sublist
grind_pattern dropLast_sublist => l.dropLast <+ _
theorem dropLast_subset (l : List α) : l.dropLast l :=
(dropLast_sublist l).subset
grind_pattern dropLast_subset => l.dropLast _
@[grind] theorem tail_suffix (l : List α) : tail l <:+ l := by rw [ drop_one]; apply drop_suffix
theorem tail_suffix (l : List α) : tail l <:+ l := by rw [ drop_one]; apply drop_suffix
grind_pattern tail_suffix => tail l <+: _
@[grind ] theorem IsPrefix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <+: l₂) : l₁.map f <+: l₂.map f := by
@[grind] theorem IsPrefix.map {β} (f : α β) l₁ l₂ : List α (h : l <+: l) : l₁.map f <+: l₂.map f := by
obtain r, rfl := h
rw [map_append]; apply prefix_append
grind_pattern IsPrefix.map => l₁ <+: l₂, l₁.map f
grind_pattern IsPrefix.map => l₁ <+: l₂, l₂.map f
@[grind ] theorem IsSuffix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
@[grind] theorem IsSuffix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+ l₂) : l₁.map f <:+ l₂.map f := by
obtain r, rfl := h
rw [map_append]; apply suffix_append
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₁.map f
grind_pattern IsSuffix.map => l₁ <:+ l₂, l₂.map f
@[grind ] theorem IsInfix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
@[grind] theorem IsInfix.map {β} (f : α β) l₁ l₂ : List α (h : l₁ <:+: l₂) : l₁.map f <:+: l₂.map f := by
obtain r₁, r₂, rfl := h
rw [map_append, map_append]; apply infix_append
grind_pattern IsInfix.map => l₁ <:+: l₂, l₁.map f
grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
@[grind ] theorem IsPrefix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <+: l₂) :
@[grind] theorem IsPrefix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <+: l₂) :
l₁.filter p <+: l₂.filter p := by
obtain xs, rfl := h
rw [filter_append]; apply prefix_append
@@ -1250,7 +1203,7 @@ grind_pattern IsInfix.map => l₁ <:+: l₂, l₂.map f
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₁.filter p
grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
@[grind ] theorem IsSuffix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+ l₂) :
@[grind] theorem IsSuffix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+ l₂) :
l₁.filter p <:+ l₂.filter p := by
obtain xs, rfl := h
rw [filter_append]; apply suffix_append
@@ -1258,7 +1211,7 @@ grind_pattern IsPrefix.filter => l₁ <+: l₂, l₂.filter p
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₁.filter p
grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
@[grind ] theorem IsInfix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+: l₂) :
@[grind] theorem IsInfix.filter (p : α Bool) l₁ l₂ : List α (h : l₁ <:+: l₂) :
l₁.filter p <:+: l₂.filter p := by
obtain xs, ys, rfl := h
rw [filter_append, filter_append]; apply infix_append _
@@ -1266,7 +1219,7 @@ grind_pattern IsSuffix.filter => l₁ <:+ l₂, l₂.filter p
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₁.filter p
grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
@[grind ] theorem IsPrefix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <+: l₂) :
@[grind] theorem IsPrefix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <+: l₂) :
filterMap f l₁ <+: filterMap f l₂ := by
obtain xs, rfl := h
rw [filterMap_append]; apply prefix_append
@@ -1274,7 +1227,7 @@ grind_pattern IsInfix.filter => l₁ <:+: l₂, l₂.filter p
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₁
grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
@[grind ] theorem IsSuffix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+ l₂) :
@[grind] theorem IsSuffix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+ l₂) :
filterMap f l₁ <:+ filterMap f l₂ := by
obtain xs, rfl := h
rw [filterMap_append]; apply suffix_append
@@ -1282,7 +1235,7 @@ grind_pattern IsPrefix.filterMap => l₁ <+: l₂, filterMap f l₂
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₁
grind_pattern IsSuffix.filterMap => l₁ <:+ l₂, filterMap f l₂
@[grind ] theorem IsInfix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+: l₂) :
@[grind] theorem IsInfix.filterMap {β} (f : α Option β) l₁ l₂ : List α (h : l₁ <:+: l₂) :
filterMap f l₁ <:+: filterMap f l₂ := by
obtain xs, ys, rfl := h
rw [filterMap_append, filterMap_append]; apply infix_append

View File

@@ -9,7 +9,6 @@ prelude
public import Init.ByCases
public import Init.Data.Prod
public import Init.Data.RArray
import Init.LawfulBEqTactics
public section
@@ -139,7 +138,21 @@ structure PolyCnstr where
eq : Bool
lhs : Poly
rhs : Poly
deriving BEq, ReflBEq, LawfulBEq
deriving BEq
-- TODO: implement LawfulBEq generator companion for BEq
instance : LawfulBEq PolyCnstr where
eq_of_beq {a b} h := by
cases a; rename_i eq₁ lhs₁ rhs₁
cases b; rename_i eq₂ lhs₂ rhs₂
have h : eq₁ == eq₂ && (lhs₁ == lhs₂ && rhs₁ == rhs₂) := h
simp at h
have h₁, h₂, h₃ := h
rw [h₁, h₂, h₃]
rfl {a} := by
cases a; rename_i eq lhs rhs
change (eq == eq && (lhs == lhs && rhs == rhs)) = true
simp
structure ExprCnstr where
eq : Bool

View File

@@ -15,30 +15,30 @@ public section
namespace Option
@[simp, grind =] theorem mem_toArray {a : α} {o : Option α} : a o.toArray o = some a := by
@[simp, grind] theorem mem_toArray {a : α} {o : Option α} : a o.toArray o = some a := by
cases o <;> simp [eq_comm]
@[simp, grind =] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toArray β m (ForInStep β)) :
@[simp, grind] theorem forIn'_toArray [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toArray β m (ForInStep β)) :
forIn' o.toArray b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> simp <;> rfl
@[simp, grind =] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind] theorem forIn_toArray [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
forIn o.toArray b f = forIn o b f := by
cases o <;> simp <;> rfl
@[simp, grind =] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
@[simp, grind] theorem foldlM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toArray.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp, grind =] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
@[simp, grind] theorem foldrM_toArray [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toArray.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp, grind =] theorem foldl_toArray (o : Option β) (a : α) (f : α β α) :
@[simp, grind] theorem foldl_toArray (o : Option β) (a : α) (f : α β α) :
o.toArray.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp, grind =] theorem foldr_toArray (o : Option β) (a : α) (f : β α α) :
@[simp, grind] theorem foldr_toArray (o : Option β) (a : α) (f : β α α) :
o.toArray.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp

View File

@@ -97,7 +97,7 @@ theorem attach_eq_some : ∀ (o : Option α) (x : {x // o = some x}), o.attach =
| none, x, h => by simp at h
| some a, x, h => by simpa using h
@[grind ]
@[grind]
theorem mem_attach : (o : Option α) (x : {x // o = some x}), x o.attach :=
attach_eq_some

View File

@@ -18,27 +18,27 @@ namespace Option
deriving instance DecidableEq for Option
deriving instance BEq for Option
@[simp, grind =] theorem getD_none : getD none a = a := rfl
@[simp, grind =] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind] theorem getD_none : getD none a = a := rfl
@[simp, grind] theorem getD_some : getD (some a) b = a := rfl
@[simp, grind =] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind =] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
@[simp, grind] theorem map_none (f : α β) : none.map f = none := rfl
@[simp, grind] theorem map_some (a) (f : α β) : (some a).map f = some (f a) := rfl
/-- Lifts an optional value to any `Alternative`, sending `none` to `failure`. -/
def getM [Alternative m] : Option α m α
| none => failure
| some a => pure a
@[simp, grind =] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind =] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
@[simp, grind] theorem getM_none [Alternative m] : getM none = (failure : m α) := rfl
@[simp, grind] theorem getM_some [Alternative m] {a : α} : getM (some a) = (pure a : m α) := rfl
/-- Returns `true` on `some x` and `false` on `none`. -/
@[inline] def isSome : Option α Bool
| some _ => true
| none => false
@[simp, grind =] theorem isSome_none : @isSome α none = false := rfl
@[simp, grind =] theorem isSome_some : isSome (some a) = true := rfl
@[simp, grind] theorem isSome_none : @isSome α none = false := rfl
@[simp, grind] theorem isSome_some : isSome (some a) = true := rfl
/--
Returns `true` on `none` and `false` on `some x`.
@@ -53,8 +53,8 @@ Examples:
| some _ => false
| none => true
@[simp, grind =] theorem isNone_none : @isNone α none = true := rfl
@[simp, grind =] theorem isNone_some : isNone (some a) = false := rfl
@[simp, grind] theorem isNone_none : @isNone α none = true := rfl
@[simp, grind] theorem isNone_some : isNone (some a) = false := rfl
/--
Checks whether an optional value is both present and equal to some other value.
@@ -89,8 +89,8 @@ Examples:
| none, _ => none
| some a, f => f a
@[simp, grind =] theorem bind_none (f : α Option β) : none.bind f = none := rfl
@[simp, grind =] theorem bind_some (a) (f : α Option β) : (some a).bind f = f a := rfl
@[simp, grind] theorem bind_none (f : α Option β) : none.bind f = none := rfl
@[simp, grind] theorem bind_some (a) (f : α Option β) : (some a).bind f = f a := rfl
@[deprecated bind_none (since := "2025-05-03")]
abbrev none_bind := @bind_none
@@ -125,8 +125,8 @@ This function only requires `m` to be an applicative functor. An alias `Option.m
| none => pure none
| some x => some <$> f x
@[simp, grind =] theorem mapM_none [Applicative m] (f : α m β) : none.mapM f = pure none := rfl
@[simp, grind =] theorem mapM_some [Applicative m] (x) (f : α m β) : (some x).mapM f = some <$> f x := rfl
@[simp, grind] theorem mapM_none [Applicative m] (f : α m β) : none.mapM f = pure none := rfl
@[simp, grind] theorem mapM_some [Applicative m] (x) (f : α m β) : (some x).mapM f = some <$> f x := rfl
/--
Applies a function in some applicative functor to an optional value, returning `none` with no
@@ -138,9 +138,9 @@ This is an alias for `Option.mapM`, which already works for applicative functors
Option.mapM f
/-- For verification purposes, we replace `mapA` with `mapM`. -/
@[simp, grind =] theorem mapA_eq_mapM [Applicative m] {f : α m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind] theorem mapA_eq_mapM [Applicative m] {f : α m β} : Option.mapA f o = Option.mapM f o := rfl
@[simp, grind =]
@[simp, grind]
theorem map_id : (Option.map id : Option α Option α) = id :=
funext (fun o => match o with | none => rfl | some _ => rfl)
@@ -182,8 +182,8 @@ Examples:
| some a => p a
| none => true
@[simp, grind =] theorem all_none : Option.all p none = true := rfl
@[simp, grind =] theorem all_some : Option.all p (some x) = p x := rfl
@[simp, grind] theorem all_none : Option.all p none = true := rfl
@[simp, grind] theorem all_some : Option.all p (some x) = p x := rfl
/--
Checks whether an optional value is not `none` and satisfies a Boolean predicate.
@@ -197,8 +197,8 @@ Examples:
| some a => p a
| none => false
@[simp, grind =] theorem any_none : Option.any p none = false := rfl
@[simp, grind =] theorem any_some : Option.any p (some x) = p x := rfl
@[simp, grind] theorem any_none : Option.any p none = false := rfl
@[simp, grind] theorem any_some : Option.any p (some x) = p x := rfl
/--
Implementation of `OrElse`'s `<|>` syntax for `Option`. If the first argument is `some a`, returns
@@ -210,8 +210,8 @@ See also `or` for a version that is strict in the second argument.
| some a, _ => some a
| none, b => b ()
@[simp, grind =] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind =] theorem orElse_none : none.orElse b = b () := rfl
@[simp, grind] theorem orElse_some : (some a).orElse b = some a := rfl
@[simp, grind] theorem orElse_none : none.orElse b = b () := rfl
instance : OrElse (Option α) where
orElse := Option.orElse
@@ -351,9 +351,9 @@ Extracts the value from an option that can be proven to be `some`.
@[inline] def get {α : Type u} : (o : Option α) isSome o α
| some x, _ => x
@[simp, grind =] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
@[simp, grind] theorem some_get : {x : Option α} (h : isSome x), some (x.get h) = x
| some _, _ => rfl
@[simp, grind =] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
@[simp, grind] theorem get_some (x : α) (h : isSome (some x)) : (some x).get h = x := rfl
/--
Returns `none` if a value doesn't satisfy a Boolean predicate, or the value itself otherwise.
@@ -431,8 +431,8 @@ Examples:
-/
@[inline] def join (x : Option (Option α)) : Option α := x.bind id
@[simp, grind =] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind =] theorem join_some : (some o).join = o := rfl
@[simp, grind] theorem join_none : (none : Option (Option α)).join = none := rfl
@[simp, grind] theorem join_some : (some o).join = o := rfl
/--
Converts an optional monadic computation into a monadic computation of an optional value.
@@ -457,8 +457,8 @@ some "world"
| none => pure none
| some f => some <$> f
@[simp, grind =] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind =] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
@[simp, grind] theorem sequence_none [Applicative m] : (none : Option (m α)).sequence = pure none := rfl
@[simp, grind] theorem sequence_some [Applicative m] (f : m α) : (some f).sequence = some <$> f := rfl
/--
A monadic case analysis function for `Option`.
@@ -483,8 +483,8 @@ This is the monadic analogue of `Option.getD`.
| some a => pure a
| none => y
@[simp, grind =] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind =] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
@[simp, grind] theorem getDM_none [Pure m] (y : m α) : (none : Option α).getDM y = y := rfl
@[simp, grind] theorem getDM_some [Pure m] (a : α) (y : m α) : (some a).getDM y = pure a := rfl
instance (α) [BEq α] [ReflBEq α] : ReflBEq (Option α) where
rfl {x} := private
@@ -520,10 +520,10 @@ protected def min [Min α] : Option α → Option α → Option α
instance [Min α] : Min (Option α) where min := Option.min
@[simp, grind =] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind =] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
@[simp, grind] theorem min_some_some [Min α] {a b : α} : min (some a) (some b) = some (min a b) := rfl
@[simp, grind] theorem min_none_left [Min α] {o : Option α} : min none o = none := by
cases o <;> rfl
@[simp, grind =] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
@[simp, grind] theorem min_none_right [Min α] {o : Option α} : min o none = none := by
cases o <;> rfl
@[deprecated min_none_right (since := "2025-05-12")]
@@ -553,10 +553,10 @@ protected def max [Max α] : Option α → Option α → Option α
instance [Max α] : Max (Option α) where max := Option.max
@[simp, grind =] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind =] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
@[simp, grind] theorem max_some_some [Max α] {a b : α} : max (some a) (some b) = some (max a b) := rfl
@[simp, grind] theorem max_none_left [Max α] {o : Option α} : max none o = o := by
cases o <;> rfl
@[simp, grind =] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
@[simp, grind] theorem max_none_right [Max α] {o : Option α} : max o none = o := by
cases o <;> rfl
@[deprecated max_none_right (since := "2025-05-12")]

View File

@@ -24,7 +24,7 @@ namespace Option
@[deprecated mem_def (since := "2025-04-07")]
theorem mem_iff {a : α} {b : Option α} : a b b = some a := .rfl
@[grind =] theorem mem_some {a b : α} : a some b b = a := by simp
@[grind] theorem mem_some {a b : α} : a some b b = a := by simp
theorem mem_some_iff {a b : α} : a some b b = a := mem_some
@@ -52,7 +52,7 @@ theorem get_of_mem : ∀ {o : Option α} (h : isSome o), a ∈ o → o.get h = a
theorem get_of_eq_some : {o : Option α} (h : isSome o), o = some a o.get h = a
| _, _, rfl => rfl
@[simp, grind ] theorem not_mem_none (a : α) : a (none : Option α) := nofun
@[simp, grind] theorem not_mem_none (a : α) : a (none : Option α) := nofun
theorem getD_of_ne_none {x : Option α} (hx : x none) (y : α) : some (x.getD y) = x := by
cases x; {contradiction}; rw [getD_some]

View File

@@ -16,38 +16,38 @@ public section
namespace Option
@[simp, grind =] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
@[simp, grind] theorem mem_toList {a : α} {o : Option α} : a o.toList o = some a := by
cases o <;> simp [eq_comm]
@[simp, grind =] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
@[simp, grind] theorem forIn'_toList [Monad m] (o : Option α) (b : β) (f : (a : α) a o.toList β m (ForInStep β)) :
forIn' o.toList b f = forIn' o b fun a m b => f a (by simpa using m) b := by
cases o <;> rfl
@[simp, grind =] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind] theorem forIn_toList [Monad m] (o : Option α) (b : β) (f : α β m (ForInStep β)) :
forIn o.toList b f = forIn o b f := by
cases o <;> rfl
@[simp, grind =] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
@[simp, grind] theorem foldlM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : α β m α) :
o.toList.foldlM f a = o.elim (pure a) (fun b => f a b) := by
cases o <;> simp
@[simp, grind =] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
@[simp, grind] theorem foldrM_toList [Monad m] [LawfulMonad m] (o : Option β) (a : α) (f : β α m α) :
o.toList.foldrM f a = o.elim (pure a) (fun b => f b a) := by
cases o <;> simp
@[simp, grind =] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
@[simp, grind] theorem foldl_toList (o : Option β) (a : α) (f : α β α) :
o.toList.foldl f a = o.elim a (fun b => f a b) := by
cases o <;> simp
@[simp, grind =] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
@[simp, grind] theorem foldr_toList (o : Option β) (a : α) (f : β α α) :
o.toList.foldr f a = o.elim a (fun b => f b a) := by
cases o <;> simp
@[simp, grind ]
@[simp, grind]
theorem pairwise_toList {P : α α Prop} {o : Option α} : o.toList.Pairwise P := by
cases o <;> simp
@[simp, grind =]
@[simp, grind]
theorem head?_toList {o : Option α} : o.toList.head? = o := by
cases o <;> simp

View File

@@ -16,20 +16,20 @@ public section
namespace Option
@[simp, grind =] theorem bindM_none [Pure m] (f : α m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind =] theorem bindM_some [Pure m] (a) (f : α m (Option β)) : (some a).bindM f = f a := by
@[simp, grind] theorem bindM_none [Pure m] (f : α m (Option β)) : none.bindM f = pure none := rfl
@[simp, grind] theorem bindM_some [Pure m] (a) (f : α m (Option β)) : (some a).bindM f = f a := by
simp [Option.bindM]
-- We simplify `Option.forM` to `forM`.
@[simp] theorem forM_eq_forM [Monad m] : @Option.forM m α _ = forM := rfl
@[simp, grind =] theorem forM_none [Monad m] (f : α m PUnit) :
@[simp, grind] theorem forM_none [Monad m] (f : α m PUnit) :
forM none f = pure .unit := rfl
@[simp, grind =] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
@[simp, grind] theorem forM_some [Monad m] (f : α m PUnit) (a : α) :
forM (some a) f = f a := rfl
@[simp, grind =] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
@[simp, grind] theorem forM_map [Monad m] [LawfulMonad m] (o : Option α) (g : α β) (f : β m PUnit) :
forM (o.map g) f = forM o (fun a => f (g a)) := by
cases o <;> simp
@@ -37,11 +37,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α
forM o.join f = forM o (forM · f) := by
cases o <;> simp
@[simp, grind =] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
@[simp, grind] theorem forIn'_none [Monad m] (b : β) (f : (a : α) a none β m (ForInStep β)) :
forIn' none b f = pure b := by
rfl
@[simp, grind =] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
@[simp, grind] theorem forIn'_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : (a' : α) a' some a β m (ForInStep β)) :
forIn' (some a) b f = bind (f a rfl b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn', bind_pure_comp]
rw [map_eq_pure_bind]
@@ -49,11 +49,11 @@ theorem forM_join [Monad m] [LawfulMonad m] (o : Option (Option α)) (f : α
funext x
split <;> simp
@[simp, grind =] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
@[simp, grind] theorem forIn_none [Monad m] (b : β) (f : α β m (ForInStep β)) :
forIn none b f = pure b := by
rfl
@[simp, grind =] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
@[simp, grind] theorem forIn_some [Monad m] [LawfulMonad m] (a : α) (b : β) (f : α β m (ForInStep β)) :
forIn (some a) b f = bind (f a b) (fun r => pure (ForInStep.value r)) := by
simp only [forIn, forIn', bind_pure_comp]
rw [map_eq_pure_bind]
@@ -106,7 +106,7 @@ theorem forIn'_id_yield_eq_pelim
o.pelim b (fun a h => f a h b) :=
forIn'_pure_yield_eq_pelim _ _ _
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn'_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : (b : β) b o.map g γ m (ForInStep γ)) :
forIn' (o.map g) init f = forIn' o init fun a h y => f (g a) (mem_map_of_mem g h) y := by
cases o <;> simp
@@ -149,7 +149,7 @@ theorem forIn_id_yield_eq_elim
o.elim b (fun a => f a b) :=
forIn_pure_yield_eq_elim _ _ _
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
@[simp, grind] theorem forIn_map [Monad m] [LawfulMonad m]
(o : Option α) (g : α β) (f : β γ m (ForInStep γ)) :
forIn (o.map g) init f = forIn o init fun a y => f (g a) y := by
cases o <;> simp

View File

@@ -349,13 +349,13 @@ theorem LawfulEqCmp.compare_beq_iff_eq {a b : α} : cmp a b == .eq ↔ a = b :=
beq_iff_eq.trans compare_eq_iff_eq
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_eq_iff_eq` -/
@[simp, grind =]
@[simp, grind]
theorem LawfulEqOrd.compare_eq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
compare a b = .eq a = b :=
LawfulEqCmp.compare_eq_iff_eq
/-- The corresponding lemma for `LawfulEqCmp` is `LawfulEqCmp.compare_beq_iff_eq` -/
@[grind =]
@[grind]
theorem LawfulEqOrd.compare_beq_iff_eq [Ord α] [LawfulEqOrd α] {a b : α} :
compare a b == .eq a = b :=
LawfulEqCmp.compare_beq_iff_eq

View File

@@ -12,8 +12,6 @@ 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

View File

@@ -1,88 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.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

View File

@@ -8,7 +8,6 @@ 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
@@ -24,7 +23,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
@@ -37,14 +36,6 @@ 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

View File

@@ -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 are finite and support this function.
type and shape support this function and the range is finite.
-/
@[always_inline, inline, expose]
def toList {sl su α} [UpwardEnumerable α] [BoundedUpwardEnumerable sl α]
@@ -37,18 +37,6 @@ 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.
-/

View File

@@ -16,7 +16,6 @@ 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
@@ -45,12 +44,6 @@ 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 α]
@@ -68,35 +61,6 @@ 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 α]
@@ -109,18 +73,6 @@ 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 α]
@@ -138,14 +90,6 @@ 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 α]
@@ -157,14 +101,6 @@ 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 α]
@@ -174,15 +110,6 @@ 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') :
@@ -374,17 +301,6 @@ 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 α]
@@ -408,18 +324,6 @@ 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 α]
@@ -431,17 +335,6 @@ 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 α]
@@ -538,20 +431,6 @@ 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 α]
@@ -576,94 +455,4 @@ 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

View File

@@ -10,12 +10,10 @@ import Init.Data.Nat.Lemmas
public import Init.Data.Nat.Order
public import Init.Data.Range.Polymorphic.Instances
public import Init.Data.Order.Classes
public import Init.Data.Order.Lemmas
import Init.Data.Order.Lemmas
public section
open Std PRange
namespace Std.PRange
instance : UpwardEnumerable Nat where
@@ -41,7 +39,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
@@ -78,7 +76,8 @@ instance : LawfulRangeSize .closed Nat where
instance : LawfulRangeSize .open Nat := inferInstance
instance : HasFiniteRanges .closed Nat := inferInstance
instance : HasFiniteRanges .open Nat := inferInstance
instance : LinearlyUpwardEnumerable Nat := inferInstance
instance : LinearlyUpwardEnumerable Nat := by
exact instLinearlyUpwardEnumerableOfTotalLeOfLawfulUpwardEnumerableOfLawfulUpwardEnumerableLE
/-!
The following instances are used for the implementation of array slices a.k.a. `Subarray`.

View File

@@ -25,17 +25,4 @@ 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

View File

@@ -1,382 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.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

View File

@@ -40,6 +40,7 @@ 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?)
/--
@@ -79,6 +80,7 @@ class Least? (α : Type u) where
-/
least? : Option α
attribute [simp] Least?.least?
export Least? (least?)
/--
@@ -93,7 +95,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 : α} :
@@ -103,7 +105,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 α]

View File

@@ -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

View File

@@ -311,13 +311,6 @@ 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

View File

@@ -193,14 +193,14 @@ 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)
rcases this with _, _, m, rfl
exact m
@[simp, grind =]
@[simp, grind]
theorem mem_attachWith {xs : Vector α n} {q : α Prop} (H) (x : {x // q x}) :
x xs.attachWith q H x.1 xs := by
rcases xs with xs, rfl
@@ -211,13 +211,12 @@ theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {xs : Vector α n} {H
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 : Vector α n} {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
theorem pmap_eq_self {xs : Vector α n} {p : α Prop} {hp : (a : α), a xs p a}
{f : (a : α) p a α} : xs.pmap f hp = xs a (h : a xs), f a (hp a h) = a := by
rcases xs with xs, rfl

View File

@@ -36,7 +36,7 @@ structure Vector (α : Type u) (n : Nat) where
size_toArray : toArray.size = n
deriving Repr, DecidableEq
attribute [simp, grind =] Vector.size_toArray
attribute [simp, grind] Vector.size_toArray
/--
Converts an array to a vector. The resulting vector's size is the array's size.

View File

@@ -32,11 +32,11 @@ open Nat
/-! ### findSome? -/
@[simp, grind =] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
@[simp, grind =] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
@[simp, grind] theorem findSome?_empty : (#v[] : Vector α 0).findSome? f = none := rfl
@[simp, grind] theorem findSome?_push {xs : Vector α n} : (xs.push a).findSome? f = (xs.findSome? f).or (f a) := by
cases xs; simp
@[grind =]
@[grind]
theorem findSome?_singleton {a : α} {f : α Option β} : #v[a].findSome? f = f a := by
simp
@@ -228,12 +228,11 @@ theorem mem_of_find?_eq_some {xs : Vector α n} (h : find? p xs = some a) : a
simp at h
simpa using Array.mem_of_find?_eq_some h
@[grind]
theorem get_find?_mem {xs : Vector α n} (h) : (xs.find? p).get h xs := by
cases xs
simp [Array.get_find?_mem]
grind_pattern get_find?_mem => (xs.find? p).get h
@[simp, grind =] theorem find?_map {f : β α} {xs : Vector β n} :
find? p (xs.map f) = (xs.find? (p f)).map f := by
cases xs; simp

View File

@@ -266,12 +266,12 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
/-! ### toArray lemmas -/
@[simp, grind =] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
@[simp, grind] theorem getElem_toArray {α n} {xs : Vector α n} {i : Nat} (h : i < xs.toArray.size) :
xs.toArray[i] = xs[i]'(by simpa using h) := by
cases xs
simp
@[simp, grind =] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
@[simp, grind] theorem getElem?_toArray {α n} {xs : Vector α n} {i : Nat} :
xs.toArray[i]? = xs[i]? := by
cases xs
simp
@@ -280,45 +280,45 @@ theorem toArray_mk {xs : Array α} (h : xs.size = n) : (Vector.mk xs h).toArray
(xs ++ ys).toArray = xs.toArray ++ ys.toArray := rfl
set_option linter.indexVariables false in
@[simp, grind =] theorem toArray_drop {xs : Vector α n} {i} :
@[simp, grind] theorem toArray_drop {xs : Vector α n} {i} :
(xs.drop i).toArray = xs.toArray.extract i n := by
simp [drop]
@[simp, grind =] theorem toArray_empty : (#v[] : Vector α 0).toArray = #[] := rfl
@[simp, grind =] theorem toArray_emptyWithCapacity {cap} :
@[simp, grind] theorem toArray_emptyWithCapacity {cap} :
(Vector.emptyWithCapacity (α := α) cap).toArray = Array.emptyWithCapacity cap := rfl
@[deprecated toArray_emptyWithCapacity (since := "2025-03-12")]
abbrev toArray_mkEmpty := @toArray_emptyWithCapacity
@[simp, grind =] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
@[simp, grind] theorem toArray_eraseIdx {xs : Vector α n} {i} (h) :
(xs.eraseIdx i h).toArray = xs.toArray.eraseIdx i (by simp [h]) := rfl
@[simp, grind =] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
@[simp, grind] theorem toArray_eraseIdx! {xs : Vector α n} {i} (hi : i < n) :
(xs.eraseIdx! i).toArray = xs.toArray.eraseIdx! i := by
cases xs; simp_all [Array.eraseIdx!]
@[simp, grind =] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
@[simp, grind] theorem toArray_insertIdx {xs : Vector α n} {i x} (h) :
(xs.insertIdx i x h).toArray = xs.toArray.insertIdx i x (by simp [h]) := rfl
@[simp, grind =] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
@[simp, grind] theorem toArray_insertIdx! {xs : Vector α n} {i x} (hi : i n) :
(xs.insertIdx! i x).toArray = xs.toArray.insertIdx! i x := by
cases xs; simp_all [Array.insertIdx!]
@[simp, grind =] theorem toArray_cast {xs : Vector α n} (h : n = m) :
@[simp, grind] theorem toArray_cast {xs : Vector α n} (h : n = m) :
(xs.cast h).toArray = xs.toArray := rfl
@[simp, grind =] theorem toArray_extract {xs : Vector α n} {start stop} :
@[simp, grind] theorem toArray_extract {xs : Vector α n} {start stop} :
(xs.extract start stop).toArray = xs.toArray.extract start stop := rfl
@[simp, grind =] theorem toArray_map {f : α β} {xs : Vector α n} :
@[simp, grind] theorem toArray_map {f : α β} {xs : Vector α n} :
(xs.map f).toArray = xs.toArray.map f := rfl
@[simp, grind =] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapIdx {f : Nat α β} {xs : Vector α n} :
(xs.mapIdx f).toArray = xs.toArray.mapIdx f := rfl
@[simp, grind =] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapFinIdx {f : (i : Nat) α (h : i < n) β} {xs : Vector α n} :
(xs.mapFinIdx f).toArray =
xs.toArray.mapFinIdx (fun i a h => f i a (by simpa [xs.size_toArray] using h)) :=
rfl
@@ -336,42 +336,42 @@ private theorem toArray_mapM_go [Monad m] [LawfulMonad m] {f : α → m β} {xs
rfl
· simp
@[simp, grind =] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
@[simp, grind] theorem toArray_mapM [Monad m] [LawfulMonad m] {f : α m β} {xs : Vector α n} :
toArray <$> xs.mapM f = xs.toArray.mapM f := by
rcases xs with xs, rfl
unfold mapM
rw [toArray_mapM_go]
rfl
@[simp, grind =] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp, grind] theorem toArray_ofFn {f : Fin n α} : (Vector.ofFn f).toArray = Array.ofFn f := rfl
@[simp, grind =] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp, grind] theorem toArray_pop {xs : Vector α n} : xs.pop.toArray = xs.toArray.pop := rfl
@[simp, grind =] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp, grind] theorem toArray_push {xs : Vector α n} {x} : (xs.push x).toArray = xs.toArray.push x := rfl
@[simp, grind =] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
@[simp, grind] theorem toArray_beq_toArray [BEq α] {xs : Vector α n} {ys : Vector α n} :
(xs.toArray == ys.toArray) = (xs == ys) := by
simp [instBEq, isEqv, Array.instBEq, Array.isEqv, xs.2, ys.2]
@[simp, grind =] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp, grind] theorem toArray_range : (Vector.range n).toArray = Array.range n := rfl
@[simp, grind =] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp, grind] theorem toArray_reverse (xs : Vector α n) : xs.reverse.toArray = xs.toArray.reverse := rfl
@[simp, grind =] theorem toArray_set {xs : Vector α n} {i x} (h) :
@[simp, grind] theorem toArray_set {xs : Vector α n} {i x} (h) :
(xs.set i x).toArray = xs.toArray.set i x (by simpa using h):= rfl
@[simp, grind =] theorem toArray_set! {xs : Vector α n} {i x} :
@[simp, grind] theorem toArray_set! {xs : Vector α n} {i x} :
(xs.set! i x).toArray = xs.toArray.set! i x := rfl
@[simp, grind =] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
@[simp, grind] theorem toArray_setIfInBounds {xs : Vector α n} {i x} :
(xs.setIfInBounds i x).toArray = xs.toArray.setIfInBounds i x := rfl
@[simp, grind =] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp, grind] theorem toArray_singleton {x : α} : (Vector.singleton x).toArray = #[x] := rfl
@[simp, grind =] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
@[simp, grind] theorem toArray_swap {xs : Vector α n} {i j} (hi hj) : (xs.swap i j).toArray =
xs.toArray.swap i j (by simp [hj]) (by simp [hi]) := rfl
@[simp, grind =] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
@[simp, grind] theorem toArray_swapIfInBounds {xs : Vector α n} {i j} :
(xs.swapIfInBounds i j).toArray = xs.toArray.swapIfInBounds i j := rfl
theorem toArray_swapAt {xs : Vector α n} {i x} (h) :
@@ -383,98 +383,98 @@ theorem toArray_swapAt! {xs : Vector α n} {i x} :
((xs.swapAt! i x).fst, (xs.swapAt! i x).snd.toArray) =
((xs.toArray.swapAt! i x).fst, (xs.toArray.swapAt! i x).snd) := rfl
@[simp, grind =] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp, grind] theorem toArray_take {xs : Vector α n} {i} : (xs.take i).toArray = xs.toArray.take i := rfl
@[simp, grind =] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
@[simp, grind] theorem toArray_zipIdx {xs : Vector α n} (k : Nat := 0) :
(xs.zipIdx k).toArray = xs.toArray.zipIdx k := rfl
@[simp, grind =] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
@[simp, grind] theorem toArray_zipWith {f : α β γ} {as : Vector α n} {bs : Vector β n} :
(Vector.zipWith f as bs).toArray = Array.zipWith f as.toArray bs.toArray := rfl
@[simp, grind =] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem anyM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.anyM p = xs.anyM p := by
cases xs
simp
@[simp, grind =] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem allM_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.allM p = xs.allM p := by
cases xs
simp
@[simp, grind =] theorem any_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem any_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.any p = xs.any p := by
cases xs
simp
@[simp, grind =] theorem all_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem all_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.all p = xs.all p := by
cases xs
simp
@[simp, grind =] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem countP_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.countP p = xs.countP p := by
cases xs
simp
@[simp, grind =] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind] theorem count_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.count a = xs.count a := by
cases xs
simp
@[simp, grind =] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
@[simp, grind] theorem replace_toArray [BEq α] {xs : Vector α n} {a b} :
xs.toArray.replace a b = (xs.replace a b).toArray := rfl
@[simp, grind =] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem find?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.find? p = xs.find? p := by
cases xs
simp
@[simp, grind =] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind] theorem findSome?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSome? f = xs.findSome? f := by
cases xs
simp
@[simp, grind =] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem findRev?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findRev? p = xs.findRev? p := by
cases xs
simp
@[simp, grind =] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
@[simp, grind] theorem findSomeRev?_toArray {f : α Option β} {xs : Vector α n} :
xs.toArray.findSomeRev? f = xs.findSomeRev? f := by
cases xs
simp
@[simp, grind =] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem findM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findM? p = xs.findM? p := by
cases xs
simp
@[simp, grind =] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind] theorem findSomeM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeM? f = xs.findSomeM? f := by
cases xs
simp
@[simp, grind =] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
@[simp, grind] theorem findRevM?_toArray [Monad m] {p : α m Bool} {xs : Vector α n} :
xs.toArray.findRevM? p = xs.findRevM? p := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
@[simp, grind] theorem findSomeRevM?_toArray [Monad m] {f : α m (Option β)} {xs : Vector α n} :
xs.toArray.findSomeRevM? f = xs.findSomeRevM? f := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
@[simp, grind] theorem finIdxOf?_toArray [BEq α] {a : α} {xs : Vector α n} :
xs.toArray.finIdxOf? a = (xs.finIdxOf? a).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
@[simp, grind] theorem findFinIdx?_toArray {p : α Bool} {xs : Vector α n} :
xs.toArray.findFinIdx? p = (xs.findFinIdx? p).map (Fin.cast xs.size_toArray.symm) := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[simp, grind] theorem toArray_replicate : (replicate n a).toArray = Array.replicate n a := rfl
@[deprecated toArray_replicate (since := "2025-03-18")]
abbrev toArray_mkVector := @toArray_replicate
@@ -503,13 +503,13 @@ protected theorem ext {xs ys : Vector α n} (h : (i : Nat) → (_ : i < n) → x
/-! ### toList -/
@[simp, grind =] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
@[simp, grind] theorem length_toList {xs : Vector α n} : xs.toList.length = n := by
rcases xs with xs, rfl
simp [toList]
@[grind =_] theorem toList_toArray {xs : Vector α n} : xs.toArray.toList = xs.toList := rfl
@[simp, grind =] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
@[simp, grind] theorem toList_mk : (Vector.mk xs h).toList = xs.toList := rfl
@[simp] theorem getElem_toList {xs : Vector α n} {i : Nat} (h : i < xs.toList.length) :
xs.toList[i] = xs[i]'(by simpa using h) := by
@@ -784,12 +784,12 @@ theorem singleton_inj : #v[a] = #v[b] ↔ a = b := by
/-! ### replicate -/
@[simp, grind =] theorem replicate_zero : replicate 0 a = #v[] := rfl
@[simp, grind] theorem replicate_zero : replicate 0 a = #v[] := rfl
@[deprecated replicate_zero (since := "2025-03-18")]
abbrev replicate_mkVector := @replicate_zero
@[grind =]
@[grind]
theorem replicate_succ : replicate (n + 1) a = (replicate n a).push a := by
simp [replicate, Array.replicate_succ]
@@ -895,35 +895,26 @@ theorem getElem?_push_size {xs : Vector α n} {x : α} : (xs.push x)[n]? = some
theorem getElem_singleton {a : α} (h : i < 1) : #v[a][i] = a := by
simp
@[grind =]
@[grind]
theorem getElem?_singleton {a : α} {i : Nat} : #v[a][i]? = if i = 0 then some a else none := by
simp [List.getElem?_singleton]
/-! ### mem -/
@[simp] theorem getElem_mem {xs : Vector α n} {i : Nat} (h : i < n) : xs[i] xs := by
@[simp, grind] 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
@[simp] theorem mem_push {xs : Vector α n} {x y : α} : x xs.push y x xs x = y := by
rcases xs with xs, rfl
simp
theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
@[grind] theorem mem_or_eq_of_mem_push {a b : α} {xs : Vector α n} :
a xs.push b a xs a = b := Vector.mem_push.mp
-- This pattern may be excessively general:
-- it fires anytime we ae thinking about membership of vectors,
-- and constructing a list via `push`, even if the elements are unrelated.
-- Nevertheless in practice it is quite helpful!
grind_pattern mem_or_eq_of_mem_push => xs.push b, a xs
theorem mem_push_self {xs : Vector α n} {x : α} : x xs.push x :=
@[grind] theorem mem_push_self {xs : Vector α n} {x : α} : x xs.push x :=
mem_push.2 (Or.inr rfl)
theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x xs) :
@@ -935,7 +926,7 @@ theorem eq_push_append_of_mem {xs : Vector α n} {x : α} (h : x ∈ xs) :
obtain rfl := h
exact _, _, as.toVector, bs.toVector, by simp, by simp, by simpa using w
theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x xs) : x xs.push y :=
@[grind] theorem mem_push_of_mem {xs : Vector α n} {x : α} (y : α) (h : x xs) : x xs.push y :=
mem_push.2 (Or.inl h)
theorem exists_mem_of_size_pos {xs : Vector α n} (h : 0 < n) : x, x xs := by
@@ -1222,9 +1213,9 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a as) :=
decidable_of_decidable_of_iff contains_iff
@[grind =] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
@[simp, grind =] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
as.contains a = decide (a as) := by
rw [Bool.eq_iff_iff, contains_iff, decide_eq_true_iff]
@@ -1245,7 +1236,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
/-! ### set -/
@[grind =] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
@[grind] theorem getElem_set {xs : Vector α n} {i : Nat} {x : α} (hi : i < n) {j : Nat} (hj : j < n) :
(xs.set i x hi)[j] = if i = j then x else xs[j] := by
cases xs
split <;> simp_all
@@ -1258,7 +1249,7 @@ instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈
@[simp] theorem getElem_set_ne {xs : Vector α n} {x : α} (hi : i < n) (hj : j < n) (h : i j) :
(xs.set i x hi)[j] = xs[j] := by simp [getElem_set, h]
@[grind =] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
@[grind] theorem getElem?_set {xs : Vector α n} {x : α} (hi : i < n) :
(xs.set i x hi)[j]? = if i = j then some x else xs[j]? := by
cases xs
split <;> simp_all
@@ -1303,10 +1294,10 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
/-! ### setIfInBounds -/
@[simp, grind =] theorem setIfInBounds_empty {i : Nat} {a : α} :
@[simp, grind] theorem setIfInBounds_empty {i : Nat} {a : α} :
#v[].setIfInBounds i a = #v[] := rfl
@[grind =] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
@[grind] theorem getElem_setIfInBounds {xs : Vector α n} {x : α} (hj : j < n) :
(xs.setIfInBounds i x)[j] = if i = j then x else xs[j] := by
cases xs
split <;> simp_all
@@ -1319,7 +1310,7 @@ grind_pattern mem_or_eq_of_mem_set => a ∈ xs.set i b
@[simp] theorem getElem_setIfInBounds_ne {xs : Vector α n} {x : α} (hj : j < n) (h : i j) :
(xs.setIfInBounds i x)[j] = xs[j] := by simp [getElem_setIfInBounds, h]
@[grind =] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
@[grind] theorem getElem?_setIfInBounds {xs : Vector α n} {x : α} :
(xs.setIfInBounds i x)[j]? = if i = j then if i < n then some x else none else xs[j]? := by
rcases xs with xs, rfl
simp [Array.getElem?_setIfInBounds]
@@ -1356,7 +1347,7 @@ theorem mem_setIfInBounds {xs : Vector α n} {a : α} (hi : i < n) :
/-! ### BEq -/
@[simp, grind =] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
@[simp, grind] theorem push_beq_push [BEq α] {a b : α} {n : Nat} {xs : Vector α n} {ys : Vector α n} :
(xs.push a == ys.push b) = (xs == ys && a == b) := by
cases xs
cases ys
@@ -1419,16 +1410,16 @@ abbrev mkVector_beq_mkVector := @replicate_beq_replicate
/-! ### back -/
@[grind =] theorem back_singleton {a : α} : #v[a].back = a := by simp
@[grind] theorem back_singleton {a : α} : #v[a].back = a := by simp
@[grind =]
@[grind]
theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by have := NeZero.ne n; omega) := by
rcases xs with xs, rfl
simp [Array.back_eq_getElem]
@[grind =] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
@[grind] theorem back?_empty : (#v[] : Vector α 0).back? = none := by simp
@[grind =] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
@[grind] theorem back?_eq_getElem? {xs : Vector α n} : xs.back? = xs[n - 1]? := by
rcases xs with xs, rfl
simp [Array.back?_eq_getElem?]
@@ -1439,22 +1430,22 @@ theorem back_eq_getElem [NeZero n] {xs : Vector α n} : xs.back = xs[n - 1]'(by
/-! ### map -/
-- The argument `f : α → β` is explicit, to facilitate rewriting from right to left.
@[simp, grind =] theorem getElem_map (f : α β) {xs : Vector α n} (hi : i < n) :
@[simp, grind] theorem getElem_map (f : α β) {xs : Vector α n} (hi : i < n) :
(xs.map f)[i] = f xs[i] := by
cases xs
simp
@[simp, grind =] theorem getElem?_map {f : α β} {xs : Vector α n} {i : Nat}:
@[simp, grind] theorem getElem?_map {f : α β} {xs : Vector α n} {i : Nat}:
(xs.map f)[i]? = xs[i]?.map f := by
cases xs
simp
/-- The empty vector maps to the empty vector. -/
@[grind =]
@[grind]
theorem map_empty {f : α β} : map f #v[] = #v[] := by
simp
@[simp, grind =] theorem map_push {f : α β} {as : Vector α n} {x : α} :
@[simp, grind] theorem map_push {f : α β} {as : Vector α n} {x : α} :
(as.push x).map f = (as.map f).push (f x) := by
cases as
simp
@@ -1629,7 +1620,7 @@ theorem append_push {as : Vector α n} {bs : Vector α m} {a : α} :
theorem singleton_eq_toVector_singleton {a : α} : #v[a] = #[a].toVector := rfl
@[simp, grind =] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
@[simp, grind] theorem mem_append {a : α} {xs : Vector α n} {ys : Vector α m} :
a xs ++ ys a xs a ys := by
cases xs
cases ys
@@ -1665,16 +1656,16 @@ theorem forall_mem_append {p : α → Prop} {xs : Vector α n} {ys : Vector α m
( (x) (_ : x xs ++ ys), p x) ( (x) (_ : x xs), p x) ( (x) (_ : x ys), p x) := by
simp only [mem_append, or_imp, forall_and]
@[simp, grind =]
@[simp, grind]
theorem empty_append {xs : Vector α n} : (#v[] : Vector α 0) ++ xs = xs.cast (by omega) := by
rcases xs with as, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem append_empty {xs : Vector α n} : xs ++ (#v[] : Vector α 0) = xs := by
rw [ toArray_inj, toArray_append, Array.append_empty]
@[grind =]
@[grind]
theorem getElem_append {xs : Vector α n} {ys : Vector α m} (hi : i < n + m) :
(xs ++ ys)[i] = if h : i < n then xs[i] else ys[i - n] := by
rcases xs with xs, rfl
@@ -1701,7 +1692,7 @@ theorem getElem?_append_right {xs : Vector α n} {ys : Vector α m} (h : n ≤ i
rcases ys with ys, rfl
simp [Array.getElem?_append_right, h]
@[grind =]
@[grind]
theorem getElem?_append {xs : Vector α n} {ys : Vector α m} {i : Nat} :
(xs ++ ys)[i]? = if i < n then xs[i]? else ys[i - n]? := by
split <;> rename_i h
@@ -1780,7 +1771,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
right
refine cs.toArray, ha, rfl
@[simp, grind =] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
@[simp, grind] theorem append_assoc {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
(xs ++ ys) ++ zs = (xs ++ (ys ++ zs)).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -1788,14 +1779,14 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
simp [Array.append_assoc]
-- Variant for rewriting the other direction: we can't use `append_assoc` as it has a `cast` on the right-hand side.
@[grind =] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
@[grind] theorem append_assoc_symm {xs : Vector α n} {ys : Vector α m} {zs : Vector α k} :
xs ++ (ys ++ zs) = ((xs ++ ys) ++ zs).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
rcases zs with zs, rfl
simp [Array.append_assoc]
@[grind =] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
@[grind] theorem set_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} (h : i < n + m) :
(xs ++ ys).set i x =
if h' : i < n then
xs.set i x ++ ys
@@ -1815,7 +1806,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
(xs ++ ys).set i x = xs ++ ys.set (i - n) x := by
rw [set_append, dif_neg (by omega)]
@[grind =] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
@[grind] theorem setIfInBounds_append {xs : Vector α n} {ys : Vector α m} {i : Nat} {x : α} :
(xs ++ ys).setIfInBounds i x =
if i < n then
xs.setIfInBounds i x ++ ys
@@ -1835,7 +1826,7 @@ theorem append_eq_append_iff {ws : Vector α n} {xs : Vector α m} {ys : Vector
(xs ++ ys).setIfInBounds i x = xs ++ ys.setIfInBounds (i - n) x := by
rw [setIfInBounds_append, if_neg (by omega)]
@[simp, grind =] theorem map_append {f : α β} {xs : Vector α n} {ys : Vector α m} :
@[simp, grind] theorem map_append {f : α β} {xs : Vector α n} {ys : Vector α m} :
map f (xs ++ ys) = map f xs ++ map f ys := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -1904,7 +1895,7 @@ theorem getElem?_flatten {xss : Vector (Vector β m) n} {i : Nat} :
none := by
simp [getElem?_def]
@[simp, grind =] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
@[simp, grind] theorem flatten_singleton {xs : Vector α n} : #v[xs].flatten = xs.cast (by simp) := by
simp [flatten]
set_option linter.listVariables false in
@@ -1931,17 +1922,17 @@ theorem forall_mem_flatten {p : α → Prop} {xss : Vector (Vector α n) m} :
induction xss using vector₂_induction with
| of xss h₁ h₂ => simp
@[simp, grind =] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
@[simp, grind] theorem flatten_append {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
flatten (xss₁ ++ xss₂) = (flatten xss₁ ++ flatten xss₂).cast (by simp [Nat.add_mul]) := by
induction xss₁ using vector₂_induction
induction xss₂ using vector₂_induction
simp
@[grind =] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
@[grind] theorem append_flatten {xss₁ : Vector (Vector α n) m₁} {xss₂ : Vector (Vector α n) m₂} :
flatten xss₁ ++ flatten xss₂ = (flatten (xss₁ ++ xss₂)).cast (by simp [Nat.add_mul]) := by
simp
@[grind =] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
@[grind] theorem flatten_push {xss : Vector (Vector α n) m} {xs : Vector α n} :
flatten (xss.push xs) = (flatten xss ++ xs).cast (by simp [Nat.add_mul]) := by
induction xss using vector₂_induction
rcases xs with xs
@@ -1991,10 +1982,10 @@ theorem flatMap_def {xs : Vector α n} {f : α → Vector β m} : xs.flatMap f =
rcases xs with xs, rfl
simp [Array.flatMap_def, Function.comp_def]
@[simp, grind =] theorem flatMap_empty {f : α Vector β m} :
@[simp, grind] theorem flatMap_empty {f : α Vector β m} :
(#v[] : Vector α 0).flatMap f = #v[].cast (by simp) := rfl
@[simp, grind =] theorem flatMap_push {xs : Vector α n} {x : α} {f : α Vector β m} :
@[simp, grind] theorem flatMap_push {xs : Vector α n} {x : α} {f : α Vector β m} :
(xs.push x).flatMap f = (xs.flatMap f ++ f x).cast (by simp [Nat.add_mul]) := by
rcases xs with xs, rfl
simp
@@ -2020,7 +2011,7 @@ theorem getElem?_flatMap {xs : Vector α n} {f : α → Vector β m} {i : Nat} :
@[simp] theorem flatMap_id' {xss : Vector (Vector α m) n} : xss.flatMap (fun xs => xs) = xss.flatten := by simp [flatMap_def]
@[simp, grind =] theorem mem_flatMap {f : α Vector β m} {b} {xs : Vector α n} : b xs.flatMap f a, a xs b f a := by
@[simp, grind] theorem mem_flatMap {f : α Vector β m} {b} {xs : Vector α n} : b xs.flatMap f a, a xs b f a := by
simp [flatMap_def, mem_flatten]
exact fun _, a, h₁, rfl, h₂ => a, h₁, h₂, fun a, h₁, h₂ => _, a, h₁, rfl, h₂
@@ -2083,7 +2074,7 @@ theorem replicate_succ' : replicate (n + 1) a = (#v[a] ++ replicate n a).cast (b
@[deprecated replicate_succ' (since := "2025-03-18")]
abbrev mkVector_succ' := @replicate_succ'
@[simp, grind =] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
@[simp, grind] theorem mem_replicate {a b : α} {n} : b replicate n a n 0 b = a := by
unfold replicate
simp only [mem_mk]
simp
@@ -2103,14 +2094,14 @@ theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
@[deprecated forall_mem_replicate (since := "2025-03-18")]
abbrev forall_mem_mkVector := @forall_mem_replicate
@[simp, grind =] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
@[simp, grind] theorem getElem_replicate {a : α} (h : i < n) : (replicate n a)[i] = a := by
rw [replicate_eq_mk_replicate, getElem_mk]
simp
@[deprecated getElem_replicate (since := "2025-03-18")]
abbrev getElem_mkVector := @getElem_replicate
@[grind =] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
@[grind] theorem getElem?_replicate {a : α} {n i : Nat} : (replicate n a)[i]? = if i < n then some a else none := by
simp [getElem?_def]
@[deprecated getElem?_replicate (since := "2025-03-18")]
@@ -2236,16 +2227,16 @@ abbrev sum_mkVector := @sum_replicate_nat
theorem reverse_empty : reverse (#v[] : Vector α 0) = #v[] := rfl
@[simp, grind =] theorem reverse_push {as : Vector α n} {a : α} :
@[simp, grind] theorem reverse_push {as : Vector α n} {a : α} :
(as.push a).reverse = (#v[a] ++ as.reverse).cast (by omega) := by
rcases as with as, rfl
simp [Array.reverse_push]
@[simp, grind =] theorem mem_reverse {x : α} {as : Vector α n} : x as.reverse x as := by
@[simp, grind] theorem mem_reverse {x : α} {as : Vector α n} : x as.reverse x as := by
cases as
simp
@[simp, grind =] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
@[simp, grind] theorem getElem_reverse {xs : Vector α n} {i : Nat} (hi : i < n) :
(xs.reverse)[i] = xs[n - 1 - i] := by
rcases xs with xs, rfl
simp
@@ -2261,14 +2252,14 @@ theorem getElem?_reverse' {xs : Vector α n} {i j : Nat} (h : i + j + 1 = n) : x
rcases xs with xs, rfl
simpa using Array.getElem?_reverse' h
@[simp, grind =]
@[simp, grind]
theorem getElem?_reverse {xs : Vector α n} {i} (h : i < n) :
xs.reverse[i]? = xs[n - 1 - i]? := by
cases xs
simp_all
-- The argument `xs : Vector α n` is explicit so we can rewrite from right to left.
@[simp, grind =] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
@[simp, grind] theorem reverse_reverse (xs : Vector α n) : xs.reverse.reverse = xs := by
rcases xs with xs, rfl
simp [Array.reverse_reverse]
@@ -2288,13 +2279,13 @@ theorem reverse_eq_iff {xs ys : Vector α n} : xs.reverse = ys ↔ xs = ys.rever
rcases xs with xs, rfl
simp [Array.map_reverse]
@[simp, grind =] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
@[simp, grind] theorem reverse_append {xs : Vector α n} {ys : Vector α m} :
(xs ++ ys).reverse = (ys.reverse ++ xs.reverse).cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp [Array.reverse_append]
@[grind =] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
@[grind] theorem append_reverse {xs : Vector α n} {ys : Vector α m} :
ys.reverse ++ xs.reverse = (xs ++ ys).reverse.cast (by omega) := by
rcases xs with xs, rfl
rcases ys with ys, rfl
@@ -2329,7 +2320,7 @@ theorem flatMap_reverse {xs : Vector α n} {f : α → Vector β m} :
rcases xs with xs, rfl
simp [Array.flatMap_reverse, Function.comp_def]
@[simp, grind =] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
@[simp, grind] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a := by
rw [ toArray_inj]
simp
@@ -2354,7 +2345,7 @@ set_option linter.indexVariables false in
rcases as with as, rfl
simp
@[grind =] theorem extract_empty {start stop : Nat} :
@[grind] theorem extract_empty {start stop : Nat} :
(#v[] : Vector α 0).extract start stop = #v[].cast (by simp) := by
simp
@@ -2370,11 +2361,11 @@ theorem foldlM_empty [Monad m] {f : β → α → m β} {init : β} :
foldlM f init #v[] = return init := by
simp
@[grind =] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} :
@[grind] theorem foldrM_empty [Monad m] {f : α β m β} {init : β} :
foldrM f init #v[] = return init := by
simp
@[simp, grind =] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β α m β} {b} :
@[simp, grind] theorem foldlM_push [Monad m] [LawfulMonad m] {xs : Vector α n} {a : α} {f : β α m β} {b} :
(xs.push a).foldlM f b = xs.foldlM f b >>= fun b => f b a := by
rcases xs with xs, rfl
simp
@@ -2419,16 +2410,16 @@ theorem id_run_foldrM {f : α → β → Id β} {b} {xs : Vector α n} :
rcases xs with xs, rfl
simp
@[simp, grind =] theorem foldrM_push [Monad m] {f : α β m β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind] theorem foldrM_push [Monad m] {f : α β m β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldrM f init = f a init >>= xs.foldrM f := by
rcases xs with xs, rfl
simp
/-! ### foldl / foldr -/
@[grind =] theorem foldl_empty {f : β α β} {init : β} : (#v[].foldl f init) = init := rfl
@[grind] theorem foldl_empty {f : β α β} {init : β} : (#v[].foldl f init) = init := rfl
@[grind =] theorem foldr_empty {f : α β β} {init : β} : (#v[].foldr f init) = init := rfl
@[grind] theorem foldr_empty {f : α β β} {init : β} : (#v[].foldr f init) = init := rfl
@[congr]
theorem foldl_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : β α β} (h₁ : f = g)
@@ -2442,12 +2433,12 @@ theorem foldr_congr {xs ys : Vector α n} (h₀ : xs = ys) {f g : α → β →
xs.foldr f a = ys.foldr g b := by
congr
@[simp, grind =] theorem foldl_push {f : β α β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind] theorem foldl_push {f : β α β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldl f init = f (xs.foldl f init) a := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem foldr_push {f : α β β} {init : β} {xs : Vector α n} {a : α} :
@[simp, grind] theorem foldr_push {f : α β β} {init : β} {xs : Vector α n} {a : α} :
(xs.push a).foldr f init = xs.foldr f (f a init) := by
rcases xs with xs, rfl
simp
@@ -2499,21 +2490,21 @@ theorem foldr_map_hom {g : α → β} {f : ααα} {f' : β → β →
@[simp, grind _=_] theorem foldr_append {f : α β β} {b} {xs : Vector α n} {ys : Vector α k} :
(xs ++ ys).foldr f b = xs.foldr f (ys.foldr f b) := foldrM_append
@[simp, grind =] theorem foldl_flatten {f : β α β} {b} {xss : Vector (Vector α m) n} :
@[simp, grind] theorem foldl_flatten {f : β α β} {b} {xss : Vector (Vector α m) n} :
(flatten xss).foldl f b = xss.foldl (fun b xs => xs.foldl f b) b := by
cases xss using vector₂_induction
simp [Array.foldl_flatten', Array.foldl_map']
@[simp, grind =] theorem foldr_flatten {f : α β β} {b} {xss : Vector (Vector α m) n} :
@[simp, grind] theorem foldr_flatten {f : α β β} {b} {xss : Vector (Vector α m) n} :
(flatten xss).foldr f b = xss.foldr (fun xs b => xs.foldr f b) b := by
cases xss using vector₂_induction
simp [Array.foldr_flatten', Array.foldr_map']
@[simp, grind =] theorem foldl_reverse {xs : Vector α n} {f : β α β} {b} :
@[simp, grind] theorem foldl_reverse {xs : Vector α n} {f : β α β} {b} :
xs.reverse.foldl f b = xs.foldr (fun x y => f y x) b :=
foldlM_reverse
@[simp, grind =] theorem foldr_reverse {xs : Vector α n} {f : α β β} {b} :
@[simp, grind] theorem foldr_reverse {xs : Vector α n} {f : α β β} {b} :
xs.reverse.foldr f b = xs.foldl (fun x y => f y x) b :=
(foldl_reverse ..).symm.trans <| by simp
@@ -2607,7 +2598,7 @@ theorem back?_eq_some_iff {xs : Vector α n} {a : α} :
simp only [mk_append_mk, back_mk]
rw [Array.back_append_of_size_pos]
@[grind =] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
@[grind] theorem back_append {xs : Vector α n} {ys : Vector α m} [NeZero (n + m)] :
(xs ++ ys).back =
if h' : m = 0 then
have : NeZero n := by subst h'; simp_all
@@ -2638,7 +2629,7 @@ theorem back_append_left {xs : Vector α n} {ys : Vector α 0} [NeZero n] :
simp only [mk_append_mk, back_mk]
rw [Array.back_append_left _ h]
@[simp, grind =] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
@[simp, grind] theorem back?_append {xs : Vector α n} {ys : Vector α m} : (xs ++ ys).back? = ys.back?.or xs.back? := by
rcases xs with xs, rfl
rcases ys with ys, rfl
simp
@@ -2690,28 +2681,24 @@ theorem contains_iff_exists_mem_beq [BEq α] {xs : Vector α n} {a : α} :
rcases xs with xs, rfl
simp [Array.contains_iff_exists_mem_beq]
-- We add this as a `grind` lemma because it is useful without `LawfulBEq α`.
-- With `LawfulBEq α`, it would be better to use `contains_iff_mem` directly.
grind_pattern contains_iff_exists_mem_beq => xs.contains a
@[grind _=_]
theorem contains_iff_mem [BEq α] [LawfulBEq α] {xs : Vector α n} {a : α} :
xs.contains a a xs := by
simp
@[simp, grind =]
@[simp, grind]
theorem contains_toList [BEq α] {xs : Vector α n} {x : α} :
xs.toList.contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem contains_toArray [BEq α] {xs : Vector α n} {x : α} :
xs.toArray.contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem contains_map [BEq β] {xs : Vector α n} {x : β} {f : α β} :
(xs.map f).contains x = xs.any (fun a => x == f a) := by
rcases xs with xs
@@ -2736,19 +2723,19 @@ theorem contains_append [BEq α] {xs : Vector α n} {ys : Vector α m} {x : α}
rcases ys with ys, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem contains_flatten [BEq α] {xs : Vector (Vector α n) m} {x : α} :
(xs.flatten).contains x = xs.any fun xs => xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem contains_reverse [BEq α] {xs : Vector α n} {x : α} :
(xs.reverse).contains x = xs.contains x := by
rcases xs with xs, rfl
simp
@[simp, grind =]
@[simp, grind]
theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α Vector β m} {x : β} :
(xs.flatMap f).contains x = xs.any fun a => (f a).contains x := by
rcases xs with xs, rfl
@@ -2760,7 +2747,7 @@ theorem contains_flatMap [BEq β] {xs : Vector α n} {f : α → Vector β m} {x
@[simp] theorem pop_push {xs : Vector α n} {x : α} : (xs.push x).pop = xs := by simp [pop]
@[simp, grind =] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
@[simp, grind] theorem getElem_pop {xs : Vector α n} {i : Nat} (h : i < n - 1) :
xs.pop[i] = xs[i] := by
rcases xs with xs, rfl
simp
@@ -2773,7 +2760,7 @@ defeq issues in the implicit size argument.
@getElem (Vector α n) Nat α (fun _ i => i < n) instGetElemNatLt xs.pop i h = xs[i] :=
getElem_pop h
@[grind =] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
@[grind] theorem getElem?_pop {xs : Vector α n} {i : Nat} :
xs.pop[i]? = if i < n - 1 then xs[i]? else none := by
rcases xs with xs, rfl
simp [Array.getElem?_pop]
@@ -2921,15 +2908,15 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
unfold all
apply allM_congr w h
@[simp, grind =] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
@[simp, grind] theorem any_flatten {xss : Vector (Vector α n) m} : xss.flatten.any f = xss.any (any · f) := by
cases xss using vector₂_induction
simp
@[simp, grind =] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
@[simp, grind] theorem all_flatten {xss : Vector (Vector α n) m} : xss.flatten.all f = xss.all (all · f) := by
cases xss using vector₂_induction
simp
@[simp, grind =] theorem any_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
@[simp, grind] theorem any_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
(xs.flatMap f).any p = xs.any fun a => (f a).any p := by
rcases xs with xs
simp only [flatMap_mk, any_mk, Array.size_flatMap, size_toArray, Array.any_flatMap']
@@ -2938,7 +2925,7 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
congr
simp [Vector.size_toArray]
@[simp, grind =] theorem all_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
@[simp, grind] theorem all_flatMap {xs : Vector α n} {f : α Vector β m} {p : β Bool} :
(xs.flatMap f).all p = xs.all fun a => (f a).all p := by
rcases xs with xs
simp only [flatMap_mk, all_mk, Array.size_flatMap, size_toArray, Array.all_flatMap']
@@ -2947,11 +2934,11 @@ theorem all_filterMap {xs : Vector α n} {f : α → Option β} {p : β → Bool
congr
simp [Vector.size_toArray]
@[simp, grind =] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
@[simp, grind] theorem any_reverse {xs : Vector α n} : xs.reverse.any f = xs.any f := by
rcases xs with xs, rfl
simp
@[simp, grind =] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
@[simp, grind] theorem all_reverse {xs : Vector α n} : xs.reverse.all f = xs.all f := by
rcases xs with xs, rfl
simp
@@ -2987,9 +2974,9 @@ variable [BEq α]
rcases xs with xs, rfl
simp
@[simp, grind =] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
@[grind =] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
@[grind] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
simp
-- This hypothesis could probably be dropped from some of the lemmas below,
@@ -3000,7 +2987,7 @@ variable [LawfulBEq α]
rcases xs with xs, rfl
simp_all
@[grind =] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
@[grind] theorem getElem?_replace {xs : Vector α n} {i : Nat} :
(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, rfl
simp [Array.getElem?_replace, -beq_iff_eq]
@@ -3009,7 +2996,7 @@ theorem getElem?_replace_of_ne {xs : Vector α n} {i : Nat} (h : xs[i]? ≠ some
(xs.replace a b)[i]? = xs[i]? := by
simp_all [getElem?_replace]
@[grind =] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
@[grind] theorem getElem_replace {xs : Vector α n} {i : Nat} (h : i < n) :
(xs.replace a b)[i] = if xs[i] == a then if a xs.take i then a else b else xs[i] := by
apply Option.some.inj
rw [ getElem?_eq_getElem, getElem?_replace]
@@ -3020,7 +3007,7 @@ theorem getElem_replace_of_ne {xs : Vector α n} {i : Nat} {h : i < n} (h' : xs[
rw [getElem_replace h]
simp [h']
@[grind =] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
@[grind] theorem replace_append {xs : Vector α n} {ys : Vector α m} :
(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, rfl
rcases ys with ys, rfl
@@ -3035,7 +3022,7 @@ theorem replace_append_right {xs : Vector α n} {ys : Vector α m} (h : ¬ a ∈
(xs ++ ys).replace a b = xs ++ ys.replace a b := by
simp [replace_append, h]
@[grind =] theorem replace_push {xs : Vector α n} {a b c : α} :
@[grind] theorem replace_push {xs : Vector α n} {a b c : α} :
(xs.push a).replace b c = if b xs then (xs.replace b c).push a else xs.push (if b == a then c else a) := by
rcases xs with xs, rfl
simp only [push_mk, replace_mk, Array.replace_push, mem_mk]
@@ -3104,7 +3091,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
/-! ### swap -/
@[grind =] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
@[grind] theorem getElem_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} (hk : k < n) :
(xs.swap i j hi hj)[k] = if k = i then xs[j] else if k = j then xs[i] else xs[k] := by
cases xs
simp_all [Array.getElem_swap]
@@ -3121,7 +3108,7 @@ theorem take_size {as : Vector α n} : as.take n = as.cast (by simp) := by
(hi' : k i) (hj' : k j) : (xs.swap i j hi hj)[k] = xs[k] := by
simp_all [getElem_swap]
@[grind =]
@[grind]
theorem getElem?_swap {xs : Vector α n} {i j : Nat} (hi hj) {k : Nat} : (xs.swap i j hi hj)[k]? =
if j = k then some xs[i] else if i = k then some xs[j] else xs[k]? := by
rcases xs with xs, rfl

View File

@@ -166,25 +166,25 @@ export LawfulGetElem (getElem?_def getElem!_def)
instance (priority := low) [GetElem coll idx elem valid] [ xs i, Decidable (valid xs i)] :
LawfulGetElem coll idx elem valid where
@[simp, grind =] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind] theorem getElem?_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
(c : cont) (i : idx) (h : dom c i) : c[i]? = some (c[i]'h) := by
have : Decidable (dom c i) := .isTrue h
rw [getElem?_def]
exact dif_pos h
@[simp, grind =] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind] theorem getElem?_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
(c : cont) (i : idx) (h : ¬dom c i) : c[i]? = none := by
have : Decidable (dom c i) := .isFalse h
rw [getElem?_def]
exact dif_neg h
@[simp, grind =] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind] theorem getElem!_pos [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : dom c i) :
c[i]! = c[i]'h := by
have : Decidable (dom c i) := .isTrue h
simp [getElem!_def, h]
@[simp, grind =] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
@[simp, grind] theorem getElem!_neg [GetElem? cont idx elem dom] [LawfulGetElem cont idx elem dom]
[Inhabited elem] (c : cont) (i : idx) (h : ¬dom c i) : c[i]! = default := by
have : Decidable (dom c i) := .isFalse h
simp [getElem!_def, h]
@@ -291,20 +291,18 @@ namespace List
instance : GetElem (List α) Nat α fun as i => i < as.length where
getElem as i h := as.get i, h
@[simp, grind =]
@[simp, grind]
theorem getElem_cons_zero (a : α) (as : List α) (h : 0 < (a :: as).length) :
getElem (a :: as) 0 h = a := rfl
@[simp, grind =]
@[simp, grind]
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] theorem getElem_mem : {l : List α} {n} (h : n < l.length), l[n]'h l
@[simp, grind] 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

View File

@@ -10,8 +10,6 @@ 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
@@ -40,7 +38,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, ReflBEq, LawfulBEq
deriving Inhabited, Repr, BEq
-- Kernel version for Seq.beq
noncomputable def Seq.beq' (s₁ : Seq) : Seq Bool :=
@@ -57,6 +55,12 @@ 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

View File

@@ -98,34 +98,28 @@ 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 subexpression which covers an argument which was not
Each time it encounters a minimal indexable 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 subexpression which covers an argument which was not
Each time it encounters a minimal indexable 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 subexpression which covers an argument which was not
Each time it encounters a minimal indexable 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("" <|> "=>")
/--
@@ -201,8 +195,6 @@ syntax grindMod :=
<|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager
<|> grindCases <|> grindIntro <|> grindExt <|> grindGen <|> grindSym
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

View File

@@ -13,7 +13,6 @@ 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
@@ -56,7 +55,7 @@ def Expr.denote {α} [IntModule α] (ctx : Context α) : Expr → α
inductive Poly where
| nil
| add (k : Int) (v : Var) (p : Poly)
deriving BEq, ReflBEq, LawfulBEq, Repr
deriving BEq, Repr
def Poly.denote {α} [IntModule α] (ctx : Context α) (p : Poly) : α :=
match p with
@@ -234,6 +233,18 @@ 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 :=

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.NotationExtra
public meta import Init.Data.String.Basic
meta import Init.Data.String.Basic
public section

View File

@@ -4,10 +4,13 @@ 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.CommSolver
public import Init.Grind.Ring.CommSemiringAdapter
public import Init.Grind.Ring.OfSemiring
public import Init.Grind.Ring.ToInt
public section

View File

@@ -179,20 +179,6 @@ 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]
@@ -345,18 +331,6 @@ 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]

View File

@@ -277,9 +277,6 @@ 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

View File

@@ -169,8 +169,7 @@ theorem zpow_add {a : α} (h : a ≠ 0) (m n : Int) : a ^ (m + n) = a ^ m * a ^
| zero => simp [Int.add_neg_one, zpow_sub_one h, zpow_neg_one]
| succ n ih => rw [Int.natCast_add_one, Int.neg_add, Int.add_neg_one, Int.add_sub_assoc, zpow_sub_one h, zpow_sub_one h, ih, Semiring.mul_assoc]
-- This is expensive as an instance. Let's see what breaks without it.
def noNatZeroDivisors.ofIsCharPZero [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
intro a b h w
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
simp only [Nat.mod_zero, h, iff_false] at this

View File

@@ -4,65 +4,79 @@ 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.CommSolver
public import Init.Grind.Ring.Poly
@[expose] public section
namespace Lean.Grind
namespace CommRing
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
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.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
abbrev Context (α : Type u) := RArray α
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 Var.denote {α} (ctx : Context α) (v : Var) : α :=
ctx.get v
def Expr.toPolyS : Expr CommRing.Poly
| .num n => .num n.natAbs
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
| .var x => CommRing.Poly.ofVar x
| .add a b => a.toPolyS.combine b.toPolyS
| .mul a b => a.toPolyS.mul b.toPolyS
| .add a b => a.toPoly.combine b.toPoly
| .mul a b => a.toPoly.mul b.toPoly
| .pow a k =>
match a with
| .num n => .num (n.natAbs ^ k)
| .num n => .num (n^k)
| .var x => CommRing.Poly.ofMon (.mult {x, k} .unit)
| _ => a.toPolyS.pow k
| .natCast n => .num n
| .sub .. | .neg .. | .intCast .. => .num 0
| _ => a.toPoly.pow k
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
end Ring.OfSemiring
namespace CommRing
attribute [local instance] Semiring.natCast Ring.intCast
@@ -95,15 +109,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 {α} [Semiring α] (ctx : Context α) (m : Mon)
theorem Poly.denoteS_ofMon {α} [CommSemiring α] (ctx : Context α) (m : Mon)
: denoteS ctx (ofMon m) = m.denote ctx := by
simp [ofMon, denoteS]
theorem Poly.denoteS_ofVar {α} [Semiring α] (ctx : Context α) (x : Var)
theorem Poly.denoteS_ofVar {α} [CommSemiring α] (ctx : Context α) (x : Var)
: denoteS ctx (ofVar x) = x.denote ctx := by
simp [ofVar, denoteS_ofMon, Mon.denote_ofVar]
theorem Poly.denoteS_addConst {α} [Semiring α] (ctx : Context α) (p : Poly) (k : Int)
theorem Poly.denoteS_addConst {α} [CommSemiring α] (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
@@ -116,7 +130,7 @@ theorem Poly.denoteS_addConst {α} [Semiring α] (ctx : Context α) (p : Poly) (
intro _ h; cases h
next h₁ h₂ => simp [*, add_assoc]
theorem Poly.denoteS_insert {α} [Semiring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
theorem Poly.denoteS_insert {α} [CommSemiring α] (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 [*]
@@ -143,13 +157,13 @@ theorem Poly.denoteS_insert {α} [Semiring α] (ctx : Context α) (k : Int) (m :
intro hk hn; cases hn; rename_i hn₁ hn₂
rw [ih hk hn₂, add_left_comm]
theorem Poly.denoteS_concat {α} [Semiring α] (ctx : Context α) (p₁ p₂ : Poly)
theorem Poly.denoteS_concat {α} [CommSemiring α] (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 {α} [Semiring α] (ctx : Context α) (k : Int) (p : Poly)
theorem Poly.denoteS_mulConst {α} [CommSemiring α] (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]
@@ -163,7 +177,30 @@ theorem Poly.denoteS_mulConst {α} [Semiring α] (ctx : Context α) (k : Int) (p
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_combine {α} [Semiring α] (ctx : Context α) (p₁ p : Poly)
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)
: 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
@@ -196,93 +233,6 @@ theorem Poly.denoteS_combine {α} [Semiring α] (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
@@ -309,29 +259,12 @@ theorem Poly.mulMon_NonnegCoeffs {p : Poly} {k : Int} (m : Mon) : k ≥ 0 → p.
apply Int.mul_nonneg <;> 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.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.concat_NonnegCoeffs {p₁ p₂ : Poly} : p₁.NonnegCoeffs p₂.NonnegCoeffs (p₁.concat p₂).NonnegCoeffs := by
fun_induction Poly.concat
@@ -379,40 +312,14 @@ 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.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.num_zero_NonnegCoeffs : (num 0).NonnegCoeffs := by
apply NonnegCoeffs.num; simp
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
@@ -435,27 +342,6 @@ 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₁
@@ -467,19 +353,13 @@ theorem Poly.denoteS_pow {α} [CommSemiring α] (ctx : Context α) (p : Poly) (k
assumption
apply Poly.pow_NonnegCoeffs; assumption
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
end CommRing
theorem Expr.toPolyS_NonnegCoeffs {e : Expr} : e.toPolyS.NonnegCoeffs := by
fun_induction toPolyS
namespace Ring.OfSemiring
open CommRing
theorem Expr.toPoly_NonnegCoeffs {e : Expr} : e.toPoly.NonnegCoeffs := by
fun_induction toPoly
next => constructor; apply Int.natCast_nonneg
next => simp [Poly.ofVar, Poly.ofMon]; constructor; decide; constructor; decide
next => apply Poly.combine_NonnegCoeffs <;> assumption
@@ -487,89 +367,29 @@ theorem Expr.toPolyS_NonnegCoeffs {e : Expr} : e.toPolyS.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
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]
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
def eq_normS_cert (lhs rhs : Expr) : Bool :=
lhs.toPolyS == rhs.toPolyS
lhs.toPoly == rhs.toPoly
theorem eq_normS {α} [CommSemiring α] (ctx : Context α) (lhs rhs : Expr)
: eq_normS_cert lhs rhs lhs.denoteS ctx = rhs.denoteS ctx := by
: eq_normS_cert lhs rhs lhs.denote ctx = rhs.denote ctx := by
simp [eq_normS_cert]; intro h
replace h := congrArg (Poly.denoteS ctx) h
simp [Expr.denoteS_toPolyS, *] at h
simp [Expr.denoteS_toPoly, *] at h
assumption
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
end Lean.Grind.Ring.OfSemiring

View File

@@ -4,32 +4,27 @@ 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
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.)
The solver uses proof-by-reflection.
-/
open Std
namespace Lean.Grind
-- 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
@@ -46,15 +41,18 @@ 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)
@@ -71,7 +69,11 @@ noncomputable def Expr.denote {α} [Ring α] (ctx : Context α) (e : Expr) : α
structure Power where
x : Var
k : Nat
deriving BEq, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
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]
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₁
@@ -79,9 +81,11 @@ 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
@@ -92,7 +96,18 @@ def Power.denote {α} [Semiring α] (ctx : Context α) : Power → α
inductive Mon where
| unit
| mult (p : Power) (m : Mon)
deriving BEq, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
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
protected noncomputable def Mon.beq' (m₁ : Mon) : Mon Bool :=
Mon.rec
@@ -106,10 +121,12 @@ 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
@@ -120,14 +137,17 @@ 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 =>
@@ -140,23 +160,15 @@ def Mon.mulPow (pw : Power) (m : Mon) : Mon :=
else
.mult { x := pw.x, k := pw.k + pw'.k } m
-- **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)
@[expose]
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₂
@@ -176,21 +188,18 @@ where
else
.mult { x := pw₁.x, k := pw₁.k + pw₂.k } (go fuel m₁ m₂)
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₂)
@[expose]
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
@@ -203,9 +212,11 @@ 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
@@ -219,6 +230,7 @@ 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 =>
@@ -238,9 +250,11 @@ 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₂)
@@ -314,7 +328,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, ReflBEq, LawfulBEq, Repr, Inhabited, Hashable
deriving BEq, Repr, Inhabited, Hashable
protected noncomputable def Poly.beq' (p₁ : Poly) : Poly Bool :=
Poly.rec
@@ -332,11 +346,27 @@ 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
@@ -354,17 +384,21 @@ 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
@@ -390,6 +424,7 @@ 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
@@ -411,11 +446,13 @@ 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
@@ -454,6 +491,7 @@ 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
@@ -507,19 +545,7 @@ noncomputable def Poly.mulMon_k (k : Int) (m : Mon) (p : Poly) : Poly :=
simp [h]
next ih => simp [ ih]
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'))
@[expose]
def Poly.combine (p₁ p₂ : Poly) : Poly :=
go hugeFuel p₁ p₂
where
@@ -583,6 +609,7 @@ 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
@@ -591,26 +618,14 @@ where
| .num k => acc.combine (p₂.mulConst k)
| .add k m p₁ => go p₁ (acc.combine (p₂.mulMon k m))
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))
@[expose]
def Poly.pow (p : Poly) (k : Nat) : Poly :=
match k with
| 0 => .num 1
| 1 => p
| k+1 => p.mul (pow p k)
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
@[expose]
def Expr.toPoly : Expr Poly
| .num k => .num k
| .intCast k => .num k
@@ -630,7 +645,7 @@ def Expr.toPoly : Expr → Poly
| .var x => Poly.ofMon (.mult {x, k} .unit)
| _ => a.toPoly.pow k
noncomputable def Expr.toPoly_k (e : Expr) : Poly :=
@[expose] 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)
@@ -676,25 +691,6 @@ noncomputable def Expr.toPoly_k (e : 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 =>
@@ -711,11 +707,13 @@ 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
@@ -736,6 +734,7 @@ 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
@@ -754,6 +753,7 @@ 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,20 +777,7 @@ where
else
.add k (m.mul m') (go p)
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'))
@[expose]
def Poly.combineC (p₁ p₂ : Poly) (c : Nat) : Poly :=
go hugeFuel p₁ p₂
where
@@ -812,6 +799,7 @@ 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
@@ -820,26 +808,14 @@ where
| .num k => acc.combineC (p₂.mulConstC k c) c
| .add k m p₁ => go p₁ (acc.combineC (p₂.mulMonC k m c) c)
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)
@[expose]
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
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
@[expose]
def Expr.toPolyC (e : Expr) (c : Nat) : Poly :=
go e
where
@@ -860,26 +836,6 @@ 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`.
-/
@@ -889,7 +845,7 @@ open Semiring hiding add_zero add_comm add_assoc
open Ring hiding sub_eq_add_neg
open CommSemiring
theorem denoteInt_eq {α} [Ring α] (k : Int) : denoteInt (α := α) k = k := by
theorem denoteInt_eq {α} [CommRing α] (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)]
@@ -932,13 +888,6 @@ 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
@@ -950,10 +899,6 @@ 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₁)
@@ -1009,15 +954,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 {α} [Ring α] (ctx : Context α) (m : Mon)
theorem Poly.denote_ofMon {α} [CommRing α] (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 {α} [Ring α] (ctx : Context α) (x : Var)
theorem Poly.denote_ofVar {α} [CommRing α] (ctx : Context α) (x : Var)
: denote ctx (ofVar x) = x.denote ctx := by
simp [ofVar, denote_ofMon, Mon.denote_ofVar]
theorem Poly.denote_addConst {α} [Ring α] (ctx : Context α) (p : Poly) (k : Int) : (addConst p k).denote ctx = p.denote ctx + k := by
theorem Poly.denote_addConst {α} [CommRing α] (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 =>
@@ -1025,7 +970,7 @@ theorem Poly.denote_addConst {α} [Ring α] (ctx : Context α) (p : Poly) (k : I
next => rw [intCast_add]
next => simp [add_comm, add_left_comm]
theorem Poly.denote_insert {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
theorem Poly.denote_insert {α} [CommRing α] (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]
@@ -1042,13 +987,13 @@ theorem Poly.denote_insert {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon)
next =>
rw [add_left_comm]
theorem Poly.denote_concat {α} [Ring α] (ctx : Context α) (p₁ p₂ : Poly)
theorem Poly.denote_concat {α} [CommRing α] (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 {α} [Ring α] (ctx : Context α) (k : Int) (p : Poly)
theorem Poly.denote_mulConst {α} [CommRing α] (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]
@@ -1072,28 +1017,7 @@ 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_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)
theorem Poly.denote_combine {α} [CommRing α] (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
@@ -1114,15 +1038,6 @@ 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
@@ -1130,13 +1045,6 @@ 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
@@ -1148,37 +1056,21 @@ 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} [Ring α] [IsCharP α c] (ctx : Context α) (p : Poly) (k : Int) : (addConstC p k c).denote ctx = p.denote ctx + k := by
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
fun_induction addConstC <;> simp [denote, *]
next => rw [IsCharP.intCast_emod, intCast_add]
next => simp [add_comm, add_left_comm]
theorem Poly.denote_insertC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
theorem Poly.denote_insertC {α c} [CommRing α] [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 =>
@@ -1195,7 +1087,7 @@ theorem Poly.denote_insertC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (
next => rw [IsCharP.intCast_emod]
next => rw [add_left_comm]
theorem Poly.denote_mulConstC {α c} [Ring α] [IsCharP α c] (ctx : Context α) (k : Int) (p : Poly)
theorem Poly.denote_mulConstC {α c} [CommRing α] [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 =>
@@ -1244,29 +1136,7 @@ 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_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)
theorem Poly.denote_combineC {α c} [CommRing α] [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
@@ -1290,15 +1160,6 @@ 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
@@ -1306,13 +1167,6 @@ 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
@@ -1328,37 +1182,17 @@ 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
@@ -1368,6 +1202,7 @@ 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
@@ -1376,6 +1211,7 @@ 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
@@ -1384,26 +1220,32 @@ 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]
@@ -1414,6 +1256,7 @@ 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₂))
@@ -1422,6 +1265,7 @@ 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₂))
@@ -1431,6 +1275,7 @@ 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))
@@ -1439,6 +1284,7 @@ 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)))
@@ -1449,6 +1295,7 @@ 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
@@ -1458,6 +1305,7 @@ 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
@@ -1466,23 +1314,28 @@ 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
@@ -1491,9 +1344,11 @@ 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]
@@ -1501,6 +1356,7 @@ 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)
@@ -1509,6 +1365,7 @@ 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)
@@ -1518,6 +1375,7 @@ 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))
@@ -1526,6 +1384,7 @@ 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)))
@@ -1540,6 +1399,7 @@ end Stepwise
/-! IntModule interface -/
@[expose]
def Mon.denoteAsIntModule [CommRing α] (ctx : Context α) (m : Mon) : α :=
match m with
| .unit => One.one
@@ -1550,6 +1410,7 @@ 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 : α)
@@ -1650,6 +1511,7 @@ 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))
@@ -1689,6 +1551,7 @@ 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))
@@ -1708,6 +1571,7 @@ 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
@@ -1725,6 +1589,7 @@ 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))
@@ -1733,10 +1598,11 @@ 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
noncomputable def norm_int_cert (e : Expr) (p : Poly) : Bool :=
@[expose] 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 Lean.Grind.CommRing
end CommRing
end Lean.Grind

View File

@@ -126,52 +126,6 @@ structure Config where
abstractProof := true
deriving Inhabited, BEq
/--
A minimal configuration, with ematching and splitting disabled, and all solver modules turned off.
`grind` will not do anything in this configuration,
which can be used a starting point for minimal configurations.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure NoopConfig extends Config where
-- Disable splitting
splits := 0
-- We don't override the various `splitMatch` / `splitIte` settings separately.
-- Disable e-matching
ematch := 0
-- We don't override `matchEqs` separately.
-- Disable extensionality
ext := false
extAll := false
etaStruct := false
funext := false
-- Disable all solver modules
ring := false
linarith := false
cutsat := false
ac := false
/--
A `grind` configuration that only uses `cutsat` and splitting.
Note: `cutsat` benefits from some amount of instantiation, e.g. `Nat.max_def`.
We don't currently have a mechanism to enable only a small set of lemmas.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure CutsatConfig extends NoopConfig where
cutsat := true
-- Allow the default number of splits.
splits := ({} : Config).splits
/--
A `grind` configuration that only uses `ring`.
-/
-- This is a `structure` rather than `def` so we can use `declare_config_elab`.
structure GrobnerConfig extends NoopConfig where
ring := true
end Lean.Grind
namespace Lean.Parser.Tactic
@@ -180,11 +134,9 @@ namespace Lean.Parser.Tactic
`grind` tactic and related tactics.
-/
syntax grindErase := "-" ident
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
-- `!` for enabling minimal indexable subexpression restriction
syntax grindLemmaMin := ppGroup("!" (Attr.grindMod ppSpace)? ident)
syntax grindParam := grindErase <|> grindLemma <|> grindLemmaMin
syntax grindErase := "-" ident
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
syntax grindParam := grindErase <|> grindLemma
/--
`grind` is a tactic inspired by modern SMT solvers. **Picture a virtual whiteboard**:
@@ -468,23 +420,6 @@ syntax (name := grindTrace)
(" [" withoutPosition(grindParam,*) "]")?
(&" on_failure " term)? : tactic
/--
`cutsat` solves linear integer arithmetic goals.
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `cutsat` solver.
Please use `grind` instead if you need additional capabilities.
-/
syntax (name := cutsat) "cutsat" optConfig : tactic
/--
`grobner` solves goals that can be phrased as polynomial equations (with further polynomial equations as hypotheses)
over commutative (semi)rings, using the Grobner basis algorithm.
It is a implemented as a thin wrapper around the `grind` tactic, enabling only the `grobner` solver.
Please use `grind` instead if you need additional capabilities.
-/
syntax (name := grobner) "grobner" optConfig : tactic
/-!
Sets symbol priorities for the E-matching pattern inference procedure used in `grind`
-/

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.Data.Int.DivMod.Lemmas
import Init.LawfulBEqTactics
public section
@@ -38,7 +37,11 @@ inductive IntInterval : Type where
io (hi : Int)
| /-- The infinite interval `(-∞, ∞)`. -/
ii
deriving BEq, ReflBEq, LawfulBEq, DecidableEq, Inhabited
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]
namespace IntInterval

View File

@@ -1,104 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joachim Breitner
-/
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 ]
))
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]
repeat deriving_LawfulEq_tactic_step
))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -94,7 +94,7 @@ structure Config where
-/
decide : Bool := false
/--
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
When `true` (default: `false`), unfolds definitions.
This can be enabled using the `simp!` syntax.
-/
autoUnfold : Bool := false
@@ -208,7 +208,7 @@ structure Config where
/-- When `true` (default: `false`), simplifies simple arithmetic expressions. -/
arith : Bool := false
/--
When `true` (default: `false`), unfolds applications of functions defined by pattern matching, when one of the patterns applies.
When `true` (default: `false`), unfolds definitions.
This can be enabled using the `simp!` syntax.
-/
autoUnfold : Bool := false

View File

@@ -1,70 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joachim Breitner
-/
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

View File

@@ -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.
-/
meta structure Parser.Category
structure Parser.Category
namespace Parser.Category

View File

@@ -25,7 +25,7 @@ syntax bracketedExplicitBinders := "(" withoutPosition((binderIdent ppSpace)+
syntax explicitBinders := (ppSpace bracketedExplicitBinders)+ <|> unbracketedExplicitBinders
open TSyntax.Compat in
meta def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax) (type? : Option Syntax) (body : Syntax) : MacroM Syntax :=
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 @@ meta def expandExplicitBindersAux (combinator : Syntax) (idents : Array Syntax)
loop i (Nat.le_of_succ_le h) acc
loop idents.size (by simp) body
meta def expandBracketedBindersAux (combinator : Syntax) (binders : Array Syntax) (body : Syntax) : MacroM Syntax :=
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 @@ meta def expandBracketedBindersAux (combinator : Syntax) (binders : Array Syntax
loop i (Nat.le_of_succ_le h) ( expandExplicitBindersAux combinator idents (some type) acc)
loop binders.size (by simp) body
meta def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
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 @@ meta def expandExplicitBinders (combinatorDeclName : Name) (explicitBinders : Sy
else
Macro.throwError "unexpected explicit binder"
meta def expandBracketedBinders (combinatorDeclName : Name) (bracketedExplicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
def expandBracketedBinders (combinatorDeclName : Name) (bracketedExplicitBinders : Syntax) (body : Syntax) : MacroM Syntax := do
let combinator := mkCIdentFrom ( getRef) combinatorDeclName
expandBracketedBindersAux combinator #[bracketedExplicitBinders] body

View File

@@ -5125,32 +5125,12 @@ 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)
/--
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.
-/
/-- 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. -/
| symbol (val : String)
/--
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.)
-/
/-- Like `symbol`, but without reserving `val` as a keyword.
If `includeIdent` is true then `ident` will 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`. -/
@@ -5170,19 +5150,6 @@ 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 ""

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.NotationExtra
public meta import Init.Data.ToString.Name
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 meta def mkAttributeCmds
private def mkAttributeCmds
(kind : TSyntax `Lean.Parser.Term.attrKind)
(pre? : Option (TSyntax [`Lean.Parser.Tactic.simpPre, `Lean.Parser.Tactic.simpPost]))
(ids? : Option (Syntax.TSepArray `ident ","))

View File

@@ -477,7 +477,7 @@ syntax negConfigItem := " -" noWs ident
As a special case, `(config := ...)` sets the entire configuration.
-/
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") ident " := ") withoutPosition(term) ")"
syntax valConfigItem := atomic(" (" notFollowedBy(&"discharger" <|> &"disch") (ident <|> &"config")) " := " withoutPosition(term) ")"
/-- A configuration item for a tactic configuration. -/
syntax configItem := posConfigItem <|> negConfigItem <|> valConfigItem
@@ -2262,18 +2262,6 @@ 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"

View File

@@ -16,7 +16,7 @@ Extra tactics and implementation for some tactics defined at `Init/Tactic.lean`
-/
namespace Lean.Parser.Tactic
private meta def expandIfThenElse
private 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,17 +24,14 @@ private meta 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 : 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)
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))
pure (hole, #[case])
let (posHole, posCase) mkCase thenTk pos `(?pos)
let (negHole, negCase) mkCase elseTk neg `(?neg)

View File

@@ -8,7 +8,6 @@ module
prelude
public import Lean.CoreM
public import Lean.MonadEnv
public import Lean.Compiler.MetaAttr
public section
@@ -142,15 +141,6 @@ 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
/--
@@ -230,35 +220,26 @@ end TagAttribute
contains the attribute `pAttr` with parameter `p`. -/
structure ParametricAttribute (α : Type) where
attr : AttributeImpl
ext : PersistentEnvExtension (Name × α) (Name × α) (List Name × NameMap α)
preserveOrder : Bool
ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α)
deriving Inhabited
structure ParametricAttributeImpl (α : Type) extends AttributeImplCore where
getParam : Name Syntax AttrM α
afterSet : Name α AttrM Unit := fun _ _ _ => pure ()
afterImport : Array (Array (Name × α)) ImportM Unit := fun _ => pure ()
/--
If set, entries are not resorted on export and `getParam?` will fall back to a linear instead of
binary search insde an imported module's entries.
-/
preserveOrder : Bool := false
def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (ParametricAttribute α) := do
let ext : PersistentEnvExtension (Name × α) (Name × α) (List Name × NameMap α) registerPersistentEnvExtension {
let ext : PersistentEnvExtension (Name × α) (Name × α) (NameMap α) registerPersistentEnvExtension {
name := impl.ref
mkInitial := pure ([], {})
addImportedFn := fun s => impl.afterImport s *> pure ([], {})
addEntryFn := fun (decls, m) (p : Name × α) => (p.1 :: decls, m.insert p.1 p.2)
exportEntriesFnEx := fun env (decls, m) _ =>
let r := if impl.preserveOrder then
decls.toArray.reverse.filterMap (fun n => return (n, m.find? n))
else
m.foldl (fun a n p => a.push (n, p)) #[]
-- Do not export info for private defs
mkInitial := pure {}
addImportedFn := fun s => impl.afterImport s *> pure {}
addEntryFn := fun (s : NameMap α) (p : Name × α) => s.insert p.1 p.2
exportEntriesFnEx := fun env m _ =>
let r : Array (Name × α) := m.foldl (fun a n p => a.push (n, p)) #[]
-- Do not export info for private defs
let r := r.filter (env.contains (skipRealize := false) ·.1)
r.qsort (fun a b => Name.quickLt a.1 b.1)
statsFn := fun (_, m) => "parametric attribute" ++ Format.line ++ "number of local entries: " ++ format m.size
statsFn := fun s => "parametric attribute" ++ Format.line ++ "number of local entries: " ++ format s.size
}
let attrImpl : AttributeImpl := {
impl.toAttributeImplCore with
@@ -272,26 +253,22 @@ def registerParametricAttribute (impl : ParametricAttributeImpl α) : IO (Parame
try impl.afterSet decl val catch _ => setEnv env
}
registerBuiltinAttribute attrImpl
pure { attr := attrImpl, ext, preserveOrder := impl.preserveOrder }
pure { attr := attrImpl, ext := ext }
namespace ParametricAttribute
def getParam? [Inhabited α] (attr : ParametricAttribute α) (env : Environment) (decl : Name) : Option α :=
match env.getModuleIdxFor? decl with
| some modIdx =>
let entry? := if attr.preserveOrder then
(attr.ext.getModuleEntries env modIdx).find? (·.1 == decl)
else
(attr.ext.getModuleEntries env modIdx).binSearch (decl, default) (fun a b => Name.quickLt a.1 b.1)
match entry? with
match (attr.ext.getModuleEntries env modIdx).binSearch (decl, default) (fun a b => Name.quickLt a.1 b.1) with
| some (_, val) => some val
| none => none
| none => (attr.ext.getState env).2.find? decl
| none => (attr.ext.getState env).find? decl
def setParam (attr : ParametricAttribute α) (env : Environment) (decl : Name) (param : α) : Except String Environment :=
if (env.getModuleIdxFor? decl).isSome then
Except.error (s!"Failed to add parametric attribute `[{attr.attr.name}]` to `{decl}`: Declaration is in an imported module")
else if ((attr.ext.getState env).2.find? decl).isSome then
else if ((attr.ext.getState env).find? decl).isSome then
Except.error (s!"Failed to add parametric attribute `[{attr.attr.name}]` to `{decl}`: Attribute has already been set")
else
Except.ok (attr.ext.addEntry env (decl, param))

View File

@@ -34,7 +34,6 @@ builtin_initialize
add := fun decl stx _ => do
Attribute.Builtin.ensureNoArgs stx
declareBuiltinDocStringAndRanges decl
applicationTime := AttributeApplicationTime.afterCompilation
}
end Lean

View File

@@ -62,7 +62,6 @@ 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

View File

@@ -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) (includeDecls := false) : Array Name :=
private def getIRExtraConstNames (env : Environment) (level : OLeanLevel) : Array Name :=
declMapExt.getEntries env |>.toArray.map (·.name)
|>.filter fun n => (includeDecls || !env.contains n) &&
|>.filter fun n => !env.contains n &&
(level == .private || Compiler.LCNF.isDeclPublic env n || isDeclMeta env n)
end IR

View File

@@ -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 isMeta ( getEnv) decl.name then
if metaExt.isTagged ( 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

Some files were not shown because too many files have changed in this diff Show More